ソースを参照

Merge branch 'xinyan' into test

xinyan 1 年間 前
コミット
0009732343

+ 14 - 4
src/views/efTools/automation/api.ts

@@ -42,7 +42,7 @@ export function DelObj(id: DelReq) {
   });
 }
 
-//关联广告活动
+// 关联广告活动
 export function getRelationCampaign(query) {
   return request({
     url: '/api/ad_manage/template/relation_campaign_list/',
@@ -51,7 +51,7 @@ export function getRelationCampaign(query) {
   });
 }
 
-//广告组合下拉框
+// 广告组合下拉框
 export function getAdGroupList(query) {
   return request({
     url: '/api/ad_manage/ad_tree/portfolios',
@@ -60,11 +60,21 @@ export function getAdGroupList(query) {
   });
 }
 
-//广告关联活动保存
+// 广告关联活动保存
 export function updateAdCampaign(body) {
   return request({
     url: '/api/ad_manage/template/relation_campaign_enable/',
     method: 'POST',
     data: body,
   });
-}
+}
+
+// 获取定向规则列表
+export function getTargetingRuleList(query) {
+  return request({
+    url: '/api/ad_manage/template/target_select',
+    method: 'GET',
+    params: query,
+  });
+}
+

+ 197 - 45
src/views/efTools/automation/components/adActivityDialog.vue

@@ -9,6 +9,7 @@ import { getAdGroupList, getRelationCampaign } from '/@/views/efTools/automation
 import { storeToRefs } from 'pinia';
 import { useShopInfo } from '/@/stores/shopInfo';
 import { ElMessage } from 'element-plus';
+import TargetRuleDialog from '/@/views/efTools/automation/components/targetRuleDialog.vue';
 
 const props = defineProps({
   templateId: {
@@ -30,7 +31,14 @@ const { templateId } = toRefs(props);
 const { activeModel } = toRefs(props);
 
 const dialogVisible = ref(props.modelValue);
-//筛选条件
+const targetRuleDialogVisible = ref(false);
+
+// 定向规则
+//const adGroupId = ref('')
+//const campaignId = ref('')
+const selectedTargetedRow = ref(null);
+
+// 筛选条件
 const searchAdCampaign = ref('');
 const selectedCampaignType = ref('sp');
 const selectedAdGroup = ref('');
@@ -49,7 +57,7 @@ const campaignStatus = [
   { value: 'PAUSED', label: '已暂停' },
 ];
 
-//表格
+// 表格
 const currentPage = ref(1);
 const pageSize = ref(25);
 const total = ref(0);
@@ -89,7 +97,6 @@ async function fetchAdCampaign() {
       limit: pageSize.value,
     });
     adCampaignName.value = resp.data;
-
     total.value = resp.total;
     currentPage.value = resp.page;
     // 开始恢复勾选状态
@@ -110,45 +117,124 @@ async function fetchAdCampaign() {
 }
 
 function handleSelectionChange(selection) {
-  if (isRestoringSelection) return; // 恢复勾选时跳过该方法
-
-  selections = selection;
-  const newSelections = selections.filter(
-      (sel) => !selectedAds.value.some((added) => added.campaignId === sel.campaignId)
-  );
-  if (newSelections.length > 0) {
-    selectedAds.value.push(...newSelections);
-  }
-  // 处理取消选中的项
-  const removedSelections = selectedAds.value.filter(
-      (added) => !selections.some((sel) => sel.campaignId === added.campaignId)
-  );
-
-  if (removedSelections.length > 0) {
-    selectedAds.value = selectedAds.value.filter(
-        (added) => !removedSelections.some((removed) => removed.campaignId === added.campaignId)
-    );
-  }
+  if (isRestoringSelection) return;
+
+  const newSelectedAds = [];
+
+  selection.forEach(item => {
+    if (item.campaignGroupInfo) {
+      // 这是父节点(广告活动)
+      newSelectedAds.push({
+        campaignId: item.campaignId,
+        campaignName: item.campaignName,
+        campaignType: item.campaignType,
+        isParent: true
+      });
+    } else {
+      // 这是子节点(广告组)
+      const parent = adCampaignName.value.find(ad =>
+          ad.campaignGroupInfo && ad.campaignGroupInfo.some(group => group.adGroupId === item.adGroupId)
+      );
+      if (parent) {
+        // 添加父节点(如果还没有添加)
+        if (!newSelectedAds.some(ad => ad.campaignId === parent.campaignId)) {
+          newSelectedAds.push({
+            campaignId: parent.campaignId,
+            campaignName: parent.campaignName,
+            campaignType: parent.campaignType,
+            isParent: true
+          });
+        }
+        // 添加子节点(广告组)
+        newSelectedAds.push({
+          adGroupId: item.adGroupId,
+          adGroupName: item.adGroupName,
+          parentCampaignId: parent.campaignId,
+          parentCampaignName: parent.campaignName,
+          campaignType: parent.campaignType
+        });
+      }
+    }
+  });
+  selectedAds.value = newSelectedAds;
 }
 
+const groupedSelectedAds = computed(() => {
+  const groups = {};
+  selectedAds.value.forEach(ad => {
+    if (ad.isParent) {
+      if (!groups[ad.campaignId]) {
+        groups[ad.campaignId] = {
+          id: ad.campaignId,
+          name: ad.campaignName,
+          campaignType: ad.campaignType,
+          campaignGroupInfo: []
+        };
+      }
+    } else {
+      if (!groups[ad.parentCampaignId]) {
+        groups[ad.parentCampaignId] = {
+          id: ad.parentCampaignId,
+          name: ad.parentCampaignName,
+          campaignType: ad.campaignType,
+          campaignGroupInfo: []
+        };
+      }
+      groups[ad.parentCampaignId].campaignGroupInfo.push({
+        id: ad.adGroupId,
+        name: ad.adGroupName
+      });
+    }
+  });
+  return Object.values(groups);
+});
+
 function removeSelectedAd(index) {
   const removedAd = selectedAds.value.splice(index, 1)[0];
-  const targetIndex = adCampaignName.value.findIndex(ad => ad.campaignName === removedAd.campaignName);
-  if (targetIndex !== -1) {
-    const adTable = refTable.value;
-    adTable.toggleRowSelection(adCampaignName.value[targetIndex], false);
-  }
-}
 
-function removeAllSelectedAds() {
-  const adTable = refTable.value;
-  selectedAds.value.forEach(ad => {
-    const targetIndex = adCampaignName.value.findIndex(item => item.campaignName === ad.campaignName);
+  if (removedAd.parentCampaignId) {
+    // 查找同一父节点下的其他子节点
+    const remainingChildren = selectedAds.value.filter(ad => ad.parentCampaignId === removedAd.parentCampaignId);
+
+    // 如果父节点下还有其他子节点,父节点不删除
+    if (remainingChildren.length > 0) {
+      // 取消表格1中该子节点的勾选
+      const targetParent = adCampaignName.value.find(ad => ad.campaignId === removedAd.parentCampaignId);
+      if (targetParent) {
+        const targetChildIndex = targetParent.campaignGroupInfo.findIndex(group => group.adGroupId === removedAd.adGroupId);
+        if (targetChildIndex !== -1) {
+          const adTable = refTable.value;
+          adTable.toggleRowSelection(targetParent.campaignGroupInfo[targetChildIndex], false);
+        }
+      }
+    } else {
+      // 如果没有其他子节点了,移除父节点
+      const parentIndex = selectedAds.value.findIndex(ad => ad.campaignId === removedAd.parentCampaignId);
+      if (parentIndex !== -1) {
+        selectedAds.value.splice(parentIndex, 1);
+      }
+
+      // 取消表格1中父节点的勾选
+      const parentIndexInTable = adCampaignName.value.findIndex(ad => ad.campaignId === removedAd.parentCampaignId);
+      if (parentIndexInTable !== -1) {
+        const adTable = refTable.value;
+        adTable.toggleRowSelection(adCampaignName.value[parentIndexInTable], false);
+      }
+    }
+  } else {
+    // 如果删除的项是父节点
+    const targetIndex = adCampaignName.value.findIndex(ad => ad.campaignId === removedAd.campaignId);
     if (targetIndex !== -1) {
+      const adTable = refTable.value;
       adTable.toggleRowSelection(adCampaignName.value[targetIndex], false);
     }
-  });
+  }
+}
+
+function removeAllSelectedAds() {
   selectedAds.value = [];
+  const adTable = refTable.value;
+  adTable.clearSelection();
 }
 
 function cancel() {
@@ -197,6 +283,51 @@ async function fetchAdGroupList() {
   }
 }
 
+function handleSelectTarget(row) {
+  console.log("=>(adActivityDialog.vue:287) row", row);
+  // 获取父节点数据
+  const parent = adCampaignName.value.find(ad =>
+      ad.campaignGroupInfo && ad.campaignGroupInfo.some(group => group.adGroupId === row.adGroupId)
+  );
+  if (parent) {
+    // 构造包含父节点和子节点的数据对象
+    selectedTargetedRow.value = {
+      parentCampaignId: parent.campaignId,
+      parentCampaignName: parent.campaignName,
+      campaignType: parent.campaignType,
+      adGroupId: row.adGroupId,
+      adGroupName: row.adGroupName,
+      isSelected: row.isSelected || false, // 同步 isSelected 状态
+    };
+  }
+
+  targetRuleDialogVisible.value = true;
+}
+
+function handleConfirm(campaignKeywordInfo) {
+  selectedTargetedRow.value.keywordInfo = campaignKeywordInfo;
+  selectedTargetedRow.value.isSelected = true;
+
+  // 更新子节点状态
+  const parent = adCampaignName.value.find(ad =>
+      ad.campaignGroupInfo && ad.campaignGroupInfo.some(group => group.adGroupId === selectedTargetedRow.value.adGroupId)
+  );
+  if (parent) {
+    const group = parent.campaignGroupInfo.find(group => group.adGroupId === selectedTargetedRow.value.adGroupId);
+    if (group) {
+      group.isSelected = true; // 更新子节点的 isSelected 状态
+    }
+  }
+
+  // 勾选子节点行
+  const table = refTable.value;
+  const targetRow = parent.campaignGroupInfo.find(group => group.adGroupId === selectedTargetedRow.value.adGroupId);
+
+  if (table && targetRow) {
+    table.toggleRowSelection(targetRow, true); // 勾选目标子节点行
+  }
+}
+
 const headerCellStyle = (args) => {
   if (args.rowIndex === 0) {
     return {
@@ -244,13 +375,16 @@ watch(dialogVisible, (newValue) => {
 
 const treeProps = computed(() => {
   if (activeModel.value === 'adGroup' || activeModel.value === 'specified') {
-    return { children: 'campaignGroupInfo' };
+    return {
+      children: 'campaignGroupInfo',
+      checkStrictly: false
+    };
   }
   return {};
 });
 
 onMounted(() => {
-  //fetchAdGroupList();
+  fetchAdGroupList();
 });
 
 </script>
@@ -258,14 +392,13 @@ onMounted(() => {
 <template>
   <el-dialog
       v-model="dialogVisible"
-      class="custom-dialog"
       style="border-radius: 10px;"
       title="关联广告活动"
       width="1158px"
   >
     <div class="container">
       <div class="container-left">
-        <el-input v-model="searchAdCampaign" placeholder="请输入广告活动" style="width: 100%;"
+        <el-input v-model="searchAdCampaign" clearable placeholder="请输入广告活动" style="width: 100%;"
                   @change="fetchAdCampaign()"></el-input>
         <div class="custom-inline">
           <el-select v-model="selectedCampaignType" placeholder="选择广告类型">
@@ -299,12 +432,11 @@ onMounted(() => {
             v-loading="loading"
             :cell-style="cellStyle"
             :data="adCampaignName"
-            :row-key="'campaignId'"
             :header-cell-style="headerCellStyle"
+            :row-key="'adGroupId'"
+            :tree-props="treeProps"
             height="400"
             style="width: 100%;"
-            :tree-props="treeProps"
-            v-bind="activeModel === 'adGroup' || activeModel === 'specified' ? treeProps : {}"
             @selection-change="handleSelectionChange"
         >
           <el-table-column label="广告活动名称">
@@ -319,6 +451,14 @@ onMounted(() => {
               </el-tag>
               {{ scope.row.campaignName }}
               {{ scope.row.adGroupName }}
+              <el-button
+                  v-if="scope.row.adGroupName && activeModel==='specified'&&!scope.row.isSelected"
+                  class="btn-link"
+                  link
+                  @click="handleSelectTarget(scope.row)">
+                选择定向
+              </el-button>
+              <span v-else-if="scope.row.adGroupName">已选择</span>
             </template>
           </el-table-column>
           <el-table-column type="selection" width="55"></el-table-column>
@@ -341,14 +481,15 @@ onMounted(() => {
         <h3>已选择({{ selectedAds.length }})</h3>
         <el-table
             :cell-style="cellStyle"
-            :data="selectedAds"
+            :data="groupedSelectedAds"
             :header-cell-style="headerCellStyle"
-            height="484"
+            :row-key="'id'"
             :tree-props="treeProps"
-            v-bind="activeModel === 'adGroup' || activeModel === 'specified' ? treeProps : {}"
+            height="484"
             style="width: 100%; margin-top: 20px;"
+            v-bind="activeModel === 'adGroup' || activeModel === 'specified' ? treeProps : {}"
         >
-          <el-table-column label="广告活动" prop="campaignName">
+          <el-table-column label="广告活动" prop="name">
             <template #default="scope">
               <el-tag
                   v-if="scope.row.campaignType"
@@ -359,7 +500,7 @@ onMounted(() => {
                 {{ scope.row.campaignType }}
               </el-tag>
               {{ scope.row.campaignName }}
-              {{ scope.row.adGroupName }}
+              {{ scope.row.name }}
             </template>
           </el-table-column>
           <el-table-column
@@ -386,6 +527,11 @@ onMounted(() => {
       </div>
     </template>
   </el-dialog>
+  <TargetRuleDialog v-if="activeModel === 'specified'"
+                    v-model="targetRuleDialogVisible"
+                    :selectedTargetedRow="selectedTargetedRow"
+                    @confirm:targetRule="handleConfirm"
+  ></TargetRuleDialog>
 </template>
 
 <style scoped>
@@ -438,4 +584,10 @@ onMounted(() => {
   padding: 15px
 }
 
+.btn-link {
+  font-size: 13px;
+  color: #0085ff;
+  /* ling-heigt: 23px; */
+}
+
 </style>

+ 130 - 19
src/views/efTools/automation/components/targetRuleDialog.vue

@@ -4,40 +4,151 @@
  * @Description: 关联广告活动-选择定向弹窗
  * @Author: xinyan
  */
-import { reactive, ref } from 'vue';
+import { onMounted, reactive, ref, watch } from 'vue';
 import { MatchType } from '../../utils/enum';
+import { getTargetingRuleList } from '/@/views/efTools/automation/api';
+import { ElMessage } from 'element-plus';
+
+const props = defineProps({
+  modelValue: {
+    type: Boolean,
+    required: true,
+  },
+  selectedTargetedRow: {
+    type: Object,
+    required: true,
+  },
+});
+const emits = defineEmits(['update:modelValue', 'confirm:targetRule']);
+const targetRuleDialogVisible = ref(props.modelValue);
+const { selectedTargetedRow } = toRefs(props);
+const adGroupId = ref(props.adGroupId);
+const campaignKeywordInfo = ref(null);
 
 // 查询、筛选条件
 const matchType = ref('');
 const keyWord = ref('');
 
 const gridOptions = reactive({
+  height: 550,
+  showOverflow: true,
+  loading: false,
+  rowConfig: {
+    isHover: true,
+    height: 34
+  },
   columns: [
-    { field: 'keyword', title: '关键词' },
-    { field: 'match', title: '匹配方式' },
-    { type: 'checkbox', title: '全选' }
+    { field: 'keywordText', title: '关键词', width: 220 },
+    {
+      field: 'matchType',
+      title: '匹配方式',
+      formatter: ({ cellValue }) => getMatchTypeLabel(cellValue).label,
+    },
+    { type: 'checkbox', align: 'right', width: 55 }
   ],
   data: []
 });
 
+async function fetchTargetRuleList() {
+  try {
+    gridOptions.loading = true;
+    const resp = await getTargetingRuleList({
+      campaignType: selectedTargetedRow.value.campaignType,
+      campaignId: selectedTargetedRow.value.parentCampaignId,
+      adGroupId: selectedTargetedRow.value.adGroupId,
+      matchType: matchType.value,
+      search: keyWord.value,
+    });
+    gridOptions.data = resp.data.targetData;
+    gridOptions.loading = false;
+  } catch (error) {
+    ElMessage.error('请求定向数据失败');
+  }
+}
+
+function handleCheckChange({ records }) {
+  campaignKeywordInfo.value = records;
+}
+
+function getMatchTypeLabel(type: string) {
+  const matchType = MatchType.find(item => item.value === type);
+  if (matchType) {
+    return { label: matchType.label, type: type };
+  }
+  return { label: type, type: '' };
+}
+
+function cancel() {
+  targetRuleDialogVisible.value = false;
+}
+
+async function confirm() {
+  targetRuleDialogVisible.value = false;
+  emits('confirm:targetRule', campaignKeywordInfo.value);
+}
+
+const headerCellStyle = () => {
+  return {
+    fontSize: '13px',
+    height: '34px',
+  };
+};
+
+const cellStyle = () => {
+  return {
+    fontSize: '13px',
+    //fontWeight: '500',
+  };
+};
+
+watch(() => props.modelValue, (newValue) => {
+  targetRuleDialogVisible.value = newValue;
+});
+
+watch(targetRuleDialogVisible, (newValue) => {
+  emits('update:modelValue', newValue);
+});
+
+watch(() => props.selectedTargetedRow, () => {
+  fetchTargetRuleList();
+});
+
+onMounted(() => {
+  //fetchTargetRuleList();
+});
+
 </script>
 
 <template>
-  <el-select
-      v-model="matchType"
-      placeholder="Select"
-      size="large"
-      style="width: 240px"
-  >
-    <el-option
-        v-for="item in MatchType"
-        :key="item.value"
-        :label="item.label"
-        :value="item.value"
-    />
-  </el-select>
-  <el-input v-model="keyWord" placeholder="快速搜索关键词" style="width: 240px" />
-  <vxe-grid v-bind="gridOptions"></vxe-grid>
+  <el-dialog v-model="targetRuleDialogVisible"
+             style="border-radius: 10px;"
+             title="关联广告活动 > 选择定向"
+             width="1158px">
+    <div>
+      <el-select
+          v-model="matchType"
+          placeholder="全部匹配方式"
+          style="width: 128px; margin-bottom: 10px"
+          @change="fetchTargetRuleList"
+      >
+        <el-option
+            v-for="item in MatchType"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"
+        />
+      </el-select>
+    </div>
+    <el-input v-model="keyWord" class="mb-3" clearable placeholder="快速搜索关键词" @change="fetchTargetRuleList" />
+    <vxe-grid :cell-style="cellStyle" :header-cell-style="headerCellStyle" @checkbox-change="handleCheckChange"
+              v-bind="gridOptions"></vxe-grid>
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button @click="cancel">取消</el-button>
+        <el-button type="primary" @click="confirm">确定</el-button>
+      </div>
+    </template>
+  </el-dialog>
 </template>
 
 <style scoped>

+ 22 - 26
src/views/efTools/automation/index.vue

@@ -1,5 +1,5 @@
 <script lang="ts" setup>
-import { onMounted, provide, reactive, ref, Ref, watch } from 'vue';
+import { onMounted, provide, reactive, ref, Ref } from 'vue';
 import { Search } from '@element-plus/icons-vue';
 import { TemplateType } from '../utils/enum';
 import { DelObj, GetList } from '/@/views/efTools/automation/api';
@@ -128,7 +128,7 @@ const gridOptions = reactive({
     pageSizes: [10, 20, 30],
   },
   columns: [
-    { field: 'id', title: 'ID' ,width:140},
+    { field: 'id', title: 'ID', width: 140 },
     { field: 'name', title: '模板名称' },
     {
       field: 'rule.type',
@@ -161,11 +161,25 @@ const gridEvents = {
   },
 };
 
-watch(templateType, () => {
+function handleTypeChange() {
+  localStorage.setItem('templateType', JSON.stringify(templateType.value));
   getList();
-});
+}
+
+function handleTemplateListChange() {
+  localStorage.setItem('templateList', JSON.stringify(templateList.value));
+  getList();
+}
 
 async function getList() {
+  const savedTemplateType = localStorage.getItem('templateType');
+  if (savedTemplateType) {
+    templateType.value = JSON.parse(savedTemplateType);
+  }
+  const savedTemplateList = localStorage.getItem('templateList');
+  if (savedTemplateList) {
+    templateList.value = JSON.parse(savedTemplateList);
+  }
   try {
     gridOptions.loading = true;
     const response = await GetList({
@@ -197,25 +211,6 @@ function getTemplateTypeLabel(type: number) {
   return { label: '', type: '' };
 }
 
-function getTagType(type) {
-  switch (type) {
-    case 1:
-      return 'danger'; // 分时调价
-    case 2:
-      return 'success'; // 分时预算
-    case 3:
-      return 'info'; // 广告活动
-    case 4:
-      return 'warning'; // 定向规则
-    case 5:
-      return 'primary'; // 添加搜索词
-    case 6:
-      return ''; // 添加否定词
-    default:
-      return '';
-  }
-}
-
 const cellStyle = () => {
   return {
     fontSize: '13px',
@@ -244,9 +239,10 @@ onMounted(() => {
                 clearable
                 placeholder="模板名称"
                 style="width: 240px"
-                @change="getList"
+                @change="handleTemplateListChange"
       />
-      <el-select v-model="templateType" placeholder="Select" style="width: 240px">
+      <el-select v-model="templateType" placeholder="所有类型" style="width: 240px" value-key="value"
+                 @change="handleTypeChange">
         <el-option
             v-for="item in TemplateType"
             :key="item.value"
@@ -294,7 +290,7 @@ onMounted(() => {
           @refresh="refreshTable"></component>
     </div>
   </el-drawer>
-  <AdActivityDialog v-model="isDialogVisible" :templateId="templateId" :activeModel="activeModel"/>
+  <AdActivityDialog v-model="isDialogVisible" :activeModel="activeModel" :templateId="templateId" @confirm="handleConfirm"/>
   <AutomatedRuleTips v-model="autoInfo"></AutomatedRuleTips>
 </template>
 

+ 3 - 3
src/views/efTools/utils/enum.ts

@@ -10,7 +10,7 @@ export const TemplateType = [
 
 export const MatchType = [
   { label: '全部匹配方式', value: '' },
-  { label: '广泛匹配', value: 1 },
-  { label: '词组匹配', value: 2 },
-  { label: '精准匹配', value: 3 },
+  { label: '广泛匹配', value: 'BROAD' },
+  { label: '词组匹配', value: 'PHRASE' },
+  { label: '精准匹配', value: 'EXACT' },
 ];

+ 2 - 1
src/views/reportManage/TaskManage/index.vue

@@ -117,7 +117,7 @@ const gridOptions = reactive<VxeGridProps<RowVO>>({
   border: 'inner',
   keepSource: true,
   //showOverflow: true,
-  height: 930,
+  height: 780,
   loading: false,
   round: true,
   toolbarConfig: {
@@ -792,6 +792,7 @@ const cellStyle = () => {
   return {
     fontSize: '12px',
     fontWeight: '600',
+    padding: 0,
   };
 };
 

+ 10 - 10
src/views/reportManage/TaskManage/utils/columns.ts

@@ -85,7 +85,7 @@ export const taskColumns = ref([
     editRender: {},
     slots: { edit: 'company_edit' },
     align: 'center',
-    minWidth: 98
+    minWidth: 184
   },
   {
     field: 'companyEnglishName',
@@ -93,7 +93,7 @@ export const taskColumns = ref([
     editRender: {},
     slots: { edit: 'companyEnglishName_edit' },
     align: 'center',
-    minWidth: 110
+    minWidth: 126
   },
   {
     field: 'address',
@@ -101,7 +101,7 @@ export const taskColumns = ref([
     editRender: {},
     slots: { edit: 'address_edit' },
     align: 'center',
-    minWidth: 95
+    minWidth: 262
   },
   {
     field: 'juridicalPerson',
@@ -125,7 +125,7 @@ export const taskColumns = ref([
     editRender: {},
     slots: { edit: 'juridicalPersonCreditCardAddress_edit' },
     align: 'center',
-    minWidth: 105
+    minWidth: 262
   },
   {
     field: 'receivablesAccount',
@@ -133,7 +133,7 @@ export const taskColumns = ref([
     editRender: {},
     slots: { edit: 'receivablesAccount_edit' },
     align: 'center',
-    minWidth: 95
+    minWidth: 156
   },
   {
     field: 'receivablesAccountCompany',
@@ -224,19 +224,19 @@ export const shopInfoColumns = ref([
     field: 'company',
     title: '注册公司',
     align: 'center',
-    minWidth: 98
+    minWidth: 184
   },
   {
     field: 'companyEnglishName',
     title: '公司英文名称',
     align: 'center',
-    minWidth: 110
+    minWidth: 120
   },
   {
     field: 'address',
     title: '公司地址',
     align: 'center',
-    minWidth: 95
+    minWidth: 262
   },
   {
     field: 'juridicalPerson',
@@ -254,13 +254,13 @@ export const shopInfoColumns = ref([
     field: 'juridicalPersonCreditCardAddress',
     title: '信用卡地址',
     align: 'center',
-    minWidth: 105
+    minWidth: 262
   },
   {
     field: 'receivablesAccount',
     title: '收款账号',
     align: 'center',
-    minWidth: 95
+    minWidth: 156
   },
   {
     field: 'receivablesAccountCompany',

+ 37 - 13
src/views/reportManage/dataCenter/api.ts

@@ -1,7 +1,6 @@
 import { request } from '/@/utils/service';
-import { UserPageQuery } from '@fast-crud/fast-crud';
 
-//卡片日数据
+// 卡片日数据
 export function getCardDayData(query) {
   return request({
     url: '/api/report_manage/data-day/sum/',
@@ -25,7 +24,8 @@ export function getCardMonthData(query) {
     params: query,
   });
 }
-//条形图日数据
+
+// 条形图日数据
 export function getLineForDay(query) {
   return request({
     url: '/api/report_manage/data-day/daily/',
@@ -50,7 +50,7 @@ export function getLineForMonth(query) {
   });
 }
 
-//合并展示月对比数据
+// 合并展示月对比数据
 export function getLineData(query) {
   return request({
     url: '/api/report_manage/data-month/compare/plan/',
@@ -84,7 +84,7 @@ export function getMonthData(query) {
   });
 }
 
-//普通展示表格数据汇总
+// 普通展示表格数据汇总
 export function getDayTotalData(query) {
   return request({
     url: `/api/report_manage/data-day/list/sum/`,
@@ -109,8 +109,7 @@ export function getMonthTotalData(query) {
   });
 }
 
-
-//日数据插入
+// 日数据插入
 export function postCreateDayData(body) {
   return request({
     url: `/api/report_manage/data-day/`,
@@ -160,10 +159,10 @@ export function getMonthTaskData(query) {
   });
 }
 
-//日数据更新
+// 日数据更新
 export function postUpdateDayData(body) {
   return request({
-    url: `/api/report_manage/data-day/${body.id}/`,
+    url: `/api/report_manage/data-day/${ body.id }/`,
     method: 'POST',
     data: body,
   });
@@ -171,7 +170,7 @@ export function postUpdateDayData(body) {
 
 export function postUpdateWeekData(body) {
   return request({
-    url: `/api/report_manage/data-week/${body.id}/`,
+    url: `/api/report_manage/data-week/${ body.id }/`,
     method: 'POST',
     data: body,
   });
@@ -179,13 +178,38 @@ export function postUpdateWeekData(body) {
 
 export function postUpdateMonthData(body) {
   return request({
-    url: `/api/report_manage/data-month/${body.id}/`,
+    url: `/api/report_manage/data-month/${ body.id }/`,
     method: 'POST',
     data: body,
   });
 }
 
-//主数据获取
+// 日数据前一天数据获取
+export function getDayBeforeData(query) {
+  return request({
+    url: '/api/report_manage/data-day/one/',
+    method: 'GET',
+    params: query,
+  });
+}
+
+export function getWeekBeforeData(query) {
+  return request({
+    url: '/api/report_manage/data-week/one/',
+    method: 'GET',
+    params: query,
+  });
+}
+
+export function getMonthBeforeData(query) {
+  return request({
+    url: '/api/report_manage/data-month/one/',
+    method: 'GET',
+    params: query,
+  });
+}
+
+// 主数据获取
 export function getMainData(query) {
   return request({
     url: '/api/report_manage/data-all/',
@@ -202,7 +226,7 @@ export function getMonthlyData(query) {
   });
 }
 
-//导出
+// 导出
 export function exportData(query) {
   return request({
     url: '/api/report_manage/data-all/download/',

+ 14 - 9
src/views/reportManage/dataCenter/combinedDisplay/components/DatePicker/index.vue

@@ -1,10 +1,11 @@
 <script lang="ts" setup>
-import { inject, onBeforeMount, onMounted, ref, Ref, watch } from 'vue';
+import { computed, inject, onMounted, ref, Ref } from 'vue';
 import dayjs from 'dayjs';
 import isoWeek from 'dayjs/plugin/isoWeek';
 import DateRangePicker from '/src/components/DateRangePicker/index.vue';
 import enLocale from 'element-plus/es/locale/lang/en';
 
+
 dayjs.extend(isoWeek);
 //import { storeToRefs } from 'pinia';
 //import { usePublicData } from '/src/stores/publicData';
@@ -22,8 +23,14 @@ const dateRange = ref([
 
 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 weekStartDate = ref<string | null>(dayjs().locale('en').subtract(2, 'week').startOf('week').format('YYYY-MM-DD'));console.log("=>(index.vue:27) weekStartDate", weekStartDate.value);
+const wEndDate = ref<string | null>(dayjs().locale('en').subtract(2, 'week').endOf('week').format('YYYY-MM-DD'));console.log("=>(index.vue:29) wEndDate", wEndDate.value);
+const wStartDate = ref<string | null>(dayjs().locale('en').subtract(1, 'week').startOf('week').format('YYYY-MM-DD'));
+const weekEndDate = ref<string | null>(dayjs().locale('en').subtract(1, 'week').endOf('week').format('YYYY-MM-DD'));
+
+const sFormat = computed(() => `${ weekStartDate.value } to ${ wEndDate.value }`);
+const wFormat = computed(() => `${ wStartDate.value } to ${ weekEndDate.value }`);
+
 const currentYear = new Date().getFullYear();
 const currentMonth = new Date().getMonth();
 const monthlyDataTime = ref([
@@ -135,8 +142,8 @@ function setDefaultDate() {
     dayjs().subtract(6, 'day').startOf('day').format('YYYY-MM-DD'),
     dayjs().subtract(1, 'day').endOf('day').format('YYYY-MM-DD')
   ];
-  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');
+  startWeek.value = dayjs().locale('en').subtract(2, 'week').startOf('week').format('YYYY-MM-DD');
+  endWeek.value = dayjs().locale('en').subtract(1, 'week').endOf('week').format('YYYY-MM-DD');
   const startOfMonth = new Date(new Date().getFullYear(), new Date().getMonth() - 2, 1);
   const endOfMonth = new Date(new Date().getFullYear(), new Date().getMonth(), 0); // 设置下个月的第一天减去1天,得到当前月的最后一天
   monthlyDataTime.value = [startOfMonth, endOfMonth];
@@ -169,11 +176,10 @@ onMounted(() => {
               v-model="startWeek"
               :clearable="false"
               :disabled-date="disabledDate"
-              format="YYYY 第 WW 周"
+              :format="sFormat"
               placeholder="选择开始周"
               type="week"
               @change="handleStartWeekChange"
-              style="width: 150px"
           />
         </el-config-provider>
       </div>
@@ -185,11 +191,10 @@ onMounted(() => {
               :clearable="false"
               :disabled="!startWeek"
               :disabled-date="weekDisabledDate"
-              format="YYYY 第 WW 周"
+              :format="wFormat"
               placeholder="选择结束周"
               type="week"
               @change="handleEndWeekChange"
-              style="width: 150px"
           />
         </el-config-provider>
       </div>

+ 10 - 6
src/views/reportManage/dataCenter/normalDisplay/components/DatePicker/index.vue

@@ -23,8 +23,12 @@ const dateRange = ref( [
 
 const startWeek = ref(null);
 const endWeek = ref(null);
-const weekStartDate = ref<string | null>(dayjs().locale('en').subtract(5, 'week').startOf('week').format('YYYY-MM-DD'));
+const weekStartDate = ref<string | null>(dayjs().locale('en').subtract(2, 'week').startOf('week').format('YYYY-MM-DD'));
+const wEndDate = ref<string | null>(dayjs().locale('en').subtract(2, 'week').endOf('week').format('YYYY-MM-DD'));
+const wStartDate = ref<string | null>(dayjs().locale('en').subtract(1, 'week').startOf('week').format('YYYY-MM-DD'));
 const weekEndDate = ref<string | null>(dayjs().locale('en').subtract(1, 'week').endOf('week').format('YYYY-MM-DD'));
+const sFormat = computed(() => `${ weekStartDate.value } to ${ wEndDate.value }`);
+const wFormat = computed(() => `${ wStartDate.value } to ${ weekEndDate.value }`);
 
 const currentYear = new Date().getFullYear();
 const currentMonth = new Date().getMonth();
@@ -144,7 +148,7 @@ function setDefaultDate() {
       dateChange();
       break;
     case 'week':
-      startWeek.value = dayjs().locale('en').subtract(5, 'week').startOf('week').format('YYYY-MM-DD');
+      startWeek.value = dayjs().locale('en').subtract(2, 'week').startOf('week').format('YYYY-MM-DD');
       endWeek.value = dayjs().locale('en').subtract(1, 'week').endOf('week').format('YYYY-MM-DD');
       dateChange();
       break;
@@ -187,11 +191,11 @@ watch(dateType, () => {
               :clearable="false"
               :disabled-date="disabledDate"
               class="date-picker"
-              format="YYYY 第 WW 周"
+              :format="sFormat"
               placeholder="选择开始周"
               type="week"
               @change="handleStartWeekChange"
-              style="width: 150px"
+              style="width: 210px"
           />
         </el-config-provider>
         <span class="demonstration">至</span>
@@ -202,11 +206,11 @@ watch(dateType, () => {
               :disabled="!startWeek"
               :disabled-date="weekDisabledDate"
               class="date-picker"
-              format="YYYY 第 WW 周"
+              :format="wFormat"
               placeholder="选择结束周"
               type="week"
               @change="handleEndWeekChange"
-              style="width: 150px"
+              style="width: 210px"
           />
         </el-config-provider>
       </div>

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

@@ -149,11 +149,11 @@ defineExpose({ fetchFilteredData, filteredData, updateData });
 
 <template>
   <div class="flex gap-2.5 flex-wrap">
-    <el-input v-model="platformNumberList" class="flex-item" clearable placeholder="平台编号" style="width: 150px;height: 30px"
+    <el-input v-model="platformNumberList" class="flex-item" clearable placeholder="平台编号" style="width: 130px"
               @change="emitChange"></el-input>
-    <el-input v-model="platformNameList" class="flex-item" clearable placeholder="平台名称" style="width: 150px;height: 30px"
+    <el-input v-model="platformNameList" class="flex-item" clearable placeholder="平台名称" style="width: 130px"
               @change="emitChange"></el-input>
-    <el-input v-model="operationList" class="flex-item" clearable placeholder="运营" style="width: 150px;height: 30px" @change="emitChange"></el-input>
+    <el-input v-model="operationList" class="flex-item" clearable placeholder="运营" style="width: 130px" @change="emitChange"></el-input>
     <el-select
         v-model="usersList"
         class="flex-item"
@@ -178,11 +178,11 @@ defineExpose({ fetchFilteredData, filteredData, updateData });
         <el-button text size="small" @click="selectCommonGroup2">欧洲+英国</el-button>
       </template>
     </el-select>
-    <el-select v-model="brandNameList" class="flex-item" clearable collapse-tags collapse-tags-tooltip multiple style="width: 150px;"
+    <el-select v-model="brandNameList" class="flex-item" clearable collapse-tags collapse-tags-tooltip multiple style="width: 145px;"
                placeholder="品牌">
       <el-option v-for="item in brandNameOptions" :key="item" :label="item" :value="item" />
     </el-select>
-    <el-select v-model="platformList" class="flex-item" clearable collapse-tags collapse-tags-tooltip multiple style="width: 150px;"
+    <el-select v-model="platformList" class="flex-item" clearable collapse-tags collapse-tags-tooltip multiple style="width: 145px;"
                placeholder="平台">
       <el-option v-for="item in platformOptions" :key="item" :label="item" :value="item" />
     </el-select>

+ 149 - 28
src/views/reportManage/dataCenter/normalDisplay/components/TableDataEntry.vue

@@ -5,8 +5,11 @@ import dayjs from 'dayjs';
 import isoWeek from 'dayjs/plugin/isoWeek';
 import { useRoute } from 'vue-router';
 import {
+  getDayBeforeData,
   getDayTaskData,
+  getMonthBeforeData,
   getMonthTaskData,
+  getWeekBeforeData,
   getWeekTaskData,
   postCreateDayData,
   postCreateMonthData,
@@ -19,6 +22,8 @@ import { dayColumns, monthColumns, weekColumns } from '../../utils/columns';
 import { ComponentSize, ElMessage, FormInstance, FormRules } from 'element-plus';
 import enLocale from 'element-plus/es/locale/lang/en';
 import Selector from '/@/views/reportManage/dataCenter/normalDisplay/components/Selector/index.vue';
+import { Warning } from '@element-plus/icons-vue';
+
 
 dayjs.extend(isoWeek);
 
@@ -67,8 +72,13 @@ const shortcuts = [
   },
 ];
 
+const yDayDate = ref(null);
+const yWeekDay = ref(null);
+const yMonthDay = ref(null);
+
 function handleDayChange(value) {
   dailySalesTime.value = dayjs(value).format('YYYY-MM-DD');
+  yDayDate.value = dayjs(dailySalesTime.value).subtract(1, 'day').format('YYYY-MM-DD');
   fetchCurrentTaskData();
 }
 
@@ -80,6 +90,7 @@ const handleWeekChange = () => {
     weeklyAdTime.value = adDate.format('YYYY-WW');
     adStartDate.value = adDate.startOf('week').format('YYYY-MM-DD');
     adEndDate.value = adDate.endOf('week').format('YYYY-MM-DD');
+    yWeekDay.value = dayjs(entryEndDate.value).locale('en').endOf('week').subtract(1, 'week').format('YYYY-MM-DD');
   }
   if (initialLoad) {
     initialLoad = false; // 只在初次加载时避免多次调用
@@ -96,6 +107,7 @@ const handleMonthChange = (value) => {
     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 }`;
+    yMonthDay.value = dayjs(endDate.value).subtract(1, 'month').endOf('month').format('YYYY-MM-DD');
     fetchCurrentTaskData();
   } else {
     startDate.value = null;
@@ -115,6 +127,7 @@ function setDefaultDate() {
   switch (dateType) {
     case 'day':
       dailySalesTime.value = dayjs().subtract(1, 'day').format('YYYY-MM-DD');
+      yDayDate.value = dayjs(dailySalesTime.value).subtract(1, 'day').format('YYYY-MM-DD');
       break;
     case 'week':
       weeklyEntryTime.value = dayjs().locale('en').subtract(1, 'week').startOf('week').format('YYYY-MM-DD');
@@ -124,6 +137,7 @@ function setDefaultDate() {
       monthlyEntryTime.value = dayjs().subtract(1, 'month').format('YYYY-MM-DD');
       startDate.value = dayjs(monthlyEntryTime.value).startOf('month').format('YYYY-MM-DD');
       endDate.value = dayjs(monthlyEntryTime.value).endOf('month').format('YYYY-MM-DD');
+      yMonthDay.value = dayjs(endDate.value).subtract(1, 'month').endOf('month').format('YYYY-MM-DD');
   }
 }
 
@@ -150,6 +164,8 @@ interface taskDataForm {
 const formSize = ref<ComponentSize>('default');
 const isSubmitting = ref(false);
 const dayFormVisible = ref(false);
+const dialogVisible = ref(false);
+const dialogMessage = ref('');
 const taskDataFormRef = ref<FormInstance>();
 const taskDataForm = reactive({
   sales_original: null,
@@ -159,7 +175,6 @@ const taskDataForm = reactive({
   impression: null,
   ad_click: null,
   ad_order: null,
-  // money_by_other: null,
   session: null,
   order: null,
   availableSalesDay: null,
@@ -195,6 +210,11 @@ const rules = reactive<FormRules>({
 const flatDayColumns = ref(flattenColumns(dayColumns.value));
 const flatWeekColumns = ref(flattenColumns(weekColumns.value));
 const flatMonthColumns = ref(flattenColumns(monthColumns.value));
+
+const ySalesData = ref({
+  sales_original: '',
+  total_sales_current_monthly_original: '',
+});
 //表格
 let taskId = 0;
 let currentId = 0;
@@ -315,7 +335,6 @@ const handelEditRow = (row: RowVO) => {
     // 强制恢复滚动条位置
     setTimeout(() => {
       bodyWrapper.scrollLeft = currentScrollLeft.value;
-      console.log('After setTimeout, scrollLeft:', bodyWrapper.scrollLeft);
     }, 0);
   }
 };
@@ -387,9 +406,9 @@ function fetchCurrentTaskData() {
 
 const editEvent = async (row: RowVO) => {
   taskId = row.task;
-  // console.log('row', taskId);
   currentId = row.id;
   Object.assign(taskDataForm, row);
+  await currentSalesTip();
   dayFormVisible.value = true;
 };
 
@@ -543,31 +562,43 @@ async function createMonthData() {
 
 //创建任务
 const submitForm = async (formEl: FormInstance | undefined) => {
-  if (!formEl || isSubmitting.value) return; // 防止重复提交
-  await formEl.validate(async (valid, fields) => {
-    if (valid) {
-      isSubmitting.value = true; // 表单开始提交,禁用按钮
-      try {
-        if (dateType === 'day') {
-          const fieldsToValidate = ['sales_original'];
-          if (!validateNumericFields(taskDataForm, fieldsToValidate)) return; // 验证字段
-          await createDayData();
-        }
-        if (dateType === 'week') {
-          const fieldsToValidate = ['sales_original', 'ad_sales_original', 'ad_cost_original', 'total_sales_current_monthly_original', 'impression', 'ad_click', 'ad_order', 'money_by_amazon', 'money_by_other', 'session', 'order', 'availableSalesDay', 'intransitInventory', 'overseasStorage', 'refundRate'];
-          if (!validateNumericFields(taskDataForm, fieldsToValidate)) return; // 验证字段
-          await createWeekData();
-        }
-        if (dateType === 'month') {
-          const fieldsToValidate = ['sales_original'];
-          if (!validateNumericFields(taskDataForm, fieldsToValidate)) return; // 验证字段
-          await createMonthData();
+  const fieldsToWarn = validateForm();
+  if (fieldsToWarn.length > 0) {
+    dialogVisible.value = true;
+    dialogMessage.value = `${ fieldsToWarn.join(', ') }`;
+    return;
+  } else {
+    if (!formEl || isSubmitting.value) return; // 防止重复提交
+    await formEl.validate(async (valid, fields) => {
+      if (valid) {
+        isSubmitting.value = true; // 表单开始提交,禁用按钮
+        try {
+          await submit(formEl);
+        } finally {
+          isSubmitting.value = false; // 无论成功或失败,恢复按钮
         }
-      } finally {
-        isSubmitting.value = false; // 无论成功或失败,恢复按钮
       }
-    }
-  });
+    });
+  }
+};
+
+const submit = async () => {
+  dialogVisible.value = false;
+  if (dateType === 'day') {
+    const fieldsToValidate = ['sales_original'];
+    if (!validateNumericFields(taskDataForm, fieldsToValidate)) return; // 验证字段
+    await createDayData();
+  }
+  if (dateType === 'week') {
+    const fieldsToValidate = ['sales_original', 'ad_sales_original', 'ad_cost_original', 'total_sales_current_monthly_original', 'impression', 'ad_click', 'ad_order', 'money_by_amazon', 'money_by_other', 'session', 'order', 'availableSalesDay', 'intransitInventory', 'overseasStorage', 'refundRate'];
+    if (!validateNumericFields(taskDataForm, fieldsToValidate)) return; // 验证字段
+    await createWeekData();
+  }
+  if (dateType === 'month') {
+    const fieldsToValidate = ['sales_original'];
+    if (!validateNumericFields(taskDataForm, fieldsToValidate)) return; // 验证字段
+    await createMonthData();
+  }
 };
 
 // 更新日数据
@@ -696,6 +727,47 @@ const editRowEvent = async (row: any) => {
   }
 };
 
+// 日数据提示
+async function salesTip(apiFunction, dateTypeKey) {
+  const dateMap = {
+    day: yDayDate.value,
+    week: yWeekDay.value,
+    month: yMonthDay.value,
+  };
+  const resp = await apiFunction({
+    task: taskId,
+    [`${ dateTypeKey }_end_date`]: dateMap[dateTypeKey],
+  });
+  if (dateType === 'week') {
+    ySalesData.value = resp.data;
+  } else {
+    ySalesData.value = resp.data[0];
+  }
+  return ySalesData.value;
+}
+
+async function daySalesTip() {
+  await salesTip(getDayBeforeData, 'day');
+}
+
+async function weekSalesTip() {
+  await salesTip(getWeekBeforeData, 'week');
+}
+
+async function monthSalesTip() {
+  await salesTip(getMonthBeforeData, 'month');
+}
+
+async function currentSalesTip() {
+  if (dateType === 'week') {
+    await weekSalesTip();
+  } else if (dateType === 'month') {
+    await monthSalesTip();
+  } else {
+    await daySalesTip();
+  }
+}
+
 const currentGridOptions = computed(() => {
   const selectedGridOptions = gridOptions[dateType] || gridOptions['day'];
   return {
@@ -749,6 +821,27 @@ const headerCellStyle = () => {
   };
 };
 
+const validateForm = () => {
+  const fieldsToWarn = [];
+  const fieldsToValidate = ['sales_original', 'total_sales_current_monthly_original'];
+  if (ySalesData.value) {
+    for (const key of fieldsToValidate) {
+      const newValue = taskDataForm[key];
+      const yDayValue = ySalesData.value[key];
+      const column = flatWeekColumns.value.find(col => col.field === key);
+      const title = column ? column.title : key;
+
+      if (newValue != null && yDayValue !== null && yDayValue !== undefined) {
+        const diffPercentage = Math.abs((newValue - yDayValue) / yDayValue) * 100;
+        if (diffPercentage > 50) {
+          fieldsToWarn.push(title);
+        }
+      }
+    }
+  }
+  return fieldsToWarn;
+};
+
 onMounted(() => {
   setDefaultDate();
   //fetchCurrentTaskData();
@@ -769,9 +862,9 @@ onMounted(() => {
                 :clearable="false"
                 :disabled-date="disabledDate"
                 :shortcuts="shortcuts"
+                style="width: 170px"
                 type="Date"
                 @change="handleDayChange"
-                style="width: 170px"
             />
           </div>
         </div>
@@ -838,6 +931,9 @@ onMounted(() => {
                      @click="editEvent(row)">创建
           </el-button>
         </template>
+        <template #total_header="{ row }">
+          <span>当月截止{{ entryEndDate }}销售额</span>
+        </template>
         <template #sales_original_edit="{ row }">
           <vxe-input v-model="row.sales_original"></vxe-input>
         </template>
@@ -925,8 +1021,8 @@ onMounted(() => {
       <div class="dialog-footer">
         <el-button @click="dayFormVisible = false ;resetForm(taskDataFormRef)">取消</el-button>
         <el-button
-            type="primary"
             :disabled="isSubmitting"
+            type="primary"
             @click="submitForm(taskDataFormRef)"
         >
           {{ isSubmitting ? '提交中...' : '确认' }}
@@ -934,6 +1030,31 @@ onMounted(() => {
       </div>
     </template>
   </el-dialog>
+  <el-dialog
+      v-model="dialogVisible"
+      align-center
+      style="border-radius: 10px;"
+      title="重要提示"
+      width="30%"
+  >
+    <template #title>
+      <el-button link style="font-size: 18px" type="warning">
+        <el-icon size="22px">
+          <warning />
+        </el-icon>
+        重要提示
+      </el-button>
+    </template>
+    <span>您输入的 </span>
+    <span style="color: #f1a055;">{{ dialogMessage }}</span>
+    <span> 相较于上次填入的数据偏离值超过 50% ,是否仍要提交?</span>
+    <template #footer>
+      <span class="dialog-footer">
+        <el-button @click="dialogVisible = false">取消</el-button>
+        <el-button type="primary" @click="submit(formEl)">确认</el-button>
+      </span>
+    </template>
+  </el-dialog>
 </template>
 
 <style lang="scss" scoped>

+ 2 - 1
src/views/reportManage/dataCenter/utils/columns.ts

@@ -98,7 +98,8 @@ export const weekColumns = ref([
     ]
   },
   {
-    title: '当月累计销售额', align: 'center', children: [
+    title: '当月累计销售额', align: 'center', slots: { header: 'total_header' },
+    children: [
       { field: 'total_sales_current_monthly', title: '当月累计销售额', width: 120 },
       {
         field: 'total_sales_current_monthly_original',