Răsfoiți Sursa

🐛 fix<数据中心>: 图表问题修复

xinyan 10 luni în urmă
părinte
comite
38c159efff

+ 57 - 27
src/views/efTools/automation/components/adActivityDialog.vue

@@ -1,22 +1,36 @@
-<script setup lang="ts">
+<script lang="ts" setup>
 /**
  * @Name: adActivityDialog.vue
  * @Description:广告关联活动弹窗
  * @Author: xinyan
  */
-import { inject, onMounted, Ref, ref } from 'vue';
+import { inject, onMounted, Ref, ref, watch } from 'vue';
 import { getRelationCampaign } from '/@/views/efTools/automation/api';
+import { storeToRefs } from 'pinia';
+import { useShopInfo } from '/@/stores/shopInfo';
 
-const dialogVisible = inject<Ref>('isDialogVisible')
+const props = defineProps({
+  templateId: {
+    type: [String, Number],
+    required: true,
+  }
+});
+const shopInfo = useShopInfo()
+const { profile } = storeToRefs(shopInfo)
+const { templateId } = toRefs(props);
+console.log(templateId);
+
+const dialogVisible = inject<Ref>('isDialogVisible');
+//广告活动输入框
 const searchAdCampaign = ref('');
-const selectedCampaignType = ref('');
+const selectedCampaignType = ref('sp');
 const selectedAdGroup = ref('');
 const selectedStatus = ref('');
 const selectedActivityTag = ref('');
 const currentPage = ref('');
 const total = ref('');
 const pageSize = ref(20);
