Browse Source

🥅 perf: 数据趋势图组件代码优化

WanGxC 10 months ago
parent
commit
07d7053520

+ 44 - 68
src/views/adManage/sb/chartComponents/dataTendency.vue

@@ -181,6 +181,16 @@ onMounted(() => {
   }, 0);
 });
 
+watch(props.query, async () => {
+  // console.log("------watch-----queryParams", props.query)
+  loading.value = true;
+  await getMetricsItems();
+  const items = await getDataset();
+  const opt = { dataset: { source: items } };
+  chartObj.setOption(opt);
+  loading.value = false;
+});
+
 onBeforeUnmount(() => {
   if (chartObj) {
     chartObj.dispose();
@@ -189,15 +199,37 @@ onBeforeUnmount(() => {
   removeResize();
 });
 
-const metricColors = {
-  Impression: '#0085ff',
-  Click: '#3fd4cf',
-  Spend: '#ff9500',
-  // ... 其他指标的颜色
-};
+async function getDataset() {
+  if (statDim.value === 'week') {
+    if (props.fetchLineWeek) {
+      const resp = await props.fetchLineWeek(queryParams.value);
+      return resp.data;
+    }
+  } else if (statDim.value === 'month') {
+    if (props.fetchLineMonth) {
+      const resp = await props.fetchLineMonth(queryParams.value);
+      return resp.data;
+    }
+  } else {
+    const resp = await props.fetchLine(queryParams.value);
+    return resp.data;
+  }
+}
 
-function getColorForMetric(metric: string): string {
-  return metricColors[metric] || '#999999'; // 如果没有预定义的颜色,返回一个默认颜色
+async function getMetricsItems() {
+  const resp = await props.fetchCard(queryParams.value);
+  const data = resp.data;
+  metricsItems.value.length = 0;
+  XEUtils.arrayEach(props.metricEnum, (info) => {
+    const tmp: MetricData = {
+      label: info.label,
+      value: info.value,
+      metricVal: data[info.value],
+      gapVal: data[`gap${info.value}`],
+      preVal: data[`prev${info.value}`],
+    };
+    metricsItems.value.push(tmp);
+  });
 }
 
 async function initLine() {
@@ -239,7 +271,7 @@ async function initLine() {
   }));
 
   // 初始化图例
-  option.legend.selected = props.metricEnum.reduce((acc, metric) => {
+  option.legend.selected = props.metricEnum.reduce((acc: any, metric) => {
     acc[metric.label] = metrics.value.some((m) => m.metric === metric.value);
     return acc;
   }, {});
@@ -248,54 +280,16 @@ async function initLine() {
   loading.value = false;
 }
 
-async function getDataset() {
-  if (statDim.value === 'week') {
-    if (props.fetchLineWeek) {
-      const resp = await props.fetchLineWeek(queryParams.value);
-      return resp.data;
-    }
-  } else if (statDim.value === 'month') {
-    if (props.fetchLineMonth) {
-      const resp = await props.fetchLineMonth(queryParams.value);
-      return resp.data;
-    }
-  } else {
-    const resp = await props.fetchLine(queryParams.value);
-    return resp.data;
-  }
-}
-
-async function getMetricsItems() {
-  const resp = await props.fetchCard(queryParams.value);
-  const data = resp.data;
-  metricsItems.value.length = 0;
-  XEUtils.arrayEach(props.metricEnum, (info) => {
-    const tmp: MetricData = {
-      label: info.label,
-      value: info.value,
-      metricVal: data[info.value],
-      gapVal: data[`gap${info.value}`],
-      preVal: data[`prev${info.value}`],
-    };
-    metricsItems.value.push(tmp);
-  });
-}
-
-// const changeMetric = () => {
-//   const opt = buildChartOpt(option, metrics.value)
-//   chartObj.setOption(opt)
-// }
-
 function changeMetric() {
   // 更新图例选中状态
-  option.legend.selected = props.metricEnum.reduce((acc, metric) => {
+  option.legend.selected = props.metricEnum.reduce((acc: any, metric) => {
     acc[metric.label] = metrics.value.some((m) => m.metric === metric.value);
     return acc;
   }, {});
 
   // 重新创建 series 数组,只包含选中的指标
   option.series = metrics.value.map((metric, index) => {
-    const baseConfig = {
+    const baseConfig: any = {
       id: index,
       name: metric.label,
       type: metric.color === '#0085ff' ? 'bar' : 'line',
@@ -306,7 +300,7 @@ function changeMetric() {
       barWidth: '10%',
     };
 
-    if (baseConfig != 'bar') {
+    if (baseConfig.type != 'bar') {
       baseConfig.areaStyle = {
         color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
           { offset: 0, color: metric.color + '53' },
@@ -343,14 +337,6 @@ function changeMetric() {
   chartObj.setOption(option, true); // 使用 true 作为第二个参数,强制完全刷新
 }
 
-watch(
-  metrics,
-  () => {
-    changeMetric();
-  },
-  { deep: true }
-);
-
 async function changeStatDim() {
   loading.value = true;
   let source = await getDataset();
@@ -360,16 +346,6 @@ async function changeStatDim() {
   loading.value = false;
 }
 
-watch(props.query, async () => {
-  // console.log("------watch-----queryParams", props.query)
-  loading.value = true;
-  await getMetricsItems();
-  const items = await getDataset();
-  const opt = { dataset: { source: items } };
-  chartObj.setOption(opt);
-  loading.value = false;
-});
-
 function resizeChart() {
   chartObj.resize();
 }

+ 49 - 72
src/views/adManage/sd/chartComponents/dataTendency.vue

@@ -116,7 +116,7 @@ const option: any = {
         x: 'Name',
         y: '',
       },
-      barWidth: '18px',
+      barWidth: '16px',
       yAxisIndex: 0,
       itemStyle: {
         color: '',
@@ -189,15 +189,47 @@ onBeforeUnmount(() => {
   removeResize();
 });
 
-const metricColors = {
-  Impression: '#0085ff',
-  Click: '#3fd4cf',
-  Spend: '#ff9500',
-  // ... 其他指标的颜色
-};
+watch(props.query, async () => {
+  // console.log("------watch-----queryParams", props.query)
+  loading.value = true;
+  await getMetricsItems();
+  const items = await getDataset();
+  const opt = { dataset: { source: items } };
+  chartObj.setOption(opt);
+  loading.value = false;
+});
+
+async function getDataset() {
+  if (statDim.value === 'week') {
+    if (props.fetchLineWeek) {
+      const resp = await props.fetchLineWeek(queryParams.value);
+      return resp.data;
+    }
+  } else if (statDim.value === 'month') {
+    if (props.fetchLineMonth) {
+      const resp = await props.fetchLineMonth(queryParams.value);
+      return resp.data;
+    }
+  } else {
+    const resp = await props.fetchLine(queryParams.value);
+    return resp.data;
+  }
+}
 
-function getColorForMetric(metric: string): string {
-  return metricColors[metric] || '#999999'; // 如果没有预定义的颜色,返回一个默认颜色
+async function getMetricsItems() {
+  const resp = await props.fetchCard(queryParams.value);
+  const data = resp.data;
+  metricsItems.value.length = 0;
+  XEUtils.arrayEach(props.metricEnum, (info) => {
+    const tmp: MetricData = {
+      label: info.label,
+      value: info.value,
+      metricVal: data[info.value],
+      gapVal: data[`gap${info.value}`],
+      preVal: data[`prev${info.value}`],
+    };
+    metricsItems.value.push(tmp);
+  });
 }
 
 async function initLine() {
@@ -213,7 +245,7 @@ async function initLine() {
     yAxisIndex: index,
     itemStyle: { color: option.series.type == 'bar' ? '#0085ff' : metric.color, borderRadius: [6, 6, 6, 6] },
     lineStyle: { color: metric.color },
-    barWidth: '10%',
+    barWidth: '16px',
     areaStyle:
       index !== 0
         ? {
@@ -239,7 +271,7 @@ async function initLine() {
   }));
 
   // 初始化图例
-  option.legend.selected = props.metricEnum.reduce((acc, metric) => {
+  option.legend.selected = props.metricEnum.reduce((acc: any, metric) => {
     acc[metric.label] = metrics.value.some((m) => m.metric === metric.value);
     return acc;
   }, {});
@@ -248,54 +280,16 @@ async function initLine() {
   loading.value = false;
 }
 
-async function getDataset() {
-  if (statDim.value === 'week') {
-    if (props.fetchLineWeek) {
-      const resp = await props.fetchLineWeek(queryParams.value);
-      return resp.data;
-    }
-  } else if (statDim.value === 'month') {
-    if (props.fetchLineMonth) {
-      const resp = await props.fetchLineMonth(queryParams.value);
-      return resp.data;
-    }
-  } else {
-    const resp = await props.fetchLine(queryParams.value);
-    return resp.data;
-  }
-}
-
-async function getMetricsItems() {
-  const resp = await props.fetchCard(queryParams.value);
-  const data = resp.data;
-  metricsItems.value.length = 0;
-  XEUtils.arrayEach(props.metricEnum, (info) => {
-    const tmp: MetricData = {
-      label: info.label,
-      value: info.value,
-      metricVal: data[info.value],
-      gapVal: data[`gap${info.value}`],
-      preVal: data[`prev${info.value}`],
-    };
-    metricsItems.value.push(tmp);
-  });
-}
-
-// const changeMetric = () => {
-//   const opt = buildChartOpt(option, metrics.value)
-//   chartObj.setOption(opt)
-// }
-
 function changeMetric() {
   // 更新图例选中状态
-  option.legend.selected = props.metricEnum.reduce((acc, metric) => {
+  option.legend.selected = props.metricEnum.reduce((acc: any, metric) => {
     acc[metric.label] = metrics.value.some((m) => m.metric === metric.value);
     return acc;
   }, {});
 
   // 重新创建 series 数组,只包含选中的指标
   option.series = metrics.value.map((metric, index) => {
-    const baseConfig = {
+    const baseConfig: any = {
       id: index,
       name: metric.label,
       type: metric.color === '#0085ff' ? 'bar' : 'line',
@@ -303,10 +297,10 @@ function changeMetric() {
       yAxisIndex: index,
       itemStyle: { color: metric.color, borderRadius: [6, 6, 6, 6] },
       lineStyle: { color: metric.color },
-      barWidth: '10%',
+      barWidth: '16px',
     };
 
-    if (baseConfig != 'bar') {
+    if (baseConfig.type != 'bar') {
       baseConfig.areaStyle = {
         color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
           { offset: 0, color: metric.color + '53' },
@@ -343,31 +337,14 @@ function changeMetric() {
   chartObj.setOption(option, true); // 使用 true 作为第二个参数,强制完全刷新
 }
 
-watch(
-  metrics,
-  () => {
-    changeMetric();
-  },
-  { deep: true }
-);
-const changeStatDim = async () => {
+async function changeStatDim() {
   loading.value = true;
   let source = await getDataset();
   if (source.length > 0) {
     chartObj.setOption({ dataset: { source: source } });
   }
   loading.value = false;
-};
-
-watch(props.query, async () => {
-  // console.log("------watch-----queryParams", props.query)
-  loading.value = true;
-  await getMetricsItems();
-  const items = await getDataset();
-  const opt = { dataset: { source: items } };
-  chartObj.setOption(opt);
-  loading.value = false;
-});
+}
 
 function resizeChart() {
   chartObj.resize();

+ 47 - 71
src/views/adManage/sp/chartComponents/dataTendency.vue

@@ -116,7 +116,7 @@ const option: any = {
         x: 'Name',
         y: '',
       },
-      barWidth: '18px',
+      barWidth: '186px',
       yAxisIndex: 0,
       itemStyle: {
         color: '',
@@ -189,15 +189,47 @@ onBeforeUnmount(() => {
   removeResize();
 });
 
-const metricColors = {
-  Impression: '#0085ff',
-  Click: '#3fd4cf',
-  Spend: '#ff9500',
-  // ... 其他指标的颜色
-};
+watch(props.query, async () => {
+  // console.log("------watch-----queryParams", props.query)
+  loading.value = true;
+  await getMetricsItems();
+  const items = await getDataset();
+  const opt = { dataset: { source: items } };
+  chartObj.setOption(opt);
+  loading.value = false;
+});
+
+async function getDataset() {
+  if (statDim.value === 'week') {
+    if (props.fetchLineWeek) {
+      const resp = await props.fetchLineWeek(queryParams.value);
+      return resp.data;
+    }
+  } else if (statDim.value === 'month') {
+    if (props.fetchLineMonth) {
+      const resp = await props.fetchLineMonth(queryParams.value);
+      return resp.data;
+    }
+  } else {
+    const resp = await props.fetchLine(queryParams.value);
+    return resp.data;
+  }
+}
 
-function getColorForMetric(metric: string): string {
-  return metricColors[metric] || '#999999'; // 如果没有预定义的颜色,返回一个默认颜色
+async function getMetricsItems() {
+  const resp = await props.fetchCard(queryParams.value);
+  const data = resp.data;
+  metricsItems.value.length = 0;
+  XEUtils.arrayEach(props.metricEnum, (info) => {
+    const tmp: MetricData = {
+      label: info.label,
+      value: info.value,
+      metricVal: data[info.value],
+      gapVal: data[`gap${info.value}`],
+      preVal: data[`prev${info.value}`],
+    };
+    metricsItems.value.push(tmp);
+  });
 }
 
 async function initLine() {
@@ -213,7 +245,7 @@ async function initLine() {
     yAxisIndex: index,
     itemStyle: { color: option.series.type == 'bar' ? '#0085ff' : metric.color, borderRadius: [6, 6, 6, 6] },
     lineStyle: { color: metric.color },
-    barWidth: '10%',
+    barWidth: '16px',
     areaStyle:
       index !== 0
         ? {
@@ -239,7 +271,7 @@ async function initLine() {
   }));
 
   // 初始化图例
-  option.legend.selected = props.metricEnum.reduce((acc, metric) => {
+  option.legend.selected = props.metricEnum.reduce((acc: any, metric) => {
     acc[metric.label] = metrics.value.some((m) => m.metric === metric.value);
     return acc;
   }, {});
@@ -248,54 +280,16 @@ async function initLine() {
   loading.value = false;
 }
 
-async function getDataset() {
-  if (statDim.value === 'week') {
-    if (props.fetchLineWeek) {
-      const resp = await props.fetchLineWeek(queryParams.value);
-      return resp.data;
-    }
-  } else if (statDim.value === 'month') {
-    if (props.fetchLineMonth) {
-      const resp = await props.fetchLineMonth(queryParams.value);
-      return resp.data;
-    }
-  } else {
-    const resp = await props.fetchLine(queryParams.value);
-    return resp.data;
-  }
-}
-
-async function getMetricsItems() {
-  const resp = await props.fetchCard(queryParams.value);
-  const data = resp.data;
-  metricsItems.value.length = 0;
-  XEUtils.arrayEach(props.metricEnum, (info) => {
-    const tmp: MetricData = {
-      label: info.label,
-      value: info.value,
-      metricVal: data[info.value],
-      gapVal: data[`gap${info.value}`],
-      preVal: data[`prev${info.value}`],
-    };
-    metricsItems.value.push(tmp);
-  });
-}
-
-// const changeMetric = () => {
-//   const opt = buildChartOpt(option, metrics.value)
-//   chartObj.setOption(opt)
-// }
-
 function changeMetric() {
   // 更新图例选中状态
-  option.legend.selected = props.metricEnum.reduce((acc, metric) => {
+  option.legend.selected = props.metricEnum.reduce((acc: any, metric) => {
     acc[metric.label] = metrics.value.some((m) => m.metric === metric.value);
     return acc;
   }, {});
 
   // 重新创建 series 数组,只包含选中的指标
   option.series = metrics.value.map((metric, index) => {
-    const baseConfig = {
+    const baseConfig: any = {
       id: index,
       name: metric.label,
       type: metric.color === '#0085ff' ? 'bar' : 'line',
@@ -303,10 +297,10 @@ function changeMetric() {
       yAxisIndex: index,
       itemStyle: { color: metric.color, borderRadius: [6, 6, 6, 6] },
       lineStyle: { color: metric.color },
-      barWidth: '10%',
+      barWidth: '16px',
     };
 
-    if (baseConfig != 'bar') {
+    if (baseConfig.type != 'bar') {
       baseConfig.areaStyle = {
         color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
           { offset: 0, color: metric.color + '53' },
@@ -343,14 +337,6 @@ function changeMetric() {
   chartObj.setOption(option, true); // 使用 true 作为第二个参数,强制完全刷新
 }
 
-watch(
-  metrics,
-  () => {
-    changeMetric();
-  },
-  { deep: true }
-);
-
 async function changeStatDim() {
   loading.value = true;
   let source = await getDataset();
@@ -360,16 +346,6 @@ async function changeStatDim() {
   loading.value = false;
 }
 
-watch(props.query, async () => {
-  // console.log("------watch-----queryParams", props.query)
-  loading.value = true;
-  await getMetricsItems();
-  const items = await getDataset();
-  const opt = { dataset: { source: items } };
-  chartObj.setOption(opt);
-  loading.value = false;
-});
-
 function resizeChart() {
   chartObj.resize();
 }

+ 22 - 30
src/views/productCenter/productAnalysis/components/DateTendency/index.vue

@@ -12,13 +12,12 @@
 
 <script lang="ts" setup>
 import * as echarts from 'echarts';
-import { Ref, computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';
+import { computed, onBeforeUnmount, onMounted, Ref, ref, watch } from 'vue';
 import { productListMetricsEnum } from '/@/views/productCenter/productList/utils/enum';
-// import MetricsCards from '/@/components/MetricsCards/index.vue'
 import XEUtils from 'xe-utils';
 import MetricsCards from '../MetricsCards/index.vue';
 import emitter from '/@/utils/emitter';
-import { buildChartOpt, parseQueryParams } from '/@/views/adManage/utils/tools.js';
+import { parseQueryParams } from '/@/views/adManage/utils/tools.js';
 
 defineOptions({
   name: 'DataTendencyChart',
@@ -153,7 +152,7 @@ const option: any = {
         x: 'Name',
         y: '',
       },
-      barWidth: '18px',
+      barWidth: '16px',
       yAxisIndex: 0,
       itemStyle: {
         color: '',
@@ -238,6 +237,7 @@ onMounted(() => {
     initLine();
   }, 0);
 });
+
 onBeforeUnmount(() => {
   if (chartObj) {
     chartObj.dispose();
@@ -246,6 +246,18 @@ onBeforeUnmount(() => {
   removeResize();
 });
 
+watch(props.query, async () => {
+  // console.log("------watch-----queryParams", props.query)
+  emitter.emit('DateTendency-changeStatDim'); // 触发DataTable的loading
+  loading.value = true;
+  await getMetricsItems();
+  const items = await getDataset();
+  emit('changeStatDim', items); // 向父组件传递数据后再传递给DataTable
+  const opt = { dataset: { source: items } };
+  chartObj.setOption(opt);
+  loading.value = false;
+});
+
 // const initLine = async () => {
 //   chartObj = echarts.init(chartRef.value)
 //   const items = await getDataset()
@@ -299,7 +311,7 @@ async function initLine() {
     yAxisIndex: index,
     itemStyle: { color: index === 0 ? '#0085ff' : metric.color, borderRadius: [6, 6, 6, 6] },
     lineStyle: { color: metric.color },
-    barWidth: '10%',
+    barWidth: '16px',
     areaStyle:
       index !== 0
         ? {
@@ -328,7 +340,7 @@ async function initLine() {
   }));
 
   // 初始化图例
-  option.legend.selected = props.metricEnum.reduce((acc, metric) => {
+  option.legend.selected = props.metricEnum.reduce((acc: any, metric) => {
     acc[metric.label] = limitedMetrics.some((m) => m.metric === metric.value);
     return acc;
   }, {});
@@ -341,14 +353,14 @@ async function initLine() {
 function changeMetric() {
   const limitedMetrics = metrics.value.slice(0, 3);
   // 更新图例选中状态
-  option.legend.selected = props.metricEnum.reduce((acc, metric) => {
+  option.legend.selected = props.metricEnum.reduce((acc: any, metric) => {
     acc[metric.label] = metrics.value.some((m) => m.metric === metric.value);
     return acc;
   }, {});
 
   // 重新创建 series 数组,只包含选中的指标
   option.series = limitedMetrics.map((metric, index) => {
-    const baseConfig = {
+    const baseConfig: any = {
       id: index,
       name: metric.label,
       type: metric.color === '#0085ff' ? 'bar' : 'line',
@@ -356,10 +368,10 @@ function changeMetric() {
       yAxisIndex: index,
       itemStyle: { color: metric.color, borderRadius: [6, 6, 6, 6] },
       lineStyle: { color: metric.color },
-      barWidth: '10%',
+      barWidth: '16px',
     };
 
-    if (baseConfig != 'bar') {
+    if (baseConfig.type != 'bar') {
       baseConfig.areaStyle = {
         color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
           { offset: 0, color: metric.color + '53' },
@@ -429,14 +441,6 @@ async function getMetricsItems() {
   });
 }
 
-watch(
-    metrics,
-    () => {
-      changeMetric();
-    },
-    { deep: true }
-);
-
 const emit = defineEmits(['changeStatDim']);
 
 async function changeStatDim() {
@@ -450,18 +454,6 @@ async function changeStatDim() {
   emit('changeStatDim', source); // 向父组件传递数据后再传递给DataTable
 }
 
-watch(props.query, async () => {
-  // console.log("------watch-----queryParams", props.query)
-  emitter.emit('DateTendency-changeStatDim'); // 触发DataTable的loading
-  loading.value = true;
-  await getMetricsItems();
-  const items = await getDataset();
-  emit('changeStatDim', items); // 向父组件传递数据后再传递给DataTable
-  const opt = { dataset: { source: items } };
-  chartObj.setOption(opt);
-  loading.value = false;
-});
-
 function resizeChart() {
   chartObj.resize();
 }

+ 28 - 55
src/views/productCenter/productList/components/DateTendency/index.vue

@@ -11,16 +11,13 @@
 </template>
 
 <script lang="ts" setup>
-import { ref, onMounted, onBeforeUnmount, Ref, unref, watch, computed } from 'vue'
-import * as echarts from 'echarts'
-import { productListMetricsEnum } from '/@/views/productCenter/productList/utils/enum'
-// import MetricsCards from '/@/components/MetricsCards/index.vue'
-import MetricsCards from '../MetricsCards/index.vue'
-import XEUtils from 'xe-utils'
-import { buildChartOpt, parseQueryParams } from '/@/views/adManage/utils/tools.js'
+import { computed, onBeforeUnmount, onMounted, Ref, ref, watch } from 'vue';
+import * as echarts from 'echarts';
+import MetricsCards from '../MetricsCards/index.vue';
+import XEUtils from 'xe-utils';
+import { parseQueryParams } from '/@/views/adManage/utils/tools.js';
 import { spCampaignMetricsEnum } from '/@/views/adManage/utils/enum';
 
-
 defineOptions({
   name: 'DataTendencyChart',
 });
@@ -131,7 +128,7 @@ const option: any = {
         x: 'Name',
         y: '',
       },
-      barWidth: '18px',
+      barWidth: '16px',
       yAxisIndex: 0,
       itemStyle: {
         color: '',
@@ -204,16 +201,15 @@ onBeforeUnmount(() => {
   removeResize();
 });
 
-const metricColors = {
-  Impression: '#0085ff',
-  Click: '#3fd4cf',
-  Spend: '#ff9500',
-  // ... 其他指标的颜色
-};
-
-function getColorForMetric(metric: string): string {
-  return metricColors[metric] || '#999999'; // 如果没有预定义的颜色,返回一个默认颜色
-}
+watch(props.query, async () => {
+  // console.log("------watch-----queryParams", props.query)
+  loading.value = true;
+  await getMetricsItems();
+  const items = await getDataset();
+  const opt = { dataset: { source: items } };
+  chartObj.setOption(opt);
+  loading.value = false;
+});
 
 async function initLine() {
   chartObj = echarts.init(chartRef.value);
@@ -228,16 +224,16 @@ async function initLine() {
     yAxisIndex: index,
     itemStyle: { color: option.series.type == 'bar' ? '#0085ff' : metric.color, borderRadius: [6, 6, 6, 6] },
     lineStyle: { color: metric.color },
-    barWidth: '10%',
+    barWidth: '16px',
     areaStyle:
-        index !== 0
-            ? {
-              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
-                { offset: 0, color: metric.color + '53' },
-                { offset: 1, color: metric.color + '03' },
-              ]),
-            }
-            : undefined,
+      index !== 0
+        ? {
+            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+              { offset: 0, color: metric.color + '53' },
+              { offset: 1, color: metric.color + '03' },
+            ]),
+          }
+        : undefined,
   }));
 
   option.yAxis = metrics.value.map((metric, index) => ({
@@ -254,7 +250,7 @@ async function initLine() {
   }));
 
   // 初始化图例
-  option.legend.selected = props.metricEnum.reduce((acc, metric) => {
+  option.legend.selected = props.metricEnum.reduce((acc: any, metric) => {
     acc[metric.label] = metrics.value.some((m) => m.metric === metric.value);
     return acc;
   }, {});
@@ -296,21 +292,16 @@ async function getMetricsItems() {
   });
 }
 
-// const changeMetric = () => {
-//   const opt = buildChartOpt(option, metrics.value)
-//   chartObj.setOption(opt)
-// }
-
 function changeMetric() {
   // 更新图例选中状态
-  option.legend.selected = props.metricEnum.reduce((acc, metric) => {
+  option.legend.selected = props.metricEnum.reduce((acc: any, metric) => {
     acc[metric.label] = metrics.value.some((m) => m.metric === metric.value);
     return acc;
   }, {});
 
   // 重新创建 series 数组,只包含选中的指标
   option.series = metrics.value.map((metric, index) => {
-    const baseConfig = {
+    const baseConfig: any = {
       id: index,
       name: metric.label,
       type: metric.color === '#0085ff' ? 'bar' : 'line',
@@ -318,7 +309,7 @@ function changeMetric() {
       yAxisIndex: index,
       itemStyle: { color: metric.color, borderRadius: [6, 6, 6, 6] },
       lineStyle: { color: metric.color },
-      barWidth: '10%',
+      barWidth: '16px',
     };
 
     if (baseConfig != 'bar') {
@@ -358,14 +349,6 @@ function changeMetric() {
   chartObj.setOption(option, true); // 使用 true 作为第二个参数,强制完全刷新
 }
 
-watch(
-    metrics,
-    () => {
-      changeMetric();
-    },
-    { deep: true }
-);
-
 async function changeStatDim() {
   loading.value = true;
   let source = await getDataset();
@@ -375,16 +358,6 @@ async function changeStatDim() {
   loading.value = false;
 }
 
-watch(props.query, async () => {
-  // console.log("------watch-----queryParams", props.query)
-  loading.value = true;
-  await getMetricsItems();
-  const items = await getDataset();
-  const opt = { dataset: { source: items } };
-  chartObj.setOption(opt);
-  loading.value = false;
-});
-
 function resizeChart() {
   chartObj.resize();
 }

+ 266 - 0
src/views/searchTerm/asinView/index.vue

@@ -0,0 +1,266 @@
+<script setup lang="ts">
+/**
+ * @Name: index.vue
+ * @Description: asinView
+ * @Author: Cheney
+ */
+
+import { Download, Refresh, Search } from '@element-plus/icons-vue';
+import enLocale from 'element-plus/es/locale/lang/en';
+import { usePagination } from '/@/utils/usePagination';
+import { nextTick, ref } from 'vue';
+import { marketplaceIdEnum } from '/@/utils/marketplaceIdEnum';
+import dayjs from 'dayjs';
+import { getTopSearchTermTable, postDownload } from '/@/views/searchTerm/topSearchTermTable/api';
+import { ElMessage } from 'element-plus';
+
+const { tableData, total, currentPage, pageSize, handlePageChange } = usePagination(fetchTableData);
+const marketplaceSelect = ref(marketplaceIdEnum[0].value); // 当前只有美国区 默认第一个为美国
+const marketplaceOptions = marketplaceIdEnum;
+const reportTypeSelect = ref('weekly');
+const searchTermInp = ref('');
+const asinInp = ref('');
+const tableLoading = ref(false);
+const downloadLoading = ref(false);
+const date = ref(calculateLastWeek()); // 设置默认日期为上周的周日到周六
+const dateDimension = ref(date.value[0]);
+
+/**
+ * 判断当前时间维度 并 计算起始和结束日期
+ */
+function calculateDate() {
+  if (reportTypeSelect.value === 'weekly') {
+    date.value[0] = dateDimension.value;
+    date.value[1] = calculateEndDate(dateDimension.value);
+  } else if (reportTypeSelect.value === 'monthly') {
+    const selectedMonth = dayjs(dateDimension.value);
+    date.value[0] = selectedMonth.startOf('month').format('YYYY-MM-DD');
+    date.value[1] = selectedMonth.endOf('month').format('YYYY-MM-DD');
+  }
+}
+
+/**
+ * 计算上周的周日到周六的日期范围
+ */
+function calculateLastWeek() {
+  const today = dayjs();
+  const lastSaturday = today.subtract(today.day() + 1, 'day'); // 上周六
+  const lastSunday = lastSaturday.subtract(6, 'day'); // 上周日
+  return [lastSunday.format('YYYY-MM-DD'), lastSaturday.format('YYYY-MM-DD')];
+}
+
+/**
+ * 计算结束日期
+ * @param startDate el-date-picker组件的value
+ */
+function calculateEndDate(startDate: string) {
+  return dayjs(startDate).add(6, 'day').format('YYYY-MM-DD');
+}
+
+async function refreshTable() {
+  currentPage.value = 1;
+  pageSize.value = 20;
+  asinInp.value = '';
+  searchTermInp.value = '';
+  reportTypeSelect.value = 'weekly';
+  marketplaceSelect.value = marketplaceIdEnum[0].value;
+  await fetchTableData();
+}
+
+async function fetchTableData() {
+  tableLoading.value = true;
+  const query = {
+    page: currentPage.value,
+    limit: pageSize.value,
+    asin: asinInp.value,
+    search_term: searchTermInp.value,
+    report_type: reportTypeSelect.value,
+    marketplace_Ids: marketplaceSelect.value,
+    date_start: date.value[0],
+    date_end: date.value[1],
+  };
+  try {
+    const response = await getTopSearchTermTable(query);
+    total.value = response.total;
+    tableData.value = response.data;
+  } catch (error) {
+    console.error('==Error==:', error);
+  } finally {
+    tableLoading.value = false;
+    await nextTick();
+    // 触发窗口 resize 事件
+    window.dispatchEvent(new Event('resize'));
+  }
+}
+
+async function handleSelectChange() {
+  calculateDate();
+  await fetchTableData();
+}
+
+/**
+ * 输入框按下回车后触发
+ */
+async function handleQueryChange() {
+  if (!validateSearchTermInput(searchTermInp.value)) {
+    if (searchTermInp.value.length == 0) {
+      return;
+    } else {
+      ElMessage.warning({ message: '搜索词只能输入数字和英文字母', plain: true });
+      return;
+    }
+  }
+  if (asinInp.value.length > 0 && !validateAsinInput(asinInp.value)) {
+    ElMessage.warning({ message: '不符合匹配规范', plain: true });
+    return;
+  }
+  await fetchTableData();
+}
+
+/**
+ * 校验SearchTerm输入是否合法
+ * @param input 输入的字符串
+ */
+function validateSearchTermInput(input: string) {
+  const regex = /^[a-zA-Z0-9\s]*$/;
+  return regex.test(input);
+}
+
+/**
+ * 校验Asin输入是否合法
+ * @param input 输入的字符串
+ */
+function validateAsinInput(input: string) {
+  const regex = /^[Bb]0[A-Za-z0-9\s]*$/i;
+  return regex.test(input);
+}
+
+async function handleDownload() {
+  downloadLoading.value = true;
+  try {
+    const body = {
+      asin: asinInp.value,
+      date_start: date.value[0],
+      date_end: date.value[1],
+      search_term: searchTermInp.value,
+      marketplace_Ids: marketplaceSelect.value,
+      report_type: reportTypeSelect.value,
+    };
+
+    const response = await postDownload(body);
+
+    const blob = new Blob([response.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
+
+    // 创建一个临时 URL
+    const url = window.URL.createObjectURL(blob);
+
+    // 创建一个临时的 <a> 元素并触发下载
+    const link = document.createElement('a');
+    link.href = url;
+
+    // 设置文件名
+    const currentTime = dayjs().format('YYYY-MM-DD_HH_mm_ss');
+    const filename = `TopSearchTerm_${currentTime}.xlsx`;
+
+    link.setAttribute('download', filename);
+
+    // 添加到 body, 触发点击, 然后移除
+    document.body.appendChild(link);
+    link.click();
+    document.body.removeChild(link);
+
+    // 释放 URL 对象
+    window.URL.revokeObjectURL(url);
+
+    ElMessage.success('文件下载成功');
+  } catch (error) {
+    console.error('==Error==:', error);
+    ElMessage.error('文件下载失败,请重试');
+  } finally {
+    downloadLoading.value = false;
+  }
+}
+</script>
+
+<template>
+  <div class="py-2 px-2.5">
+    <el-card class="mb-2.5">
+      <div class="flex justify-between">
+        <div class="flex gap-5 flex-wrap">
+          <div>
+            <span class="font-medium mr-0.5">报告类型 </span>
+            <el-select v-model="reportTypeSelect" @change="handleSelectChange" style="width: 90px">
+              <el-option label="周度" value="weekly" />
+              <el-option label="月度" value="monthly" />
+            </el-select>
+          </div>
+          <div>
+            <span class="font-medium mr-0.5">搜索词 </span>
+            <el-input
+              v-model="searchTermInp"
+              @keyup.enter="handleQueryChange"
+              :prefix-icon="Search"
+              placeholder="输入后回车查询"
+              clearable
+              @clear="handleSelectChange"
+              style="width: 240px" />
+          </div>
+          <div>
+            <span class="font-medium mr-0.5">ASIN </span>
+            <el-input
+              v-model="asinInp"
+              @keyup.enter="handleQueryChange"
+              :prefix-icon="Search"
+              placeholder="输入后回车查询"
+              clearable
+              @clear="handleSelectChange"
+              style="width: 180px" />
+          </div>
+          <div>
+            <span class="font-medium mr-0.5">报告日期 </span>
+            <el-config-provider :locale="enLocale">
+              <el-date-picker
+                v-if="reportTypeSelect === 'weekly'"
+                v-model="dateDimension"
+                type="week"
+                value-format="YYYY-MM-DD"
+                :format="`${date[0]} To ${date[1]}`"
+                :popper-options="{ placement: 'bottom-end' }"
+                :disabled-date="(time: Date) => time > new Date()"
+                :clearable="false" />
+              <el-date-picker
+                v-else
+                v-model="dateDimension"
+                type="month"
+                value-format="YYYY-MM"
+                :format="`${date[0]} To ${date[1]}`"
+                :popper-options="{ placement: 'bottom-end' }"
+                :disabled-date="(time: Date) => time > new Date()"
+                :clearable="false">
+                <template #default> 123</template>
+              </el-date-picker>
+            </el-config-provider>
+          </div>
+        </div>
+        <div class="flex">
+          <el-button
+            type="success"
+            plain
+            @click="handleDownload"
+            :icon="Download"
+            round
+            :loading="downloadLoading"
+            :disabled="!tableData.length"
+            >下载表格
+          </el-button>
+          <el-button @click="refreshTable" :icon="Refresh" circle></el-button>
+        </div>
+      </div>
+    </el-card>
+    <el-card>
+      <el-table></el-table>
+    </el-card>
+  </div>
+</template>
+
+<style scoped></style>

+ 15 - 0
src/views/searchTerm/brandView/index.vue

@@ -0,0 +1,15 @@
+<script setup lang="ts">
+/**
+ * @Name: index.vue
+ * @Description: brandView
+ * @Author: Cheney
+ */
+</script>
+
+<template>
+
+</template>
+
+<style scoped>
+
+</style>

+ 2 - 2
src/views/searchTerm/rootWordManage/components/root-word-manage-table.vue

@@ -5,7 +5,7 @@
  * @Author: Cheney
  */
 
-import { nextTick, onBeforeMount, onMounted, reactive, ref } from 'vue';
+import { nextTick, onMounted, reactive, ref } from 'vue';
 import { Plus, Search, Upload } from '@element-plus/icons-vue';
 import * as api from '../api';
 import type { UploadInstance, UploadRawFile } from 'element-plus';
@@ -361,7 +361,7 @@ function handleResponse(response: any) {
       </el-card>
       <!-- 表格 -->
       <el-card shadow="hover" style="border: none">
-        <div style="height: 800px;">
+        <div style="height: 800px">
           <el-table :data="tableData" height="800" stripe style="width: 100%">
             <el-table-column fixed prop="add_date" label="添加日期" width="180" sortable>
               <template #header>

+ 7 - 6
src/views/searchTerm/topSearchTermTable/index.vue

@@ -16,7 +16,6 @@ import dayjs from 'dayjs';
 import enLocale from 'element-plus/es/locale/lang/en';
 
 const router = useRouter();
-
 const { tableData, total, currentPage, pageSize, handlePageChange } = usePagination(fetchTableData);
 const marketplaceSelect = ref(marketplaceIdEnum[0].value); // 当前只有美国区 默认第一个为美国
 const marketplaceOptions = marketplaceIdEnum;
@@ -107,11 +106,17 @@ async function fetchTableData() {
   }
 }
 
+/**
+ * 下拉框值改变和input清空事件触发
+ */
 async function handleSelectChange() {
   calculateDate();
   await fetchTableData();
 }
 
+/**
+ * 输入框按下回车后触发
+ */
 async function handleQueryChange() {
   if (!validateSearchTermInput(searchTermInp.value)) {
     if (searchTermInp.value.length == 0) {
@@ -280,7 +285,6 @@ function arraySpanMethod({ row, column, rowIndex, columnIndex }) {
         </div>
         <div>
           <span class="font-medium mr-0.5">报告日期 </span>
-
           <el-config-provider :locale="enLocale">
             <el-date-picker
               v-if="reportTypeSelect === 'weekly'"
@@ -350,7 +354,6 @@ function arraySpanMethod({ row, column, rowIndex, columnIndex }) {
               <span class="font-medium">{{ row.searchFrequencyRank }}</span>
             </template>
           </el-table-column>
-
           <el-table-column prop="clickShareSummary" label="点击分享率(SUM)" align="center" width="150">
             <template #header>
               <el-icon style="top: 2px; margin-right: 4px">
@@ -373,7 +376,6 @@ function arraySpanMethod({ row, column, rowIndex, columnIndex }) {
               <span class="font-medium">{{ row.conversionShareSummary }}</span>
             </template>
           </el-table-column>
-
           <el-table-column prop="clickedAsin" label="Asin" align="center">
             <template #header>
               <el-icon style="top: 2px; margin-right: 5px">
@@ -404,7 +406,6 @@ function arraySpanMethod({ row, column, rowIndex, columnIndex }) {
               <div class="text-sm text-left">
                 <el-tooltip class="box-item" effect="dark" :content="row.clickedItemName" placement="top" :show-after="500">
                   <div class="tooltip-text">
-                    <!--<span class="font-medium mr-1">Title:</span>-->
                     {{ row.clickedItemName }}
                   </div>
                 </el-tooltip>
@@ -419,7 +420,6 @@ function arraySpanMethod({ row, column, rowIndex, columnIndex }) {
               <span>点击分享率排名</span>
             </template>
             <template #default="{ row }">
-              <!--<span class="font-semibold">{{ row.clickShareRank }}</span>-->
               <el-tag :style="getTagStyle(row.clickShareRank)">
                 {{ row.clickShareRank }}
               </el-tag>
@@ -463,6 +463,7 @@ function arraySpanMethod({ row, column, rowIndex, columnIndex }) {
 </template>
 
 <style scoped>
+/* 修改 el-divider 的背景颜色 */
 :deep(.el-divider__text.is-center.el-divider__text) {
   background-color: #f8f8f8;
 }