|
@@ -69,6 +69,16 @@
|
|
|
<a-form :model="formModel" :label-col-props="{ span: 6 }" :wrapper-col-props="{ span: 18 }"
|
|
<a-form :model="formModel" :label-col-props="{ span: 6 }" :wrapper-col-props="{ span: 18 }"
|
|
|
label-align="left">
|
|
label-align="left">
|
|
|
<a-row :gutter="16">
|
|
<a-row :gutter="16">
|
|
|
|
|
+ <a-col :span="6">
|
|
|
|
|
+ <a-form-item field="channels" label="渠道">
|
|
|
|
|
+ <a-select v-model="formModel.channels" multiple allow-clear placeholder="全部渠道"
|
|
|
|
|
+ @change="search">
|
|
|
|
|
+ <a-option v-for="item in channelOptions" :key="item.value" :value="item.value">
|
|
|
|
|
+ {{ item.label }}
|
|
|
|
|
+ </a-option>
|
|
|
|
|
+ </a-select>
|
|
|
|
|
+ </a-form-item>
|
|
|
|
|
+ </a-col>
|
|
|
<a-col :span="6">
|
|
<a-col :span="6">
|
|
|
<a-form-item field="bucket_type" label="统计粒度">
|
|
<a-form-item field="bucket_type" label="统计粒度">
|
|
|
<a-select v-model="formModel.bucket_type" @change="search">
|
|
<a-select v-model="formModel.bucket_type" @change="search">
|
|
@@ -130,6 +140,11 @@
|
|
|
<a-table row-key="redis_key" :loading="loading" :pagination="pagination" :columns="columns"
|
|
<a-table row-key="redis_key" :loading="loading" :pagination="pagination" :columns="columns"
|
|
|
:data="renderData" :bordered="{ headerCell: true }" size="small" @page-change="onPageChange"
|
|
:data="renderData" :bordered="{ headerCell: true }" size="small" @page-change="onPageChange"
|
|
|
@page-size-change="onPageSizeChange">
|
|
@page-size-change="onPageSizeChange">
|
|
|
|
|
+ <template #channel="{ record }">
|
|
|
|
|
+ <a-tag :color="channelColorMap[record.channel] || 'gray'">
|
|
|
|
|
+ {{ channelLabelMap[record.channel] || record.channel }}
|
|
|
|
|
+ </a-tag>
|
|
|
|
|
+ </template>
|
|
|
<template #bucket_type="{ record }">
|
|
<template #bucket_type="{ record }">
|
|
|
<a-tag :color="bucketColorMap[record.bucket_type] || 'gray'">
|
|
<a-tag :color="bucketColorMap[record.bucket_type] || 'gray'">
|
|
|
{{ bucketLabelMap[record.bucket_type] || record.bucket_type }}
|
|
{{ bucketLabelMap[record.bucket_type] || record.bucket_type }}
|
|
@@ -172,6 +187,19 @@ const bucketColorMap: Record<string, string> = {
|
|
|
month: 'orange',
|
|
month: 'orange',
|
|
|
year: 'purple',
|
|
year: 'purple',
|
|
|
};
|
|
};
|
|
|
|
|
+const defaultChannels = ['xhs', 'ks'];
|
|
|
|
|
+const channelOptions = [
|
|
|
|
|
+ { label: '小红书', value: 'xhs' },
|
|
|
|
|
+ { label: '快手', value: 'ks' },
|
|
|
|
|
+];
|
|
|
|
|
+const channelLabelMap: Record<string, string> = {
|
|
|
|
|
+ xhs: '小红书',
|
|
|
|
|
+ ks: '快手',
|
|
|
|
|
+};
|
|
|
|
|
+const channelColorMap: Record<string, string> = {
|
|
|
|
|
+ xhs: 'red',
|
|
|
|
|
+ ks: 'blue',
|
|
|
|
|
+};
|
|
|
|
|
|
|
|
const { loading, setLoading } = useLoading(false);
|
|
const { loading, setLoading } = useLoading(false);
|
|
|
const renderData = ref<XhsZlongForwardReportRecord[]>([]);
|
|
const renderData = ref<XhsZlongForwardReportRecord[]>([]);
|
|
@@ -188,6 +216,7 @@ const summary = ref<XhsZlongForwardReportSummary>({
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
const formModel = reactive({
|
|
const formModel = reactive({
|
|
|
|
|
+ channels: [...defaultChannels],
|
|
|
bucket_type: 'day',
|
|
bucket_type: 'day',
|
|
|
});
|
|
});
|
|
|
|
|
|
|
@@ -209,13 +238,41 @@ const pagination = reactive({
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
const toNumber = (value: unknown) => Number(value || 0);
|
|
const toNumber = (value: unknown) => Number(value || 0);
|
|
|
|
|
+const normalizeChannels = (channels?: string[]) => {
|
|
|
|
|
+ const list = (channels || [])
|
|
|
|
|
+ .map((item) => String(item || '').trim().toLowerCase())
|
|
|
|
|
+ .filter((item) => defaultChannels.includes(item));
|
|
|
|
|
+
|
|
|
|
|
+ return list.length > 0 ? Array.from(new Set(list)) : [...defaultChannels];
|
|
|
|
|
+};
|
|
|
|
|
+const buildChannelsValue = (channels?: string[]) => normalizeChannels(channels).join(',');
|
|
|
const normalizeRecord = (item: XhsZlongForwardReportRecord): XhsZlongForwardReportRecord => ({
|
|
const normalizeRecord = (item: XhsZlongForwardReportRecord): XhsZlongForwardReportRecord => ({
|
|
|
...item,
|
|
...item,
|
|
|
|
|
+ channel: String(item.channel || '').toLowerCase(),
|
|
|
total: toNumber(item.total),
|
|
total: toNumber(item.total),
|
|
|
exception_count: toNumber(item.exception_count),
|
|
exception_count: toNumber(item.exception_count),
|
|
|
});
|
|
});
|
|
|
const sortedChartData = computed(() => {
|
|
const sortedChartData = computed(() => {
|
|
|
- return [...chartData.value].sort((left, right) => {
|
|
|
|
|
|
|
+ const grouped = new Map<string, XhsZlongForwardReportRecord>();
|
|
|
|
|
+
|
|
|
|
|
+ chartData.value.forEach((item) => {
|
|
|
|
|
+ const key = String(item.report_time || item.display_time || '');
|
|
|
|
|
+ const current = grouped.get(key);
|
|
|
|
|
+
|
|
|
|
|
+ if (current) {
|
|
|
|
|
+ current.total += toNumber(item.total);
|
|
|
|
|
+ current.exception_count += toNumber(item.exception_count);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ grouped.set(key, {
|
|
|
|
|
+ ...item,
|
|
|
|
|
+ total: toNumber(item.total),
|
|
|
|
|
+ exception_count: toNumber(item.exception_count),
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ return Array.from(grouped.values()).sort((left, right) => {
|
|
|
return new Date(left.report_time).getTime() - new Date(right.report_time).getTime();
|
|
return new Date(left.report_time).getTime() - new Date(right.report_time).getTime();
|
|
|
});
|
|
});
|
|
|
});
|
|
});
|
|
@@ -316,6 +373,11 @@ const { chartOption } = useChartOption(() => ({
|
|
|
}));
|
|
}));
|
|
|
|
|
|
|
|
const columns = computed<TableColumnData[]>(() => [
|
|
const columns = computed<TableColumnData[]>(() => [
|
|
|
|
|
+ {
|
|
|
|
|
+ title: '渠道',
|
|
|
|
|
+ slotName: 'channel',
|
|
|
|
|
+ width: 110,
|
|
|
|
|
+ },
|
|
|
{
|
|
{
|
|
|
title: '统计粒度',
|
|
title: '统计粒度',
|
|
|
slotName: 'bucket_type',
|
|
slotName: 'bucket_type',
|
|
@@ -342,6 +404,7 @@ const buildParams = (current = 1, pageSize = pagination.pageSize): XhsZlongForwa
|
|
|
return {
|
|
return {
|
|
|
current,
|
|
current,
|
|
|
pageSize,
|
|
pageSize,
|
|
|
|
|
+ channels: buildChannelsValue(formModel.channels),
|
|
|
bucket_type: formModel.bucket_type,
|
|
bucket_type: formModel.bucket_type,
|
|
|
start: dateRange.value?.[0] || undefined,
|
|
start: dateRange.value?.[0] || undefined,
|
|
|
end: dateRange.value?.[1] || undefined,
|
|
end: dateRange.value?.[1] || undefined,
|