瀏覽代碼

✨ feat<报表管理-数据中心>: 添加筛选查询功能,普通展示-图表功能
筛选-图表和表格
日期选择器修改

xinyan 11 月之前
父節點
當前提交
940f6222d7
共有 35 個文件被更改,包括 3490 次插入1939 次删除
  1. 19 35
      src/views/demo/index.vue
  2. 2 2
      src/views/productCenter/productAnalysis/components/DateTendency/index.vue
  3. 51 0
      src/views/reportManage/TaskManage/api.ts
  4. 58 34
      src/views/reportManage/TaskManage/index.vue
  5. 40 42
      src/views/reportManage/dataCenter/api.ts
  6. 123 103
      src/views/reportManage/dataCenter/combinedDisplay/components/DateTendency/index.vue
  7. 0 0
      src/views/reportManage/dataCenter/combinedDisplay/components/MetricsCards/index.vue
  8. 1 1
      src/views/reportManage/dataCenter/combinedDisplay/components/MetricsCards/mCard.vue
  9. 227 0
      src/views/reportManage/dataCenter/combinedDisplay/components/chartDateTendency/index.vue
  10. 111 0
      src/views/reportManage/dataCenter/combinedDisplay/components/monthDatePicker/index.vue
  11. 162 0
      src/views/reportManage/dataCenter/combinedDisplay/components/tableData/mainData.vue
  12. 117 0
      src/views/reportManage/dataCenter/combinedDisplay/components/tableData/monthlyComparativeData.vue
  13. 186 0
      src/views/reportManage/dataCenter/combinedDisplay/index.vue
  14. 0 164
      src/views/reportManage/dataCenter/components/CombinedDisplay.vue
  15. 0 27
      src/views/reportManage/dataCenter/components/CompareData.vue
  16. 0 161
      src/views/reportManage/dataCenter/components/DataExport.vue
  17. 0 180
      src/views/reportManage/dataCenter/components/DatePicker/index.vue
  18. 0 67
      src/views/reportManage/dataCenter/components/NormalDisplay.vue
  19. 0 42
      src/views/reportManage/dataCenter/components/Selector/index.vue
  20. 0 228
      src/views/reportManage/dataCenter/components/TableDataDisplay.vue
  21. 0 597
      src/views/reportManage/dataCenter/components/TableDataEntry.vue
  22. 8 8
      src/views/reportManage/dataCenter/index.vue
  23. 10 0
      src/views/reportManage/dataCenter/normalDisplay/components/CompareData.vue
  24. 11 0
      src/views/reportManage/dataCenter/normalDisplay/components/DataExport.vue
  25. 244 0
      src/views/reportManage/dataCenter/normalDisplay/components/DatePicker/index.vue
  26. 339 0
      src/views/reportManage/dataCenter/normalDisplay/components/DateTendency/index.vue
  27. 149 0
      src/views/reportManage/dataCenter/normalDisplay/components/MetricsCards/index.vue
  28. 100 0
      src/views/reportManage/dataCenter/normalDisplay/components/MetricsCards/mCard.vue
  29. 115 0
      src/views/reportManage/dataCenter/normalDisplay/components/Selector/index.vue
  30. 194 0
      src/views/reportManage/dataCenter/normalDisplay/components/TableDataDisplay.vue
  31. 826 0
      src/views/reportManage/dataCenter/normalDisplay/components/TableDataEntry.vue
  32. 98 0
      src/views/reportManage/dataCenter/normalDisplay/index.vue
  33. 165 225
      src/views/reportManage/dataCenter/utils/columns.ts
  34. 49 23
      src/views/reportManage/dataCenter/utils/enum.ts
  35. 85 0
      src/views/reportManage/dataCenter/utils/tools.ts

+ 19 - 35
src/views/demo/index.vue

@@ -1,49 +1,33 @@
 <script setup lang="ts">
 import * as ww from '@wecom/jssdk';
 import { WeComLogin } from './api';
+import { ref } from 'vue';
+import enLocale from 'element-plus/es/locale/lang/en';
 
-// const txt = defineModel()
+// const localeRef = ref(enLocale); // 直接使用ref包装英文语言包
+
+const value = ref(null); // 假设这是你的日期选择器的v-model值
+const defaultTime = ref(null); // 你的默认时间设定
 
-function createWXQRCode() {
-  ww.createWWLoginPanel({
-    el: '#wx_qrcode',
-    params: {
-      login_type: 'CorpApp',
-      appid: 'ww467ec1685e8262e6',
-      agentid: '1000065',
-      redirect_uri: 'http://amzads.zositechc.cn/web/',
-      state: 'Wechat',
-      scope: 'snsapi_privateinfo',
-      redirect_type: 'callback',
-    },
-    onCheckWeComLogin({ isWeComLogin }) {
-      console.log(isWeComLogin);
-    },
-    onLoginSuccess({ code }) {
-      // console.log({ code })
-      handleWeComLogin({ code: code, state: 'Wechat' });
-    },
-    onLoginFail(err) {
-      console.log(err);
-    },
-  });
-}
 
-async function handleWeComLogin(query) {
-  try {
-    const res = await WeComLogin(query);
-    console.log('res', res);
-  } catch (error) {
-    console.log('error:', error);
-  }
-}
 </script>
 
 <template>
+  <!--<div>-->
+  <!--  <el-button type="primary" @click="createWXQRCode" class="m-2.5">发送</el-button>-->
+  <!--</div>-->
+  <!--<div id="wx_qrcode" style="height: 300px; width: 300px"></div>-->
+
   <div>
-    <el-button type="primary" @click="createWXQRCode" class="m-2.5">发送</el-button>
+    <el-config-provider :locale="enLocale">
+      <el-date-picker
+          v-model="value"
+          type="week"
+          format="[Week] ww"
+          placeholder="Pick a week"
+      />
+    </el-config-provider>
   </div>
-  <div id="wx_qrcode" style="height: 300px; width: 300px"></div>
 </template>
 
 <style scoped></style>

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