-const loading = ref(false)
+const loading = ref(false);
 const handleSizeChange = (size) => {
   pageSize.value = size;
   fetchAdCampaign(); // 调用 fetchAdCampaign 重新获取数据
@@ -30,8 +44,9 @@ const handleCurrentChange = (newPage) => {
 };
 
 const campaignType = [
-  {value: 'SB', label: 'SB'},
-  {value: 'SP', label: 'SP'}
+  {value: 'sb', label: 'SB'},
+  {value: 'sp', label: 'SP'},
+  {value: 'sd', label: 'SD'},
 ];
 
 const adGroups = [
@@ -52,21 +67,21 @@ const activityTags = [
 const adCampaignName = ref([]);
 
 async function fetchAdCampaign() {
-  try{
+  try {
     const resp = await getRelationCampaign({
-      profileId: 3006125408623189,
-      templateId:49,
-      campaignName: "",
-      portfolioId:"",
-      campaignStatus:"",
-      campaignType:"sp",
+      profileId: profile.value.profile_id,
+      templateId: templateId.value,
+      campaignName: '',
+      portfolioId: '',
+      campaignStatus: '',
+      campaignType: selectedCampaignType.value,
       page: currentPage.value,
       limit: pageSize.value,
     });
     adCampaignName.value = resp.data;
     total.value = resp.total;
     currentPage.value = resp.page;
-  }catch (error) {
+  } catch (error) {
     console.error('Error fetching task data:', error);
   }
 }
@@ -93,25 +108,29 @@ const headerCellStyle = (args) => {
   if (args.rowIndex === 0) {
     return {
       backgroundColor: 'rgba(245, 245, 245, 0.9)',
-    }
+    };
   }
-}
+};
 
-onMounted(()=>{
+watch(selectedCampaignType, () => {
   fetchAdCampaign();
 });
 
+watch(templateId,()=>{
+  fetchAdCampaign();
+})
+
 </script>
 
 <template>
   <el-dialog
-      class="custom-dialog"
       v-model="dialogVisible"
+      class="custom-dialog"
+      style="border-radius: 10px;"
       title="关联广告活动"
       width="1158px"
-      style="border-radius: 10px;"
   >
-    <div style="display: flex;" class="custom-border">
+    <div class="custom-border" style="display: flex;">
       <div style="width: 50%;">
         <el-input v-model="searchAdCampaign" placeholder="请输入广告活动" style="width: 100%;"></el-input>
         <div class="custom-inline">
@@ -151,14 +170,25 @@ onMounted(()=>{
           </el-select>
         </div>
         <el-table
+            v-loading="loading"
             :data="adCampaignName"
-            style="width: 100%;"
+            :header-cell-style="headerCellStyle"
             height="400"
-            v-loading="loading"
+            style="width: 100%;"
             @selection-change="handleSelectionChange"
-            :header-cell-style="headerCellStyle"
         >
-          <el-table-column label="广告活动名称" prop="campaignName"></el-table-column>
+          <el-table-column label="广告活动名称" prop="campaignName">
+            <template #default="scope">
+              <el-tag
+                  :type="scope.row.campaignType === 'SB' ? 'primary' : 'success'"
+                  disable-transitions
+                  round
+              >
+                {{ scope.row.campaignType }}
+              </el-tag>
+              {{ scope.row.campaignName }}」
+            </template>
+          </el-table-column>
           <el-table-column type="selection" width="55"></el-table-column>
         </el-table>
         <el-pagination
@@ -176,9 +206,9 @@ onMounted(()=>{
         <h3>已选择({{ selectedAds.length }})</h3>
         <el-table
             :data="selectedAds"
+            :header-cell-style="headerCellStyle"
             height="484"
             style="width: 100%; margin-top: 20px;"
-            :header-cell-style="headerCellStyle"
         >
           <el-table-column label="广告活动" prop="campaignName"></el-table-column>
           <el-table-column
@@ -186,7 +216,7 @@ onMounted(()=>{
               width="100"
           >
             <template #header>
-              <el-button type="danger" size="normal" link @click="removeAllSelectedAds">删除全部</el-button>
+              <el-button link size="normal" type="danger" @click="removeAllSelectedAds">删除全部</el-button>
             </template>
             <template #default="scope">
               <el-button type="text" @click="removeSelectedAd(scope.$index)">删除</el-button>

+ 146 - 87
src/views/reportManage/dataCenter/normalDisplay/components/DateTendency/index.vue

@@ -1,23 +1,11 @@
-<template>
-  <div v-loading="loading">
-    <MetricsCards v-model="metrics" :metric-items="metricsItems" @change="changeMetric"></MetricsCards>
-    <el-radio-group v-model="statDim" class="chart-button-group" @change="changeStatDim">
-      <el-radio-button label="day">日</el-radio-button>
-      <el-radio-button :disabled="!props.fetchLineWeek" label="week">周</el-radio-button>
-      <el-radio-button :disabled="!props.fetchLineWeek" label="month">月</el-radio-button>
-    </el-radio-group>
-    <div ref="chartRef" style="height: 350px"></div>
-  </div>
-</template>
-
 <script lang="ts" setup>
 import * as echarts from 'echarts';
-import { Ref, computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';
-import { dayMetricsEnum, weekMetricsEnum, monthMetricsEnum } from '/src/views/reportManage/dataCenter/utils/enum';
+import { computed, onBeforeUnmount, onMounted, Ref, ref, watch } from 'vue';
+import { dayMetricsEnum, initData } from '/src/views/reportManage/dataCenter/utils/enum';
 import XEUtils from 'xe-utils';
 import MetricsCards from '../MetricsCards/index.vue';
 import emitter from '/src/utils/emitter';
-import { buildChartOpt, parseQueryParams } from '/src/views/reportManage/dataCenter/utils/tools';
+import { parseQueryParams } from '/src/views/reportManage/dataCenter/utils/tools';
 
 defineOptions({
   name: 'DataTendencyChart',
@@ -36,16 +24,11 @@ interface Props {
 }
 
 const props = withDefaults(defineProps<Props>(), {
-  initMetric: () => [
-    {metric: 'sales', color: '#0085ff', label: '销售额'},
-    {metric: 'ad_sales', color: '#ff9500', label: '广告销售额'},
-    {metric: 'ad_cost', color: '#3fd4cf', label: '广告花费'},
-  ],
+  initMetric: () => initData,
   metricEnum: () => dayMetricsEnum,
 });
 
 const metrics = ref(props.initMetric);
-
 const metricsItems: Ref<MetricData[]> = ref([]);
 let chartObj: any;
 const chartRef = ref();
@@ -136,7 +119,7 @@ const option: any = {
       yAxisIndex: 0,
       itemStyle: {
         color: '',
-        borderRadius: 4,
+        borderRadius: [4, 4, 4, 4],
       },
     },
     {
@@ -147,11 +130,22 @@ const option: any = {
         x: 'data_datetime',
         y: '',
       },
-      barWidth: '18px',
-      yAxisIndex: 0,
+      symbolSize: 6,
+      symbol: 'circle',
+      smooth: true,
+      yAxisIndex: 1,
       itemStyle: {
-        color: '',
-        borderRadius: 4,
+        // color: '#ff9500',
+        // borderColor: '#ff9500'
+      },
+      areaStyle: {
+        // color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+        //   { offset: 0, color: '#3fd4cf53' },
+        //   { offset: 1, color: '#3fd4cf03' },
+        // ]),
+      },
+      emphasis: {
+        focus: 'series',
       },
     },
     {
@@ -184,6 +178,7 @@ onMounted(() => {
     initLine();
   }, 0);
 });
+
 onBeforeUnmount(() => {
   if (chartObj) {
     chartObj.dispose();
@@ -192,67 +187,71 @@ onBeforeUnmount(() => {
   removeResize();
 });
 
-//初始化图表
-const initLine = async () => {
+async function initLine() {
   chartObj = echarts.init(chartRef.value);
-  const items = await getDataset();
-  option.dataset.source = items;
+  option.dataset.source = await getDataset();
 
-  XEUtils.arrayEach(option.series, (info: any, index) => {
-    const color = metrics.value[index].color;
-    info.name = metrics.value[index].label;
-    info.encode.y = metrics.value[index].metric;
-    if (info.type === 'bar') {
-      info.itemStyle.color = color;
-    } else {
-      info.itemStyle = {color: color, borderColor: color};
-      info.areaStyle = {
-        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
-          {offset: 0, color: color + '53'},
-          {offset: 1, color: color + '03'},
-        ]),
-      };
-    }
-  });
-  XEUtils.arrayEach(option.yAxis, (info: any, index) => {
-    info.name = metrics.value[index].label;
-    info.axisLine.lineStyle.color = metrics.value[index].color;
-  });
+  // 初始化系列和 y 轴
+  option.series = metrics.value.map((metric, index) => ({
+    id: index,
+    name: metric.label,
+    type: index === 0 ? 'bar' : 'line',
+    encode: {x: 'Name', y: metric.metric},
+    yAxisIndex: index,
+    itemStyle: {color: option.series.type == 'bar' ? '#0085ff' : metric.color, borderRadius: [6, 6, 6, 6]},
+    lineStyle: {color: metric.color},
+    barWidth: '10%',
+    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,
+  }));
+
+  option.yAxis = metrics.value.map((metric, index) => ({
+    id: index,
+    name: metric.label,
+    type: 'value',
+    position: index === 0 ? 'left' : 'right',
+    offset: index > 1 ? (index - 1) * 80 : 0,
+    axisLine: {show: true, lineStyle: {color: metric.color}},
+    splitLine: {
+      show: index === 0,
+    },
+    show: true,
+  }));
+
+  // 初始化图例
+  option.legend.selected = props.metricEnum.reduce((acc, metric) => {
+    acc[metric.label] = metrics.value.some((m) => m.metric === metric.value);
+    return acc;
+  }, {});
 
-  XEUtils.arrayEach(props.metricEnum, (info) => {
-    option.legend.selected[info.label] = false;
-  });
-  for (const info of metrics.value) {
-    option.legend.selected[info.label] = true;
-  }
-  // console.log(option)
   chartObj.setOption(option);
   loading.value = false;
-};
+}
 
-//条形图数据
-const getDataset = async () => {
-  // console.log('getDataset,line');
+async function getDataset() {
   if (statDim.value === 'week') {
     if (props.fetchLineWeek) {
       const resp = await props.fetchLineWeek(queryParams.value);
-      // console.log('week',resp.data);
       return resp.data;
     }
   } else if (statDim.value === 'month') {
     if (props.fetchLineMonth) {
       const resp = await props.fetchLineMonth(queryParams.value);
-      // console.log('month',resp.data);
       return resp.data;
     }
   } else {
     const resp = await props.fetchLine(queryParams.value);
     return resp.data;
   }
+}
 
-};
-
-//卡片数据
 const getMetricsItems = async () => {
   let resp;
   if (statDim.value === 'week' && props.fetchCardWeek) {
@@ -278,54 +277,114 @@ const getMetricsItems = async () => {
   });
 };
 
-//更新图表的选项
-const changeMetric = () => {
-  const opt = buildChartOpt(option, metrics.value);
-  chartObj.setOption(opt);
-};
+function changeMetric() {
+  // 更新图例选中状态
+  option.legend.selected = props.metricEnum.reduce((acc, metric) => {
+    acc[metric.label] = metrics.value.some((m) => m.metric === metric.value);
+    return acc;
+  }, {});
+
+  // 重新创建 series 数组,只包含选中的指标
+  option.series = metrics.value.map((metric, index) => {
+    const baseConfig = {
+      id: index,
+      name: metric.label,
+      type: metric.color === '#0085ff' ? 'bar' : 'line',
+      encode: {x: 'Name', y: metric.metric},
+      yAxisIndex: index,
+      itemStyle: {color: metric.color, borderRadius: [6, 6, 6, 6]},
+      lineStyle: {color: metric.color},
+      barWidth: '10%',
+    };
+
+    if (baseConfig != 'bar') {
+      baseConfig.areaStyle = {
+        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+          {offset: 0, color: metric.color + '53'},
+          {offset: 1, color: metric.color + '03'},
+        ]),
+      };
+    }
+
+    return baseConfig;
+  });
+
+  // 更新 y 轴显示状态
+  option.yAxis = metrics.value.map((metric, index) => ({
+    id: index,
+    name: metric.label,
+    type: 'value',
+    position: index === 0 ? 'left' : 'right',
+    offset: index > 1 ? (index - 1) * 80 : 0,
+    axisLine: {
+      show: true,
+      lineStyle: {color: metric.color},
+    },
+    splitLine: {
+      show: index === 0,
+    },
+    show: true,
+  }));
+
+  while (option.yAxis.length > metrics.value.length) {
+    option.yAxis.pop();
+  }
+
+  chartObj.setOption(option, true); // 使用 true 作为第二个参数,强制完全刷新
+}
 
-//根据日,周,月更新图表
-const emit = defineEmits(['changeStatDim']);
 const changeStatDim = async () => {
   emitter.emit('DateTendency-dateChange', statDim.value);
-  // loading.value = true;
-  // // let source = await getDataset();
-  // // if (source.length > 0) {
-  // //   chartObj.setOption({dataset: {source: source}});
-  // // }
-  // // await getMetricsItems();
-  // loading.value = false;
 };
 
-//监测dataRange的变化
 let initialized = false;
-
 watch(props.query, async () => {
   if (!initialized) {
     initialized = true;
     return;
   }
-  // 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);
+  option.dataset.source = await getDataset();
+  chartObj.setOption(option);
   loading.value = false;
 });
 
+watch(
+    () => props.initMetric,
+    (newVal) => {
+      metrics.value = newVal;
+      initLine(); // 重新初始化图表数据
+      //console.log('initMetric', props.initMetric);
+    },
+    { immediate: true }
+);
+
 const resizeChart = () => {
   chartObj.resize();
 };
+
 const addResize = () => {
   window.addEventListener('resize', resizeChart);
 };
+
 const removeResize = () => {
   window.removeEventListener('resize', resizeChart);
 };
 </script>
 
+<template>
+  <div v-loading="loading">
+    <MetricsCards v-model="metrics" :metric-items="metricsItems" @change="changeMetric"></MetricsCards>
+    <el-radio-group v-model="statDim" class="chart-button-group" @change="changeStatDim">
+      <el-radio-button label="day">日</el-radio-button>
+      <el-radio-button :disabled="!props.fetchLineWeek" label="week">周</el-radio-button>
+      <el-radio-button :disabled="!props.fetchLineWeek" label="month">月</el-radio-button>
+    </el-radio-group>
+    <div ref="chartRef" style="height: 350px"></div>
+  </div>
+</template>
+
 <style scoped>
 .metrics-cards {
   display: flex;

+ 20 - 8
src/views/reportManage/dataCenter/normalDisplay/index.vue

@@ -1,15 +1,21 @@
 <script lang="ts" setup>
-import { dayMetricsEnum, monthMetricsEnum, weekMetricsEnum } from '/src/views/reportManage/dataCenter/utils/enum';
+import {
+  dayInitData,
+  dayMetricsEnum, initData, monthInitData,
+  monthMetricsEnum,
+  weekInitData,
+  weekMetricsEnum
+} from '/src/views/reportManage/dataCenter/utils/enum';
 import {
   getCardDayData,
-  getCardWeekData,
   getCardMonthData,
+  getCardWeekData,
   getLineForDay,
-  getLineForWeek,
-  getLineForMonth
+  getLineForMonth,
+  getLineForWeek
 } from '/src/views/reportManage/dataCenter/api';
 import DateTendency from '/src/views/reportManage/dataCenter/normalDisplay/components/DateTendency/index.vue';
-import { onBeforeUnmount, provide, computed, ref, watch } from 'vue';
+import { computed, onBeforeUnmount, provide, ref } from 'vue';
 import Selector from '/src/views/reportManage/dataCenter/normalDisplay/components/Selector/index.vue';
 import TableSelect from '/src/views/reportManage/dataCenter/normalDisplay/components/TableDataDisplay.vue';
 import DataPicker from '/src/views/reportManage/dataCenter/normalDisplay/components/DatePicker/index.vue';
@@ -32,9 +38,6 @@ const handelDateChange = (date) => {
   currentDate.value = date;
 };
 
-// watch(currentDate, (value) => {
-// });
-
 emitter.on('DateTendency-dateChange', (value: string) => {
   dateDimension.value = value;
   // console.log('dateDimension', dateDimension.value);
@@ -60,6 +63,14 @@ const currentMetricEnum = computed(() => {
   }
 });
 
+const InitMetric = computed(() => {
+  if (dateDimension.value === 'week') {
+    return weekInitData;
+  }
+    return initData;
+});
+
+
 onBeforeUnmount(() => {
   emitter.all.clear();
 });
@@ -80,6 +91,7 @@ onBeforeUnmount(() => {
           :fetchCardMonth="getCardMonthData"
           :fetchCardWeek="getCardWeekData"
           :fetchLine="getLineForDay"
+          :initMetric="InitMetric"
           :metricEnum="currentMetricEnum"
           :query="queryParams"
       >

+ 16 - 1
src/views/reportManage/dataCenter/utils/enum.ts

@@ -1,5 +1,7 @@
 export const dayMetricsEnum = [
   {value: 'sales', label: '销售额'},
+  {value: 'sales_last_year', label: '上年销售额'},
+  {value: 'sales_last_month', label: '上月销售额'},
   {value: 'ad_cost', label: '广告花费'},
   {value: 'ad_sales', label: '广告销售额'},
   {value: 'acos', label: '广告ACOS'},
@@ -30,9 +32,10 @@ export const weekMetricsEnum = [
 
 export const monthMetricsEnum = [
   {value: 'sales', label: '销售额'},
+  {value: 'sales_last_year', label: '上年销售额'},
+  {value: 'sales_last_month', label: '上月销售额'},
   {value: 'ad_cost', label: '广告花费'},
   {value: 'ad_sales', label: '广告销售额'},
-
   {value: 'acos', label: '广告ACOS'},
   {value: 'roi', label: '广告ROI'},
   {value: 'roas', label: '广告ROAS'},
@@ -47,3 +50,15 @@ export const monthCompareMetricsEnum = [
   { value: 'sales', label: '销售额'},
   { value: 'planSales', label: '计划销售额'},
 ]
+
+export const weekInitData = [
+{metric: 'sales', color: '#0085ff', label: '销售额'},
+{metric: 'ad_sales', color: '#ff9500', label: '广告销售额'},
+{metric: 'ad_cost', color: '#3fd4cf', label: '广告花费'},
+]
+
+export const initData = [
+  {metric: 'sales', color: '#0085ff', label: '销售额'},
+  {metric: 'sales_last_year', color: '#ff9500', label: '上年销售额'},
+  {metric: 'sales_last_month', color: '#3fd4cf', label: '上月销售额'},
+]