Преглед изворни кода

Merge branch 'xinyan' into test

xinyan пре 9 месеци
родитељ
комит
343f2d122c

+ 2 - 3
src/views/components/auto/auto-campaigns/timer-bid.vue

@@ -85,7 +85,6 @@ async function submit() {
   formRef.value.validate(async (valid: any) => {
     if (valid) {
       await submitFormData();
-      console.log('formData', formData.value);
       emits('refresh');
       submitDialogVisible.value = true;
     } else {
@@ -163,10 +162,10 @@ const handleApply = () => {
           </template>
           <div class="flex flex-col">
             <div class="flex gap-2 my-2">
-              <el-select v-model="timeRange" :disabled="formData.useTmpl">
+              <el-select v-model="timeRange" :disabled="formData.useTmpl" style="width: 186px">
                 <el-option v-for="item in timeRangeOptions" :key="item.value" :label="item.label" :value="item.value" />
               </el-select>
-              <el-select v-model="schedule" :disabled="formData.useTmpl">
+              <el-select v-model="schedule" :disabled="formData.useTmpl" style="width: 186px">
                 <el-option v-for="item in scheduleOptions" :key="item.value" :label="item.label" :value="item.value" />
               </el-select>
               <el-input v-model="bid" :disabled="formData.useTmpl"

+ 2 - 2
src/views/components/auto/auto-templates/timer-bid.vue

@@ -167,10 +167,10 @@ const handleApply = () => {
         </template>
         <div class="flex flex-col">
           <div class="flex gap-2 my-2">
-            <el-select v-model="timeRange">
+            <el-select v-model="timeRange" style="width: 186px">
               <el-option v-for="item in timeRangeOptions" :key="item.value" :label="item.label" :value="item.value" />
             </el-select>
-            <el-select v-model="schedule">
+            <el-select v-model="schedule" style="width: 186px">
               <el-option v-for="item in scheduleOptions" :key="item.value" :label="item.label" :value="item.value" />
             </el-select>
             <el-input v-model="bid"

+ 1 - 1
src/views/components/auto/target-select.vue

@@ -16,7 +16,7 @@ interface Props {
 const props = defineProps<Props>();
 
 watch(()=>props.data.campaignAd, (val)=>{
-  console.log(11, props.data.campaignAd);
+
 })
 
 </script>

+ 61 - 10
src/views/efTools/automation/components/adActivityDialog.vue

@@ -4,7 +4,7 @@
  * @Description:广告关联活动弹窗
  * @Author: xinyan
  */
-import { onMounted, ref, watch } from 'vue';
+import { computed, onMounted, ref, watch } from 'vue';
 import { getAdGroupList, getRelationCampaign } from '/@/views/efTools/automation/api';
 import { storeToRefs } from 'pinia';
 import { useShopInfo } from '/@/stores/shopInfo';
@@ -15,6 +15,9 @@ const props = defineProps({
     type: [String, Number],
     required: true,
   },
+  activeModel: {
+    type: String,
+  },
   modelValue: {
     type: Boolean,
     required: true,
@@ -24,6 +27,7 @@ const emits = defineEmits(['update:modelValue']);
 const shopInfo = useShopInfo();
 const { profile } = storeToRefs(shopInfo);
 const { templateId } = toRefs(props);
+const { activeModel } = toRefs(props);
 
 const dialogVisible = ref(props.modelValue);
 //筛选条件
@@ -52,7 +56,7 @@ const total = ref(0);
 
 const loading = ref(false);
 const refTable = ref(null);
-const selectedAds = ref([]);
+let selectedAds = ref([]);
 let selections = []; // 添加选中的项
 
 function handleCurrentChange(newPage) {
@@ -68,9 +72,12 @@ function handleSizeChange(newSize) {
   fetchAdCampaign();
 }
 
+let isRestoringSelection = false;
+
 async function fetchAdCampaign() {
   try {
     loading.value = true;
+    const cachedSelectedAds = [...selectedAds.value];
     const resp = await getRelationCampaign({
       profileId: profile.value.profile_id,
       templateId: templateId.value,
@@ -82,15 +89,18 @@ async function fetchAdCampaign() {
       limit: pageSize.value,
     });
     adCampaignName.value = resp.data;
+
     total.value = resp.total;
     currentPage.value = resp.page;
-    // 恢复勾选状态
+    // 开始恢复勾选状态
+    isRestoringSelection = true;
     nextTick(() => {
       adCampaignName.value.forEach(item => {
-        if (selectedAds.value.some(ad => ad.campaignId === item.campaignId)) {
+        if (cachedSelectedAds.some(ad => ad.campaignId === item.campaignId)) {
           refTable.value.toggleRowSelection(item, true);
         }
       });
+      isRestoringSelection = false;
     });
   } catch (error) {
     ElMessage.error('请求广告活动数据失败');
@@ -100,6 +110,8 @@ async function fetchAdCampaign() {
 }
 
 function handleSelectionChange(selection) {
+  if (isRestoringSelection) return; // 恢复勾选时跳过该方法
+
   selections = selection;
   const newSelections = selections.filter(
       (sel) => !selectedAds.value.some((added) => added.campaignId === sel.campaignId)
@@ -230,6 +242,13 @@ watch(dialogVisible, (newValue) => {
   emits('update:modelValue', newValue);
 });
 
+const treeProps = computed(() => {
+  if (activeModel.value === 'adGroup' || activeModel.value === 'specified') {
+    return { children: 'campaignGroupInfo' };
+  }
+  return {};
+});
+
 onMounted(() => {
   //fetchAdGroupList();
 });
@@ -244,8 +263,8 @@ onMounted(() => {
       title="关联广告活动"
       width="1158px"
   >
-    <div style="display: flex;">
-      <div style="width: 50%;">
+    <div class="container">
+      <div class="container-left">
         <el-input v-model="searchAdCampaign" placeholder="请输入广告活动" style="width: 100%;"
                   @change="fetchAdCampaign()"></el-input>
         <div class="custom-inline">
@@ -257,7 +276,7 @@ onMounted(() => {
             ></el-option>
           </el-select>
 
-          <el-select v-model="selectedAdGroup" placeholder="广告组合" style="margin-bottom: 10px;">
+          <el-select v-model="selectedAdGroup" clearable placeholder="广告组合" style="margin-bottom: 10px;">
             <el-option
                 v-for="item in adGroups"
                 :key="item.value"
@@ -280,14 +299,18 @@ onMounted(() => {
             v-loading="loading"
             :cell-style="cellStyle"
             :data="adCampaignName"
+            :row-key="'campaignId'"
             :header-cell-style="headerCellStyle"
             height="400"
             style="width: 100%;"
+            :tree-props="treeProps"
+            v-bind="activeModel === 'adGroup' || activeModel === 'specified' ? treeProps : {}"
             @selection-change="handleSelectionChange"
         >
-          <el-table-column label="广告活动名称" prop="campaignName">
+          <el-table-column label="广告活动名称">
             <template #default="scope">
               <el-tag
+                  v-if="scope.row.campaignType"
                   :color="scope.row.campaignType === 'sb' ? '#0163d2' : (scope.row.campaignType === 'sp' ? '#ff7424' : '#365672')"
                   class="campaign-type"
                   disable-transitions
@@ -295,6 +318,7 @@ onMounted(() => {
                 {{ scope.row.campaignType }}
               </el-tag>
               {{ scope.row.campaignName }}
+              {{ scope.row.adGroupName }}
             </template>
           </el-table-column>
           <el-table-column type="selection" width="55"></el-table-column>
@@ -313,19 +337,21 @@ onMounted(() => {
           />
         </div>
       </div>
-
-      <div style="flex: 1; padding-left: 20px;">
+      <div class="container-right">
         <h3>已选择({{ selectedAds.length }})</h3>
         <el-table
             :cell-style="cellStyle"
             :data="selectedAds"
             :header-cell-style="headerCellStyle"
             height="484"
+            :tree-props="treeProps"
+            v-bind="activeModel === 'adGroup' || activeModel === 'specified' ? treeProps : {}"
             style="width: 100%; margin-top: 20px;"
         >
           <el-table-column label="广告活动" prop="campaignName">
             <template #default="scope">
               <el-tag
+                  v-if="scope.row.campaignType"
                   :color="scope.row.campaignType === 'sb' ? '#0163d2' : (scope.row.campaignType === 'sp' ? '#ff7424' : '#365672')"
                   class="campaign-type"
                   disable-transitions
@@ -333,6 +359,7 @@ onMounted(() => {
                 {{ scope.row.campaignType }}
               </el-tag>
               {{ scope.row.campaignName }}
+              {{ scope.row.adGroupName }}
             </template>
           </el-table-column>
           <el-table-column
@@ -387,4 +414,28 @@ onMounted(() => {
   margin-right: 4px;
 }
 
+.container {
+  width: 100%;
+  height: 100%;
+  border: 1px solid #d6dbe2;
+  border-radius: 4px;
+  display: flex;
+  overflow: hidden;
+  align-content: center;
+  flex-wrap: nowrap;
+  flex-direction: row;
+  /* padding: 10px; */
+}
+
+.container-left {
+  width: 50%;
+  border-right: 1px solid #d6dbe2;
+  padding: 15px
+}
+
+.container-right {
+  flex: 1;
+  padding: 15px
+}
+
 </style>

+ 45 - 0
src/views/efTools/automation/components/targetRuleDialog.vue

@@ -0,0 +1,45 @@
+<script lang="ts" setup>
+/**
+ * @Name: targetRuleDialog.vue
+ * @Description: 关联广告活动-选择定向弹窗
+ * @Author: xinyan
+ */
+import { reactive, ref } from 'vue';
+import { MatchType } from '../../utils/enum';
+
+// 查询、筛选条件
+const matchType = ref('');
+const keyWord = ref('');
+
+const gridOptions = reactive({
+  columns: [
+    { field: 'keyword', title: '关键词' },
+    { field: 'match', title: '匹配方式' },
+    { type: 'checkbox', title: '全选' }
+  ],
+  data: []
+});
+
+</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>
+</template>
+
+<style scoped>
+
+</style>

+ 3 - 1
src/views/efTools/automation/index.vue

@@ -19,6 +19,7 @@ const autoInfo = ref(false);
 //关联广告活动弹窗
 const isDialogVisible = ref(false);
 const templateId = ref('');
+const activeModel = ref('');
 provide('isDialogVisible', isDialogVisible);
 
 //查询
@@ -59,6 +60,7 @@ function refreshTable() {
 
 const showDialog = (row: any) => {
   templateId.value = row.id;
+  activeModel.value = row.rule.activeModel;
   isDialogVisible.value = true;
 };
 
@@ -292,7 +294,7 @@ onMounted(() => {
           @refresh="refreshTable"></component>
     </div>
   </el-drawer>
-  <AdActivityDialog v-model="isDialogVisible" :templateId="templateId" />
+  <AdActivityDialog v-model="isDialogVisible" :templateId="templateId" :activeModel="activeModel"/>
   <AutomatedRuleTips v-model="autoInfo"></AutomatedRuleTips>
 </template>
 

+ 7 - 0
src/views/efTools/utils/enum.ts

@@ -7,3 +7,10 @@ export const TemplateType = [
   { label: '添加搜索词', value: 5 },
   { label: '添加否定词', value: 6 },
 ];
+
+export const MatchType = [
+  { label: '全部匹配方式', value: '' },
+  { label: '广泛匹配', value: 1 },
+  { label: '词组匹配', value: 2 },
+  { label: '精准匹配', value: 3 },
+];

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

@@ -551,7 +551,7 @@ async function updateRow(row) {
       country: row.country,
       brandName: row.brandName,
       user: row.user,
-      operater: row.operater?.split(',').map(item => item.trim()),
+      operater: Array.isArray(row.operater) ? row.operater : row.operater.split(',').map(item => item.trim()),
       currencyCode: row.currencyCode,
       currencyCodePlatform: row.currencyCodePlatform,
       line: row.line,

+ 0 - 309
src/views/system/dictionary/subDict/crud.tsx

@@ -1,309 +0,0 @@
-import * as api from './api';
-import {
-    dict,
-    UserPageQuery,
-    AddReq,
-    DelReq,
-    EditReq,
-    CrudOptions,
-    CreateCrudOptionsProps,
-    CreateCrudOptionsRet
-} from '@fast-crud/fast-crud';
-import {dictionary} from '/@/utils/dictionary';
-
-export const createCrudOptions = function ({crudExpose, context}: CreateCrudOptionsProps): CreateCrudOptionsRet {
-    const pageRequest = async (query: UserPageQuery) => {
-        return await api.GetList(query);
-    };
-    const editRequest = async ({form, row}: EditReq) => {
-        form.id = row.id;
-        return await api.UpdateObj(form);
-    };
-    const delRequest = async ({row}: DelReq) => {
-        return await api.DelObj(row.id);
-    };
-    const addRequest = async ({form}: AddReq) => {
-        const data = crudExpose!.getSearchFormData()
-        const parent = data.parent
-        form.parent = parent
-        if (parent) {
-            return await api.AddObj(form);
-        } else {
-            return undefined
-        }
-
-    };
-
-    return {
-        crudOptions: {
-            request: {
-                pageRequest,
-                addRequest,
-                editRequest,
-                delRequest,
-            },
-            rowHandle: {
-                //固定右侧
-                fixed: 'right',
-                width: 200,
-                buttons: {
-                    view: {
-                        show: false,
-                    },
-                    edit: {
-                        iconRight: 'Edit',
-                        type: 'text',
-                    },
-                    remove: {
-                        iconRight: 'Delete',
-                        type: 'text',
-                    },
-                },
-            },
-            columns: {
-                _index: {
-                    title: '序号',
-                    form: {show: false},
-                    column: {
-                        //type: 'index',
-                        align: 'center',
-                        width: '70px',
-                        columnSetDisabled: true, //禁止在列设置中选择
-                        formatter: (context) => {
-                            //计算序号,你可以自定义计算规则,此处为翻页累加
-                            let index = context.index ?? 1;
-                            let pagination = crudExpose!.crudBinding.value.pagination;
-                            // @ts-ignore
-                            return ((pagination.currentPage ?? 1) - 1) * pagination.pageSize + index + 1;
-                        },
-                    },
-                },
-                label: {
-                    title: '名称',
-                    search: {
-                        show: true,
-                        component: {
-                            props: {
-                                clearable: true,
-                            },
-                        },
-                    },
-                    type: 'input',
-                    form: {
-                        rules: [
-                            // 表单校验规则
-                            {required: true, message: '名称必填项'},
-                        ],
-                        component: {
-                            props: {
-                                clearable: true,
-                            },
-                            placeholder: '请输入名称',
-                        },
-                    },
-                },
-                type: {
-                    title: '数据值类型',
-                    type: 'dict-select',
-                    search: {
-                        disabled: true,
-                        component: {
-                            props: {
-                                clearable: true,
-                            },
-                        },
-                    },
-                    show: false,
-                    dict: dict({
-                        data: [
-                            {label: 'text', value: 0},
-                            {label: 'number', value: 1},
-                            {label: 'date', value: 2},
-                            {label: 'datetime', value: 3},
-                            {label: 'time', value: 4},
-                            {label: 'file', value: 5},
-                            {label: 'boolean', value: 6},
-                            {label: 'images', value: 7},
-                        ],
-                    }),
-                    form: {
-                        rules: [
-                            // 表单校验规则
-                            {required: true, message: '数据值类型必填项'},
-                        ],
-                        value: 0,
-                        component: {
-                            props: {
-                                clearable: true,
-                            },
-                            placeholder: '请选择数据值类型',
-                        },
-                        /* valueChange(key, value, form, { getColumn, mode, component, immediate, getComponent }) {
-                            const template = vm.getEditFormTemplate('value')
-                            // 选择框重新选择后,情况value值
-                            if (!immediate) {
-                                form.value = undefined
-                            }
-                            if (value === 0) {
-                                template.component.name = 'el-input'
-                            } else if (value === 1) {
-                                template.component.name = 'el-input-number'
-                            } else if (value === 2) {
-                                template.component.name = 'el-date-picker'
-                                template.component.props = {
-                                    type: 'date',
-                                    valueFormat: 'yyyy-MM-dd'
-                                }
-                            } else if (value === 3) {
-                                template.component.name = 'el-date-picker'
-                                template.component.props = {
-                                    type: 'datetime',
-                                    valueFormat: 'yyyy-MM-dd HH:mm:ss'
-                                }
-                            } else if (value === 4) {
-                                template.component.name = 'el-time-picker'
-                                template.component.props = {
-                                    pickerOptions: {
-                                        arrowControl: true
-                                    },
-                                    valueFormat: 'HH:mm:ss'
-                                }
-                            } else if (value === 5) {
-                                template.component.name = 'd2p-file-uploader'
-                                template.component.props = { elProps: { listType: 'text' } }
-                            } else if (value === 6) {
-                                template.component.name = 'dict-switch'
-                                template.component.value = true
-                                template.component.props = {
-                                    dict: {
-                                        data: [
-                                            { label: '是', value: 'true' },
-                                            { label: '否', value: 'false' }
-                                        ]
-                                    }
-                                }
-                            } else if (value === 7) {
-                                template.component.name = 'd2p-cropper-uploader'
-                                template.component.props = { accept: '.png,.jpeg,.jpg,.ico,.bmp,.gif', cropper: { viewMode: 1 } }
-                            }
-                        }, */
-                    },
-                },
-                value: {
-                    title: '数据值',
-                    search: {
-                        show: true,
-                        component: {
-                            props: {
-                                clearable: true,
-                            },
-                        },
-                    },
-                    view: {
-                        component: {props: {height: 100, width: 100}},
-                    },
-                    /* // 提交时,处理数据
-                    valueResolve(row: any, col: any) {
-                        const value = row[col.key]
-                        const type = row.type
-                        if (type === 5 || type === 7) {
-                            if (value != null) {
-                                if (value.length >= 0) {
-                                    if (value instanceof Array) {
-                                        row[col.key] = value.toString()
-                                    } else {
-                                        row[col.key] = value
-                                    }
-                                } else {
-                                    row[col.key] = null
-                                }
-                            }
-                        } else {
-                            row[col.key] = value
-                        }
-                    },
-                    // 接收时,处理数据
-                    valueBuilder(row: any, col: any) {
-                        const value = row[col.key]
-                        const type = row.type
-                        if (type === 5 || type === 7) {
-                            if (value != null && value) {
-                                row[col.key] = value.split(',')
-                            }
-                        } else {
-                            row[col.key] = value
-                        }
-                    }, */
-                    type: 'input',
-                    form: {
-                        rules: [
-                            // 表单校验规则
-                            {required: true, message: '数据值必填项'},
-                        ],
-                        component: {
-                            props: {
-                                clearable: true,
-                            },
-                            placeholder: '请输入数据值',
-                        },
-                    },
-                },
-                status: {
-                    title: '状态',
-                    width: 80,
-                    search: {
-                        show: true
-                    },
-                    type: 'dict-radio',
-                    dict: dict({
-                        data: dictionary('button_status_bool'),
-                    }),
-                    form: {
-                        value: true,
-                        rules: [
-                            // 表单校验规则
-                            {required: true, message: '状态必填项'},
-                        ],
-                    },
-                },
-                sort: {
-                    title: '排序',
-                    width: 70,
-                    type: 'number',
-                    form: {
-                        value: 1,
-                        component: {},
-                        rules: [
-                            // 表单校验规则
-                            {required: true, message: '排序必填项'},
-                        ],
-                    },
-                },
-                color: {
-                    title: '标签颜色',
-                    width: 90,
-                    search: {
-                        disabled: true,
-                    },
-                    type: 'dict-select',
-                    dict: dict({
-                        data: [
-                            {label: 'success', value: 'success', color: 'success'},
-                            {label: 'primary', value: 'primary', color: 'primary'},
-                            {label: 'info', value: 'info', color: 'info'},
-                            {label: 'danger', value: 'danger', color: 'danger'},
-                            {label: 'warning', value: 'warning', color: 'warning'},
-                        ],
-                    }),
-                    form: {
-                        component: {
-                            props: {
-                                clearable: true,
-                            },
-                        },
-                    },
-                },
-            },
-        },
-    };
-};