@@ -360,7 +360,7 @@ const changeMetric = () => {
 
 const emit = defineEmits(['changeStatDim'])
 const changeStatDim = async () => {
-  emitter.emit('DateTendency-changeStatDim') // 触发DataTable的loading
+  emitter.emit('chartDateTendency-changeStatDim') // 触发DataTable的loading
   loading.value = true
   let source = await getDataset()
   if (source.length > 0) {
@@ -372,7 +372,7 @@ const changeStatDim = async () => {
 
 watch(props.query, async () => {
   // console.log("------watch-----queryParams", props.query)
-  emitter.emit('DateTendency-changeStatDim') // 触发DataTable的loading
+  emitter.emit('chartDateTendency-changeStatDim') // 触发DataTable的loading
   loading.value = true
   await getMetricsItems()
   const items = await getDataset()

+ 51 - 0
src/views/reportManage/TaskManage/api.ts

@@ -0,0 +1,51 @@
+import { request } from '/@/utils/service';
+import { UserPageQuery } from '@fast-crud/fast-crud';
+
+// 任务列表
+export function postCreateTask(body) {
+  return request({
+    url: '/api/report_manage/summary-tasks/',
+    method: 'POST',
+    data: body,
+  });
+}
+
+export function getTasks(query) {
+  return request({
+    url: '/api/report_manage/summary-tasks/',
+    method: 'GET',
+    params: query,
+  });
+}
+
+export function getTasksId(query) {
+  return request({
+    url: `/api/report_manage/summary-tasks/search/`,
+    method: 'GET',
+    params: query,
+  });
+}
+
+export function postDeleteTask(body) {
+  return request({
+    url: `/api/report_manage/summary-tasks/delete/`,
+    method: 'POST',
+    data: body,
+  });
+}
+
+export function postUpdateTask(body) {
+  return request({
+    url: `/api/report_manage/summary-tasks/${body.id}/`,
+    method: 'POST',
+    data: body,
+  });
+}
+
+export function getOperationSelect(query) {
+  return request({
+    url: '/api/system/user-select/',
+    method: 'GET',
+    params: query,
+  });
+}

+ 58 - 34
src/views/reportManage/dataCenter/components/TaskManage.vue → src/views/reportManage/TaskManage/index.vue

@@ -1,10 +1,16 @@
 <script setup lang="ts">
-import Selector from '/@/views/reportManage/dataCenter/components/Selector/index.vue';
-import { ref, reactive, onMounted, nextTick } from 'vue';
+import Selector from '/src/views/reportManage/dataCenter/normalDisplay/components/Selector/index.vue';
+import { ref, reactive, onMounted, nextTick, watch } from 'vue';
 import { VXETable, VxeGridInstance, VxeGridProps, VxeGridListeners } from 'vxe-table';
-import { getTasks, postCreateTask, getOperationSelect, postUpdateTask, postDeleteTask } from '../api';
+import {
+  getTasks,
+  postCreateTask,
+  getOperationSelect,
+  postUpdateTask,
+  postDeleteTask
+} from '/src/views/reportManage/TaskManage/api.ts';
 import { ComponentSize, ElMessage, FormInstance, FormRules } from 'element-plus';
-import { length } from 'sortablejs';
+
 
 //表单
 interface taskRuleForm {
@@ -44,7 +50,6 @@ const rules = reactive<FormRules>({
 let page = 1;
 let limit = 10;
 
-// const  loading = ref(false)
 
 interface RowVO {
   platformNumber: string;
@@ -70,7 +75,6 @@ const gridOptions = reactive<VxeGridProps<RowVO>>({
     slots: {
       buttons: 'toolbar_buttons',
     },
-    refresh: true,
   },
   rowConfig: {
     isHover: true,
@@ -82,7 +86,7 @@ const gridOptions = reactive<VxeGridProps<RowVO>>({
     enabled: true,
     total: 20,
     currentPage: 1,
-    pageSize: 10,
+    pageSize: 20,
     pageSizes: [10, 20, 30],
   },
   editConfig: {
@@ -136,13 +140,31 @@ const gridEvents: VxeGridListeners<RowVO> = {
   },
 };
 
-async function getTaskList() {
-  const resp = await getTasks({
-    page: gridOptions.pagerConfig.currentPage,
-    limit: gridOptions.pagerConfig.pageSize
+async function getTaskList(filters = {}) {
+  try {
+    gridOptions.loading = true;
+    const response = await getTasks({
+      page: gridOptions.pagerConfig.currentPage,
+      limit: gridOptions.pagerConfig.pageSize,
+      ...filters,
   });
-  gridOptions.data = resp.data;
-  gridOptions.pagerConfig.total = resp.total;
+    gridOptions.data = response.data;
+    gridOptions.pagerConfig.total = response.total;
+  }catch (error) {
+      console.error('Error fetching task data:', error);
+    } finally {
+      gridOptions.loading = false;
+    }
+  }
+
+const selectorRef = ref(null);
+
+function filteredDataChange(newList) {
+  // console.log('newList:', newList.value);
+  if (selectorRef.value) {
+    getTaskList(newList.value);
+    // gridOptions.data = newList.value;
+  }
 }
 
 /**
@@ -162,7 +184,6 @@ const editRowEvent = (row: RowVO) => {
   const $grid = xGrid.value;
   if ($grid) {
     $grid.setEditRow(row);
-    // console.log(row)
   }
 };
 
@@ -177,26 +198,27 @@ const clearRowEvent = () => {
 async function deleteTask() {
   const $grid = xGrid.value;
   if ($grid) {
-  const selectRecords = $grid.getCheckboxRecords();
-  const selectedIds = selectRecords.map(record => record.id);
-    console.log(selectedIds);
-  const obj = {keys: selectedIds};
-  try {
-    const resp = await postDeleteTask(obj);
-    if (resp.code === 2000) {
+    const selectRecords = $grid.getCheckboxRecords();
+    const selectedIds = selectRecords.map(record => record.id);
+    // console.log(selectedIds);
+    const obj = {keys: selectedIds};
+    try {
+      const resp = await postDeleteTask(obj);
+      if (resp.code === 2000) {
+        ElMessage({
+          message: '删除成功',
+          type: 'success',
+        });
+        await getTaskList();
+      }
+    } catch (e) {
       ElMessage({
-        message: '删除成功',
-        type: 'success',
+        message: '删除失败',
+        type: 'error',
       });
-      await getTaskList();
     }
-  } catch (e) {
-    ElMessage({
-      message: '删除失败',
-      type: 'error',
-    });
   }
-}}
+}
 
 // 删除选中行
 const removeEvent = async () => {
@@ -236,9 +258,10 @@ async function updateRow(row: RowVO) {
       user: [transUser.value],
       currencyCode: row.currencyCode,
     };
-    console.log(updatedRowData);
+    // console.log(updatedRowData);
     try {
       const response = await postUpdateTask(updatedRowData);
+      console.log(response);
       if (response.code === 2000) {
         ElMessage.success('更新成功');
       } else if (response.code == 400) {
@@ -296,7 +319,6 @@ async function createTask() {
 
 // 新建任务
 const submitEvent = async () => {
-
   // 创建一个新的行对象,用于保存表单数据
   const newRow: RowVO = {
     platformNumber: taskRuleForm.number,
@@ -331,8 +353,9 @@ const submitForm = async (formEl: FormInstance | undefined) => {
       await submitEvent();
       await nextTick();
       taskRuleFormRef.value.resetFields();
+      await VXETable.modal.message({content: '创建成功', status: 'success'});
     } else {
-      console.log('error submit!', fields);
+      // console.log('error submit!', fields);
     }
   });
 };
@@ -348,6 +371,7 @@ async function fetchOperationSelect() {
   }
 }
 
+
 onMounted(() => {
   getTaskList();
   fetchOperationSelect();
@@ -356,7 +380,7 @@ onMounted(() => {
 
 <template>
   <el-card class="custom-card-style flex gap-1.5 justify-between my-1.5 mx-2">
-    <Selector></Selector>
+    <Selector ref="selectorRef" @update:filteredData="filteredDataChange" />
   </el-card>
   <el-card class="mx-2">
     <div style="position: relative">

+ 40 - 42
src/views/reportManage/dataCenter/api.ts

@@ -1,79 +1,59 @@
 import { request } from '/@/utils/service';
 import { UserPageQuery } from '@fast-crud/fast-crud';
 
-export const apiPrefix = '/api/sellers/product/trend/daily/';
-
-export function getCardData(query: UserPageQuery) {
+//卡片日数据
+export function getCardDayData(query) {
   return request({
-    url: '/api/sellers/home/total/',//需要修改
+    url: '/api/report_manage/data-day/sum/',
     method: 'GET',
     params: query,
   });
 }
 
-export function getLineData(query: UserPageQuery) {
-  query['dateRangeType'] = 'D';
+export function getCardWeekData(query) {
   return request({
-    url: apiPrefix,
+    url: '/api/report_manage/data-week/sum/',
     method: 'GET',
     params: query,
   });
 }
 
-export function getLineWeekData(query: UserPageQuery) {
-  query['dateRangeType'] = 'W';
+export function getCardMonthData(query) {
   return request({
-    url: apiPrefix,
+    url: '/api/report_manage/data-month/sum/',
     method: 'GET',
     params: query,
   });
 }
-
-export function getLineMonthData(query: UserPageQuery) {
-  query['dateRangeType'] = 'M';
+//条形图日数据
+export function getLineForDay(query) {
   return request({
-    url: apiPrefix,
+    url: '/api/report_manage/data-day/daily/',
     method: 'GET',
     params: query,
   });
 }
 
-// 任务列表
-export function postCreateTask(body) {
+export function getLineForWeek(query) {
   return request({
-    url: '/api/report_manage/summary-tasks/',
-    method: 'POST',
-    data: body,
-  });
-}
-
-export function getTasks(query) {
-  return request({
-    url: '/api/report_manage/summary-tasks/',
+    url: '/api/report_manage/data-week/weekly/',
     method: 'GET',
     params: query,
   });
 }
 
-export function postDeleteTask(body) {
+export function getLineForMonth(query) {
   return request({
-    url: `/api/report_manage/summary-tasks/delete/`,
-    method: 'POST',
-    data: body,
-  });
-}
-
-export function postUpdateTask(body) {
-  return request({
-    url: `/api/report_manage/summary-tasks/${body.id}/`,
-    method: 'POST',
-    data: body,
+    url: '/api/report_manage/data-month/monthly/',
+    method: 'GET',
+    params: query,
   });
 }
 
-export function getOperationSelect(query) {
+//合并展示月对比数据
+export function getLineData(query) {
   return request({
-    url: '/api/system/user-select/',
+    url: '/api/report_manage/data-month/compare/plan/',
     method: 'GET',
     params: query,
   });
@@ -160,7 +140,7 @@ export function postUpdateDayData(body) {
   return request({
     url: `/api/report_manage/data-day/${body.id}/`,
     method: 'POST',
-    params: body,
+    data: body,
   });
 }
 
@@ -168,14 +148,32 @@ export function postUpdateWeekData(body) {
   return request({
     url: `/api/report_manage/data-week/${body.id}/`,
     method: 'POST',
-    params: body,
+    data: body,
   });
 }
+
 export function postUpdateMonthData(body) {
   return request({
     url: `/api/report_manage/data-month/${body.id}/`,
     method: 'POST',
-    params: body,
+    data: body,
+  });
+}
+
+//主数据获取
+export function getMainData(query) {
+  return request({
+    url: '/api/report_manage/data-all/',
+    method: 'GET',
+    params: query,
+  });
+}
+
+export function getMonthlyData(query) {
+  return request({
+    url: '/api/report_manage/data-month/compare/',
+    method: 'GET',
+    params: query,
   });
 }
 

+ 123 - 103
src/views/reportManage/dataCenter/components/DateTendency/index.vue → src/views/reportManage/dataCenter/combinedDisplay/components/DateTendency/index.vue

@@ -11,44 +11,45 @@
 </template>
 
 <script lang="ts" setup>
-import * as echarts from 'echarts'
-import { Ref, computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
-import { dataCenterMetricsEnum } from '/@/views/reportManage/dataCenter/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 * 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 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';
 
 defineOptions({
   name: 'DataTendencyChart',
-})
+});
 
 interface Props {
-  fetchCard: Function
-  fetchLine: Function
-  fetchLineMonth?: Function
-  fetchLineWeek?: Function
-  query: { [key: string]: any }
-  initMetric?: ShowMetric[]
-  metricEnum?: { [key: string]: string }[]
+  fetchCard: Function;
+  fetchCardWeek?: Function;
+  fetchCardMonth?: Function;
+  fetchLine: Function;
+  fetchLineMonth?: Function;
+  fetchLineWeek?: Function;
+  query: { [key: string]: any };
+  initMetric?: ShowMetric[];
+  metricEnum?: { [key: string]: string }[];
 }
 
 const props = withDefaults(defineProps<Props>(), {
   initMetric: () => [
-    { metric: 'Impression', color: '#0085ff', label: '曝光量' },
-    { metric: 'Click', color: '#3fd4cf', label: '点击量' },
-    { metric: 'Spend', color: '#ff9500', label: '花费' },
+    {metric: 'sales', color: '#0085ff', label: '销售额'},
+    {metric: 'ad_cost', color: '#3fd4cf', label: '广告花费'},
+    {metric: 'ad_sales', color: '#ff9500', label: '广告销售额'},
   ],
-  metricEnum: () => dataCenterMetricsEnum,
-})
+  metricEnum: () => dayMetricsEnum,
+});
 
-const metrics = ref(props.initMetric)
+const metrics = ref(props.initMetric);
 
-const metricsItems: Ref<MetricData[]> = ref([])
-let chartObj: any
-const chartRef = ref()
-const statDim = ref('day')
+const metricsItems: Ref<MetricData[]> = ref([]);
+let chartObj: any;
+const chartRef = ref();
+const statDim = ref('day');
 const option: any = {
   dataset: {
     source: [],
@@ -84,7 +85,7 @@ const option: any = {
       },
       axisLine: {
         show: true,
-        lineStyle: { color: '' },
+        lineStyle: {color: ''},
       },
       show: true,
     },
@@ -128,7 +129,7 @@ const option: any = {
       name: '',
       type: 'bar',
       encode: {
-        x: 'Name',
+        x: 'data_datetime',
         y: '',
       },
       barWidth: '18px',
@@ -143,7 +144,7 @@ const option: any = {
       name: '',
       type: 'line',
       encode: {
-        x: 'Name',
+        x: 'data_datetime',
         y: '',
       },
       symbolSize: 6,
@@ -169,7 +170,7 @@ const option: any = {
       name: '',
       type: 'line',
       encode: {
-        x: 'Name',
+        x: 'data_datetime',
         y: '',
       },
       symbolSize: 6,
@@ -183,135 +184,154 @@ const option: any = {
       },
     },
   ],
-}
-const loading = ref(true)
-const queryParams = computed(() => parseQueryParams(props.query))
+};
+const loading = ref(true);
+const queryParams = computed(() => parseQueryParams(props.query));
 
 onMounted(() => {
-  getMetricsItems()
-  addResize()
+  getMetricsItems();
+  addResize();
   // initLine()
   setTimeout(() => {
-    initLine()
-  }, 0)
-})
+    initLine();
+  }, 0);
+});
 onBeforeUnmount(() => {
   if (chartObj) {
-    chartObj.dispose()
-    chartObj = null
+    chartObj.dispose();
+    chartObj = null;
   }
-  removeResize()
-})
+  removeResize();
+});
 
+//初始化图表
 const initLine = async () => {
-  chartObj = echarts.init(chartRef.value)
-  const items = await getDataset()
-  option.dataset.source = items
+  chartObj = echarts.init(chartRef.value);
+  const items = await getDataset();
+  option.dataset.source = items;
 
   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
+    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
+      info.itemStyle.color = color;
     } else {
-      info.itemStyle = { color: color, borderColor: color }
+      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' },
+          {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
-  })
+    info.name = metrics.value[index].label;
+    info.axisLine.lineStyle.color = metrics.value[index].color;
+  });
 
   XEUtils.arrayEach(props.metricEnum, (info) => {
-    option.legend.selected[info.label] = false
-  })
+    option.legend.selected[info.label] = false;
+  });
   for (const info of metrics.value) {
-    option.legend.selected[info.label] = true
+    option.legend.selected[info.label] = true;
   }
   // console.log(option)
-  chartObj.setOption(option)
-  loading.value = false
-}
+  chartObj.setOption(option);
+  loading.value = false;
+};
 
+//条形图数据
 const getDataset = async () => {
   if (statDim.value === 'week') {
     if (props.fetchLineWeek) {
-      const resp = await props.fetchLineWeek(queryParams.value)
-      return resp.data
+      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)
-      return resp.data
+      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 resp = await props.fetchLine(queryParams.value);
+    return resp.data;
   }
-}
+};
 
+//卡片数据
 const getMetricsItems = async () => {
-  const resp = await props.fetchCard(queryParams.value)
-  const data = resp.data
-  metricsItems.value.length = 0
+  let resp;
+  if (statDim.value === 'week' && props.fetchCardWeek) {
+    resp = await props.fetchCardWeek(queryParams.value);
+  } else if (statDim.value === 'month' && props.fetchCardMonth) {
+    resp = await props.fetchCardMonth(queryParams.value);
+  } else if (props.fetchCard) {
+    resp = await props.fetchCard(queryParams.value);
+  }
+  const data = resp.data;
+  // console.log('卡片数据', data);
+  metricsItems.value.length = 0;
   XEUtils.arrayEach(props.metricEnum, (info) => {
+    // console.log('info', 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)
-  })
-}
+    };
+    // console.log('122', tmp);
+    metricsItems.value.push(tmp);
+  });
+};
 
+//更新图表的选项
 const changeMetric = () => {
-  const opt = buildChartOpt(option, metrics.value)
-  chartObj.setOption(opt)
-}
+  const opt = buildChartOpt(option, metrics.value);
+  chartObj.setOption(opt);
+};
 
-const emit = defineEmits(['changeStatDim'])
+//根据日,周,月更新图表
+const emit = defineEmits(['changeStatDim']);
 const changeStatDim = async () => {
   // emitter.emit('DateTendency-changeStatDim') // 触发DataTable的loading
-  emitter.emit('DateTendency-dateChange', statDim.value)
-  loading.value = true
-  let source = await getDataset()
+  emitter.emit('DateTendency-dateChange', statDim.value);
+  loading.value = true;
+  let source = await getDataset();
   if (source.length > 0) {
-    chartObj.setOption({ dataset: { source: source } })
+    chartObj.setOption({dataset: {source: source}});
   }
-  loading.value = false
-  emit('changeStatDim', source) // 向父组件传递数据后再传递给DataTable
-}
+  await getMetricsItems();
+  loading.value = false;
+  emit('changeStatDim', source); // 向父组件传递数据后再传递给DataTable
+};
 
+//监测dataRange的变化
 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
-})
+  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 resizeChart = () => {
-  chartObj.resize()
-}
+  chartObj.resize();
+};
 const addResize = () => {
-  window.addEventListener('resize', resizeChart)
-}
+  window.addEventListener('resize', resizeChart);
+};
 const removeResize = () => {
-  window.removeEventListener('resize', resizeChart)
-}
+  window.removeEventListener('resize', resizeChart);
+};
 </script>
 
 <style scoped>

+ 0 - 0
src/views/reportManage/dataCenter/components/MetricsCards/index.vue → src/views/reportManage/dataCenter/combinedDisplay/components/MetricsCards/index.vue


+ 1 - 1
src/views/reportManage/dataCenter/components/MetricsCards/mCard.vue → src/views/reportManage/dataCenter/combinedDisplay/components/MetricsCards/mCard.vue

@@ -16,7 +16,7 @@
 
 <script lang="ts" setup>
 import { ref, computed } from 'vue'
-import TextSelector from '/@/components/TextSelector/index.vue'
+import TextSelector from '/src/components/TextSelector/index.vue'
 
 defineOptions({
   name: 'MCard'

+ 227 - 0
src/views/reportManage/dataCenter/combinedDisplay/components/chartDateTendency/index.vue

@@ -0,0 +1,227 @@
+<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 label="week" :disabled="!props.fetchLineWeek">周</el-radio按钮>-->
+    <!--  <el-radio-button label="month" :disabled="!props.fetchLineWeek">月</el-radio按钮>-->
+    <!--</el-radio-group>-->
+    <div style="height: 350px" ref="chartRef"></div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import * as echarts from 'echarts'
+import { Ref, computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
+import { monthCompareMetricsEnum } from '/src/views/reportManage/dataCenter/utils/enum'
+// import MetricsCards from '/@/components/MetricsCards/index.vue'
+import XEUtils from 'xe-utils'
+import MetricsCards from '../MetricsCards/index.vue'
+import emitter from '/src/utils/emitter'
+import { buildChartOpt, monthlyQueryParams } from '/src/views/reportManage/dataCenter/utils/tools'
+import { getLineData } from '/@/views/reportManage/dataCenter/api'
+
+defineOptions({
+  name: 'DataTendencyChart',
+})
+
+interface Props {
+  fetchLine: Function
+  query: { [key: string]: any }
+  initMetric?: ShowMetric[]
+  metricEnum?: { [key: string]: string }[]
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  initMetric: () => [
+    { metric: 'sales', color: '#0085ff', label: '销售额' },
+    { metric: 'planSales', color: '#3fd4cf', label: '计划销售额' },
+    { metric: 'planSales', color: '#3fd4cf', label: '计划销售额' },
+  ],
+  metricEnum: () => monthCompareMetricsEnum,
+})
+
+const metrics = ref(props.initMetric)
+
+const metricsItems: Ref<MetricData[]> = ref([])
+let chartObj: any
+const chartRef = ref()
+const statDim = ref('day')
+const option: any = {
+  dataset: {
+    source: [],
+  },
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      label: {
+        backgroundColor: '#6a7985',
+      },
+    },
+  },
+  legend: {
+    selected: {}, // 控制显隐
+    show: false,
+  },
+  grid: {
+    top: 50,
+    right: 150,
+    bottom: 30,
+    left: 65,
+  },
+  xAxis: {
+    type: 'category',
+  },
+  yAxis: [
+    {
+      id: 0,
+      type: 'value',
+      name: '',
+      splitLine: {
+        show: true, // 设置显示分割线
+      },
+      axisLine: {
+        show: true,
+        lineStyle: {color: ''},
+      },
+      show: true,
+    },
+    {
+      id: 1,
+      type: 'value',
+      name: '',
+      position: 'right',
+      splitLine: {
+        show: false,
+      },
+      axisLine: {
+        show: true,
+        lineStyle: {
+          color: '',
+        },
+      },
+      show: true,
+    },
+  ],
+  series: [
+    {
+      id: 0,
+      name: '',
+      type: 'bar',
+      encode: {
+        x: 'data_datetime',
+        y: '',
+      },
+      barWidth: '18px',
+      yAxisIndex: 0,
+      itemStyle: {
+        color: '',
+        borderRadius: 4,
+      },
+    },
+    {
+      id: 1,
+      name: '',
+      type: 'bar',
+      encode: {
+        x: 'data_datetime',
+        y: '',
+      },
+      barWidth: '18px',
+      yAxisIndex: 0,
+      itemStyle: {
+        color: '',
+        borderRadius: 4,
+      },
+    },
+  ],
+};
+const loading = ref(true)
+const queryParams = computed(() => monthlyQueryParams(props.query))
+
+onMounted(() => {
+  addResize()
+  setTimeout(() => {
+    initLine()
+  }, 0)
+})
+onBeforeUnmount(() => {
+  if (chartObj) {
+    chartObj.dispose()
+    chartObj = null
+  }
+  removeResize()
+})
+
+const initLine = async () => {
+  chartObj = echarts.init(chartRef.value)
+  const items = await getDataset()
+  option.dataset.source = items
+
+  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
+    }
+  })
+  XEUtils.arrayEach(option.yAxis, (info: any, index) => {
+    info.name = metrics.value[index].label
+    info.axisLine.lineStyle.color = metrics.value[index].color
+  })
+
+  XEUtils.arrayEach(props.metricEnum, (info) => {
+    option.legend.selected[info.label] = false
+  })
+  for (const info of metrics.value) {
+    option.legend.selected[info.label] = true
+  }
+
+  chartObj.setOption(option)
+  loading.value = false
+}
+
+const getDataset = async () => {
+  const resp = await props.fetchLine(queryParams.value)
+  return resp.data
+}
+
+const emit = defineEmits(['changeStatDim'])
+
+watch(props.query, async () => {
+  emitter.emit('chartDateTendency-changeStatDim') // 触发DataTable的loading
+  loading.value = true
+  const items = await getDataset()
+  emit('changeStatDim', items) // 向父组件传递数据后再传递给DataTable
+  const opt = { dataset: { source: items } }
+  chartObj.setOption(opt)
+  loading.value = false
+})
+
+const resizeChart = () => {
+  chartObj.resize()
+}
+const addResize = () => {
+  window.addEventListener('resize', resizeChart)
+}
+const removeResize = () => {
+  window.removeEventListener('resize', resizeChart)
+}
+</script>
+
+<style scoped>
+.metrics-cards {
+  display: flex;
+  justify-content: space-between;
+  align-items: flex-start;
+  gap: 12px;
+  width: 100%;
+}
+
+.chart-button-group {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 5px;
+}
+</style>

+ 111 - 0
src/views/reportManage/dataCenter/combinedDisplay/components/monthDatePicker/index.vue

@@ -0,0 +1,111 @@
+<script setup lang="ts">
+import { ref, onMounted } from 'vue';
+
+const currentYear = new Date().getFullYear();
+const currentMonth = new Date().getMonth();
+const monthlyDataTime = ref([
+  new Date(currentYear, 0, 1),
+  new Date(currentYear, currentMonth + 1, 0),
+]);
+
+const startDate = ref(null);
+const endDate = ref(null);
+
+const formatDate = (date) => {
+  const year = date.getFullYear();
+  const month = String(date.getMonth() + 1).padStart(2, '0');
+  const day = String(date.getDate()).padStart(2, '0');
+  return `${year}-${month}-${day}`;
+};
+
+const initializeDates = () => {
+  if (monthlyDataTime.value[0]) {
+    startDate.value = formatDate(monthlyDataTime.value[0]);
+  }
+  if (monthlyDataTime.value[1]) {
+    endDate.value = formatDate(monthlyDataTime.value[1]);
+  }
+  monthDateChange()
+};
+
+onMounted(() => {
+  initializeDates();
+});
+
+const monthShortCuts = [
+  {
+    text: '本月',
+    value: [new Date(), new Date()],
+  },
+  {
+    text: '今年',
+    value: () => {
+      const end = new Date();
+      const start = new Date(new Date().getFullYear(), 0);
+      return [start, end];
+    },
+  },
+  {
+    text: '上六个月',
+    value: () => {
+      const end = new Date();
+      const start = new Date();
+      start.setMonth(start.getMonth() - 6);
+      return [start, end];
+    },
+  },
+];
+
+const emit = defineEmits(['monthDateChange']);
+const monthDateChange = async () => {
+  emit('monthDateChange', {
+    startDate: startDate.value,
+    endDate: endDate.value,
+  });
+};
+
+const handleMonthChange = (value) => {
+  if (value) {
+    if (value[0]) {
+      const start = new Date(value[0]);
+      startDate.value = formatDate(start);
+    }
+    if (value[1]) {
+      const end = new Date(value[1]);
+      endDate.value = formatDate(end);
+    }
+    monthDateChange();
+  }
+};
+
+const disabledDate = (time) => {
+  return time.getTime() > Date.now();
+};
+</script>
+
+<template>
+  <div class="block">
+    <span class="demonstration">月数据时间:</span>
+    <el-date-picker
+        v-model="monthlyDataTime"
+        type="monthrange"
+        unlink-panels
+        range-separator="To"
+        start-placeholder="开始月"
+        end-placeholder="结束月"
+        :disabled-date="disabledDate"
+        @change="handleMonthChange"
+        :shortcuts="monthShortCuts"
+    />
+  </div>
+</template>
+
+<style scoped>
+.block {
+  margin: 10px 0;
+}
+.demonstration {
+  font-size: 14px;
+  color: var(--el-text-color-secondary);
+}
+</style>

+ 162 - 0
src/views/reportManage/dataCenter/combinedDisplay/components/tableData/mainData.vue

@@ -0,0 +1,162 @@
+<script setup lang="ts">
+import { onMounted, reactive, ref, watch, defineProps } from 'vue';
+import { getMainData } from '/@/views/reportManage/dataCenter/api';
+
+const props = defineProps({
+  taskIds: Object,
+  dayDate: Array,
+  weekDate: Array,
+  monthDate: Array,
+});
+
+const tableColumns = ref([]);
+const tableData = ref([]);
+
+const dayStartDate = ref(null);
+const dayEndDate = ref(null);
+const weekStartDate = ref(null);
+const monthStartDate = ref(null);
+
+const gridOptions = reactive({
+  border: false,
+  height: 900,
+  align: null,
+  round: true,
+  loading: false,
+  columnConfig: {
+    resizable: true,
+  },
+  pagerConfig: {
+    enabled: true,
+    total: 20,
+    currentPage: 1,
+    pageSize: 20,
+    pageSizes: [10, 20, 30],
+  },
+  toolbarConfig: {
+    custom: true
+  },
+  columns: tableColumns.value,
+  data: []
+});
+
+// 分页
+const gridEvents = {
+  pageChange({ currentPage, pageSize }) {
+    if (gridOptions.pagerConfig) {
+      gridOptions.pagerConfig.currentPage = currentPage;
+      gridOptions.pagerConfig.pageSize = pageSize;
+      fetchMainData(props.taskIds);
+    }
+  },
+};
+
+// 获取数据
+async function fetchMainData(taskIds) {
+  try {
+    gridOptions.loading = true;
+    const response = await getMainData({
+      page: gridOptions.pagerConfig.currentPage,
+      limit: gridOptions.pagerConfig.pageSize,
+      task_ids: taskIds,
+      day_start_date: dayStartDate.value,
+      day_end_date: dayEndDate.value,
+      week_start_date: weekStartDate.value,
+      month_start_date: monthStartDate.value,
+    });
+    gridOptions.data = response.data;
+    gridOptions.pagerConfig.total = response.total;
+    return response.data;
+  } catch (error) {
+    console.error('Error fetching task data:', error);
+  } finally {
+    gridOptions.loading = false;
+  }
+}
+
+// 监测 taskIds 变化
+watch(() => props.taskIds, (newTaskIds) => {
+  loadData();
+});
+
+// 监测 dayDate 变化
+watch(() => props.dayDate, (newDayDate) => {
+  if (newDayDate) {
+    const [startDate, endDate] = newDayDate;
+    dayStartDate.value = startDate;
+    dayEndDate.value = endDate;
+    loadData();
+  }
+});
+// 监测 weekDate 变化
+watch(() => props.weekDate, (newWeekDate) => {
+  if (newWeekDate) {
+    const [startDate] = newWeekDate;
+    weekStartDate.value = startDate;
+    loadData();
+  }
+});
+// 监测 monthDate 变化
+watch(() => props.monthDate, (newMonthDate) => {
+  if (newMonthDate) {
+    const [startDate] = newMonthDate;
+    monthStartDate.value = startDate;
+    loadData();
+  }
+});
+
+// 获取列名数据
+async function fetchColumnNames(data) {
+  const firstItem = data[0];
+  if (firstItem) {
+    const excludedColumns = ['任务ID', '可录人数','_X_ROW_KEY'];
+    tableColumns.value = Object.keys(firstItem)
+        .filter(key => !excludedColumns.includes(key))
+        .map((key, index) => ({
+          field: key,
+          title: key, // 使用字段名作为列标题
+          width: index < 5 ? 100 : 150,
+          fixed: index < 5 ? 'left' : undefined // 前五列固定
+        }));
+  }
+}
+
+// 加载数据
+async function loadData() {
+  const data = await fetchMainData(props.taskIds);
+  await fetchColumnNames(data);
+  tableData.value = data;
+  gridOptions.columns = tableColumns.value;
+  gridOptions.data = tableData.value;
+}
+
+// 初始化日期值
+function initializeDateValues() {
+  if (props.dayDate) {
+    const [startDate, endDate] = props.dayDate;
+    dayStartDate.value = startDate;
+    dayEndDate.value = endDate;
+  }
+  if (props.weekDate) {
+    const [startDate] = props.weekDate;
+    weekStartDate.value = startDate;
+  }
+  if (props.monthDate) {
+    const [startDate] = props.monthDate;
+    monthStartDate.value = startDate;
+  }
+}
+
+onMounted(async () => {
+  initializeDateValues();
+  await loadData();
+});
+</script>
+
+<template>
+  <vxe-grid v-bind="gridOptions" v-on="gridEvents">
+  </vxe-grid>
+</template>
+
+<style scoped>
+</style>

+ 117 - 0
src/views/reportManage/dataCenter/combinedDisplay/components/tableData/monthlyComparativeData.vue

@@ -0,0 +1,117 @@
+<script setup lang="ts">
+import { defineProps, onMounted, reactive, ref, watch, inject, Ref } from 'vue';
+import { getMainData, getMonthlyData } from '/@/views/reportManage/dataCenter/api';
+import { Session } from '/@/utils/storage';
+
+const props = defineProps({
+  taskIds: Object,
+  monthCurrentDate: Object,
+});
+
+const tableColumns = ref([]);
+const tableData = ref([]);
+
+// const taskIds = ref(props.taskIds);
+const monthStartDate = ref(null);
+const monthEndDate = ref(null);
+
+const gridOptions = reactive({
+  border: false,
+  height: 900,
+  align: null,
+  round: true,
+  loading: false,
+  columnConfig: {
+    resizable: true,
+  },
+  pagerConfig: {
+    enabled: true,
+    total: 20,
+    currentPage: 1,
+    pageSize: 20,
+    pageSizes: [10, 20, 30],
+  },
+  toolbarConfig: {
+    custom: true
+  },
+  columns: tableColumns,
+  data: tableData,
+});
+
+
+watch(() => props.monthCurrentDate, (newMonthDate) => {
+  if (newMonthDate) {
+    console.log('newMonthDate', newMonthDate);
+    monthStartDate.value = newMonthDate.startDate;
+    monthEndDate.value = newMonthDate.endDate;
+    fetchMonthlyData(props.taskIds);
+  }
+});
+// 分页
+const gridEvents = {
+  pageChange({currentPage, pageSize}) {
+    if (gridOptions.pagerConfig) {
+      gridOptions.pagerConfig.currentPage = currentPage;
+      gridOptions.pagerConfig.pageSize = pageSize;
+      fetchMonthlyData();
+    }
+  },
+};
+
+async function fetchMonthlyData(taskIds) {
+  try {
+    gridOptions.loading = true;
+    const response = await getMonthlyData({
+      page: gridOptions.pagerConfig.currentPage,
+      limit: gridOptions.pagerConfig.pageSize,
+      task_ids: taskIds,
+      month_start_date: monthStartDate.value,
+      month_end_date: monthEndDate.value,
+    });
+    if (response.data && response.data.length > 0) {
+      tableData.value = response.data;
+      gridOptions.pagerConfig.total = response.total;
+      const firstRow = response.data[0];
+      const dynamicColumns = [];
+      for (const key in firstRow) {
+        if (key.includes('的销售额')) {
+          dynamicColumns.push({ field: key, title: key,});
+        }
+      }
+      tableColumns.value = [
+        { field: 'platformNumber', title: '平台编号', fixed: "left",},
+        { field: 'platformName', title: '平台名称', fixed: "left", },
+        { field: 'user_name', title: '运营', fixed: "left",},
+        { field: 'country', title: '国家', fixed: "left",},
+        { field: 'brandName', title: '品牌', fixed: "left",},
+        ...dynamicColumns
+      ];
+    } else {
+      tableData.value = [];
+      gridOptions.pagerConfig.total = 0;
+    }
+
+  } catch (error) {
+    console.error('Error fetching data:', error);
+  } finally {
+    gridOptions.loading = false;
+  }
+}
+
+watch(() => props.taskIds, (newTaskIds) => {
+  fetchMonthlyData(newTaskIds);
+});
+
+
+onMounted(() => {
+
+});
+</script>
+
+<template>
+  <vxe-grid v-bind="gridOptions" v-on="gridEvents">
+  </vxe-grid>
+</template>
+
+<style scoped>
+</style>

+ 186 - 0
src/views/reportManage/dataCenter/combinedDisplay/index.vue

@@ -0,0 +1,186 @@
+<script setup lang="ts">
+import { dayMetricsEnum, monthMetricsEnum, weekMetricsEnum } from '/src/views/reportManage/dataCenter/utils/enum';
+import { getCardDayData, getCardMonthData, getCardWeekData, getLineForDay, getLineForMonth, getLineForWeek, getLineData, } from '/src/views/reportManage/dataCenter/api';
+import chartDateTendency from '/src/views/reportManage/dataCenter/combinedDisplay/components/chartDateTendency/index.vue'
+import DateTendency from '/src/views/reportManage/dataCenter/normalDisplay/components/DateTendency/index.vue'
+import { computed, provide, ref, watch } from 'vue';
+import DateRangePicker from '/src/components/DateRangePicker/index.vue'
+import MonthlyDatePicker from '/src/views/reportManage/dataCenter/combinedDisplay/components/monthDatePicker/index.vue'
+import Selector from '/src/views/reportManage/dataCenter/normalDisplay/components/Selector/index.vue'
+import mainData from '/src/views/reportManage/dataCenter/combinedDisplay/components/tableData/mainData.vue'
+import monthlyComparativeData from '/src/views/reportManage/dataCenter/combinedDisplay/components/tableData/monthlyComparativeData.vue'
+import emitter from '/@/utils/emitter';
+
+//日周月
+const dateDimension = ref('day')
+
+const dayDate = ref(getLastSevenDays());
+const weekDate = ref(getLastSevenDays());
+const monthDate = ref(getLastSevenDays());
+const monthCurrentDate = ref({});
+const actualDate = computed(() => {
+  if (dateDimension.value === 'day') {
+    return dayDate.value;
+  } else if (dateDimension.value === 'week') {
+    return weekDate.value;
+  } else if (dateDimension.value === 'month') {
+    return monthDate.value;
+  }
+});
+
+watch(actualDate, (val) => {
+  console.log('actualDate', val);
+});
+// 筛选查询
+const selectorRef = ref(null);
+const taskIds = ref({});
+
+const mainQueryParams = ref({
+  actualDate,
+  taskIds,
+})
+const monthQueryParams = ref({
+  taskIds,
+  monthCurrentDate,
+})
+
+
+
+
+// 表格
+const showTable = ref('mainData'); // 初始显示表格
+const currentTable: any = {
+  mainData,
+  monthlyComparativeData,
+}
+const panes = [
+  { label: '主数据', name: 'mainData' },
+  { label: '月度对比数据', name: 'monthlyComparativeData' },
+]
+
+function updateDataChange(newId) {
+  if (selectorRef.value) {
+    taskIds.value = newId.value;
+  }
+}
+
+const handelDateChange = (date)=>{
+  monthCurrentDate.value = date
+}
+
+function handleButtonClick(tableName) {
+  showTable.value = tableName;
+}
+
+function getLastSevenDays() {
+  const endDate = new Date();
+  const startDate = new Date();
+  startDate.setDate(endDate.getDate() - 6);
+  return [startDate.toISOString().substring(0, 10), endDate.toISOString().substring(0, 10)];
+}
+
+emitter.on('DateTendency-dateChange', (value: string) => {
+  dateDimension.value = value;
+});
+
+const currentMetricEnum = computed(() => {
+  if (dateDimension.value === 'day') {
+    return dayMetricsEnum;
+  } else if (dateDimension.value === 'week') {
+    return weekMetricsEnum;
+  } else if (dateDimension.value === 'month') {
+    return monthMetricsEnum;
+  }
+});
+
+</script>
+
+<template>
+  <div>
+    <el-card>
+      <div class="custom-card-style flex gap-1.5 justify-between my-1.5 mx-2" style="display: flex; align-items: center;">
+        <Selector ref="selectorRef" @update:updateData="updateDataChange"/>
+        <div v-if="showTable === 'monthlyComparativeData'">
+          <MonthlyDatePicker @monthDateChange="handelDateChange"></MonthlyDatePicker>
+        </div>
+      </div>
+      <div  v-if="showTable === 'mainData'" class="custom-card-style flex gap-1.5 justify-between my-1.5 mx-2">
+      <div class="block" style="display: flex; align-items: center;">
+        <span class="demonstration" style="margin-right: 8px;">日数据:</span>
+        <DateRangePicker v-model="dayDate" style="flex-grow: 1;"></DateRangePicker>
+      </div>
+      <div class="block" style="display: flex; align-items: center;">
+        <span class="demonstration" style="margin-right: 8px;">周数据:</span>
+        <DateRangePicker v-model="weekDate" style="flex-grow: 1;"></DateRangePicker>
+      </div>
+      <div class="block" style="display: flex; align-items: center;">
+        <span class="demonstration" style="margin-right: 8px;">月数据:</span>
+        <DateRangePicker v-model="monthDate" style="flex-grow: 1;"></DateRangePicker>
+      </div>
+    </div>
+    </el-card>
+    <el-card v-if="showTable === 'mainData'" class="mb-1.5">
+      <DateTendency
+          :metricEnum="currentMetricEnum"
+          :query="mainQueryParams"
+          :fetchCard="getCardDayData"
+          :fetchCardWeek="getCardWeekData"
+          :fetchCardMonth="getCardMonthData"
+          :fetchLine="getLineForDay"
+          :fetch-line-week="getLineForWeek"
+          :fetch-line-month="getLineForMonth"
+      >
+      </DateTendency>
+    </el-card>
+    <el-card v-if="showTable === 'monthlyComparativeData'" class="mb-1.5">
+      <chartDateTendency
+          :metricEnum="currentMetricEnum"
+          :query="monthQueryParams"
+          :fetchLine="getLineData"
+          :fetch-line-week="getLineForWeek"
+          :fetch-line-month="getLineForMonth"
+      >
+      </chartDateTendency>
+    </el-card>
+    <el-card>
+      <div class="custom-button my">
+        <el-button
+            v-for="pane in panes"
+            :key="pane.name"
+            @click="handleButtonClick(pane.name)"
+            :type="showTable === pane.name ? 'primary' : 'default'">
+          {{ pane.label }}
+        </el-button>
+      </div>
+      <component :is="currentTable[showTable]"
+                 :taskIds="taskIds"
+                 :dayDate="dayDate"
+                 :weekDate="weekDate"
+                 :monthDate="monthDate"
+                 :monthCurrentDate="monthCurrentDate">
+      </component>
+    </el-card>
+  </div>
+</template>
+
+<style scoped>
+.custom-card-style {
+  z-index: 999;
+  position: sticky;
+  top: 0;
+}
+.demonstration {
+  color: var(--el-text-color-secondary);
+  font-size: 14px;
+  margin: 10px;
+}
+.custom-button {
+  z-index: 1000;
+  position: absolute;
+  color: #3a83f7 !important;
+}
+.my {
+  margin-top: 0.8rem;
+  margin-bottom: 0.8rem;
+}
+</style>

+ 0 - 164
src/views/reportManage/dataCenter/components/CombinedDisplay.vue

@@ -1,164 +0,0 @@
-<script setup lang="ts">
-import { dataCenterMetricsEnum } from '/@/views/reportManage/dataCenter/utils/enum'
-import { getCardData, getLineData, getLineMonthData, getLineWeekData } from '/@/views/reportManage/dataCenter/api'
-import DataTendencyChart from '/@/views/reportManage/dataCenter/components/DateTendency/index.vue'
-import { reactive, ref } from 'vue'
-import DateRangePicker from '/@/components/DateRangePicker/index.vue'
-import { storeToRefs } from 'pinia'
-import { useShopInfo } from '/@/stores/shopInfo'
-import { usePublicData } from '/@/stores/publicData'
-import Selector from '/@/views/reportManage/dataCenter/components/Selector/index.vue'
-
-// 店铺信息
-const shopInfo = useShopInfo()
-const { profile } = storeToRefs(shopInfo)
-//公共数据
-const publicData = usePublicData()
-const { dateRange } = storeToRefs(publicData)
-
-const queryParams = ref({
-  profileId: profile.value.profile_id,
-  dateRange,
-  // parentAsin,
-  // childAsin,
-  // sku,
-})
-//表格
-const tableColumns = [
-  { type: 'seq', title: '平台编号' },
-  { field: 'Name', title: '平台名称' },
-  { field: 'Operation', title: '运营' },
-  { field: 'Country', title: '国家' },
-  { field: 'Brand', title: '品牌' },
-  { field: 'Sales', title: '销售额' },
-  { field: 'YearOnYear', title: '期末同比变化' },
-  { field: 'MonthOnMonth', title: '期末环比变化' },
-  { field: 'AdSpend', title: '广告花费' },
-  { field: 'TotalAdSales', title: '广告销售额' },
-  { field: 'ROI', title: '广告ROI' },
-  { field: 'ACOS', title: '广告ACOS' },
-  { field: 'ROAS', title: '广告ROAS' },
-  { field: 'AdExposure', title: '广告曝光' },
-  { field: 'AdOrder', title: '广告订单' },
-  { field: 'AdClick', title: '广告点击' },
-  { field: 'AdConversionRate', title: '广告转化率' },
-  { field: 'CumulativeSales', title: '累计销售额' },
-  { field: 'SalesCompletion', title: '销售额完成情况' },
-  { field: 'MonthOnMonthGrowthRate', title: '环比上周增长率' },
-]
-const tableData = ref([])
-
-const gridOptions = reactive({
-  border: true,
-  height: 300,
-  align: null,
-  round: true,
-  columnConfig: {
-    resizable: true,
-  },
-  columns: tableColumns,
-  toolbarConfig: {
-    slots: {
-      buttons: 'toolbar_buttons',
-    },
-  },
-  data: [
-    {
-      id: 10001,
-      npmName: 'Test1',
-      Operation: 'T1',
-      Country: 'Develop',
-      Brand: 'Man',
-      Sales: 28,
-      YearOnYear: 11,
-      MonthOnMonth: 22,
-      AdSpend: 33,
-      TotalAdSales: 100,
-      ROI: 11,
-      ACOS: 11,
-      ROAS: 11,
-      MonthSalesCompletionRate: 11,
-      AdExposure: 11,
-      AdOrder: 11,
-      AdClick: 11,
-      AdConversionRate: 11,
-      CumulativeSales: 11,
-      SalesCompletion: 11,
-      MonthOnMonthGrowthRate: 11,
-    },
-  ],
-})
-// 模拟从后端获取列名数据
-async function fetchColumnNames() {
-  // 这里替换成实际的后端数据请求
-  const response = await fetch('/api/columns'); // 假设后端接口为 /api/columns
-  const data = await response.json();
-  return data;
-}
-
-// 根据后端数据生成表格列配置
-async function generateColumns() {
-  const columnNames = await fetchColumnNames();
-  columns.value = columnNames.map(columnName => ({
-    field: columnName,
-    title: columnName,
-  }));
-}
-
-// 模拟从后端获取表格数据
-async function fetchTableData() {
-  // 这里替换成实际的后端数据请求
-  const response = await fetch('/api/data'); // 假设后端接口为 /api/data
-  const data = await response.json();
-  return data;
-}
-
-// 加载表格数据
-async function loadData() {
-  tableData.value = await fetchTableData();
-}
-
-// 组件挂载时生成表格列配置并加载数据
-onMounted(async () => {
-  await generateColumns();
-  await loadData();
-});
-
-</script>
-
-<template>
-  <div>
-    <div class="custom-card-style flex gap-1.5 justify-between my-1.5 mx-2">
-      <Selector></Selector>
-      <DateRangePicker v-model="dateRange"></DateRangePicker>
-    </div>
-    <el-card class="mb-1.5">
-      <DataTendencyChart
-        :metricEnum="dataCenterMetricsEnum"
-        :query="queryParams"
-        :fetchCard="getCardData"
-        :fetchLine="getLineData"
-        :fetch-line-month="getLineMonthData"
-        :fetch-line-week="getLineWeekData"
-        >np
-      </DataTendencyChart>
-    </el-card>
-    <el-card>
-      <vxe-grid v-bind="gridOptions">
-        <template #toolbar_buttons>
-          <!--TODO: 主数据-->
-          <vxe-button @click="mainData">主数据</vxe-button>
-          <vxe-button @click="monthlyComparativeData">月对比数据</vxe-button>
-        </template>
-      </vxe-grid>
-    </el-card>
-  </div>
-</template>
-
-<style scoped>
-.custom-card-style {
-  z-index: 999;
-  position: sticky;
-  top: 0;
-}
-</style>

+ 0 - 27
src/views/reportManage/dataCenter/components/CompareData.vue

@@ -1,27 +0,0 @@
-<script setup lang="ts">
-
-</script>
-
-<template>
-<!--  <div class="flex gap-1.5 justify-between">-->
-<!--    <div class="flex gap-1.5">-->
-<!--      <el-select v-model="value1" multiple placeholder="平台编号" style="width: 160px">-->
-<!--        <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />-->
-<!--      </el-select>-->
-<!--      <el-select v-model="value2" multiple placeholder="平台名称" style="width: 160px">-->
-<!--        <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />-->
-<!--      </el-select>-->
-<!--      <el-select v-model="value3" multiple placeholder="运营" style="width: 160px">-->
-<!--        <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />-->
-<!--      </el-select>-->
-<!--      <el-select v-model="value4" multiple placeholder="国家" style="width: 160px">-->
-<!--        <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />-->
-<!--      </el-select>-->
-<!--      <el-select v-model="value4" multiple placeholder="品牌" style="width: 160px">-->
-<!--        <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />-->
-<!--      </el-select>-->
-<!--    </div>-->
-<!--  </div>-->
-</template>
-
-<style scoped></style>

+ 0 - 161
src/views/reportManage/dataCenter/components/DataExport.vue

@@ -1,161 +0,0 @@
-<template>
-  <div>
-    <vxe-grid ref="xGrid" v-bind="gridOptions" v-on="gridEvents">
-      <template #operate="{ row }">
-        <template v-if="hasActiveEditRow(row)">
-          <vxe-button content="取消" @click="clearRowEvent"></vxe-button>
-          <vxe-button status="primary" content="保存" @click="saveRowEvent(row)"></vxe-button>
-        </template>
-        <template v-else>
-          <vxe-button content="编辑" @click="editRowEvent(row)"></vxe-button>
-        </template>
-        <vxe-button status="danger" content="删除" @click="removeRowEvent(row)"></vxe-button>
-      </template>
-
-      <template #name_edit="{ row }">
-        <vxe-input v-model="row.name"></vxe-input>
-      </template>
-      <template #nickname_edit="{ row }">
-        <vxe-input v-model="row.nickname"></vxe-input>
-      </template>
-      <template #sex_default="{ row }">
-        <span>{{ formatSex(row.sex) }}</span>
-      </template>
-      <template #sex_edit="{ row }">
-        <vxe-select v-model="row.sex" transfer>
-          <vxe-option v-for="item in sexList1" :key="item.value" :value="item.value" :label="item.label"></vxe-option>
-        </vxe-select>
-      </template>
-      <template #role_edit="{ row }">
-        <vxe-input v-model="row.role"></vxe-input>
-      </template>
-      <template #describe_edit="{ row }">
-        <vxe-input v-model="row.describe"></vxe-input>
-      </template>
-    </vxe-grid>
-  </div>
-</template>
-
-<script setup>
-import { ref, reactive } from 'vue'
-import { VXETable } from 'vxe-table'
-const xGrid = ref()
-const gridOptions = reactive({
-  border: true,
-  keepSource: true,
-  showOverflow: true,
-  height: 530,
-  loading: false,
-  columnConfig: {
-    resizable: true
-  },
-  pagerConfig: {
-    enabled: true,
-    total: 0,
-    currentPage: 1,
-    pageSize: 10,
-    pageSizes: [10, 20, 50, 100, 200, 500]
-  },
-  editConfig: {
-    trigger: 'manual',
-    mode: 'row',
-    showStatus: true
-  },
-  columns: [
-    { type: 'seq', width: 60 },
-    { type: 'checkbox', width: 50 },
-    { field: 'name', title: 'Name', editRender: { autofocus: '.vxe-input--inner' }, slots: { edit: 'name_edit' } },
-    { field: 'nickname', title: 'Nickname', editRender: { autofocus: '.vxe-input--inner' }, slots: { edit: 'nickname_edit' } },
-    { field: 'sex', title: 'Sex', editRender: {}, slots: { default: 'sex_default', edit: 'sex_edit' } },
-    { field: 'role', title: 'Role', editRender: {}, slots: { edit: 'role_edit' } },
-    { field: 'describe', title: 'Describe', showOverflow: true, editRender: {}, slots: { edit: 'describe_edit' } },
-    { title: '操作', width: 300, slots: { default: 'operate' } }
-  ],
-  data: []
-})
-const sexList1 = ref([
-  { value: '1', label: '男' },
-  { value: '0', label: '女' }
-])
-const findList = () => {
-  gridOptions.loading = true
-  setTimeout(() => {
-    gridOptions.loading = false
-    if (gridOptions.pagerConfig) {
-      gridOptions.pagerConfig.total = 10
-    }
-    gridOptions.data = [
-      { id: 10001, name: 'Test1', nickname: 'T1', role: 'Develop', sex: '1', age: 28, address: 'Shenzhen' },
-      { id: 10002, name: 'Test2', nickname: 'T2', role: 'Test', sex: '0', age: 22, address: 'Guangzhou' },
-      { id: 10003, name: 'Test3', nickname: 'T3', role: 'PM', sex: '1', age: 32, address: 'Shanghai' },
-      { id: 10004, name: 'Test4', nickname: 'T4', role: 'Designer', sex: '0', age: 23, address: 'Shenzhen' },
-      { id: 10005, name: 'Test5', nickname: 'T5', role: 'Develop', sex: '0', age: 30, address: 'Shanghai' },
-      { id: 10006, name: 'Test6', nickname: 'T6', role: 'Develop', sex: '0', age: 27, address: 'Shanghai' },
-      { id: 10007, name: 'Test7', nickname: 'T7', role: 'Develop', sex: '1', age: 29, address: 'Shenzhen' },
-      { id: 10008, name: 'Test8', nickname: 'T8', role: 'Develop', sex: '0', age: 32, address: 'Shanghai' },
-      { id: 10009, name: 'Test9', nickname: 'T9', role: 'Develop', sex: '1', age: 30, address: 'Shenzhen' },
-      { id: 10010, name: 'Test10', nickname: 'T10', role: 'Develop', sex: '0', age: 34, address: 'Shanghai' }
-    ]
-  }, 300)
-}
-const gridEvents = {
-  pageChange ({ currentPage, pageSize }) {
-    if (gridOptions.pagerConfig) {
-      gridOptions.pagerConfig.currentPage = currentPage
-      gridOptions.pagerConfig.pageSize = pageSize
-    }
-    findList()
-  }
-}
-const formatSex = (value) => {
-  if (value === '1') {
-    return '男'
-  }
-  if (value === '0') {
-    return '女'
-  }
-  return ''
-}
-const hasActiveEditRow = (row) => {
-  const $grid = xGrid.value
-  if ($grid) {
-    return $grid.isEditByRow(row)
-  }
-  return false
-}
-const editRowEvent = (row) => {
-  const $grid = xGrid.value
-  if ($grid) {
-    $grid.setEditRow(row)
-  }
-}
-
-const clearRowEvent = () => {
-  const $grid = xGrid.value
-  if ($grid) {
-    $grid.clearEdit()
-  }
-}
-const saveRowEvent = async (row) => {
-  const $grid = xGrid.value
-  if ($grid) {
-    await $grid.clearEdit()
-    gridOptions.loading = true
-    // 模拟异步保存
-    setTimeout(() => {
-      gridOptions.loading = false
-      VXETable.modal.message({ content: `${JSON.stringify(row)}`, status: 'success' })
-    }, 300)
-  }
-}
-const removeRowEvent = async (row) => {
-  const type = await VXETable.modal.confirm('您确定要删除该数据?')
-  const $grid = xGrid.value
-  if ($grid) {
-    if (type === 'confirm') {
-      await $grid.remove(row)
-    }
-  }
-}
-findList()
-</script>

+ 0 - 180
src/views/reportManage/dataCenter/components/DatePicker/index.vue

@@ -1,180 +0,0 @@
-<script setup lang="ts">
-import { computed, ref, watch } from 'vue';
-import dayjs from 'dayjs';
-
-
-
-const dailyEntryTime = ref(dayjs().format("YYYY-MM-DD"));
-const dailyTime = ref(dayjs().subtract(1, "day").format("YYYY-MM-DD"));
-
-const weeklyEntryTime = ref<string | null>(null);
-const weeklySalesTime = ref<string | null>(null);
-const weeklyAdTime = ref<string | null>(null);
-
-
-const entryStartDate = ref<string>("");
-const entryEndDate = ref<string>("");
-const salesStartDate = ref<string>("");
-const salesEndDate = ref<string>("");
-const adStartDate = ref<string>("");
-const adEndDate = ref<string>("");
-
-const monthlyEntryTime = ref(null);
-const startDate = ref(null);
-const endDate = ref(null);
-
-const shortcuts = [
-  {
-    text: "今天",
-    value: new Date(),
-  },
-  {
-    text: "昨天",
-    value: () => {
-      const date = new Date();
-      date.setTime(date.getTime() - 3600 * 1000 * 24);
-      return date;
-    },
-  },
-  {
-    text: "最近七天",
-    value: () => {
-      const date = new Date();
-      date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
-      return date;
-    },
-  },
-];
-
-function handleDayChange(event) {
-  const $dailyEntryTime = dailyEntryTime.value;
-  if ($dailyEntryTime) {
-    const dailyTimeValue = new Date($dailyEntryTime);
-    dailyTimeValue.setDate(dailyTimeValue.getDate());
-    dailyTime.value = dailyTimeValue.toISOString().split("T")[0];
-  } else {
-    dailyTime.value = "";
-  }
-}
-
-const handleWeekChange
-    = () => {
-  if (weeklyEntryTime.value) {
-    entryStartDate.value = dayjs(weeklyEntryTime.value).startOf("isoWeek").format("YYYY-MM-DD");
-    entryEndDate.value = dayjs(weeklyEntryTime.value).endOf("isoWeek").format("YYYY-MM-DD");
-
-    weeklySalesTime.value = weeklyEntryTime.value;
-    salesStartDate.value = entryStartDate.value;
-    salesEndDate.value = entryEndDate.value;
-
-    const adDate = dayjs(weeklyEntryTime.value).subtract(7, "day");
-    weeklyAdTime.value = adDate.format("YYYY-WW");
-    adStartDate.value = adDate.startOf("isoWeek").format("YYYY-MM-DD");
-    adEndDate.value = adDate.endOf("isoWeek").format("YYYY-MM-DD");
-  }
-};
-
-const entryFormat = computed(() => `${entryStartDate.value} to ${entryEndDate.value}`);
-const salesFormat = computed(() => `${salesStartDate.value} to ${salesEndDate.value}`);
-const adFormat = computed(() => `${adStartDate.value} to ${adEndDate.value}`);
-
-watch(weeklyEntryTime, handleWeekChange
-);
-
-const handleMonthChange = (value) => {
-  if (value) {
-    const date = new Date(value);
-    const year = date.getFullYear();
-    const month = date.getMonth() + 1; // getMonth() 返回值为 0-11,需要加 1
-    const lastDay = new Date(year, month, 0).getDate();
-    startDate.value = `${year}-${String(month).padStart(2, "0")}-01`;
-    endDate.value = `${year}-${String(month).padStart(2, "0")}-${lastDay}`;
-  } else {
-    startDate.value = null;
-    endDate.value = null;
-  }
-};
-const monthlyEntryFormat = computed(() => `${startDate.value} to ${endDate.value}`);
-
-const disabledDate = (time: Date) => {
-  return time.getTime() > Date.now();
-};
-
-</script>
-
-<template>
-  <div>
-    <div class="demo-date-picker" v-if="dateType === 'day'">
-      <div class="block">
-        <span class="demonstration">日录入数据时间:</span>
-        <el-date-picker
-            v-model="dailyEntryTime"
-            type="Date"
-            :disabled-date="disabledDate"
-            :shortcuts="shortcuts"
-            @change="handleDayChange"
-        />
-      </div>
-      <div class="block">
-        <span class="demonstration">日数据时间:</span>
-        <el-date-picker
-            v-model="dailyTime"
-            type="Date"
-            :shortcuts="shortcuts"
-            disabled
-        />
-      </div>
-    </div>
-    <div class="demo-date-picker" v-if="dateType === 'week'">
-      <div class="block">
-        <span class="demonstration">周录入数据时间:</span>
-        <el-date-picker
-            v-model="weeklyEntryTime"
-            type="week"
-            :format="entryFormat"
-            placeholder="选择一周"
-            :disabled-date="disabledDate"
-            @change="handleWeekChange
-"
-        />
-      </div>
-      <div class="block">
-        <span class="demonstration">周销售数据时间:</span>
-        <el-date-picker
-            v-model="weeklySalesTime"
-            type="week"
-            :format="salesFormat"
-            placeholder="选择一周"
-            disabled
-        />
-      </div>
-      <div class="block">
-        <span class="demonstration">周广告数据时间:</span>
-        <el-date-picker
-            v-model="weeklyAdTime"
-            type="week"
-            :format="adFormat"
-            placeholder="选择一周"
-            disabled
-        />
-      </div>
-    </div>
-    <div class="demo-date-picker" v-if="dateType === 'month'">
-      <div class="block">
-        <span class="demonstration">月录入数据时间:</span>
-        <el-date-picker
-            v-model="monthlyEntryTime"
-            type="month"
-            :format="monthlyEntryFormat"
-            placeholder="选择月份"
-            @change="handleMonthChange"
-            :disabled-date="disabledDate"
-        />
-      </div>
-    </div>
-  </div>
-</template>
-
-<style scoped>
-
-</style>

+ 0 - 67
src/views/reportManage/dataCenter/components/NormalDisplay.vue

@@ -1,67 +0,0 @@
-<script setup lang="ts">
-import { dataCenterMetricsEnum } from '/@/views/reportManage/dataCenter/utils/enum'
-import { getCardData, getLineData, getLineMonthData, getLineWeekData } from '/@/views/reportManage/dataCenter/api'
-import DataTendencyChart from '/@/views/reportManage/dataCenter/components/DateTendency/index.vue'
-import {onBeforeUnmount, provide, reactive, ref} from 'vue'
-import DateRangePicker from '/@/components/DateRangePicker/index.vue'
-import { storeToRefs } from 'pinia'
-import { useShopInfo } from '/@/stores/shopInfo'
-import { usePublicData } from '/@/stores/publicData'
-import Selector from "/@/views/reportManage/dataCenter/components/Selector/index.vue";
-import TableSelect from "/src/views/reportManage/dataCenter/components/TableDataDisplay.vue"
-import emitter from "/@/utils/emitter";
-// 店铺信息
-const shopInfo = useShopInfo()
-const { profile } = storeToRefs(shopInfo)
-//公共数据
-const publicData = usePublicData()
-const { dateRange } = storeToRefs(publicData)
-
-const queryParams = ref({
-  profileId: profile.value.profile_id,
-  dateRange,
-  // parentAsin,
-  // childAsin,
-  // sku,
-})
-
-const dateDimension = ref('day')
-provide('dateDimension', dateDimension)
-emitter.on('DateTendency-dateChange', (value: string)=>{
-  dateDimension.value = value
-  console.log(1, dateDimension.value)
-})
-
-onBeforeUnmount(()=>{
-  emitter.all.clear();
-})
-</script>
-
-<template>
-  <div>
-    <div class="custom-card-style flex gap-1.5 justify-between my-1.5 mx-2">
-      <Selector></Selector>
-      <DateRangePicker v-model="dateRange"></DateRangePicker>
-    </div>
-    <el-card class="mb-1.5">
-      <DataTendencyChart
-        :metricEnum="dataCenterMetricsEnum"
-        :query="queryParams"
-        :fetchCard="getCardData"
-        :fetchLine="getLineData"
-        :fetch-line-month="getLineMonthData"
-        :fetch-line-week="getLineWeekData"
-        >
-      </DataTendencyChart>
-    </el-card>
-  </div>
-  <el-card><TableSelect></TableSelect></el-card>
-</template>
-
-<style scoped>
-.custom-card-style {
-  z-index: 999;
-  position: sticky;
-  top: 0;
-}
-</style>

+ 0 - 42
src/views/reportManage/dataCenter/components/Selector/index.vue

@@ -1,42 +0,0 @@
-<script setup lang="ts">
-import {ref} from "vue";
-
-const value1 = ref([]) // 平台编号
-const value2 = ref([])
-const value3 = ref([])
-const value4 = ref([])
-const options = [
-  {
-    value: 'Option1',
-    label: 'Option1',
-  },
-  {
-    value: 'Option2',
-    label: 'Option2',
-  },
-]
-</script>
-
-<template>
-    <div class="flex gap-1.5">
-      <el-select v-model="value1" multiple placeholder="平台编号" style="width: 160px">
-        <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
-      </el-select>
-      <el-select v-model="value2" multiple placeholder="平台名称" style="width: 160px">
-        <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
-      </el-select>
-      <el-select v-model="value3" multiple placeholder="运营" style="width: 160px">
-        <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
-      </el-select>
-      <el-select v-model="value4" multiple placeholder="国家" style="width: 160px">
-        <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
-      </el-select>
-      <el-select v-model="value4" multiple placeholder="品牌" style="width: 160px">
-        <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
-      </el-select>
-    </div>
-</template>
-
-<style scoped>
-
-</style>

+ 0 - 228
src/views/reportManage/dataCenter/components/TableDataDisplay.vue

@@ -1,228 +0,0 @@
-<script setup lang="ts">
-import {ref, reactive, computed, inject, watch, Ref, onMounted} from 'vue'
-import {useRouter} from "vue-router";
-import { getDayData, getMonthData, getWeekData } from '/@/views/reportManage/dataCenter/api';
-import {VxeGridListeners} from "vxe-table";
-
-const router = useRouter()
-
-const dateType = inject<Ref>('dateDimension')
-
-//表格
-const dayColumns = [
-  {field: 'platformNumber', title: '平台编号', slots: {default: 'platformNumber_default'}},
-  {field: 'platformName', title: '平台名称', slots: {default: 'platformName_default'}},
-  {field: 'user_name', title: '运营', slots: {default: 'user_name_default'}},
-  {field: 'country', title: '国家' , slots: {default: 'country_default'}},
-  {field: 'brandName', title: '品牌' ,slots: {default: 'brandName_default'}},
-
-  {field: 'sales', title: '销售额'},
-  {field: 'sales_year_on_year', title: '期末同比变化'},
-  {field: 'sales_monthly_year_on_year', title: '期末环比变化'},
-  {field: 'ad_cost', title: '广告花费'},
-  {field: 'ad_sales', title: '广告销售额'},
-  {field: 'roi', title: '广告ROI'},
-  {field: 'acos', title: '广告ACOS'},
-  {field: 'roas', title: '广告ROAS'},
-]
-const weekColumns = [
-  {field: 'platformNumber', title: '平台编号', slots: {default: 'platformNumber_default'}},
-  {field: 'platformName', title: '平台名称', slots: {default: 'platformName_default'}},
-  {field: 'user_name', title: '运营', slots: {default: 'user_name_default'}},
-  {field: 'country', title: '国家' , slots: {default: 'country_default'}},
-  {field: 'brandName', title: '品牌' ,slots: {default: 'brandName_default'}},
-
-  {field: 'sales', title: '销售额'},
-  {field: 'ad_cost', title: '广告花费'},
-  {field: 'ad_sales', title: '广告销售额'},
-  {field: 'roi', title: '广告ROI'},
-  {field: 'acos', title: '广告ACOS'},
-  {field: 'roas', title: '广告ROAS'},
-  {field: 'impression', title: '广告曝光',},
-  {field: 'ad_click', title: '广告点击',},
-  {field: 'ad_order', title: '广告订单',},
-  {field: 'ad_conversion_rate', title: '广告转化率',},
-  {field: 'money_by_amazon', title: 'Amazon回款金额',},
-  {field: 'money_by_other', title: 'Ebay及其他平台可用余额',},
-  {field: 'currencyCode', title: '回款/余额币种',},
-  {field: 'total_sales_current_monthly', title: '销售额完成情况',},
-  {field: 'sales_year_on_year', title: '环比上周增长率',},
-  {field: 'sales_monthly_year_on_year', title: '环比上月周增长率',},
-  {field: 'sales_weekly_year_on_year', title: '环比上年周增长率',},
-  {field: 'session', title: '流量',},
-  {field: 'ad_order', title: '订单',},
-  {field: 'order', title: '转化',},
-  {field: "availableSalesDay", title: "当前存货可售天",},
-  {field: "intransitInventory", title: "当前在途库存",},
-  {field: "overseasStorage", title: "当前海外仓库存",},
-  {field: "refundRate", title: "最近90天平台退货率",},
-]
-const monthColumns = [
-  {field: 'platformNumber', title: '平台编号', slots: {default: 'platformNumber_default'}},
-  {field: 'platformName', title: '平台名称', slots: {default: 'platformName_default'}},
-  {field: 'user_name', title: '运营', slots: {default: 'user_name_default'}},
-  {field: 'country', title: '国家' , slots: {default: 'country_default'}},
-  {field: 'brandName', title: '品牌' ,slots: {default: 'brandName_default'}},
-
-  {field: 'sales', title: '销售额'},
-  {field: 'ad_cost', title: '广告花费'},
-  {field: 'ad_sales', title: '广告销售额'},
-  {field: 'roi', title: '广告ROI'},
-  {field: 'acos', title: '广告ACOS'},
-  {field: 'roas', title: '广告ROAS'},
-  {field: 'impression', title: '广告曝光',},
-  {field: 'ad_click', title: '广告点击',},
-  {field: 'ad_order', title: '广告订单',},
-  {field: 'ad_conversion_rate', title: '广告转化率',},
-  {field: 'total_sales_current_monthly', title: '销售额完成情况',},
-]
-
-const dayData = []
-const weekData = []
-const monthData = []
-
-const gridOptions = reactive({
-  border: false,
-  height: 600,
-  align: null,
-  round: true,
-  columnConfig: {
-    resizable: true,
-  },
-  pagerConfig: {
-    enabled: true,
-    total: 20,
-    currentPage: 1,
-    pageSize: 10,
-    pageSizes: [10, 20, 30],
-  },
-  toolbarConfig: {
-    slots: {
-      buttons: 'toolbar_buttons',
-    },
-  },
-  day: {
-    columns: dayColumns,
-    data: dayData
-  },
-  week: {
-    columns: weekColumns,
-    data: weekData
-  },
-  month: {
-    columns: monthColumns,
-    data: monthData
-  }
-})
-
-const currentGridOptions = computed(() => {
-  const selectedGridOptions = gridOptions[dateType.value];
-  return {
-    ...gridOptions,
-    ...selectedGridOptions
-  };
-})
-// 分页
-const gridEvents = {
-  pageChange({currentPage, pageSize}) {
-    if (gridOptions.pagerConfig) {
-      gridOptions.pagerConfig.currentPage = currentPage
-      gridOptions.pagerConfig.pageSize = pageSize
-      if (dateType.value === 'day') {
-        fetchDayData();
-      } else if (dateType.value === 'week') {
-        fetchWeekData();
-      } else if (dateType.value === 'month') {
-        fetchMonthData();
-      }
-    }
-  }
-}
-
-async function fetchData(apiFunction) {
-  const resp = await apiFunction({
-    page: gridOptions.pagerConfig.currentPage,
-    limit: gridOptions.pagerConfig.pageSize
-  });
-  gridOptions[dateType.value].data = resp.data;
-  gridOptions.pagerConfig.total = resp.total;
-}
-
-async function fetchDayData() {
-  await fetchData(getDayData);
-}
-
-async function fetchWeekData() {
-  await fetchData(getWeekData);
-}
-
-async function fetchMonthData() {
-  await fetchData(getMonthData);
-}
-
-function fetchCurrentData() {
-  if (dateType.value === 'day') {
-    fetchDayData();
-  } else if (dateType.value === 'week') {
-    fetchWeekData();
-  } else if (dateType.value === 'month') {
-    fetchMonthData();
-  }
-}
-
-const handleImport = () => {
-  router.push({
-    name: 'TableDataEntry',
-    query: {
-      dateType: dateType.value,
-    }
-  })
-}
-
-// const QueryTask = (row: any) => {
-//   router.push({
-//     name: 'TaskManage',
-//   })
-// }
-
-onMounted(() => {
-  fetchCurrentData();
-
-  // 监听 dateType 的变化
-  watch(dateType, () => {
-    fetchCurrentData();
-  });
-});
-</script>
-
-<template>
-  <div>
-    <vxe-grid v-bind="currentGridOptions" v-on="gridEvents">
-      <template #toolbar_buttons>
-        <vxe-button @click="handleImport">数据录入</vxe-button>
-        <!--<vxe-button @click="QueryTask">任务列表</vxe-button>-->
-      </template>
-      <template #platformNumber_default ="{ row }">
-        <div>{{ row.task_info.platformNumber }}</div>
-      </template>
-      <template #platformName_default ="{ row }">
-        <div>{{ row.task_info.platformName }}</div>
-      </template>
-      <template #user_name_default ="{ row }">
-        <div>{{ row.task_info.user_name}}</div>
-      </template>
-      <template #country_default ="{ row }">
-        <div>{{ row.task_info.country }}</div>
-      </template>
-      <template #brandName_default ="{ row }">
-        <div>{{ row.task_info.brandName }}</div>
-      </template>
-    </vxe-grid>
-  </div>
-</template>
-
-<style scoped>
-.vxe-grid {
-  border-radius: 10px;
-}
-</style>

+ 0 - 597
src/views/reportManage/dataCenter/components/TableDataEntry.vue

@@ -1,597 +0,0 @@
-<script setup lang="ts">
-import { reactive, ref, computed, inject, watch, onMounted } from 'vue';
-import { VXETable, VxeGridInstance, VxeGridProps, VxeGridEvents } from 'vxe-table';
-import dayjs from 'dayjs';
-import isoWeek from 'dayjs/plugin/isoWeek';
-import { useRouter, useRoute } from 'vue-router';
-import {
-  getDayTaskData,
-  postCreateDayData,
-  postCreateWeekData,
-  postCreateMonthData, getMonthTaskData, getWeekTaskData, postUpdateDayData
-} from '/@/views/reportManage/dataCenter/api';
-
-dayjs.extend(isoWeek);
-
-const router = useRouter();
-const route = useRoute();
-const dateType = <string>route.query.dateType;
-
-//日期选择
-const dailyEntryTime = ref(dayjs().format('YYYY-MM-DD'));
-const dailyTime = ref(dayjs().subtract(1, 'day').format('YYYY-MM-DD'));
-
-const weeklyEntryTime = ref<string | null>(null);
-const weeklySalesTime = ref<string | null>(null);
-const weeklyAdTime = ref<string | null>(null);
-
-const entryStartDate = ref<string>('');
-const entryEndDate = ref<string>('');
-const salesStartDate = ref<string>('');
-const salesEndDate = ref<string>('');
-const adStartDate = ref<string>('');
-const adEndDate = ref<string>('');
-
-const monthlyEntryTime = ref(null);
-const startDate = ref(null);
-const endDate = ref(null);
-
-const shortcuts = [
-  {
-    text: '今天',
-    value: new Date(),
-  },
-  {
-    text: '昨天',
-    value: () => {
-      const date = new Date();
-      date.setTime(date.getTime() - 3600 * 1000 * 24);
-      return date;
-    },
-  },
-  {
-    text: '最近七天',
-    value: () => {
-      const date = new Date();
-      date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
-      return date;
-    },
-  },
-];
-
-function handleDayChange(event) {
-  const $dailyEntryTime = dailyEntryTime.value;
-  if ($dailyEntryTime) {
-    const dailyTimeValue = new Date($dailyEntryTime);
-    dailyTimeValue.setDate(dailyTimeValue.getDate());
-    dailyTime.value = dailyTimeValue.toISOString().split('T')[0];
-  } else {
-    dailyTime.value = '';
-  }
-}
-
-const handleWeekChange = () => {
-  if (weeklyEntryTime.value) {
-    entryStartDate.value = dayjs(weeklyEntryTime.value).startOf('isoWeek').format('YYYY-MM-DD');
-    entryEndDate.value = dayjs(weeklyEntryTime.value).endOf('isoWeek').format('YYYY-MM-DD');
-
-    weeklySalesTime.value = weeklyEntryTime.value;
-    salesStartDate.value = entryStartDate.value;
-    salesEndDate.value = entryEndDate.value;
-
-    const adDate = dayjs(weeklyEntryTime.value).subtract(7, 'day');
-    weeklyAdTime.value = adDate.format('YYYY-WW');
-    adStartDate.value = adDate.startOf('isoWeek').format('YYYY-MM-DD');
-    adEndDate.value = adDate.endOf('isoWeek').format('YYYY-MM-DD');
-  }
-};
-
-const entryFormat = computed(() => `${entryStartDate.value} to ${entryEndDate.value}`);
-const salesFormat = computed(() => `${salesStartDate.value} to ${salesEndDate.value}`);
-const adFormat = computed(() => `${adStartDate.value} to ${adEndDate.value}`);
-
-watch(weeklyEntryTime, handleWeekChange
-);
-
-const handleMonthChange = (value) => {
-  if (value) {
-    const date = new Date(value);
-    const year = date.getFullYear();
-    const month = date.getMonth() + 1; // getMonth() 返回值为 0-11,需要加 1
-    const lastDay = new Date(year, month, 0).getDate();
-    startDate.value = `${year}-${String(month).padStart(2, '0')}-01`;
-    endDate.value = `${year}-${String(month).padStart(2, '0')}-${lastDay}`;
-  } else {
-    startDate.value = null;
-    endDate.value = null;
-  }
-};
-const monthlyEntryFormat = computed(() => `${startDate.value} to ${endDate.value}`);
-
-const disabledDate = (time: Date) => {
-  return time.getTime() > Date.now();
-};
-
-//表格
-const dayColumns = [
-  {field: 'task', title: 'ID', width: 50},
-  {field: 'platformNumber', title: '平台编号'},
-  {field: 'platformName', title: '平台名称'},
-  {field: 'country', title: '国家'},
-  {field: 'brandName', title: '品牌'},
-
-  {field: 'sales', title: '销售额', editRender: {}, slots: {edit: 'sales_edit'}},
-  {field: 'ad_sales', title: '广告销售额', editRender: {}, slots: {edit: 'ad_sales_edit'}},
-  {field: 'ad_cost', title: '广告花费', editRender: {}, slots: {edit: 'ad_cost_edit'}},
-  {title: '操作', width: 300, slots: {default: 'operate'}},
-];
-const weekColumns = [
-  {field: 'task', title: 'ID', width: 50},
-  {field: 'platformNumber', title: '平台编号',},
-  {field: 'platformName', title: '平台名称'},
-  {field: 'country', title: '国家'},
-  {field: 'brandName', title: '品牌'},
-
-  {field: 'sales', title: '销售额',editRender: {}, slots: {edit: 'sales_edit'}},
-  {field: 'total_sales_current_monthly', title: '当月累计销售额',editRender: {}, slots: {edit: 'total_sales_current_monthly_edit'}},
-  {field: 'ad_sales', title: '广告销售额',editRender: {},slots: {edit: 'ad_sales_edit'}},
-  { field: 'ad_cost', title: '广告花费', editRender: {}, slots: { edit: 'ad_cost_edit' } },
-  { field: 'impression', title: '广告曝光', editRender: {}, slots: { edit: 'impression_edit' } },
-  { field: 'ad_click', title: '广告点击', editRender: {}, slots: { edit: 'ad_click_edit' } },
-  { field: 'ad_order', title: '广告订单', editRender: {}, slots: { edit: 'ad_order_edit' } },
-  { field: 'money_by_amazon', title: 'Amazon回款金额', editRender: {}, slots: { edit: 'money_by_amazon_edit' } },
-  { field: 'money_by_other', title: 'Other回款金额', editRender: {}, slots: { edit: 'money_by_other_edit' } },
-  { field: 'session', title: '流量', editRender: {}, slots: { edit: 'session_edit' } },
-  { field: 'order', title: '转化', editRender: {}, slots: { edit: 'order_edit' } },
-  { field: 'availableSalesDay', title: '当前存货可售天', editRender: {}, slots: { edit: 'availableSalesDay_edit' } },
-  { field: 'intransitInventory', title: '当前在途库存', editRender: {}, slots: { edit: 'intransitInventory_edit' } },
-  { field: 'overseasStorage', title: '当前海外仓库存', editRender: {}, slots: { edit: 'overseasStorage_edit' } },
-  { field: 'refundRate', title: '最近90天平台退货率', editRender: {}, slots: { edit: 'refundRate_edit' } },
-  {title: '操作', width: 150, slots: {default: 'operate'}},
-];
-const monthColumns = [
-  {type: 'seq', title: 'ID', width: 50},
-  {field: 'platformName', title: '平台名称'},
-  {field: 'country', title: '国家'},
-  {field: 'brandName', title: '品牌'},
-
-  {field: 'sales', title: '销售额',editRender: {}, slots: {edit: 'sales_edit'}},
-  {field: 'ad_sales', title: '广告销售额',editRender: {},slots: {edit: 'ad_sales_edit'}},
-  { field: 'ad_cost', title: '广告花费', editRender: {}, slots: { edit: 'ad_cost_edit' } },
-  { field: 'impression', title: '广告曝光', editRender: {}, slots: { edit: 'impression_edit' } },
-  { field: 'ad_click', title: '广告点击', editRender: {}, slots: { edit: 'ad_click_edit' } },
-  { field: 'ad_order', title: '广告订单', editRender: {}, slots: { edit: 'ad_order_edit' } },
-  {title: '操作', width: 300, slots: {default: 'operate'}},
-];
-
-const dayData = [];
-const weekData = [];
-const monthData = [];
-
-interface RowVO {
-  task: number;
-  sales: number;
-  ad_sales: number;
-  ad_cost: number;
-
-  total_sales_current_monthly: number;
-  impression: number;
-  ad_click: number;
-  ad_order: number;
-  money_by_amazon: number;
-  money_by_other: number;
-  session: string;
-  order: string;
-  availableSalesDay: number;
-  intransitInventory: number;
-  overseasStorage: number;
-  refundRate: number;
-}
-
-const xGrid = ref<VxeGridInstance<RowVO>>();
-const gridOptions = reactive({
-  border: false,
-  height: 600,
-  align: null,
-  round: true,
-  loading: false,
-  columnConfig: {
-    resizable: true
-  },
-  pagerConfig: {
-    enabled: true,
-    total: 20,
-    currentPage: 1,
-    pageSize: 10,
-    pageSizes: [10, 20, 30],
-  },
-  editConfig: {
-    trigger: 'click',
-    mode: 'row',
-    showStatus: true,
-  },
-  day: {
-    columns: dayColumns,
-    data: dayData
-  },
-  week: {
-    columns: weekColumns,
-    data: weekData
-  },
-  month: {
-    columns: monthColumns,
-    data: monthData
-  }
-});
-
-function fetchCurrentTaskData() {
-  if (dateType === 'day') {
-    fetchDayTaskData();
-  } else if (dateType === 'week') {
-    fetchWeekTaskData();
-  } else if (dateType === 'month') {
-    fetchMonthTaskData();
-  }
-}
-
-const gridEvents = {
-  pageChange({currentPage, pageSize}) {
-    if (gridOptions.pagerConfig) {
-      gridOptions.pagerConfig.currentPage = currentPage;
-      gridOptions.pagerConfig.pageSize = pageSize;
-    }
-    fetchCurrentTaskData();
-  }
-};
-
-// 获取表格数据
-async function fetchTaskData(apiFunction) {
-  try {
-    const resp = await apiFunction({
-      page: gridOptions.pagerConfig.currentPage,
-      limit: gridOptions.pagerConfig.pageSize,
-    });
-    gridOptions[dateType].data = resp.data;
-    console.log('resp', resp.data);
-    gridOptions.pagerConfig.total = resp.total;
-  } catch (error) {
-    console.error('Error fetching task data:', error);
-  }
-}
-async function fetchDayTaskData() {
-  await fetchTaskData(getDayTaskData);
-}
-
-async function fetchWeekTaskData() {
-  await fetchTaskData(getWeekTaskData);
-}
-
-async function fetchMonthTaskData() {
-  await fetchTaskData(getMonthTaskData);
-}
-//创建日数据
-async function createDayData(row: RowVO) {
-  const body = {
-    sales: row.sales,
-    ad_sales: row.ad_sales,
-    ad_cost: row.ad_cost,
-    enter_datetime: dailyEntryTime.value,
-    data_datetime: dailyTime.value,
-    task: row.task,
-  };
-  try {
-    const resp = await postCreateDayData(body);
-    if (resp.code === 2000) {
-      await fetchDayTaskData();
-      await VXETable.modal.message({
-        content: '创建成功',
-        status: 'success',
-      });
-    }
-  } catch (e) {
-    await VXETable.modal.message({content: '创建失败',});
-  }
-}
-//创建周数据
-async function createWeekData(row: RowVO) {
-  const body = {
-    sales:row.sales,
-    total_sales_current_monthly:row.total_sales_current_monthly,
-    ad_sales:row.ad_sales,
-    ad_cost:row.ad_cost,
-    impression:row.impression,
-    ad_click:row.ad_click,
-    ad_order:row.ad_order,
-    money_by_amazon:row.money_by_amazon,
-    money_by_other:row.money_by_other,
-    session:row.session,
-    order:row.order,
-    availableSalesDay:row.availableSalesDay,
-    intransitInventory:row.intransitInventory,
-    overseasStorage:row.overseasStorage,
-    refundRate:row.refundRate,
-    sales_start_time:salesStartDate.value,
-    sales_end_time:salesEndDate.value,
-    ad_start_time:adStartDate.value,
-    ad_end_time:adEndDate.value,
-    enter_start_datetime:entryStartDate.value,
-    enter_end_datetime:entryEndDate.value,
-    task:row.task,
-  };
-  try {
-    const resp = await postCreateWeekData(body);
-    console.log(body);
-    if (resp.code === 2000) {
-      await fetchWeekTaskData();
-      await VXETable.modal.message({
-        content: '创建成功',
-        status: 'success',
-      });
-    }
-  } catch (e) {
-    await VXETable.modal.message({content: '创建失败',});
-  }
-}
-//创建月数据
-async function createMonthData(row: RowVO) {
-  const body = {
-    sales:row.sales,
-    ad_sales:row.ad_sales,
-    ad_cost:row.ad_cost,
-    impression:row.impression,
-    ad_click:row.ad_click,
-    ad_order:row.ad_order,
-    data_start_time:startDate.value,
-    data_end_time:endDate.value,
-    enter_start_time:startDate.value,
-    enter_end_time:endDate.value,
-    task:row.task,
-  };
-  try {
-    const resp = await postCreateMonthData(body);
-    console.log(body);
-    if (resp.code === 2000) {
-      await fetchMonthTaskData();
-      await VXETable.modal.message({
-        content: '创建成功',
-        status: 'success',
-      });
-    }
-  } catch (e) {
-    await VXETable.modal.message({content: '创建失败',});
-  }
-}
-
-const saveRowEvent = async (row: RowVO) => {
-  const $grid = xGrid.value;
-  if ($grid) {
-    await $grid.clearEdit();
-    gridOptions.loading = true;
-    if (dateType === 'day') {
-      await createDayData(row);
-    } else if (dateType === 'week') {
-      await createWeekData(row);
-    } else if (dateType === 'month') {
-      await createMonthData(row);
-    }
-    // 模拟异步保存
-    setTimeout(() => {
-      gridOptions.loading = false;
-    }, 300);
-  }
-};
-
-// 更新日数据
-async function updateDayData(row: RowVO) {
-  const $grid = xGrid.value;
-  if ($grid) {
-    const body = {
-    id: row.id,
-    sales: row.sales,
-    ad_sales: row.ad_sales,
-    ad_cost: row.ad_cost,
-    enter_datetime: dailyEntryTime.value,
-    data_datetime: dailyTime.value,
-    task: row.task,
-  };
-    console.log(body);
-  try {
-    const resp = await postUpdateDayData(body);
-    if (resp.code === 2000) {
-      await fetchDayTaskData();
-      await VXETable.modal.message({
-        content: '更新成功',
-        status: 'success',
-      });
-    }
-  } catch (error) {
-    console.log('error:', error);
-  }
-  }
-}
-//更新周数据
-async function updateWeekData(row: RowVO) {
-}
-//更新月数据
-async function updateMonthData(row: RowVO) {
-}
-const editRowEvent = async (row: any) => {
-  const $grid = xGrid.value;
-  if ($grid) {
-    await $grid.clearEdit();
-    await updateDayData(row)
-    gridOptions.loading = true;
-    // 模拟异步保存
-    setTimeout(() => {
-      gridOptions.loading = false;
-    }, 300);
-  }
-};
-
-const currentGridOptions = computed(() => {
-  const selectedGridOptions = gridOptions[dateType] || gridOptions['day'];
-  return {
-    ...gridOptions,
-    ...selectedGridOptions
-  };
-});
-
-onMounted(() => {
-  fetchCurrentTaskData();
-});
-</script>
-
-<template>
-  <div>
-    <el-card class="custom-card-style flex gap-1.5 justify-between my-1.5 mx-2">
-      <div class="demo-date-picker" v-if="dateType === 'day'">
-        <div class="block">
-          <span class="demonstration">日录入数据时间:</span>
-          <el-date-picker
-              v-model="dailyEntryTime"
-              type="Date"
-              :disabled-date="disabledDate"
-              :shortcuts="shortcuts"
-              @change="handleDayChange"
-          />
-        </div>
-        <div class="block">
-          <span class="demonstration">日数据时间:</span>
-          <el-date-picker
-              v-model="dailyTime"
-              type="Date"
-              :shortcuts="shortcuts"
-              disabled
-          />
-        </div>
-      </div>
-      <div class="demo-date-picker" v-if="dateType === 'week'">
-        <div class="block">
-          <span class="demonstration">周录入数据时间:</span>
-          <el-date-picker
-              v-model="weeklyEntryTime"
-              type="week"
-              :format="entryFormat"
-              placeholder="选择一周"
-              :disabled-date="disabledDate"
-              @change="handleWeekChange
-"
-          />
-        </div>
-        <div class="block">
-          <span class="demonstration">周销售数据时间:</span>
-          <el-date-picker
-              v-model="weeklySalesTime"
-              type="week"
-              :format="salesFormat"
-              placeholder="选择一周"
-              disabled
-          />
-        </div>
-        <div class="block">
-          <span class="demonstration">周广告数据时间:</span>
-          <el-date-picker
-              v-model="weeklyAdTime"
-              type="week"
-              :format="adFormat"
-              placeholder="选择一周"
-              disabled
-          />
-        </div>
-      </div>
-      <div class="demo-date-picker" v-if="dateType === 'month'">
-        <div class="block">
-          <span class="demonstration">月录入数据时间:</span>
-          <el-date-picker
-              v-model="monthlyEntryTime"
-              type="month"
-              :format="monthlyEntryFormat"
-              placeholder="选择月份"
-              @change="handleMonthChange"
-              :disabled-date="disabledDate"
-          />
-        </div>
-      </div>
-    </el-card>
-  </div>
-  <el-card class="mx-2">
-    <div style="position: relative">
-      <vxe-grid ref="xGrid" v-bind="currentGridOptions" v-on="gridEvents">
-        <template #operate="{ row }">
-          <vxe-button content="创建" @click="saveRowEvent(row)"></vxe-button>
-          <vxe-button content="更新" @click="editRowEvent(row)"></vxe-button>
-        </template>
-        <template #sales_edit="{ row }">
-          <vxe-input v-model="row.sales"></vxe-input>
-        </template>
-        <template #ad_sales_edit="{ row }">
-          <vxe-input v-model="row.ad_sales"></vxe-input>
-        </template>
-        <template #ad_cost_edit="{ row }">
-          <vxe-input v-model="row.ad_cost"></vxe-input>
-        </template>
-        <template #total_sales_current_monthly_edit="{ row }">
-          <vxe-input v-model="row.total_sales_current_monthly"></vxe-input>
-        </template>
-        <template #impression_edit="{ row }">
-          <vxe-input v-model="row.impression"></vxe-input>
-        </template>
-        <template #ad_click_edit="{ row }">
-          <vxe-input v-model="row.ad_click"></vxe-input>
-        </template>
-        <template #ad_order_edit="{ row }">
-          <vxe-input v-model="row.ad_order"></vxe-input>
-        </template>
-        <template #money_by_amazon_edit="{ row }">
-          <vxe-input v-model="row.money_by_amazon"></vxe-input>
-        </template>
-        <template #money_by_other_edit="{ row }">
-          <vxe-input v-model="row.money_by_other"></vxe-input>
-        </template>
-        <template #session_edit="{ row }">
-          <vxe-input v-model="row.session"></vxe-input>
-        </template>
-        <template #order_edit="{ row }">
-          <vxe-input v-model="row.order"></vxe-input>
-        </template>
-        <template #availableSalesDay_edit="{ row }">
-          <vxe-input v-model="row.availableSalesDay"></vxe-input>
-        </template>
-        <template #intransitInventory_edit="{ row }">
-          <vxe-input v-model="row.intransitInventory"></vxe-input>
-        </template>
-        <template #overseasStorage_edit="{ row }">
-          <vxe-input v-model="row.overseasStorage"></vxe-input>
-        </template>
-        <template #refundRate_edit="{ row }">
-          <vxe-input v-model="row.refundRate"></vxe-input>
-        </template>
-
-      </vxe-grid>
-    </div>
-  </el-card>
-</template>
-
-<style scoped>
-.demo-date-picker {
-  display: flex;
-  width: 100%;
-  padding: 0;
-  flex-wrap: wrap;
-}
-
-.demo-date-picker .block:last-child {
-  border-right: none;
-}
-
-.demo-date-picker .demonstration {
-  color: var(--el-text-color-secondary);
-  font-size: 14px;
-  margin: 10px;
-}
-
-.vxe-grid {
-  border-radius: 10px;
-  margin-bottom: 10px;
-}
-</style>

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

@@ -1,23 +1,23 @@
 <script setup lang="ts">
 import { ref } from 'vue'
 import type { TabsPaneContext } from 'element-plus'
-import CombinedDisplay from '/src/views/reportManage/dataCenter/components/CombinedDisplay.vue'
-import DataExport from '/@/views/reportManage/dataCenter/components/DataExport.vue'
-import CompareData from '/@/views/reportManage/dataCenter/components/CompareData.vue'
-import NormalDisplay from '/@/views/reportManage/dataCenter/components/NormalDisplay.vue'
+import CombinedDisplay from '/src/views/reportManage/dataCenter/combinedDisplay/index.vue'
+// import DataExport from '/src/views/reportManage/dataCenter/normalDisplay/components/DataExport.vue'
+import CompareData from '/src/views/reportManage/dataCenter/normalDisplay/components/CompareData.vue'
+import NormalDisplay from '/src/views/reportManage/dataCenter/normalDisplay/index.vue'
 
 const activeName = ref('NormalDisplay')
 const tabsComponents: any = {
   NormalDisplay,
   CombinedDisplay,
   // CompareData,
-  DataExport,
+  // DataExport,
 }
 const panes = [
   { label: '普通展示', name: 'NormalDisplay' },
   { label: '合并展示', name: 'CombinedDisplay' },
   // { label: '对比数据', name: 'CompareData' },
-  { label: '数据导出', name: 'DataExport' },
+  // { label: '数据导出', name: 'DataExport' },
 ]
 
 /**
@@ -31,8 +31,8 @@ function handleTabClick(tab: TabsPaneContext, event: Event) {
 </script>
 
 <template>
-  <div class="px-2">
-    <el-tabs v-model="activeName" type="card" class="demo-tabs" @tab-click="handleTabClick">
+  <div class="px-2 my-2">
+    <el-tabs v-model="activeName" type="border-card" class="demo-tabs" @tab-click="handleTabClick">
       <el-tab-pane v-for="pane in panes" :key="pane.name" :label="pane.label" :name="pane.name"></el-tab-pane>
       <component :is="tabsComponents[activeName]"></component>
     </el-tabs>

+ 10 - 0
src/views/reportManage/dataCenter/normalDisplay/components/CompareData.vue

@@ -0,0 +1,10 @@
+<template>
+
+</template>
+
+<script setup lang="ts">
+
+</script>
+
+<style scoped>
+</style>

+ 11 - 0
src/views/reportManage/dataCenter/normalDisplay/components/DataExport.vue

@@ -0,0 +1,11 @@
+<template>
+
+</template>
+
+<script setup>
+
+</script>
+
+<style scoped>
+
+</style>

+ 244 - 0
src/views/reportManage/dataCenter/normalDisplay/components/DatePicker/index.vue

@@ -0,0 +1,244 @@
+<script lang="ts" setup>
+import { computed, inject, provide, Ref, ref, onMounted, watch } from 'vue';
+import dayjs from 'dayjs';
+import isoWeek from 'dayjs/plugin/isoWeek';
+import emitter from '/@/utils/emitter';
+import DateRangePicker from '/src/components/DateRangePicker/index.vue';
+
+dayjs.extend(isoWeek);
+import enLocale from 'element-plus/es/locale/lang/en';
+import { storeToRefs } from 'pinia';
+import { usePublicData } from '/src/stores/publicData';
+
+const dateType = inject<Ref>('dateDimension');
+
+//公共数据
+const publicData = usePublicData();
+const {dateRange} = storeToRefs(publicData);
+
+const startWeek = ref(null);
+const endWeek = ref(null);
+const weekStartDate = ref<string | null>(dayjs().locale('en').subtract(1, 'week').startOf('week').format('YYYY-MM-DD'));
+const weekEndDate = ref<string | null>(dayjs().locale('en').endOf('week').format('YYYY-MM-DD'));
+
+const currentYear = new Date().getFullYear();
+const currentMonth = new Date().getMonth();
+const monthlyDataTime = ref([
+  new Date(currentYear, 0, 1),
+  new Date(new Date().getFullYear(), currentMonth, 0),
+]);
+
+const startDate = ref(null);
+const endDate = ref(null);
+
+const emit = defineEmits(['dateChange']);
+const dateChange = async () => {
+  if (dateType.value === 'day') {
+    emit('dateChange', {
+      dailyStartDate: dateRange.value[0],
+      dailyTime: dateRange.value[1],
+    });
+  } else if (dateType.value === 'week') {
+    emit('dateChange', {
+      weekStartDate: weekStartDate.value,
+      weekEndDate: weekEndDate.value,
+    });
+  } else if (dateType.value === 'month') {
+    emit('dateChange', {
+      startDate,
+      endDate,
+    });
+  }
+};
+
+const monthShortCuts = [
+  {
+    text: '本月',
+    value: [new Date(), new Date()],
+  },
+  {
+    text: '今年',
+    value: () => {
+      const end = new Date();
+      const start = new Date(new Date().getFullYear(), 0);
+      return [start, end];
+    },
+  },
+  {
+    text: '上六个月',
+    value: () => {
+      const end = new Date();
+      const start = new Date();
+      start.setMonth(start.getMonth() - 6);
+      return [start, end];
+    },
+  },
+];
+
+// 处理开始周变化的函数
+const handleStartWeekChange = (value) => {
+  if (value) {
+    weekStartDate.value = dayjs(value).locale('en').startOf('week').format('YYYY-MM-DD');
+  }
+  checkAndEmitDateChange();
+};
+
+const handleEndWeekChange = (value) => {
+  if (value) {
+    weekEndDate.value = dayjs(value).locale('en').endOf('week').format('YYYY-MM-DD');
+  }
+  checkAndEmitDateChange();
+};
+
+const checkAndEmitDateChange = () => {
+  if (startWeek.value && endWeek.value) {
+    dateChange();
+  }
+};
+
+const handleMonthChange = (value) => {
+  if (value) {
+    if (monthlyDataTime.value[0]) {
+      const start = new Date(monthlyDataTime.value[0]);
+      const year = start.getFullYear();
+      const month = start.getMonth();
+      startDate.value = `${year}-${String(month + 1).padStart(2, '0')}-01`;
+      if (monthlyDataTime.value[1]) {
+        const end = new Date(monthlyDataTime.value[1]);
+        const year = end.getFullYear();
+        const month = end.getMonth() + 1;
+        const lastDay = new Date(year, month, 0).getDate();
+        endDate.value = `${year}-${String(month).padStart(2, '0')}-${lastDay}`;
+      }
+      dateChange();
+    }
+  }
+};
+
+const disabledDate = (time: Date) => {
+  return time.getTime() > Date.now();
+};
+
+const weekDisabledDate = (time: Date) => {
+  if (startWeek.value) {
+    const startDate = dayjs(startWeek.value).toDate();
+    const currentDate = new Date();
+    // 禁用结束日期不是在当前日期之前或不是在开始日期之后的日期
+    return time.getTime() >= currentDate.getTime() || time.getTime() <= startDate.getTime();
+  }
+  return time.getTime() >= new Date().getTime();
+};
+
+function setDefaultDate() {
+  switch (dateType.value) {
+    case 'day':
+      dateRange.value = [
+        dayjs().subtract(6, 'day').startOf('day').format('YYYY-MM-DD'),
+        dayjs().endOf('day').format('YYYY-MM-DD')
+      ];
+      dateChange();
+      console.log(dateRange.value);
+      break;
+    case 'week':
+      startWeek.value = dayjs().locale('en').subtract(1, 'week').startOf('week').format('YYYY-MM-DD');
+      endWeek.value = dayjs().locale('en').endOf('week').format('YYYY-MM-DD');
+      dateChange();
+      break;
+    case 'month':
+      const startOfMonth = new Date(new Date().getFullYear(), new Date().getMonth() - 1, 1);
+      const endOfMonth = new Date();
+      monthlyDataTime.value = [startOfMonth, endOfMonth];
+      const formattedStartDate = dayjs(startOfMonth).format('YYYY-MM-DD');
+      const formattedEndDate = dayjs(endOfMonth).format('YYYY-MM-DD');
+      startDate.value = formattedStartDate;
+      endDate.value = formattedEndDate;
+      dateChange();
+      break;
+  }
+}
+
+onMounted(() => {
+  setDefaultDate();
+});
+
+watch(dateType, () => {
+  setDefaultDate();
+});
+</script>
+
+<template>
+  <div>
+    <div v-if="dateType === 'day'" class="demo-date-picker">
+      <div class="block" style="display: flex; align-items: center;">
+        <span class="demonstration" style="margin-right: 8px;">日数据时间:</span>
+        <DateRangePicker v-model="dateRange" style="flex-grow: 1;" @change="dateChange"></DateRangePicker>
+      </div>
+    </div>
+    <div v-if="dateType === 'week'" class="demo-date-picker">
+      <div class="block">
+        <span class="demonstration">周数据时间:</span>
+        <el-config-provider :locale="enLocale">
+          <el-date-picker
+              v-model="startWeek"
+              :clearable="false"
+              :disabled-date="disabledDate"
+              format="YYYY 第 WW 周"
+              placeholder="选择开始周"
+              type="week"
+              @change="handleStartWeekChange"
+          />
+        </el-config-provider>
+      </div>
+      <div class="block">
+        <span class="demonstration">至</span>
+        <el-config-provider :locale="enLocale">
+          <el-date-picker
+              v-model="endWeek"
+              :clearable="false"
+              :disabled="!startWeek"
+              :disabled-date="weekDisabledDate"
+              format="YYYY 第 WW 周"
+              placeholder="选择结束周"
+              type="week"
+              @change="handleEndWeekChange"
+          />
+        </el-config-provider>
+      </div>
+    </div>
+    <div v-if="dateType === 'month'" class="demo-date-picker">
+      <div class="block">
+        <span class="demonstration">月数据时间:</span>
+        <el-date-picker
+            v-model="monthlyDataTime"
+            :disabled-date="disabledDate"
+            :shortcuts="monthShortCuts"
+            end-placeholder="结束月"
+            range-separator="To"
+            start-placeholder="开始月"
+            type="monthrange"
+            unlink-panels
+            @change="handleMonthChange"
+        />
+      </div>
+    </div>
+  </div>
+</template>
+
+<style scoped>
+.demo-date-picker {
+  display: flex;
+  width: 100%;
+  padding: 0;
+  flex-wrap: wrap;
+}
+
+.demo-date-picker .block:last-child {
+  border-right: none;
+}
+
+.demo-date-picker .demonstration {
+  color: var(--el-text-color-secondary);
+  font-size: 14px;
+  margin: 10px;
+}
+</style>

+ 339 - 0
src/views/reportManage/dataCenter/normalDisplay/components/DateTendency/index.vue

@@ -0,0 +1,339 @@
+<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 label="week" :disabled="!props.fetchLineWeek">周</el-radio-button>
+      <el-radio-button label="month" :disabled="!props.fetchLineWeek">月</el-radio-button>
+    </el-radio-group>
+    <div style="height: 350px" ref="chartRef"></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 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';
+
+defineOptions({
+  name: 'DataTendencyChart',
+});
+
+interface Props {
+  fetchCard: Function;
+  fetchCardWeek?: Function;
+  fetchCardMonth?: Function;
+  fetchLine: Function;
+  fetchLineMonth?: Function;
+  fetchLineWeek?: Function;
+  query: { [key: string]: any };
+  initMetric?: ShowMetric[];
+  metricEnum?: { [key: string]: string }[];
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  initMetric: () => [
+    {metric: 'sales', color: '#0085ff', label: '销售额'},
+    {metric: 'ad_sales', color: '#ff9500', label: '广告销售额'},
+    {metric: 'ad_cost', color: '#3fd4cf', label: '广告花费'},
+  ],
+  metricEnum: () => dayMetricsEnum,
+});
+
+const metrics = ref(props.initMetric);
+
+const metricsItems: Ref<MetricData[]> = ref([]);
+let chartObj: any;
+const chartRef = ref();
+const statDim = ref('day');
+const option: any = {
+  dataset: {
+    source: [],
+  },
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      label: {
+        backgroundColor: '#6a7985',
+      },
+    },
+  },
+  legend: {
+    selected: {}, // 控制显隐
+    show: false,
+  },
+  grid: {
+    top: 50,
+    right: 150,
+    bottom: 30,
+    left: 65,
+  },
+  xAxis: {
+    type: 'category',
+  },
+  yAxis: [
+    {
+      id: 0,
+      type: 'value',
+      name: '',
+      splitLine: {
+        show: true, // 设置显示分割线
+      },
+      axisLine: {
+        show: true,
+        lineStyle: {color: ''},
+      },
+      show: true,
+    },
+    {
+      id: 1,
+      type: 'value',
+      name: '',
+      position: 'right',
+      splitLine: {
+        show: false,
+      },
+      axisLine: {
+        show: true,
+        lineStyle: {
+          color: '',
+        },
+      },
+      show: true,
+    },
+    {
+      id: 2,
+      type: 'value',
+      position: 'right',
+      offset: 90,
+      name: '',
+      splitLine: {
+        show: false,
+      },
+      axisLine: {
+        show: true,
+        lineStyle: {
+          color: '',
+        },
+      },
+      show: true,
+    },
+  ],
+  series: [
+    {
+      id: 0,
+      name: '',
+      type: 'bar',
+      encode: {
+        x: 'data_datetime',
+        y: '',
+      },
+      barWidth: '18px',
+      yAxisIndex: 0,
+      itemStyle: {
+        color: '',
+        borderRadius: 4,
+      },
+    },
+    {
+      id: 1,
+      name: '',
+      type: 'bar',
+      encode: {
+        x: 'data_datetime',
+        y: '',
+      },
+      barWidth: '18px',
+      yAxisIndex: 0,
+      itemStyle: {
+        color: '',
+        borderRadius: 4,
+      },
+    },
+    {
+      id: 2,
+      name: '',
+      type: 'line',
+      encode: {
+        x: 'data_datetime',
+        y: '',
+      },
+      symbolSize: 6,
+      symbol: 'circle',
+      smooth: true,
+      yAxisIndex: 2,
+      itemStyle: {},
+      areaStyle: {},
+      emphasis: {
+        focus: 'series',
+      },
+    },
+  ],
+};
+const loading = ref(true);
+const queryParams = computed(() => parseQueryParams(props.query));
+
+onMounted(() => {
+  getMetricsItems();
+  addResize();
+  setTimeout(() => {
+    initLine();
+  }, 0);
+});
+onBeforeUnmount(() => {
+  if (chartObj) {
+    chartObj.dispose();
+    chartObj = null;
+  }
+  removeResize();
+});
+
+//初始化图表
+const initLine = async () => {
+  chartObj = echarts.init(chartRef.value);
+  const items = await getDataset();
+  option.dataset.source = items;
+
+  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;
+  });
+
+  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 () => {
+  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) {
+    resp = await props.fetchCardWeek(queryParams.value);
+  } else if (statDim.value === 'month' && props.fetchCardMonth) {
+    resp = await props.fetchCardMonth(queryParams.value);
+  } else if (props.fetchCard) {
+    resp = await props.fetchCard(queryParams.value);
+  }
+  const data = resp.data;
+  console.log('卡片数据', queryParams.value);
+  metricsItems.value.length = 0;
+  XEUtils.arrayEach(props.metricEnum, (info) => {
+    // console.log('info', info);
+    const tmp: MetricData = {
+      label: info.label,
+      value: info.value,
+      metricVal: data[info.value],
+      gapVal: data[`gap${info.value}`],
+      preVal: data[`prev${info.value}`],
+    };
+    // console.log('122', tmp);
+    metricsItems.value.push(tmp);
+  });
+};
+
+//更新图表的选项
+const changeMetric = () => {
+  const opt = buildChartOpt(option, metrics.value);
+  chartObj.setOption(opt);
+};
+
+//根据日,周,月更新图表
+const emit = defineEmits(['changeStatDim']);
+const changeStatDim = async () => {
+  // emitter.emit('DateTendency-changeStatDim') // 触发DataTable的loading
+  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;
+  emit('changeStatDim', source); // 向父组件传递数据后再传递给DataTable
+};
+
+//监测dataRange的变化
+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 resizeChart = () => {
+  chartObj.resize();
+};
+const addResize = () => {
+  window.addEventListener('resize', resizeChart);
+};
+const removeResize = () => {
+  window.removeEventListener('resize', resizeChart);
+};
+</script>
+
+<style scoped>
+.metrics-cards {
+  display: flex;
+  justify-content: space-between;
+  align-items: flex-start;
+  gap: 12px;
+  width: 100%;
+}
+
+.chart-button-group {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 5px;
+}
+</style>

+ 149 - 0
src/views/reportManage/dataCenter/normalDisplay/components/MetricsCards/index.vue

@@ -0,0 +1,149 @@
+<template>
+  <div class="metrics-cards">
+    <MCard
+     v-model="info.metric"
+     :metric-items="props.metricItems"
+     :color="info.color"
+     v-for="info in displayMetrics"
+     @change-metric="changedMetric"
+     @click="clickCard(info.metric)"/>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { ref, Ref, onBeforeMount, watch, onMounted, computed } from 'vue'
+import MCard from './mCard.vue'
+import XEUtils from 'xe-utils';
+
+interface Props {
+  modelValue: ShowMetric[],
+  metricItems: MetricData[],
+}
+const colorsMap: { [key: string]: boolean } = {}
+const props = defineProps<Props>()
+const emits = defineEmits(['change', 'update:modelValue'])
+// const allMetricItems = ref(props.metricItems)
+const selectedMetric = ref(props.modelValue)
+const displayMetrics: Ref<{metric:string, color?: string}[]> = ref([])
+
+const metricMap = computed(():{[key: string]: string} => {
+  const tmp:{[key: string]: string} = {}
+  for (const info of props.metricItems) {
+    tmp[info.value] = info.label
+  }
+  return tmp
+})
+onBeforeMount(()=> {
+  const dup:{[key: string]: boolean} = {}
+  // 初始显示图线的三个维度
+  for (const info of selectedMetric.value) {
+    displayMetrics.value.push({ metric: info.metric, color: info.color })
+    dup[info.metric] = true
+    if (info.color) { colorsMap[info.color] = true }
+  }
+})
+
+const getColor = () => {
+  for (const [k,v] of Object.entries(colorsMap)) {
+    if (!v) {
+      colorsMap[k] = true
+      return k
+    }
+  }
+  return ""
+}
+const unsetColor = (color: string ) => {
+  if (XEUtils.has(colorsMap, color)) {
+    colorsMap[color] = false
+  }
+}
+const changedMetric = (newVal: string, oldVal: string) => {
+  for (const info of props.metricItems) {
+    if (info.value === newVal) {
+      info.disabled = true 
+    } else if (info.value === oldVal) {
+      info.disabled = false
+    }
+  }
+  const index = selectedMetric.value.findIndex( info => info.metric === oldVal)
+  if (index > -1) {
+    selectedMetric.value[index].metric = newVal
+    selectedMetric.value[index].label = metricMap.value[newVal]
+    emits('update:modelValue', selectedMetric.value)
+    emits('change', selectedMetric.value)
+  }
+}
+const clickCard = (metric: string) => {
+  const index = selectedMetric.value.findIndex( info => info.metric === metric)
+  if (index > -1) {  // 已存在则删除
+    if (selectedMetric.value.length <= 1 ) return
+    const tmp = selectedMetric.value[index]
+    selectedMetric.value.splice(index, 1)
+    unsetColor(tmp.color)
+    emits('update:modelValue', selectedMetric.value)
+    emits('change', selectedMetric.value)
+  } else {  // 不存在则添加
+    if (selectedMetric.value.length === 3) { 
+      selectedMetric.value[2].metric = metric
+      selectedMetric.value[2].label = metricMap.value[metric]
+    } else {
+      const color = getColor()
+      selectedMetric.value.push({ metric: metric, color: color, label: metricMap.value[metric]})
+    }
+    emits('update:modelValue', selectedMetric.value)
+    emits('change', selectedMetric.value)
+  }
+}
+watch(selectedMetric.value, () => {
+  const cache:{ [key: string]: string } = {}
+  for (const info of selectedMetric.value) {
+    cache[info.metric] = info.color
+  }
+  for (const info of displayMetrics.value) {
+    const color = cache[info.metric]
+    if (color) {
+      info.color = color
+    } else {
+      info.color = undefined
+    }
+  }
+})
+
+watch(
+  props.metricItems,
+  () => {
+    const dup:{[key: string]: boolean} = {}
+    for (const info of displayMetrics.value) { dup[info.metric] = true }
+    let needNum = 6 - displayMetrics.value.length
+    if (needNum > 0) {  
+      // 从所有维度中选择剩余
+      for (const info of props.metricItems) {
+        if (!dup[info.value]) {
+          displayMetrics.value.push({ metric: info.value })
+          dup[info.value] = true
+          needNum --
+          if (needNum === 0) break
+        }
+      }
+    }
+    for (const info of props.metricItems) {
+      if (dup[info.value]) {
+        info.disabled = true
+      } else {
+        info.disabled = false
+      }  
+    }
+  }
+)
+
+</script>
+
+<style scoped>
+.metrics-cards {
+  display: flex;
+  justify-content: space-between;
+  align-items: flex-start;
+  gap: 12px;
+  width: 100%;
+}
+</style>

+ 100 - 0
src/views/reportManage/dataCenter/normalDisplay/components/MetricsCards/mCard.vue

@@ -0,0 +1,100 @@
+<template>
+  <el-card class="metric-card">
+    <div class="metric-card__color" :style="boardTopStyle"></div>
+    <TextSelector v-model="metric" :options="props.metricItems" @change="changeMetric"></TextSelector>
+    <div class="metric-value">{{ selectedData?.metricVal }}</div>
+    <div class="metric-pre">
+      <span>{{ selectedData?.preVal }}&nbsp;&nbsp;</span>
+      <el-icon v-show="selectedData?.gapVal" style="display: inline-block; padding-top: 2px">
+        <Top :class="colorClass" v-if="isBoost"/>
+        <Bottom :class="colorClass" v-else/>
+      </el-icon>
+      <span :class="colorClass">{{ selectedData?.gapVal ? selectedData?.gapVal + '%' : '' }}</span>
+    </div>
+  </el-card>
+</template>
+
+<script lang="ts" setup>
+import { ref, computed } from 'vue'
+import TextSelector from '/src/components/TextSelector/index.vue'
+
+defineOptions({
+  name: 'MCard'
+})
+
+interface Props {
+  modelValue: string,
+  metricItems: MetricData[],
+  color?: string,
+}
+const props = defineProps<Props>()
+const emits = defineEmits(["update:modelValue", "change-metric"])
+const metric = ref(props.modelValue)
+const changeMetric = ( newVal: string, oldVal: string) => {
+  emits('update:modelValue', newVal)
+  emits('change-metric', newVal, oldVal)
+}
+const selectedData = computed(():MetricData|null => {
+  const info = props.metricItems.find(item => item.value === metric.value)
+  if(!info) return null
+  return info
+})
+const boardTopStyle = computed(() => {
+  const style_ = { "border-top-color": "rgb(232, 244, 255)" }
+  if (props.color) { style_["border-top-color"] = props.color }
+  return style_
+})
+const isBoost = computed(():boolean => {
+  return (selectedData.value?.gapVal ?? -1) > 0
+})
+const colorClass = computed((): "green"|"red" => isBoost.value ? "green": "red")
+
+</script>
+
+<style scoped>
+:deep(.el-card__body) {
+  padding: 0;
+}
+.metric-card {
+  padding: 12px 8px;
+  height: 100px;
+
+  position: relative;
+  min-width: 150px;
+  overflow-y: hidden;
+  line-height: 1.4;
+  background-color: #fff;
+  border-radius: 10px;
+  box-shadow: 0 0 12px rgba(51,89,181,.1607843137254902);
+  cursor: pointer;
+  flex-grow: 1;
+}
+.metric-card__color {
+  position: absolute;
+  top: 0;
+  left: 8px;
+  width: calc(100% - 16px);
+  height: 0;
+  border-top: 4px solid #86909c;
+  border-left: 2px solid transparent;
+  border-right: 2px solid transparent;
+}
+.metric-value {
+  padding: 8px 0;
+  font-size: 18px;
+  font-weight: 700;
+  line-height: 25px;
+}
+
+.metric-pre {
+  color: #6b7785;
+  font-size: 12px;
+  white-space: nowrap;
+}
+.red {
+  color: red;
+}
+.green {
+  color: #1cbc0e;
+}
+</style>

+ 115 - 0
src/views/reportManage/dataCenter/normalDisplay/components/Selector/index.vue

@@ -0,0 +1,115 @@
+<script setup lang="ts">
+import { onMounted, ref, watch } from 'vue';
+import { getOperationSelect, getTasks, getTasksId } from '/@/views/reportManage/TaskManage/api';
+
+const emit = defineEmits();
+const platformNumberList = ref([]);
+const platformNameList = ref([]);
+const operationList = ref([]);
+const countryList = ref([]);
+const brandNameList = ref([]);
+
+const platformNumberOptions = ref([]);
+const platformNameOptions = ref([]);
+const operationOptions = ref([]);
+const countryOptions = ref([]);
+const brandNameOptions = ref([]);
+
+async function fetchInitialData() {
+  try {
+    const response = await getTasks();
+    const data = response.data;
+    platformNumberOptions.value = [...new Set(data.map(item => item.platformNumber))];
+    platformNameOptions.value = [...new Set(data.map(item => item.platformName))];
+    countryOptions.value = [...new Set(data.map(item => item.country))];
+    brandNameOptions.value = [...new Set(data.map(item => item.brandName))];
+  } catch (error) {
+    console.error('Error fetching initial data:', error);
+  }
+}
+
+async function fetchOperationSelect() {
+  try {
+    const resp = await getOperationSelect();
+    operationOptions.value = resp.data.map((item: any) => {
+      return {value: item.id, label: item.name};
+    });
+  } catch (e) {
+    console.error('Failed to fetch operation select:', e);
+  }
+}
+const updateData = ref([])
+const filteredData = ref([]);
+
+async function fetchFilteredData() {
+  const filters: any = {};
+  const processFilter = (list: any, singleKey: string, multipleKey: string) => {
+    if (list.value.length === 1) {
+      filters[singleKey] = list.value[0];
+    } else if (list.value.length > 1) {
+      filters[multipleKey] = list.value.join(',');
+    }
+  };
+
+  processFilter(platformNumberList, 'platformNumber', 'platformNumbers');
+  processFilter(platformNameList, 'platformName', 'platformNames');
+  processFilter(countryList, 'country', 'countrys');
+  processFilter(brandNameList, 'brandName', 'brandNames');
+
+  if (operationList.value.length > 0) {
+    filters.users = operationList.value.join(',');
+  }
+  // console.log('filters',filters);
+  filteredData.value = filters;
+  try {
+    const response = await getTasksId(filters);
+    updateData.value = response.data.map(item => item.id).join(',');
+  } catch (error) {
+    console.error('Error fetching filtered data:', error);
+  }
+}
+
+async function emitChange() {
+  await fetchFilteredData();
+  // await fetchFilteredDataId();
+  emit('update:filteredData', filteredData);
+  emit('update:updateData', updateData);
+}
+
+watch([platformNumberList, platformNameList, countryList, brandNameList, operationList], () => {
+  emitChange();
+
+})
+
+onMounted(() => {
+  fetchInitialData();
+  fetchOperationSelect();
+});
+
+defineExpose({fetchFilteredData, filteredData, updateData});
+
+
+</script>
+
+<template>
+  <div class="flex gap-1.5">
+    <el-select v-model="platformNumberList" multiple collapse-tags collapse-tags-tooltip placeholder="平台编号" style="width: 160px">
+      <el-option v-for="item in platformNumberOptions" :key="item" :label="item" :value="item" />
+    </el-select>
+    <el-select v-model="platformNameList" multiple collapse-tags collapse-tags-tooltip placeholder="平台名称" style="width: 160px">
+      <el-option v-for="item in platformNameOptions" :key="item" :label="item" :value="item" />
+    </el-select>
+    <el-select v-model="operationList" multiple collapse-tags collapse-tags-tooltip placeholder="运营" style="width: 160px">
+      <el-option v-for="item in operationOptions" :key="item.value" :label="item.label" :value="item.value" />
+    </el-select>
+    <el-select v-model="countryList" multiple collapse-tags collapse-tags-tooltip placeholder="国家" style="width: 160px">
+      <el-option v-for="item in countryOptions" :key="item" :label="item" :value="item" />
+    </el-select>
+    <el-select v-model="brandNameList" multiple collapse-tags collapse-tags-tooltip placeholder="品牌" style="width: 160px">
+      <el-option v-for="item in brandNameOptions" :key="item" :label="item" :value="item" />
+    </el-select>
+  </div>
+</template>
+
+<style scoped>
+</style>

+ 194 - 0
src/views/reportManage/dataCenter/normalDisplay/components/TableDataDisplay.vue

@@ -0,0 +1,194 @@
+<script setup lang="ts">
+import { ref, reactive, computed, inject, watch, Ref, onMounted, provide } from 'vue';
+import { useRouter } from 'vue-router';
+import { getDayData, getMonthData, getWeekData } from '/src/views/reportManage/dataCenter/api';
+import { dayDataColumns, weekDataColumns, monthDataColumns } from '../../utils/columns';
+import dayjs from 'dayjs';
+
+const router = useRouter();
+const dateType = inject<Ref>('dateDimension');
+const currentDate = inject<Ref>('currentDate')
+const props = defineProps({
+  taskIds: Object,
+});
+
+
+//表格
+const dayData = [];
+const weekData = [];
+const monthData = [];
+
+const gridOptions = reactive({
+  border: false,
+  height: 600,
+  align: null,
+  round: true,
+  loading: false,
+  showHeaderOverflow: true,
+  showOverflow: true,
+  columnConfig: {
+    resizable: true,
+  },
+  rowConfig: {
+    isHover: true,
+  },
+  pagerConfig: {
+    enabled: true,
+    total: 20,
+    currentPage: 1,
+    pageSize: 10,
+    pageSizes: [10, 20, 30],
+  },
+  toolbarConfig: {
+    slots: {
+      buttons: 'toolbar_buttons',
+    },
+  },
+  day: {
+    columns: dayDataColumns,
+    data: dayData
+  },
+  week: {
+    columns: weekDataColumns,
+    data: weekData
+  },
+  month: {
+    columns: monthDataColumns,
+    data: monthData
+  }
+});
+
+const currentGridOptions = computed(() => {
+  const selectedGridOptions = gridOptions[dateType.value];
+  return {
+    ...gridOptions,
+    ...selectedGridOptions
+  };
+});
+// 分页
+const gridEvents = {
+  pageChange({currentPage, pageSize}) {
+    if (gridOptions.pagerConfig) {
+      gridOptions.pagerConfig.currentPage = currentPage;
+      gridOptions.pagerConfig.pageSize = pageSize;
+      fetchCurrentData(props.taskIds);
+    }
+  }
+};
+
+let dailyTime, weekEndDate, endDate, data_datetime_exact;
+watch(currentDate,(newValue)=>{
+  if (dateType.value === 'day') {
+    dailyTime = dayjs(newValue.dailyTime).format("YYYY-MM-DD");
+    // console.log('dailyTime',dailyTime);
+  }else if (dateType.value === 'week') {
+    weekEndDate = dayjs(newValue.weekEndDate).format("YYYY-MM-DD");
+    console.log('week',weekEndDate);
+  }else if(dateType.value === 'month'){
+    endDate = dayjs(newValue.endDate).format("YYYY-MM-DD");
+  }
+  fetchCurrentData(props.taskIds);
+})
+
+async function fetchData(apiFunction, taskIds) {
+  try {
+    gridOptions.loading = true;
+    const resp = await apiFunction({
+      page: gridOptions.pagerConfig.currentPage,
+      limit: gridOptions.pagerConfig.pageSize,
+      data_datetime_exact: data_datetime_exact,
+      task_ids: taskIds,
+    });
+    gridOptions[dateType.value].data = resp.data;
+    gridOptions.pagerConfig.total = resp.total;
+  } catch (error) {
+    console.error('Error fetching task data:', error);
+  } finally {
+    gridOptions.loading = false;
+  }
+}
+
+async function fetchDayData(taskIds) {
+  await fetchData(getDayData, taskIds);
+}
+
+async function fetchWeekData(taskIds) {
+  await fetchData(getWeekData, taskIds);
+}
+
+async function fetchMonthData(taskIds) {
+  await fetchData(getMonthData, taskIds);
+}
+
+function fetchCurrentData(taskIds) {
+  if (dateType.value === 'day') {
+    data_datetime_exact = dailyTime;
+    fetchDayData(taskIds);
+  } else if (dateType.value === 'week') {
+    data_datetime_exact = weekEndDate;
+    fetchWeekData(taskIds);
+  } else if (dateType.value === 'month') {
+    data_datetime_exact = endDate;
+    fetchMonthData(taskIds);
+  }
+}
+
+watch(() => props.taskIds, (newTaskIds) => {
+  fetchCurrentData(newTaskIds);
+}, );
+
+const handleImport = () => {
+  router.push({
+    name: 'TableDataEntry',
+    query: {
+      dateType: dateType.value,
+    }
+  });
+};
+
+onMounted(() => {
+  fetchCurrentData(props.taskIds);
+  watch(dateType, () => {
+    fetchCurrentData(props.taskIds);
+  });
+});
+</script>
+
+<template>
+  <div>
+    <vxe-grid v-bind="currentGridOptions" v-on="gridEvents">
+      <template #toolbar_buttons>
+        <vxe-button status="primary" icon="vxe-icon-add" @click="handleImport" >数据录入</vxe-button>
+        <p v-if="dateType === 'day'">{{dailyTime}}日数据</p>
+        <p v-else-if="dateType === 'week'">{{weekEndDate}}周数据</p>
+        <p v-else-if="dateType === 'month'">{{endDate}}月数据</p>
+      </template>
+      <template #platformNumber_default="{ row }">
+        <div>{{ row.task_info.platformNumber }}</div>
+      </template>
+      <template #platformName_default="{ row }">
+        <div>{{ row.task_info.platformName }}</div>
+      </template>
+      <template #user_name_default="{ row }">
+        <div>{{ row.task_info.user_name }}</div>
+      </template>
+      <template #country_default="{ row }">
+        <div>{{ row.task_info.country }}</div>
+      </template>
+      <template #brandName_default="{ row }">
+        <div>{{ row.task_info.brandName }}</div>
+      </template>
+      <template #currencyCode_default="{ row }">
+        <div>{{ row.task_info.currencyCode }}</div>
+      </template>
+
+    </vxe-grid>
+  </div>
+</template>
+
+<style scoped>
+.vxe-grid {
+  border-radius: 10px;
+}
+
+</style>

+ 826 - 0
src/views/reportManage/dataCenter/normalDisplay/components/TableDataEntry.vue

@@ -0,0 +1,826 @@
+<script setup lang="ts">
+import { reactive, ref, computed, inject, watch, onMounted, nextTick } from 'vue';
+import { VXETable, VxeGridInstance, VxeGridProps, VxeGridEvents } from 'vxe-table';
+import dayjs from 'dayjs';
+import isoWeek from 'dayjs/plugin/isoWeek';
+import { useRouter, useRoute } from 'vue-router';
+import {
+  getDayTaskData,
+  postCreateDayData,
+  postCreateWeekData,
+  postCreateMonthData, getMonthTaskData, getWeekTaskData, postUpdateDayData, postUpdateWeekData, postUpdateMonthData
+} from '/src/views/reportManage/dataCenter/api';
+import { dayColumns, weekColumns, monthColumns } from '../../utils/columns';
+import { ComponentSize, FormInstance, FormRules } from 'element-plus';
+import enLocale from 'element-plus/es/locale/lang/en';
+
+dayjs.extend(isoWeek);
+
+const router = useRouter();
+const route = useRoute();
+const dateType = <string>route.query.dateType;
+
+//日期选择
+const dailyEntryTime = ref(dayjs().format('YYYY-MM-DD'));
+const dailyTime = ref(dayjs().subtract(1, 'day').format('YYYY-MM-DD'));
+
+const weeklyEntryTime = ref(null);
+const weeklySalesTime = ref(null);
+const weeklyAdTime = ref(null);
+
+const entryStartDate = ref('');
+const entryEndDate = ref('');
+const salesStartDate = ref('');
+const salesEndDate = ref('');
+const adStartDate = ref('');
+const adEndDate = ref('');
+
+const monthlyEntryTime = ref(null);
+const startDate = ref(null);
+const endDate = ref(null);
+
+const shortcuts = [
+  {
+    text: '今天',
+    value: new Date(),
+  },
+  {
+    text: '昨天',
+    value: () => {
+      const date = new Date();
+      date.setTime(date.getTime() - 3600 * 1000 * 24);
+      return date;
+    },
+  },
+  {
+    text: '最近七天',
+    value: () => {
+      const date = new Date();
+      date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
+      return date;
+    },
+  },
+];
+
+function handleDayChange(event) {
+  const $dailyEntryTime = dailyEntryTime.value;
+  if ($dailyEntryTime) {
+    const dailyTimeValue = new Date($dailyEntryTime);
+    dailyTimeValue.setDate(dailyTimeValue.getDate());
+    dailyTime.value = dailyTimeValue.toISOString().split('T')[0];
+  } else {
+    dailyTime.value = '';
+  }
+}
+
+const handleWeekChange = () => {
+  if (weeklyEntryTime.value) {
+    entryStartDate.value = dayjs(weeklyEntryTime.value).locale('en').startOf('week').format('YYYY-MM-DD');
+    entryEndDate.value = dayjs(weeklyEntryTime.value).locale('en').endOf('week').format('YYYY-MM-DD');
+
+    weeklySalesTime.value = weeklyEntryTime.value;
+    salesStartDate.value = entryStartDate.value;
+    salesEndDate.value = entryEndDate.value;
+
+    const adDate = dayjs(weeklyEntryTime.value).locale('en').subtract(7, 'day');
+    weeklyAdTime.value = adDate.format('YYYY-WW');
+    adStartDate.value = adDate.startOf('week').format('YYYY-MM-DD');
+    adEndDate.value = adDate.endOf('week').format('YYYY-MM-DD');
+  }
+};
+
+const entryFormat = computed(() => `${entryStartDate.value} to ${entryEndDate.value}`);
+const salesFormat = computed(() => `${salesStartDate.value} to ${salesEndDate.value}`);
+const adFormat = computed(() => `${adStartDate.value} to ${adEndDate.value}`);
+
+watch(weeklyEntryTime, handleWeekChange);
+
+const handleMonthChange = (value) => {
+  if (value) {
+    const date = new Date(value);
+    const year = date.getFullYear();
+    const month = date.getMonth() + 1; // getMonth() 返回值为 0-11,需要加 1
+    const lastDay = new Date(year, month, 0).getDate();
+    startDate.value = `${year}-${String(month).padStart(2, '0')}-01`;
+    endDate.value = `${year}-${String(month).padStart(2, '0')}-${lastDay}`;
+  } else {
+    startDate.value = null;
+    endDate.value = null;
+  }
+};
+const monthlyEntryFormat = computed(() => `${startDate.value} to ${endDate.value}`);
+
+const disabledDate = (time: Date) => {
+  return time.getTime() > Date.now();
+};
+
+//表单
+interface taskDataForm {
+  sales: number;
+  ad_sales: number;
+  ad_cost: number;
+
+  total_sales_current_monthly: number;
+  impression: number;
+  ad_click: number;
+  ad_order: number;
+  money_by_amazon: number;
+  money_by_other: number;
+  session: string;
+  order: string;
+  availableSalesDay: number;
+  intransitInventory: number;
+  overseasStorage: number;
+  refundRate: number;
+}
+
+const formSize = ref<ComponentSize>('default');
+const dayFormVisible = ref(false);
+const taskDataFormRef = ref<FormInstance>();
+const taskDataForm = reactive({
+  sales: 0,
+  ad_sales: 0,
+  ad_cost: 0,
+  total_sales_current_monthly: 0,
+  impression: 0,
+  ad_click: 0,
+  ad_order: 0,
+  money_by_amazon: 0,
+  money_by_other: 0,
+  session: '',
+  order: '',
+  availableSalesDay: 0,
+  intransitInventory: 0,
+  overseasStorage: 0,
+  refundRate: 0,
+});
+
+const resetForm = (formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  formEl.resetFields();
+};
+const rules = reactive<FormRules>({
+  sales: [{required: true, message: '请输入销售额', trigger: 'blur'}],
+  ad_sales: [{required: true, message: '请输入广告销售额', trigger: 'blur'}],
+  ad_cost: [{required: true, message: '请输入广告花费', trigger: 'blur'}],
+  total_sales_current_monthly: [{required: true, message: '请输入当月销售额', trigger: 'blur'}],
+  impression: [{required: true, message: '请输入广告展示量', trigger: 'blur'}],
+  ad_click: [{required: true, message: '请输入广告点击量', trigger: 'blur'}],
+  ad_order: [{required: true, message: '请输入广告订单量', trigger: 'blur'}],
+  money_by_amazon: [{required: true, message: '请输入亚马逊佣金', trigger: 'blur'}],
+  money_by_other: [{required: true, message: '请输入其他佣金', trigger: 'blur'}],
+  session: [{required: true, message: '请输入会话数', trigger: 'blur'}],
+  order: [{required: true, message: '请输入订单数', trigger: 'blur'}],
+  availableSalesDay: [{required: true, message: '请输入可用销量天数', trigger: 'blur'}],
+  intransitInventory: [{required: true, message: '请输入在途库存', trigger: 'blur'}],
+  overseasStorage: [{required: true, message: '请输入海外仓库存', trigger: 'blur'}],
+  refundRate: [{required: true, message: '请输入最近90天平台退货率', trigger: 'blur'}],
+});
+
+//表格
+let taskId = 0;
+let currentId = 0;
+
+const dayData = [];
+const weekData = [];
+const monthData = [];
+
+interface RowVO {
+  id: number;
+  task: number;
+  sales: number;
+  ad_sales: number;
+  ad_cost: number;
+
+  total_sales_current_monthly: number;
+  impression: number;
+  ad_click: number;
+  ad_order: number;
+  money_by_amazon: number;
+  money_by_other: number;
+  session: string;
+  order: string;
+  availableSalesDay: number;
+  intransitInventory: number;
+  overseasStorage: number;
+  refundRate: number;
+}
+
+const xGrid = ref<VxeGridInstance<RowVO>>();
+const gridOptions = reactive({
+  border: false,
+  height: 600,
+  align: null,
+  round: true,
+  loading: false,
+  showHeaderOverflow: true,
+  showOverflow: true,
+  columnConfig: {
+    resizable: true
+  },
+  rowConfig: {
+    // isCurrent: true,
+    isHover: true,
+  },
+  pagerConfig: {
+    enabled: true,
+    total: 20,
+    currentPage: 1,
+    pageSize: 10,
+    pageSizes: [10, 20, 30],
+  },
+  editConfig: {
+    trigger: 'manual',
+    mode: 'row',
+    showStatus: true,
+  },
+  day: {
+    columns: dayColumns,
+    data: dayData
+  },
+  week: {
+    columns: weekColumns,
+    data: weekData
+  },
+  month: {
+    columns: monthColumns,
+    data: monthData
+  }
+});
+
+
+const gridEvents = {
+  pageChange({currentPage, pageSize}) {
+    if (gridOptions.pagerConfig) {
+
+      gridOptions.pagerConfig.currentPage = currentPage;
+      gridOptions.pagerConfig.pageSize = pageSize;
+    }
+    fetchCurrentTaskData();
+  }
+};
+
+const hasActiveEditRow = (row: RowVO) => {
+  const $grid = xGrid.value;
+  if ($grid) {
+    return $grid.isEditByRow(row);
+  }
+  return false;
+};
+
+const clearRowEvent = () => {
+  const $grid = xGrid.value;
+  if ($grid) {
+    $grid.clearEdit();
+  }
+};
+
+const handelEditRow = (row: RowVO) => {
+  const $grid = xGrid.value;
+  if ($grid) {
+    $grid.setEditRow(row);
+  }
+};
+
+// 获取表格数据
+let dateParams;
+
+async function fetchTaskData(apiFunction) {
+  try {
+    gridOptions.loading = true;
+    const resp = await apiFunction({
+      page: gridOptions.pagerConfig.currentPage,
+      limit: gridOptions.pagerConfig.pageSize,
+      ...dateParams
+    });
+    gridOptions[dateType].data = resp.data;
+    gridOptions.pagerConfig.total = resp.total;
+  } catch (error) {
+    console.error('Error fetching task data:', error);
+  } finally {
+    gridOptions.loading = false;
+  }
+}
+
+watch(dailyTime, () => {
+  fetchCurrentTaskData();
+});
+
+watch(salesEndDate, () => {
+  fetchCurrentTaskData();
+});
+
+watch(endDate, () => {
+  fetchCurrentTaskData();
+});
+
+async function fetchDayTaskData() {
+  await fetchTaskData(getDayTaskData);
+}
+
+async function fetchWeekTaskData() {
+  await fetchTaskData(getWeekTaskData);
+}
+
+async function fetchMonthTaskData() {
+  await fetchTaskData(getMonthTaskData);
+}
+
+function fetchCurrentTaskData() {
+  if (dateType === 'day') {
+    dateParams = {
+      day_start_date: dailyTime.value,
+      day_end_date: dailyTime.value
+    };
+    fetchDayTaskData();
+  } else if (dateType === 'week') {
+    dateParams = {
+      week_start_date: salesEndDate.value,
+      week_end_date: salesEndDate.value
+    };
+    fetchWeekTaskData();
+  } else if (dateType === 'month') {
+    dateParams = {
+      month_start_date: endDate.value,
+      month_end_date: endDate.value
+    };
+    fetchMonthTaskData();
+  }
+}
+
+const editEvent = async (row: RowVO) => {
+  taskId = row.task;
+  currentId = row.id;
+  Object.assign(taskDataForm, row);
+  dayFormVisible.value = true;
+};
+
+//创建日数据
+async function createDayData() {
+  const body = {
+    sales: taskDataForm.sales,
+    ad_sales: taskDataForm.ad_sales,
+    ad_cost: taskDataForm.ad_cost,
+    enter_datetime: dailyEntryTime.value,
+    data_datetime: dailyTime.value,
+    task: taskId,
+  };
+  if (!currentId) {
+    try {
+      const resp = await postCreateDayData(body);
+      if (resp.code === 2000) {
+        dayFormVisible.value = false;
+        await fetchDayTaskData();
+        await VXETable.modal.message({content: '创建成功', status: 'success'});
+      }
+    } catch (e) {
+      await VXETable.modal.message({content: '创建失败', status: 'error'});
+    }
+  } else {
+    dayFormVisible.value = false;
+    await VXETable.modal.message({content: '此日期对应数据已存在', status: 'error'});
+  }
+}
+
+//创建周数据
+async function createWeekData() {
+  const body = {
+    sales: taskDataForm.sales,
+    total_sales_current_monthly: taskDataForm.total_sales_current_monthly,
+    ad_sales: taskDataForm.ad_sales,
+    ad_cost: taskDataForm.ad_cost,
+    impression: taskDataForm.impression,
+    ad_click: taskDataForm.ad_click,
+    ad_order: taskDataForm.ad_order,
+    money_by_amazon: taskDataForm.money_by_amazon,
+    money_by_other: taskDataForm.money_by_other,
+    session: taskDataForm.session,
+    order: taskDataForm.order,
+    availableSalesDay: taskDataForm.availableSalesDay,
+    intransitInventory: taskDataForm.intransitInventory,
+    overseasStorage: taskDataForm.overseasStorage,
+    refundRate: taskDataForm.refundRate,
+    sales_start_time: salesStartDate.value,
+    sales_end_time: salesEndDate.value,
+    ad_start_time: adStartDate.value,
+    ad_end_time: adEndDate.value,
+    enter_start_datetime: entryStartDate.value,
+    enter_end_datetime: entryEndDate.value,
+    task: taskId,
+  };
+  if (!currentId) {
+    try {
+      const resp = await postCreateWeekData(body);
+      if (resp.code === 2000) {
+        dayFormVisible.value = false;
+        await fetchWeekTaskData();
+        await VXETable.modal.message({content: '创建成功', status: 'success'});
+      }
+    } catch (e) {
+      await VXETable.modal.message({content: '创建失败', status: 'error'});
+    }
+  } else {
+    dayFormVisible.value = false;
+    await VXETable.modal.message({content: '此日期对应数据已存在', status: 'error'});
+  }
+}
+
+//创建月数据
+async function createMonthData() {
+  const body = {
+    sales: taskDataForm.sales,
+    ad_sales: taskDataForm.ad_sales,
+    ad_cost: taskDataForm.ad_cost,
+    impression: taskDataForm.impression,
+    ad_click: taskDataForm.ad_click,
+    ad_order: taskDataForm.ad_order,
+    data_start_time: startDate.value,
+    data_end_time: endDate.value,
+    enter_start_time: startDate.value,
+    enter_end_time: endDate.value,
+    task: taskId,
+  };
+  if (!currentId) {
+    try {
+      const resp = await postCreateMonthData(body);
+      if (resp.code === 2000) {
+        dayFormVisible.value = false;
+        await fetchMonthTaskData();
+        await VXETable.modal.message({content: '创建成功', status: 'success'});
+      }
+    } catch (e) {
+      await VXETable.modal.message({content: '创建失败', status: 'error'});
+    }
+  } else {
+    dayFormVisible.value = false;
+    await VXETable.modal.message({content: '此日期对应数据已存在', status: 'error'});
+  }
+}
+
+//创建任务
+const submitForm = async (formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  await formEl.validate(async (valid, fields) => {
+    if (valid) {
+      if (dateType === 'day') {
+        await createDayData();
+      }
+      if (dateType === 'week') {
+        await createWeekData();
+      }
+      if (dateType === 'month') {
+        await createMonthData();
+      }
+      taskDataFormRef.value.resetFields();
+    }
+  });
+};
+
+// 更新日数据
+async function updateDayData(row: RowVO) {
+  const $grid = xGrid.value;
+  if ($grid) {
+    const body = {
+      id: row.id,
+      sales: row.sales,
+      ad_sales: row.ad_sales,
+      ad_cost: row.ad_cost,
+      enter_datetime: dailyEntryTime.value,
+      data_datetime: dailyTime.value,
+      task: row.task,
+    };
+    try {
+      const resp = await postUpdateDayData(body);
+      if (resp.code === 2000) {
+        await fetchDayTaskData();
+        await VXETable.modal.message({
+          content: '更新成功',
+          status: 'success',
+        });
+      }
+    } catch (error) {
+      console.log('error:', error);
+    }
+  }
+}
+
+//更新周数据
+async function updateWeekData(row: RowVO) {
+  const $grid = xGrid.value;
+  if ($grid) {
+    const body = {
+      id: row.id,
+      sales: row.sales,
+      total_sales_current_monthly: row.total_sales_current_monthly,
+      ad_sales: row.ad_sales,
+      ad_cost: row.ad_cost,
+      impression: row.impression,
+      ad_click: row.ad_click,
+      ad_order: row.ad_order,
+      money_by_amazon: row.money_by_amazon,
+      money_by_other: row.money_by_other,
+      session: row.session,
+      order: row.order,
+      availableSalesDay: row.availableSalesDay,
+      intransitInventory: row.intransitInventory,
+      overseasStorage: row.overseasStorage,
+      refundRate: row.refundRate,
+      sales_start_time: salesStartDate.value,
+      sales_end_time: salesEndDate.value,
+      ad_start_time: adStartDate.value,
+      ad_end_time: adEndDate.value,
+      enter_start_datetime: entryStartDate.value,
+      enter_end_datetime: entryEndDate.value,
+      task: row.task,
+    };
+    try {
+      const resp = await postUpdateWeekData(body);
+      if (resp.code === 2000) {
+        await fetchWeekTaskData();
+        await VXETable.modal.message({
+          content: '更新成功',
+          status: 'success',
+        });
+      }
+    } catch (error) {
+      console.log('error:', error);
+    }
+  }
+}
+
+//更新月数据
+async function updateMonthData(row: RowVO) {
+  const $grid = xGrid.value;
+  if ($grid) {
+    const body = {
+      id: row.id,
+      sales: row.sales,
+      ad_sales: row.ad_sales,
+      ad_cost: row.ad_cost,
+      impression: row.impression,
+      ad_click: row.ad_click,
+      ad_order: row.ad_order,
+      data_start_time: startDate.value,
+      data_end_time: endDate.value,
+      enter_start_time: startDate.value,
+      enter_end_time: endDate.value,
+      task: row.task,
+    };
+    try {
+      const resp = await postUpdateMonthData(body);
+      if (resp.code === 2000) {
+        await fetchMonthTaskData();
+        await VXETable.modal.message({
+          content: '更新成功',
+          status: 'success',
+        });
+      }
+    } catch (error) {
+      console.log('error:', error);
+    }
+  }
+}
+
+const editRowEvent = async (row: any) => {
+  const $grid = xGrid.value;
+  if ($grid) {
+    await $grid.clearEdit();
+    if (dateType === 'day') {
+      await updateDayData(row);
+    } else if (dateType === 'week') {
+      await updateWeekData(row);
+    } else if (dateType === 'month') {
+      await updateMonthData(row);
+    }
+
+    gridOptions.loading = true;
+    // 模拟异步保存
+    setTimeout(() => {
+      gridOptions.loading = false;
+    }, 300);
+  }
+};
+
+const currentGridOptions = computed(() => {
+  const selectedGridOptions = gridOptions[dateType] || gridOptions['day'];
+  return {
+    ...gridOptions,
+    ...selectedGridOptions
+  };
+});
+
+const filteredDayColumns = computed(() => {
+  return dayColumns.value.filter(item => !['平台编号', '平台名称', '国家', '品牌', '操作'].includes(item.title));
+});
+
+const filteredWeekColumns = computed(() => {
+  return weekColumns.value.filter(item => !['平台编号', '平台名称', '国家', '品牌', '操作'].includes(item.title));
+});
+
+const filteredMonthColumns = computed(() => {
+  return monthColumns.value.filter(item => !['平台编号', '平台名称', '国家', '品牌', '操作'].includes(item.title));
+});
+
+onMounted(() => {
+  fetchCurrentTaskData();
+});
+</script>
+
+<template>
+  <div>
+    <el-card class="custom-card-style flex gap-1.5 justify-between my-1.5 mx-2">
+      <div class="demo-date-picker" v-if="dateType === 'day'">
+        <div class="block">
+          <span class="demonstration">日录入数据时间:</span>
+          <el-date-picker
+              v-model="dailyEntryTime"
+              type="Date"
+              :disabled-date="disabledDate"
+              :shortcuts="shortcuts"
+              @change="handleDayChange"
+          />
+        </div>
+        <div class="block">
+          <span class="demonstration">日数据时间:</span>
+          <el-date-picker
+              v-model="dailyTime"
+              type="Date"
+              :shortcuts="shortcuts"
+              disabled
+          />
+        </div>
+      </div>
+      <div class="demo-date-picker" v-if="dateType === 'week'">
+        <el-config-provider :locale="enLocale">
+        <div class="block">
+          <span class="demonstration">周录入数据时间:</span>
+          <el-date-picker
+              v-model="weeklyEntryTime"
+              type="week"
+              :format="entryFormat"
+              placeholder="选择一周"
+              :disabled-date="disabledDate"
+              @change="handleWeekChange"
+          />
+        </div>
+        <div class="block">
+          <span class="demonstration">周销售数据时间:</span>
+          <el-date-picker
+              v-model="weeklySalesTime"
+              type="week"
+              :format="salesFormat"
+              placeholder="选择一周"
+              disabled
+          />
+        </div>
+        <div class="block">
+          <span class="demonstration">周广告数据时间:</span>
+          <el-date-picker
+              v-model="weeklyAdTime"
+              type="week"
+              :format="adFormat"
+              placeholder="选择一周"
+              disabled
+          />
+        </div>
+        </el-config-provider>
+      </div>
+      <div class="demo-date-picker" v-if="dateType === 'month'">
+        <div class="block">
+          <span class="demonstration">月录入数据时间:</span>
+          <el-date-picker
+              v-model="monthlyEntryTime"
+              type="month"
+              :format="monthlyEntryFormat"
+              placeholder="选择月份"
+              @change="handleMonthChange"
+              :disabled-date="disabledDate"
+          />
+        </div>
+      </div>
+    </el-card>
+  </div>
+  <el-card class="mx-2">
+    <div style="position: relative">
+      <vxe-grid ref="xGrid" v-bind="currentGridOptions" v-on="gridEvents" stripe>
+        <template #operate="{ row }">
+          <template v-if="hasActiveEditRow(row)">
+            <el-button @click="clearRowEvent" size="small" link>取消</el-button>
+            <el-button @click="editRowEvent(row)" size="small" link type="warning">保存</el-button>
+          </template>
+          <template v-else>
+            <el-button @click="handelEditRow(row)" size="small" type="success" link :disabled="!row.id">更新</el-button>
+          </template>
+          <el-button @click="editEvent(row)" size="small" type="primary" link :disabled="row.id">创建</el-button>
+        </template>
+        <template #sales_edit="{ row }">
+          <vxe-input v-model="row.sales"></vxe-input>
+        </template>
+        <template #ad_sales_edit="{ row }">
+          <vxe-input v-model="row.ad_sales"></vxe-input>
+        </template>
+        <template #ad_cost_edit="{ row }">
+          <vxe-input v-model="row.ad_cost"></vxe-input>
+        </template>
+        <template #total_sales_current_monthly_edit="{ row }">
+          <vxe-input v-model="row.total_sales_current_monthly"></vxe-input>
+        </template>
+        <template #impression_edit="{ row }">
+          <vxe-input v-model="row.impression"></vxe-input>
+        </template>
+        <template #ad_click_edit="{ row }">
+          <vxe-input v-model="row.ad_click"></vxe-input>
+        </template>
+        <template #ad_order_edit="{ row }">
+          <vxe-input v-model="row.ad_order"></vxe-input>
+        </template>
+        <template #money_by_amazon_edit="{ row }">
+          <vxe-input v-model="row.money_by_amazon"></vxe-input>
+        </template>
+        <template #money_by_other_edit="{ row }">
+          <vxe-input v-model="row.money_by_other"></vxe-input>
+        </template>
+        <template #session_edit="{ row }">
+          <vxe-input v-model="row.session"></vxe-input>
+        </template>
+        <template #order_edit="{ row }">
+          <vxe-input v-model="row.order"></vxe-input>
+        </template>
+        <template #availableSalesDay_edit="{ row }">
+          <vxe-input v-model="row.availableSalesDay"></vxe-input>
+        </template>
+        <template #intransitInventory_edit="{ row }">
+          <vxe-input v-model="row.intransitInventory"></vxe-input>
+        </template>
+        <template #overseasStorage_edit="{ row }">
+          <vxe-input v-model="row.overseasStorage"></vxe-input>
+        </template>
+        <template #refundRate_edit="{ row }">
+          <vxe-input v-model="row.refundRate"></vxe-input>
+        </template>
+      </vxe-grid>
+    </div>
+  </el-card>
+  <el-dialog v-model="dayFormVisible" title="创建任务" width="600">
+    <el-form
+        ref="taskDataFormRef"
+        style="max-width: 600px"
+        :model="taskDataForm"
+        :rules="rules"
+        label-width="auto"
+        :size="formSize"
+        label-position="top"
+        status-icon>
+      <div v-if="dateType === 'day'">
+        <el-form-item v-for="item in filteredDayColumns" :key="item.field" :label="item.title" :prop="item.field">
+          <el-input v-model="taskDataForm[item.field]" :placeholder="`请输入${item.title}`" />
+        </el-form-item>
+      </div>
+      <div v-if="dateType === 'week'" style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 5px">
+        <el-form-item v-for="item in filteredWeekColumns" :key="item.field" :label="item.title" :prop="item.field">
+          <el-input style="width: 100%" v-model="taskDataForm[item.field]" />
+        </el-form-item>
+      </div>
+      <div v-if="dateType === 'month'">
+        <el-form-item v-for="item in filteredMonthColumns" :key="item.field" :label="item.title" :prop="item.field">
+          <el-input v-model="taskDataForm[item.field]" :placeholder="`请输入${item.title}`" />
+        </el-form-item>
+      </div>
+    </el-form>
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button @click="dayFormVisible = false ;resetForm(taskDataFormRef)">取消</el-button>
+        <el-button type="primary" @click="submitForm(taskDataFormRef)"> 确认</el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+
+<style scoped>
+.demo-date-picker {
+  display: flex;
+  width: 100%;
+  padding: 0;
+  flex-wrap: wrap;
+}
+
+.demo-date-picker .block:last-child {
+  border-right: none;
+}
+
+.demo-date-picker .demonstration {
+  color: var(--el-text-color-secondary);
+  font-size: 14px;
+  margin: 10px;
+}
+
+.vxe-grid {
+  border-radius: 10px;
+  margin-bottom: 10px;
+}
+
+.flex-between {
+  display: flex;
+  justify-content: space-between;
+}
+</style>

+ 98 - 0
src/views/reportManage/dataCenter/normalDisplay/index.vue

@@ -0,0 +1,98 @@
+<script setup lang="ts">
+import { dayMetricsEnum, monthMetricsEnum, weekMetricsEnum } from '/src/views/reportManage/dataCenter/utils/enum';
+import {
+  getCardDayData,
+  getCardWeekData,
+  getCardMonthData,
+  getLineForDay,
+  getLineForWeek,
+  getLineForMonth
+} 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 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';
+import emitter from '/src/utils/emitter';
+
+//筛选查询
+const selectorRef = ref(null);
+const taskIds = ref({});
+//日周月选择
+const currentDate = ref({});
+const dateDimension = ref('day');
+provide('dateDimension', dateDimension);
+
+const queryParams = ref({
+  currentDate,
+  taskIds
+});
+
+const handelDateChange = (date) => {
+  currentDate.value = date;
+};
+
+watch(currentDate, (value) => {
+});
+
+emitter.on('DateTendency-dateChange', (value: string) => {
+  dateDimension.value = value;
+  // console.log('dateDimension', dateDimension.value);
+});
+
+provide('currentDate', currentDate);
+
+//选择器筛选后数据的任务id
+function updateDataChange(newId) {
+  if (selectorRef.value) {
+    taskIds.value = newId.value;
+  }
+}
+
+const currentMetricEnum = computed(() => {
+  if (dateDimension.value === 'day') {
+    return dayMetricsEnum;
+  } else if (dateDimension.value === 'week') {
+    return weekMetricsEnum;
+  } else if (dateDimension.value === 'month') {
+    return monthMetricsEnum;
+  }
+});
+
+onBeforeUnmount(() => {
+  emitter.all.clear();
+});
+</script>
+
+<template>
+  <div>
+    <div class="custom-card-style flex gap-1.5 justify-between items-center my-1.5 mx-2">
+      <Selector ref="selectorRef" @update:updateData="updateDataChange" />
+      <DataPicker @dateChange="handelDateChange" style="display: flex; align-items: center;" />
+    </div>
+    <el-card class="mb-1.5">
+      <DateTendency
+          :metricEnum="currentMetricEnum"
+          :query="queryParams"
+          :fetchCard="getCardDayData"
+          :fetchCardWeek="getCardWeekData"
+          :fetchCardMonth="getCardMonthData"
+          :fetchLine="getLineForDay"
+          :fetch-line-week="getLineForWeek"
+          :fetch-line-month="getLineForMonth"
+      >
+      </DateTendency>
+    </el-card>
+  </div>
+  <el-card>
+    <TableSelect :taskIds="taskIds"></TableSelect>
+  </el-card>
+</template>
+
+<style scoped>
+.custom-card-style {
+  z-index: 999;
+  position: sticky;
+  top: 0;
+}
+</style>

+ 165 - 225
src/views/reportManage/dataCenter/utils/columns.ts

@@ -1,229 +1,169 @@
-const universal = [
-  {
-    field: 'TotalSales',
-    title: '总销售额',
-    align: 'right',
-    width: 130,
-    sortable: true,
-    slots: { default: 'TotalSales_default', footer: 'TotalSales_footer' },
-  },
-  {
-    field: 'TotalOrderItems',
-    title: '总订单数',
-    align: 'right',
-    width: 130,
-    sortable: true,
-    slots: { default: 'TotalOrderItems_default', footer: 'TotalOrderItems_footer' },
-  },
-  {
-    field: 'TotalUnitOrdered',
-    title: '总销量',
-    align: 'right',
-    width: 130,
-    sortable: true,
-    slots: { default: 'TotalUnitOrdered_default', footer: 'TotalUnitOrdered_footer' },
-  },
-  { field: 'SAP', title: '单均价', align: 'right', width: 130, sortable: true, slots: { default: 'SAP_default', footer: 'SAP_footer' } },
-  {
-    field: 'TotalAdSales',
-    title: '广告销售额',
-    align: 'right',
-    width: 130,
-    sortable: true,
-    slots: { default: 'TotalAdSales_default', footer: 'TotalAdSales_footer' },
-  },
-  {
-    field: 'TotalAdSalesSameSKU',
-    title: '本商品广告销售额',
-    align: 'right',
-    width: 180,
-    sortable: true,
-    slots: { default: 'TotalAdSalesSameSKU_default', footer: 'TotalAdSalesSameSKU_footer' },
-  },
-  {
-    field: 'TotalAdPurchases',
-    title: '广告订单数',
-    align: 'right',
-    width: 130,
-    sortable: true,
-    slots: { default: 'TotalAdPurchases_default', footer: 'TotalAdPurchases_footer' },
-  },
-  {
-    field: 'TotalAdPurchasesSameSKU',
-    title: '本商品广告订单数',
-    align: 'right',
-    width: 180,
-    sortable: true,
-    slots: { default: 'TotalAdPurchasesSameSKU_default', footer: 'TotalAdPurchasesSameSKU_footer' },
-  },
-  {
-    field: 'TotalAdUnitOrdered',
-    title: '广告销量',
-    align: 'right',
-    width: 130,
-    sortable: true,
-    slots: { default: 'TotalAdUnitOrdered_default', footer: 'TotalAdUnitOrdered_footer' },
-  },
-  {
-    field: 'TotalAdUnitOrderedSameSKU',
-    title: '本商品广告销量',
-    align: 'right',
-    width: 180,
-    sortable: true,
-    slots: { default: 'TotalAdUnitOrderedSameSKU_default', footer: 'TotalAdUnitOrderedSameSKU_footer' },
-  },
-  {
-    field: 'Spend',
-    title: '花费',
-    align: 'right',
-    width: 130,
-    sortable: true,
-    showOverflow: true,
-    slots: { default: 'Spend_default', footer: 'Spend_footer' },
-  },
-  { field: 'ACOS', title: 'ACOS', align: 'right', width: 130, sortable: true, slots: { default: 'ACOS_default', footer: 'ACOS_footer' } },
-  { field: 'ROAS', title: 'ROAS', align: 'right', width: 130, sortable: true, slots: { default: 'ROAS_default', footer: 'ROAS_footer' } },
-  { field: 'TACOS', title: 'TACOS', align: 'right', width: 130, sortable: true, slots: { default: 'TACOS_default', footer: 'TACOS_footer' } },
-  { field: 'CR', title: '转化率', align: 'right', width: 130, sortable: true, slots: { default: 'CR_default', footer: 'CR_footer' } },
-  { field: 'CTR', title: '点击率', align: 'right', width: 130, sortable: true, slots: { default: 'CTR_default', footer: 'CTR_footer' } },
-  { field: 'CPC', title: '点击成本', align: 'right', width: 130, sortable: true, slots: { default: 'CPC_default', footer: 'CPC_footer' } },
-  { field: 'CPO', title: '总订单成本', align: 'right', width: 130, sortable: true, slots: { default: 'CPO_default', footer: 'CPO_footer' } },
-  { field: 'CPA', title: '广告订单成本', align: 'right', width: 180, sortable: true, slots: { default: 'CPA_default', footer: 'CPA_footer' } },
-  {
-    field: 'Impression',
-    title: '曝光量',
-    align: 'right',
-    width: 130,
-    sortable: true,
-    slots: { default: 'Impression_default', footer: 'Impression_footer' },
-  },
-  { field: 'Click', title: '点击量', align: 'right', width: 130, sortable: true, slots: { default: 'Click_default', footer: 'Click_footer' } },
-  {
-    field: 'Sessions',
-    title: '会话次数',
-    align: 'right',
-    width: 150,
-    sortable: true,
-    slots: { default: 'Sessions_default', footer: 'Sessions_footer' },
-  },
-  {
-    field: 'ProductCr',
-    title: '商品会话百分比',
-    align: 'right',
-    width: 150,
-    sortable: true,
-    slots: { default: 'ProductCr_default', footer: 'ProductCr_footer' },
-  },
-  {
-    field: 'PageViews',
-    title: '页面浏览量',
-    align: 'right',
-    width: 130,
-    sortable: true,
-    slots: { default: 'PageViews_default', footer: 'PageViews_footer' },
-  },
-  {
-    field: 'BuyBoxPercentage',
-    title: '推荐报价(购买按钮)百分比',
-    align: 'right',
-    width: 180,
-    sortable: true,
-    showHeaderOverflow: true,
-    slots: { default: 'BuyBoxPercentage_default', footer: 'BuyBoxPercentage_footer' },
-  },
-  { field: 'FBAQuantity', title: 'FBA库存', align: 'right', width: 130, sortable: true, slots: { footer: 'FBAQuantity_footer' } },
-  {
-    field: 'FBMQuantity',
-    title: 'FBM库存',
-    align: 'right',
-    width: 130,
-    sortable: true,
-    showHeaderOverflow: true,
-    slots: { footer: 'FBMQuantity_footer' },
-  },
-]
+export const dayColumns = ref([
+  { field: 'platformNumber', title: '平台编号' },
+  { field: 'platformName', title: '平台名称' },
+  { field: 'country', title: '国家' },
+  { field: 'brandName', title: '品牌' },
 
-export const productLineColumns = [
-  {
-    field: 'productlineName',
-    title: '产品线',
-    align: 'left',
-    fixed: 'left',
-    width: 180,
-    sortable: true,
-    slots: { default: 'productlineName_default', footer: 'productlineName_footer' },
-  },
-  ...universal,
-]
+  { field: 'sales', title: '销售额', editRender: {}, slots: { edit: 'sales_edit' } },
+  { field: 'ad_sales', title: '广告销售额', editRender: {}, slots: { edit: 'ad_sales_edit' } },
+  { field: 'ad_cost', title: '广告花费', editRender: {}, slots: { edit: 'ad_cost_edit' } },
+  { title: '操作', width: 300, slots: { default: 'operate' } },
+]);
 
-export const parentAsinColumns = [
-  {
-    field: 'parentAsin',
-    title: '父ASIN',
-    align: 'left',
-    fixed: 'left',
-    width: 180,
-    sortable: true,
-    slots: { default: 'parentAsin_default', footer: 'parentAsin_footer' },
-  },
-  { field: 'bestSku', title: '最佳SKU', align: 'left', width: 300, sortable: true, slots: { default: 'bestSku_default', footer: 'bestSku_footer' } },
-  // { field: 'TACOS', title: '预警TACOS', align: 'right', width: 130, slots: { default: 'TACOS_default', footer: 'TACOS_footer' } },
-  ...universal,
-]
+export const weekColumns = ref([
+  {field: 'platformNumber', title: '平台编号',fixed:"left",width: 90},
+  {field: 'platformName', title: '平台名称',fixed:"left",width: 90},
+  {field: 'country', title: '国家',fixed:"left",width: 90},
+  {field: 'brandName', title: '品牌',fixed:"left",width: 90},
 
-export const asinColumns = [
-  {
-    field: 'Asin',
-    title: 'ASIN',
-    align: 'left',
-    fixed: 'left',
-    width: 300,
-    sortable: true,
-    slots: { default: 'Asin_default', footer: 'Asin_footer' },
-  },
-  {
-    field: 'productlineName',
-    title: '产品线',
-    align: 'left',
-    fixed: 'left',
-    width: 180,
-    sortable: true,
-    slots: { default: 'productlineName_default', footer: 'productlineName_footer' },
-  },
-  {
-    field: 'rank',
-    title: '排名',
-    align: 'left',
-    fixed: 'left',
-    width: 120,
-    sortable: true,
-    slots: { default: 'rank_default', footer: 'rank_footer' },
-  },
-  // { field: 'TACOS', title: '预警TACOS', align: 'right', width: 130, slots: { default: 'TACOS_default', footer: 'TACOS_footer' } },
-  ...universal,
-]
+  {field: 'sales', title: '销售额',editRender: {}, slots: {edit: 'sales_edit'},width: 120},
+  {field: 'total_sales_current_monthly', title: '当月累计销售额',editRender: {}, slots: {edit: 'total_sales_current_monthly_edit'},width: 120},
+  {field: 'ad_sales', title: '广告销售额',editRender: {},slots: {edit: 'ad_sales_edit'},width: 120},
+  { field: 'ad_cost', title: '广告花费', editRender: {}, slots: { edit: 'ad_cost_edit' } ,width: 120},
+  { field: 'impression', title: '广告曝光', editRender: {}, slots: { edit: 'impression_edit' } ,width: 120},
+  { field: 'ad_click', title: '广告点击', editRender: {}, slots: { edit: 'ad_click_edit' } ,width: 120},
+  { field: 'ad_order', title: '广告订单', editRender: {}, slots: { edit: 'ad_order_edit' } ,width: 120},
+  { field: 'money_by_amazon', title: 'Amazon回款金额', editRender: {}, slots: { edit: 'money_by_amazon_edit' } ,width: 120},
+  { field: 'money_by_other', title: 'Other回款金额', editRender: {}, slots: { edit: 'money_by_other_edit' } ,width: 120},
+  { field: 'session', title: '流量', editRender: {}, slots: { edit: 'session_edit' } ,width: 120},
+  { field: 'order', title: '转化', editRender: {}, slots: { edit: 'order_edit' } ,width: 120},
+  { field: 'availableSalesDay', title: '当前存货可售天', editRender: {}, slots: { edit: 'availableSalesDay_edit' } ,width: 120},
+  { field: 'intransitInventory', title: '当前在途库存', editRender: {}, slots: { edit: 'intransitInventory_edit' } ,width: 120},
+  { field: 'overseasStorage', title: '当前海外仓库存', editRender: {}, slots: { edit: 'overseasStorage_edit' } ,width: 120},
+  { field: 'refundRate', title: '最近90天平台退货率', editRender: {}, slots: { edit: 'refundRate_edit' } ,width: 120},
+  {title: '操作', width: 120, slots: {default: 'operate'},fixed:"right"},
+]);
 
-export const skuColumns = [
-  { field: 'sku', title: 'SKU', align: 'left', fixed: 'left', width: 300, slots: { default: 'sku_default', footer: 'sku_footer' } },
-  {
-    field: 'productlineName',
-    title: '产品线',
-    align: 'left',
-    width: 180,
-    slots: { default: 'productlineName_default', footer: 'productlineName_footer' },
-  },
-  { field: 'status', title: '商品状态', align: 'center', width: 80, slots: { default: 'status_default', footer: 'status_footer' } },
-  { field: 'rank', title: '排名', align: 'left', width: 130, slots: { default: 'rank_default', footer: 'rank_footer' } },
-  { field: 'parentAsin', title: '父ASIN', align: 'left', width: 130, slots: { default: 'parentAsin_default', footer: 'parentAsin_footer' } },
-  {
-    field: 'launchDatetime',
-    title: '上架时间',
-    align: 'center',
-    width: 120,
-    sortable: true,
-    slots: { default: 'launchDatetime_default', footer: 'launchDatetime_footer' },
-  },
-  ...universal,
-  // { field: 'ABP', title: '异常推广', align: 'right', width: 130, slots: { default: 'ABP_default', footer: 'ABP_footer' } },
-  // { field: 'TACOS', title: '预警TACOS', align: 'right', width: 130, slots: { default: 'TACOS_default', footer: 'TACOS_footer' } },
-]
+export const monthColumns = ref([
+  {field: 'platformNumber', title: '平台编号' },
+  {field: 'platformName', title: '平台名称'},
+  {field: 'country', title: '国家'},
+  {field: 'brandName', title: '品牌'},
+
+  {field: 'sales', title: '销售额',editRender: {}, slots: {edit: 'sales_edit'}},
+  {field: 'ad_sales', title: '广告销售额',editRender: {},slots: {edit: 'ad_sales_edit'}},
+  { field: 'ad_cost', title: '广告花费', editRender: {}, slots: { edit: 'ad_cost_edit' } },
+  { field: 'impression', title: '广告曝光', editRender: {}, slots: { edit: 'impression_edit' } },
+  { field: 'ad_click', title: '广告点击', editRender: {}, slots: { edit: 'ad_click_edit' } },
+  { field: 'ad_order', title: '广告订单', editRender: {}, slots: { edit: 'ad_order_edit' } },
+  {title: '操作', width: 300, slots: {default: 'operate'}},
+]);
+
+export const dayDataColumns = [
+  {field: 'platformNumber', title: '平台编号', slots: {default: 'platformNumber_default'}},
+  {field: 'platformName', title: '平台名称', slots: {default: 'platformName_default'}},
+  {field: 'user_name', title: '运营', slots: {default: 'user_name_default'}},
+  {field: 'country', title: '国家', slots: {default: 'country_default'}},
+  {field: 'brandName', title: '品牌', slots: {default: 'brandName_default'}},
+  {field: 'currencyCode', title: '汇款币种', slots: {default: 'currencyCode_default'}},
+
+  {field: 'sales', title: '销售额'},
+  {field: 'sales_year_on_year', title: '期末同比变化'},
+  {field: 'sales_monthly_year_on_year', title: '期末环比变化'},
+  {field: 'ad_cost', title: '广告花费'},
+  {field: 'ad_sales', title: '广告销售额'},
+  {field: 'roi', title: '广告ROI'},
+  {field: 'acos', title: '广告ACOS'},
+  {field: 'roas', title: '广告ROAS'},
+];
+export const weekDataColumns = [
+  {field: 'platformNumber', title: '平台编号', slots: {default: 'platformNumber_default'}, fixed: 'left', width: 90},
+  {field: 'platformName', title: '平台名称', slots: {default: 'platformName_default'}, fixed: 'left', width: 90},
+  {field: 'user_name', title: '运营', slots: {default: 'user_name_default'}, fixed: 'left', width: 90},
+  {field: 'country', title: '国家', slots: {default: 'country_default'}, fixed: 'left', width: 90},
+  {field: 'brandName', title: '品牌', slots: {default: 'brandName_default'}, fixed: 'left', width: 90},
+  {field: 'currencyCode', title: '汇款币种', slots: {default: 'currencyCode_default'}, fixed: 'left', width: 90},
+
+  {field: 'sales', title: '销售额', width: 120},
+  {field: 'ad_cost', title: '广告花费', width: 120},
+  {field: 'ad_sales', title: '广告销售额', width: 120},
+  {field: 'roi', title: '广告ROI', width: 120},
+  {field: 'acos', title: '广告ACOS', width: 120},
+  {field: 'roas', title: '广告ROAS', width: 120},
+  {field: 'impression', title: '广告曝光', width: 120},
+  {field: 'ad_click', title: '广告点击', width: 120},
+  {field: 'ad_order', title: '广告订单', width: 120},
+  {field: 'ad_conversion_rate', title: '广告转化率', width: 120},
+  {field: 'money_by_amazon', title: 'Amazon回款金额', width: 120},
+  {field: 'money_by_other', title: 'Ebay及其他平台可用余额', width: 120},
+  {field: 'currencyCode', title: '回款/余额币种', width: 120},
+  {field: 'total_sales_current_monthly', title: '销售额完成情况', width: 120},
+  {field: 'sales_weekly_year_on_year', title: '环比上周增长率', width: 120},
+  {field: 'sales_monthly_year_on_year', title: '环比上月周增长率', width: 120},
+  {field: 'sales_year_on_year', title: '环比上年周增长率', width: 120},
+  {field: 'session', title: '流量', width: 120},
+  {field: 'ad_order', title: '订单', width: 120},
+  {field: 'order', title: '转化', width: 120},
+  {field: 'availableSalesDay', title: '当前存货可售天', width: 120},
+  {field: 'intransitInventory', title: '当前在途库存', width: 120},
+  {field: 'overseasStorage', title: '当前海外仓库存', width: 120},
+  {field: 'refundRate', title: '最近90天平台退货率', width: 120},
+];
+export const monthDataColumns = [
+  {field: 'platformNumber', title: '平台编号', slots: {default: 'platformNumber_default'}},
+  {field: 'platformName', title: '平台名称', slots: {default: 'platformName_default'}},
+  {field: 'user_name', title: '运营', slots: {default: 'user_name_default'}},
+  {field: 'country', title: '国家', slots: {default: 'country_default'}},
+  {field: 'brandName', title: '品牌', slots: {default: 'brandName_default'}},
+  {field: 'currencyCode', title: '汇款币种', slots: {default: 'currencyCode_default'}},
+
+  {field: 'sales', title: '销售额'},
+  {field: 'ad_cost', title: '广告花费'},
+  {field: 'ad_sales', title: '广告销售额'},
+  {field: 'roi', title: '广告ROI'},
+  {field: 'acos', title: '广告ACOS'},
+  {field: 'roas', title: '广告ROAS'},
+  {field: 'impression', title: '广告曝光',},
+  {field: 'ad_click', title: '广告点击',},
+  {field: 'ad_order', title: '广告订单',},
+  {field: 'ad_conversion_rate', title: '广告转化率',},
+  {field: 'total_sales_current_monthly', title: '销售额完成情况',},
+];
+
+// export const mainColumns = ref([
+//   {field: 'platformNumber', title: '平台编号',fixed:"left",width: 90},
+//   {field: 'platformName', title: '平台名称',fixed:"left",width: 90},
+//   {field: 'country', title: '国家',fixed:"left",width: 90},
+//   {field: 'user_name', title: '运营'},
+//   {field: 'brandName', title: '品牌',fixed:"left",width: 90},
+//   //需增加日销售额
+//   {field: 'sales_monthly_year_on_year_day', title: '销售额期末月同比'},
+//   {field: 'sales_year_on_year_day', title: '销售额期末年同比'},
+//
+//   {field: 'ad_cost_day', title: '日广告花费'},
+//   {field: 'ad_sales_day', title: '日广告销售额'},
+//   {field: 'roi_day', title: '日广告ROI'},
+//
+//   {field: 'total_sales_current_monthly', title: '月份销售额完成情况'},
+//   {field: 'sales_weekly_year_on_year', title: '环比上周增长率'},
+//   {field: 'sales_monthly_year_on_year_week', title: '环比上月周增长率'},
+//   {field: 'sales_year_on_year', title: '同比上年周增长率'},
+//   {field: 'money_by_amazon', title: 'Amazon平台已回款金额'},
+//   {field: 'currencyCode', title: '回款/余额币种'},
+//   {field: 'money_by_other', title: 'Ebay及其他平台可用余额'},
+//   // // { field: 'session', title: '周流量'},
+//   // {field: 'ad_order', title: '订单'},
+//   {field: 'availableSalesDay', title: '当前存货可售天'},
+//   {field: 'intransitInventory', title: '当前在途库存'},
+//   {field: 'overseasStorage', title: '当前海外仓库存'},
+//   {field: 'refundRate', title: '最近90天平台退货率'},
+//   //需增加周广告花费,销售额等
+//   {field: 'ad_cost_week', title: '周广告花费'},
+//   {field: 'ad_sales_week', title: '周广告销售额'},
+//   {field: 'acos_week', title: '周广告ACOS'},
+//   {field: 'roas_week', title: '周广告ROAS'},
+//   {field: 'roi_week', title: '周广告ROI'},
+//   {field: 'impression_week', title: '周广告曝光'},
+//   {field: 'ad_order_week', title: '周广告订单'},
+//   {field: 'ad_click_week', title: '周广告点击'},
+//   {field: 'ad_click_rate_week', title: '周广告转化率'},
+//   {field: 'ad_cost', title: '月广告费用'},
+//   {field: 'ad_sales', title: '月广告销售额'},
+//   {field: 'acos', title: '月ACOS'},
+//   {field: 'roas', title: '月ROAS'},
+//   {field: 'roi', title: '月广告ROI'},
+//   {field: 'impression_month', title: '月广告曝光'},
+//   {field: '', title: '月广告订单'},
+//   {field: 'ad_click_month', title: '月广告点击'},
+//   {field: 'ad_conversion_rate_month', title: '月广告转化率'},
+// ])

+ 49 - 23
src/views/reportManage/dataCenter/utils/enum.ts

@@ -1,23 +1,49 @@
-export const dataCenterMetricsEnum = [
-  {label: '曝光量', value: 'Impression'},
-  {label: '点击量', value: 'Click'},
-  {label: '花费', value: 'Spend'},
-  {label: '总订单数', value: 'TotalOrderItems'},
-  {label: '总销售额', value: 'TotalSales'},
-  {label: '单均价', value: 'SAP'},
-  {label: '广告订单数', value: 'TotalAdPurchases'},
-  {label: '广告销售额', value: 'TotalAdSales'},
-  {label: '广告销量', value: 'TotalAdUnitOrdered'},
-  {label: '本商品广告销售额', value: 'TotalAdSalesSameSKU'},
-  {label: '本商品广告订单数', value: 'TotalAdPurchasesSameSKU'},
-  {label: '本商品广告销量', value: 'TotalAdUnitOrderedSameSKU'},
-  // {label: 'SAP', value: 'SAP'},
-  {label: 'ACOS', value: 'ACOS'},
-  {label: 'ROAS', value: 'ROAS'},
-  {label: 'TACOS', value: 'TACOS'},
-  {label: '转化率', value: 'CR'},
-  {label: '点击率', value: 'CTR'},
-  {label: '点击成本', value: 'CPC'},
-  {label: '总订单成本', value: 'CPO'},
-  {label: '广告订单成本', value: 'CPA'},
-]
+export const dayMetricsEnum = [
+  {value: 'sales', label: '销售额'},
+  {value: 'ad_cost', label: '广告花费'},
+  {value: 'ad_sales', label: '广告销售额'},
+  {value: 'acos', label: '广告ACOS'},
+  {value: 'roi', label: '广告ROI'},
+  {value: 'roas', label: '广告ROAS'},
+]
+
+export const weekMetricsEnum = [
+  {value: 'sales', label: '销售额'},
+  {value: 'ad_cost', label: '广告花费'},
+  {value: 'ad_sales', label: '广告销售额'},
+  { value: 'impression', label: '广告曝光'},
+  { value: 'ad_click', label: '广告点击'},
+  { value: 'ad_order', label: '广告订单'},
+  { value: 'session', label: '流量'},
+  { value: 'order', label: '转化'},
+  { value: 'availableSalesDay', label: '当前存货可售天'},
+  { value: 'intransitInventory', label: '当前在途库存'},
+  { value: 'overseasStorage', label: '当前海外仓库存'},
+  { value: 'refundRate', label: '最近90天平台退货率'},
+  { value: 'acos', label: '广告ACOS'},
+  { value: 'roi', label: '广告ROI'},
+  { value: 'roas', label: '广告ROAS'},
+  { value: 'ad_click_rate', label: '广告点击率'},
+  { value: 'ad_conversion_rate', label: '广告转化率'},
+  { value: 'conversion_rate', label: '转化率'},
+]
+
+export const monthMetricsEnum = [
+  {value: 'sales', label: '销售额'},
+  {value: 'ad_cost', label: '广告花费'},
+  {value: 'ad_sales', label: '广告销售额'},
+
+  {value: 'acos', label: '广告ACOS'},
+  {value: 'roi', label: '广告ROI'},
+  {value: 'roas', label: '广告ROAS'},
+  { value: 'impression', label: '广告曝光'},
+  { value: 'ad_click', label: '广告点击'},
+  { value: 'ad_order', label: '广告订单'},
+  { value: 'ad_click_rate', label: '广告点击率'},
+  { value: 'ad_conversion_rate', label: '广告转化率'},
+]
+
+export const monthCompareMetricsEnum = [
+  { value: 'sales', label: '销售额'},
+  { value: 'planSales', label: '计划销售额'},
+]

+ 85 - 0
src/views/reportManage/dataCenter/utils/tools.ts

@@ -0,0 +1,85 @@
+import dayjs, { Dayjs } from 'dayjs'
+import { unref } from 'vue'
+import XEUtils from 'xe-utils'
+
+export function buildChartOpt(option: any, metrics: any[]) {
+  const tmp: any = {}
+  const opt: any = {
+    legend: { selected: {} },
+    yAxis: [],
+    series: [],
+  }
+  for (const info of metrics) {
+    tmp[info.color] = info
+  }
+  for (const info of option.series) {
+    const color = info.itemStyle.color
+    const metricInfo = tmp[color]
+    if (metricInfo) {
+      opt.series.push({
+        id: info.id,
+        name: metricInfo.label,
+        encode: { y: metricInfo.metric },
+      })
+      opt.yAxis.push({ id: info.id, name: metricInfo.label, show: true })
+    } else {
+      opt.yAxis.push({ id: info.id, show: false })
+    }
+  }
+  for (const label of Object.keys(option.legend.selected)) {
+    if (XEUtils.findIndexOf(metrics, (info) => info.label === label) === -1) {
+      opt.legend.selected[label] = false
+    } else {
+      opt.legend.selected[label] = true
+    }
+  }
+  console.log(opt)
+  return opt
+}
+
+export function parseQueryParams(body: any) {
+  const ret: any = {};
+
+  for (const key in body) {
+    const val = unref(body[key]);
+
+    if (key === 'currentDate') {
+      if (val.dailyStartDate && val.dailyTime) {
+        ret['data_start_date'] = val.dailyStartDate;
+        ret['data_end_date'] = val.dailyTime;
+      }
+      if (val.weekStartDate && val.weekEndDate) {
+        ret['data_start_date'] = val.weekStartDate;
+        ret['data_end_date'] = val.weekEndDate;
+      }
+      if (val.startDate && val.endDate) {
+        ret['data_start_date'] = val.startDate;
+        ret['data_end_date'] = val.endDate;
+      }
+    } else if (key === 'taskIds') {
+      ret['task_ids'] = val; // 将 task_ids 直接赋给返回对象的属性
+    }else if (key === 'actualDate') {
+      ret['data_start_date'] = val[0];
+      ret['data_end_date'] = val[1];
+    } else {
+      ret[key] = val;
+    }
+  }
+  return ret;
+}
+export function monthlyQueryParams(body: any) {
+  const date: any = {}
+  for (const key in body) {
+    const val = unref(body[key])
+    if (key === 'monthCurrentDate') {
+        date['month_start_date'] = val.startDate
+        date['month_end_date'] = val.endDate
+    } else if (key === 'taskIds') {
+      date['task_ids'] = val; // 将 task_ids 直接赋给返回对象的属性
+    }else {
+      date[key] = val
+    }
+  }
+  console.log('date',date);
+  return date
+}