소스 검색

✨ feat<自动化规则>: 新增广告关联活动

xinyan 10 달 전
부모
커밋
77bacaf843

+ 156 - 63
src/components/TimerBidTable/index.vue

@@ -1,5 +1,6 @@
 <script lang="ts" setup>
 import { ref, onMounted, watch, reactive } from 'vue';
+import { ElMessage } from 'element-plus';
 
 interface Props {
   data: number[][];
@@ -25,51 +26,52 @@ const WeekMap = {
   6: '星期日',
 };
 const dialogVisible = ref(false);
-const bid = ref(0);
+const bid = ref(1.00);
 const selectedItems = ref({});
 
+const form = ref({
+  bid: 1.00, // 将 bid 添加到 form 对象中
+});
+
+const rules = ref({
+  bid: [
+    { required: true, message: '请输入数值小于100的数值,可精确到小数点后2位', trigger: 'blur' },
+    {
+      validator: (rule, value, callback) => {
+        if (Number(value) > 100) {
+          return callback(new Error('请输入数值小于100的数值,可精确到小数点后2位'));
+        }
+        return callback();
+      },
+      trigger: 'blur'
+    }
+  ]
+});
+const formRef = ref(null);
+
+//根据 props.disabled 和 info.selected 来返回一个包含样式的对象,用于设置单元格的样式
 function getTdStyle(info: any) {
   if (props.disabled) {
-    return { cursor: 'not-allowed', background: '#fff' };
+    return {cursor: 'not-allowed', background: '#fff'};
   }
-  return { background: info.selected ? '#ccdbff' : '' };
+  return {background: info.selected ? '#ccdbff' : ''};
 }
 
 for (let i = 0; i < 7; i++) {
   selectedItems.value[i] = [];
   const tmp = [];
   for (let j = 0; j < 24; j++) {
-    tmp.push({ value: bidData.value.length === 0 ? 0 : bidData.value[i][j], selected: false });
+    tmp.push({value: bidData.value.length === 0 ? 0 : bidData.value[i][j], selected: false});
   }
   items.value.push(tmp);
 }
 
-watch(
-  () => props.data,
-  () => {
-    // console.log(100, 'watch', props.data)
-    if (props.data.length === 0) {
-      for (let i = 0; i < 7; i++) {
-        const tmp = [];
-        for (let j = 0; j < 24; j++) {
-          tmp.push(0);
-        }
-        props.data.push(tmp);
-      }
-    }
-    for (let i = 0; i < 7; i++) {
-      for (let j = 0; j < 24; j++) {
-        items.value[i][j].value = props.data[i][j];
-      }
-    }
-    bidData.value = props.data;
-  },
-  { immediate: true }
-);
-
+//在单元格上按下鼠标时触发的函数
 function handleMouseDown(rowIndex: number, colIndex: number, event: any) {
   if (props.disabled) return;
   if (event.button === 0) {
+    clearCellBackgroundColor();
+
     mouseDown.value = true;
     startRowIndex.value = rowIndex;
     startColIndex.value = colIndex;
@@ -88,13 +90,18 @@ function handleMouseUp(event: any) {
   }
 }
 
+//在单元格上移动鼠标时触发的函数,用于选择多个单元格。
 function handleMouseMove(rowIndex: number, colIndex: number) {
   if (props.disabled) return;
+  //if (info.selected) {
+  //  info.selected = false;
+  //}
   if (mouseDown.value) {
     selectCell(rowIndex, colIndex);
   }
 }
 
+//选择多个单元格
 function selectCell(rowIndex: number, colIndex: number) {
   if (props.disabled) return;
   const rowStart = Math.min(startRowIndex.value, rowIndex);
@@ -110,12 +117,12 @@ function selectCell(rowIndex: number, colIndex: number) {
   }
 }
 
+//提交出价,将选中的单元格的值设置为 bid,并清除选中状态和单元格背景色。
 function submitBid() {
-  // console.log(151, 'submitBid', bidData)
   for (const row of Object.keys(selectedItems.value)) {
     for (const col of selectedItems.value[row]) {
-      items.value[row][col].value = bid.value;
-      bidData.value[row][col] = bid.value;
+      items.value[row][col].value = Number(form.value.bid);
+      bidData.value[row][col] = Number(form.value.bid);
     }
   }
   clearSelectedItems();
@@ -123,12 +130,29 @@ function submitBid() {
   dialogVisible.value = false;
 }
 
+const submitForm = async (formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  await formEl.validate((valid, fields) => {
+    if (valid) {
+      submitBid();
+    }
+  });
+};
+
+const resetForm = (formEl: FormInstance | undefined) => {
+  if (!formEl) return
+  cancelBid()
+  formEl.resetFields()
+}
+
+//取消出价
 function cancelBid() {
   clearSelectedItems();
   clearCellBackgroundColor();
   dialogVisible.value = false;
 }
 
+//清除所有单元格的背景色。
 function clearCellBackgroundColor() {
   for (const hoursList of items.value) {
     for (const info of hoursList) {
@@ -143,6 +167,7 @@ function clearSelectedItems() {
   }
 }
 
+//重置所有单元格的出价为 1,并清除选中状态。
 function resetAllBid() {
   for (let i = 0; i < 7; i++) {
     for (let j = 0; j < 24; j++) {
@@ -158,56 +183,124 @@ function closeDialog(done: Function) {
   cancelBid();
   done();
 }
+
+const applyBid = (timeRangeValue: string, scheduleValue: string, bidValue: number) => {
+  const timeRangeMap = {
+    'Option1': {start: 0, end: 23},
+    'Option2': {start: 0, end: 6},
+    'Option3': {start: 7, end: 11},
+    'Option4': {start: 9, end: 16},
+    'Option5': {start: 12, end: 16},
+    'Option6': {start: 17, end: 20},
+    'Option7': {start: 21, end: 23},
+  };
+
+  const scheduleMap = {
+    'Option1': [0, 1, 2, 3, 4, 5, 6],
+    'Option2': [0, 1, 2, 3, 4],
+    'Option3': [5, 6],
+  };
+
+  const {start, end} = timeRangeMap[timeRangeValue];
+  const days = scheduleMap[scheduleValue];
+
+  days.forEach(day => {
+    for (let hour = start; hour <= end; hour++) {
+      items.value[day][hour].value = bidValue;
+      items.value[day][hour].selected = true;
+    }
+  });
+};
+
+defineExpose({
+  applyBid,
+});
+
+watch(
+    () => props.data,
+    () => {
+      if (props.data.length === 0) {
+        for (let i = 0; i < 7; i++) {
+          const tmp = [];
+          for (let j = 0; j < 24; j++) {
+            tmp.push(0);
+          }
+          props.data.push(tmp);
+        }
+      }
+      for (let i = 0; i < 7; i++) {
+        for (let j = 0; j < 24; j++) {
+          items.value[i][j].value = props.data[i][j];
+        }
+      }
+      bidData.value = props.data;
+      console.log('watch', props.data);
+    },
+    {immediate: true}
+);
+
 </script>
 
 <template>
   <div class="calendar">
     <table class="calendar-table calendar-table-hour">
       <thead class="calendar-head">
-        <tr>
-          <th rowspan="8" class="week-td">星期 / 时间</th>
-          <th colspan="12">00:00 - 12:00</th>
-          <th colspan="12">12:00 - 24:00</th>
-          <th colspan="4" rowspan="2" class="week-td" style="display: none">小时</th>
-        </tr>
-        <tr>
-          <th colspan="1" v-for="(_, i) in 24" :key="i">{{ i }}</th>
-        </tr>
+      <tr>
+        <th class="week-td" rowspan="8">星期 / 时间</th>
+        <th colspan="12">00:00 - 12:00</th>
+        <th colspan="12">12:00 - 24:00</th>
+        <th class="week-td" colspan="4" rowspan="2" style="display: none">小时</th>
+      </tr>
+      <tr>
+        <th v-for="(_, i) in 24" :key="i" colspan="1">{{ i }}</th>
+      </tr>
       </thead>
       <tbody>
-        <template v-for="(hoursList, week) in items">
-          <tr>
-            <th>{{ WeekMap[week] }}</th>
-            <td
+      <template v-for="(hoursList, week) in items">
+        <tr>
+          <th>{{ WeekMap[week] }}</th>
+          <td
               v-for="(info, hour) in hoursList"
               :key="hour"
+              :style="getTdStyle(info)"
               @mousedown="handleMouseDown(week, hour, $event)"
               @mouseover="handleMouseMove(week, hour)"
-              @mouseup="handleMouseUp"
-              :style="getTdStyle(info)">
-              <span class="cell-text"> {{ info.value ? info.value : '' }} </span>
-            </td>
-          </tr>
-        </template>
-        <tr>
-          <th colspan="28" class="clear-bar">
-            <span class="middle">可拖动鼠标选择时间段</span>
-            <el-button class="hover-link fr" link @click="resetAllBid" :disabled="disabled">全部重置</el-button>
-          </th>
+              @mouseup="handleMouseUp">
+            <span class="cell-text"> {{
+                info.value || info.value == 0 ? Number(info.value).toFixed(2) : '0.00'
+              }} </span>
+          </td>
         </tr>
+      </template>
+      <tr>
+        <th class="clear-bar" colspan="28">
+          <span class="middle">可拖动鼠标选择时间段</span>
+          <el-button :disabled="disabled" class="hover-link fr" link @click="resetAllBid">全部重置</el-button>
+        </th>
+      </tr>
       </tbody>
     </table>
-
-    <el-dialog v-model="dialogVisible" title="修改出价系数" width="30%" :close-on-click-modal="false" :before-close="closeDialog">
-      <el-input-number v-model="bid" :min="0" :max="100" :step="0.1" controls-position="right" />
-      <template #footer>
+  </div>
+  <el-dialog v-model="dialogVisible" :before-close="closeDialog" :close-on-click-modal="false" title="修改出价系数"
+             width="30%">
+    <el-form ref="formRef" :model="form" :rules="rules" style="display: inline-block;">
+      <el-form-item label="Bid" prop="bid" label-width="80px">
+        <el-input
+            v-model="form.bid"
+            clearable
+            oninput="value=value.replace(/[^\d.]/g, '').replace(/\.{2,}/g, '.').replace('.', '$#$').replace(/\./g, '').replace('$#$', '.').replace(/^(\-)*(\d+)\.(\d\d).*$/, '$1$2.$3').replace(/^\./g, '')"
+            placeholder="1.0"
+            style="width: 150px;"
+        ></el-input>
+      </el-form-item>
+    </el-form>
+    <template #footer>
         <span class="dialog-footer">
-          <el-button @click="cancelBid">取消</el-button>
-          <el-button type="primary" @click="submitBid">确认</el-button>
+          <el-button @click="resetForm(formRef)">取消</el-button>
+          <el-button type="primary" @click="submitForm(formRef)">确认</el-button>
         </span>
-      </template>
-    </el-dialog>
-  </div>
+    </template>
+  </el-dialog>
 </template>
 
 <style lang="scss" scoped>

+ 1 - 1
src/components/TimerBudgetTable/index.vue

@@ -83,7 +83,7 @@
           </el-select>
         </el-form-item>
         <el-form-item prop="value" v-if="formData.type !== ''" :rules="{ validator: checkValue, trigger: 'blur' }">
-          <InputFloat v-model="formData.value" :prefix="isNumber ? '$' : ''" :suffix="!isNumber ? '%' : ''"></InputFloat>
+          <InputFloat v-model="formData.value" :prefix="isNumber ? '$' : ''" :suffix="!isNumber ? '%' : ''" maxlength="111111"></InputFloat>
         </el-form-item>
       </el-form>
       <template #footer>

+ 8 - 0
src/components/conditionBuilder/condition-group2.vue

@@ -135,6 +135,14 @@ const getFormProp = (conditionInfo: ConditionItem, index: number) => {
   }
   return `items[${index}].num`
 }
+
+//const getFormTrigger = (conditionInfo: ConditionItem) => {
+//  const fieldInfo = getFieldInfo(conditionInfo.dataType)
+//  console.log('fieldInfo',fieldInfo);
+//  if (fieldInfo.options && fieldInfo.options.length > 0) return 'change'
+//  return 'blur'
+//}
+
 const getFormTrigger = (conditionInfo: ConditionItem) => {
   const fieldInfo = getFieldInfo(conditionInfo.dataType)
   if (fieldInfo.options && fieldInfo.options.length > 0) return 'change'

+ 9 - 2
src/components/conditionBuilder/utils.ts

@@ -13,12 +13,19 @@ export const useSymbolOptions = (candidateFields: CandidateField[]) => {
     // { label: '不包含', value: 'not_in' }
   ]
 
+  //const getFieldInfo = (field: string) => {
+  //  return XEUtils.find(candidateFields, (item) => item.value === field) || SymbolOptionsList
+  //}
   const getFieldInfo = (field: string) => {
-    return XEUtils.find(candidateFields, (item) => item.value === field)
+    const foundItem = XEUtils.find(candidateFields, (item) => item.value === field);
+    if (foundItem) {
+     return foundItem;
+    }
   }
-
   const getSymbolOptions = (field: string) => {
     const FieldInfo = getFieldInfo(field)
+    //console.log('FieldInfo',FieldInfo);
+    //console.log('type',FieldInfo.type);
     if (FieldInfo.type === 'array')
       return [
         { label: '包含', value: 'in' },

+ 4 - 0
src/components/select-button/index.vue

@@ -10,6 +10,10 @@
 </template>
 
 <script lang="ts" setup>
+/**
+ * @Name:select-button/index.vue
+ * @Description: 自动化规则新建模版按钮
+ */
 import { ref } from 'vue'
 
 interface Props {

+ 11 - 0
src/views/adManage/sb/campaigns/campaignDetail/automation/api.ts

@@ -0,0 +1,11 @@
+import { request } from '/@/utils/service'
+
+const urlPrefix = "/api/ad_manage/auto_plan_template/"
+
+export function getCampaignRuleInfo (params: any) {
+  return request({
+    url: '/api/ad_manage/campaign_rule/get_info',
+    method: 'get',
+    params: params
+  })
+}

+ 149 - 0
src/views/adManage/sb/campaigns/campaignDetail/automation/index.vue

@@ -0,0 +1,149 @@
+<script lang="ts" setup>
+import { nextTick, onMounted, ref } from 'vue';
+import TimerBid from '/@/views/components/auto/auto-campaigns/timer-bid.vue';
+import TimerBudget from '/@/views/components/auto/auto-campaigns/timer-budget.vue';
+import SwitchCampaign from '/@/views/components/auto/auto-campaigns/switch-campaign.vue';
+import TargetRule from '/@/views/components/auto/auto-campaigns/target-rule.vue';
+import SearchTermRule from '/@/views/components/auto/auto-campaigns/search-term.vue';
+import NegKeywordRule from '/@/views/components/auto/auto-campaigns/neg-keyword.vue';
+import * as api from './api';
+
+interface Props {
+  campaignId: string;
+  profileId: string;
+}
+
+const props = defineProps<Props>();
+const campaignType = 'sb';
+const activeTab = ref(1);
+const RuleStatusButton = ref({
+  '1': '-',
+  '2': '-',
+  '3': '-',
+  '4': '-',
+  '5': '-',
+  '6': '-',
+});
+// const height = ref(800)
+// const campaignRuleStatus = ref({
+//   campaignId: props.campaignId,
+//   campaignType: campaignType,
+//   profileId: props.profileId,
+//   ruleType: activeTab.value,
+//   templateName: '',
+//   useTmpl: false,
+//   template: null,
+//   rule: {
+//     type: activeTab.value,
+//     campaignType: campaignType,
+//     campaignAd: [],
+//     action: {},
+//     activeModel: '',
+//     setTime: '',
+//     weekdays: [],
+//     conditions: [],
+//   },
+//   RuleStatusButton: RuleStatusButton,
+// })
+const baseData = ref({
+  campaignId: props.campaignId,
+  campaignType: campaignType,
+  profileId: props.profileId,
+  ruleType: activeTab,
+});
+
+onMounted(async () => {
+  await initData();
+});
+
+async function initData() {
+  const resp = await api.getCampaignRuleInfo(baseData.value);
+  const info = resp.data[0];
+  if (info) {
+    for (const i of ['1', '2', '3', '4', '5', '6']) {
+      RuleStatusButton.value[i] = info.RuleStatusButton[i];
+    }
+  }
+}
+
+async function changeTab() {
+  // await initData()
+}
+
+async function refresh(tab: number) {
+  activeTab.value = 0;
+  nextTick(() => {
+    activeTab.value = tab;
+  });
+}
+</script>
+
+<template>
+  <el-tabs tab-position="left" v-model="activeTab" @tab-change="changeTab">
+    <el-tab-pane label="分时调价" :name="1">
+      <template #label>
+        <div class="tab-label">
+          <el-switch size="small" v-model="RuleStatusButton['1']" :disabled="RuleStatusButton['1'] === '-'"></el-switch>
+          <span>分时调价</span>
+        </div>
+      </template>
+      <TimerBid :data="baseData" :RuleStatusButton="RuleStatusButton" @refresh="refresh(1)" v-if="activeTab === 1" />
+    </el-tab-pane>
+    <el-tab-pane label="分时预算" :name="2">
+      <template #label>
+        <div class="tab-label">
+          <el-switch size="small" v-model="RuleStatusButton['2']" :disabled="RuleStatusButton['2'] === '-'"></el-switch>
+          <span>分时预算</span>
+        </div>
+      </template>
+      <TimerBudget :data="baseData" :RuleStatusButton="RuleStatusButton" @refresh="refresh(2)" v-if="activeTab === 2" />
+    </el-tab-pane>
+    <el-tab-pane label="广告活动" :name="3">
+      <template #label>
+        <div class="tab-label">
+          <el-switch size="small" v-model="RuleStatusButton['3']" :disabled="RuleStatusButton['3'] === '-'"></el-switch>
+          <span>广告活动</span>
+        </div>
+      </template>
+      <SwitchCampaign :data="baseData" :RuleStatusButton="RuleStatusButton" @refresh="refresh(3)" v-if="activeTab === 3" />
+    </el-tab-pane>
+    <el-tab-pane label="定向规则" :name="4">
+      <template #label>
+        <div class="tab-label">
+          <el-switch size="small" v-model="RuleStatusButton['4']" :disabled="RuleStatusButton['4'] === '-'"></el-switch>
+          <span>定向规则</span>
+        </div>
+      </template>
+      <TargetRule :data="baseData" :RuleStatusButton="RuleStatusButton" @refresh="refresh(4)" v-if="activeTab === 4"></TargetRule>
+    </el-tab-pane>
+    <el-tab-pane label="添加搜索词" :name="5">
+      <template #label>
+        <div class="tab-label">
+          <el-switch size="small" v-model="RuleStatusButton['5']" :disabled="RuleStatusButton['5'] === '-'"></el-switch>
+          <span>添加搜索词</span>
+        </div>
+      </template>
+      <SearchTermRule :data="baseData" :RuleStatusButton="RuleStatusButton" @refresh="refresh(5)" v-if="activeTab === 5">
+      </SearchTermRule>
+    </el-tab-pane>
+    <el-tab-pane label="添加否定词" :name="6">
+      <template #label>
+        <div class="tab-label">
+          <el-switch size="small" v-model="RuleStatusButton['6']" :disabled="RuleStatusButton['6'] === '-'"></el-switch>
+          <span>添加否定词</span>
+        </div>
+      </template>
+      <NegKeywordRule :data="baseData" :RuleStatusButton="RuleStatusButton" @refresh="refresh(6)" v-if="activeTab === 6">
+      </NegKeywordRule>
+    </el-tab-pane>
+  </el-tabs>
+</template>
+
+<style lang="scss" scoped>
+.tab-label {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  width: 120px;
+}
+</style>

+ 4 - 1
src/views/adManage/sb/campaigns/campaignDetail/index.vue

@@ -24,7 +24,7 @@
         <Budget :campaignId="route.query.campaignId" v-if="tabActiveName==='budget'"></Budget>
       </el-tab-pane>
       <el-tab-pane label="自动化" name="automation">
-        自动化
+        <Automation :campaignId="campaignId" :profileId="profile.profile_id" v-if="tabActiveName==='automation'"></Automation>
       </el-tab-pane>
       <el-tab-pane label="广告位" name="placement">
         <Placement :campaignId="route.query.campaignId" v-if="tabActiveName==='placement'"/>
@@ -46,6 +46,7 @@ import {useShopInfo} from '/@/stores/shopInfo'
 import {storeToRefs} from 'pinia'
 
 import {GetObj} from './api'
+import Automation from '/@/views/adManage/sb/campaigns/campaignDetail/automation/index.vue';
 
 const shopInfo = useShopInfo()
 const { profile } = storeToRefs(shopInfo)
@@ -53,6 +54,8 @@ const route = useRoute()
 const campaignInfo: Ref<SpCampaign> = ref({})
 const tabActiveName = ref('adGroup')
 
+const campaignId = ref(route.query.campaignId)
+
 onMounted(async () => {
   const resp = await GetObj(route.query.campaignId)
   campaignInfo.value = resp.data

+ 1 - 1
src/views/adManage/sp/campaigns/campaignDetail/automation/index.vue

@@ -57,7 +57,7 @@ const baseData = ref({
   profileId: props.profileId,
   ruleType: activeTab,
 });
-
+console.log('sp',baseData.value);
 onMounted(async () => {
   await initData();
 });

+ 2 - 2
src/views/components/ad-group-select/index.vue

@@ -32,7 +32,7 @@ const props = withDefaults(defineProps<Props>(), {
   width: '',
   multiple: false
 })
-const adGroupId = ref(props.modelValue)
+const adGroupId = ref(props.multiple ? (Array.isArray(props.modelValue) ? props.modelValue : []) : (typeof props.modelValue === 'string' ? props.modelValue : ''))
 const adGroupList = ref([])
 const emits = defineEmits(['update:modelValue', 'change-ad-group'])
 
@@ -67,7 +67,7 @@ watch(
 )
 watch(
   () => props.modelValue,
-  () => { adGroupId.value = props.modelValue }
+  () => { adGroupId.value = props.multiple ? (Array.isArray(props.modelValue) ? props.modelValue : []) : (typeof props.modelValue === 'string' ? props.modelValue : '') }
 )
 
 </script>

+ 5 - 5
src/views/components/auto/auto-campaigns/select-tmpl.vue

@@ -79,11 +79,11 @@ defineExpose({ getTmplList });
     <el-radio-group v-model="ruleUsage" @change="changeRuleUsage">
       <div style="display: flex; justify-content: flex-start; flex-direction: column">
         <el-radio label="custom">自定义规则</el-radio>
-        <el-input
-          v-model="data.templateName"
-          v-show="ruleUsage === 'custom'"
-          style="margin-left: 22px; width: 220px"
-          placeholder="将规则同时保存为模板(可选)" />
+        <!--<el-input-->
+        <!--  v-model="data.templateName"-->
+        <!--  v-show="ruleUsage === 'custom'"-->
+        <!--  style="margin-left: 22px; width: 220px"-->
+        <!--  placeholder="将规则同时保存为模板(可选)" />-->
         <el-radio label="tmpl">使用已有模板</el-radio>
         <el-select v-show="ruleUsage === 'tmpl'" @change="changeTmpl" v-model="tmplId" style="margin-left: 22px">
           <el-option v-for="info in tmplList" :label="info.name" :value="info.id" :key="info.id" />

+ 100 - 15
src/views/components/auto/auto-campaigns/timer-bid.vue

@@ -18,17 +18,18 @@ interface Props {
     ruleType: number;
   };
   RuleStatusButton?: { [key: string]: any };
+  //data: AutoCampaignRule;
 }
 
 const props = defineProps<Props>();
 const emits = defineEmits(['refresh']);
 
 const formRef = ref();
-const { formData, submitFormData } = userFormData(props);
+const {formData, submitFormData} = userFormData(props);
 
 const timeRange = ref('Option1');
 const schedule = ref('Option1');
-const bid = ref('');
+const bid = ref('1.0');
 const timeRangeOptions = [
   {
     value: 'Option1',
@@ -76,10 +77,23 @@ const scheduleOptions = [
 ];
 const isVisible = ref(true);
 
+const submitDialogVisible = ref(false)
+const selectedOption = ref(1);
+const form = ref({
+  templateName: ''
+});
+const rules = {
+  templateName: [
+    { required: true, message: '请输入不大于150个字符的模板名称', trigger: 'blur' },
+  ]
+
+};
+
+//验证是否已设置竞价
 function checkConditions(rule: any, value: any, callback: any) {
   for (const bidList of formData.value.rule.conditions) {
     for (const val of bidList) {
-      if (val > 0) {
+      if (val > 0 && val < 100) {
         return callback();
       }
     }
@@ -92,6 +106,7 @@ async function submit() {
     if (valid) {
       await submitFormData();
       emits('refresh');
+      submitDialogVisible.value = true
     } else {
       console.log('验证失败');
     }
@@ -105,6 +120,14 @@ function cancel() {
 function handleClose() {
   isVisible.value = false;
 }
+
+const tableRef = ref(null);
+
+const handleApply = () => {
+  if (tableRef.value) {
+    tableRef.value.applyBid(timeRange.value, schedule.value, parseFloat(bid.value));
+  }
+};
 </script>
 
 <template>
@@ -113,7 +136,7 @@ function handleClose() {
     <div class="mt-3.5">
       规则执行时区: PDT
       <div>
-        <el-tag v-if="isVisible" closable @close="handleClose" color="#e7edf4" class="custom-tag">
+        <el-tag v-if="isVisible" class="custom-tag" closable color="#e7edf4" @close="handleClose">
           <template #default>
             <div class="tag-content">
               <strong>自动化分时规则:</strong>
@@ -129,35 +152,79 @@ function handleClose() {
     </div>
     <SelectTmpl :data="formData" />
     <el-card class="mt-3">
-      <el-form :model="formData" label-position="top" style="margin-top: 20px" ref="formRef">
-        <el-form-item prop="rule.conditions" :rules="[{ validator: checkConditions, trigger: 'xxx' }]">
+      <el-form ref="formRef" :model="formData" label-position="top" style="margin-top: 20px">
+        <el-form-item :rules="[{ validator: checkConditions, trigger: 'blur' }]" prop="rule.conditions">
           <template #label>
             <span class="custom-title-icon"></span>
             <span class="asj-h3">设置竞价</span>
           </template>
           <div class="flex flex-col">
             <div class="flex gap-2 my-2">
-              <el-select v-model="timeRange">
+              <el-select v-model="timeRange" :disabled="formData.useTmpl">
                 <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" :disabled="formData.useTmpl">
                 <el-option v-for="item in scheduleOptions" :key="item.value" :label="item.label" :value="item.value" />
               </el-select>
-              <el-input v-model="bid" style="width: 150px" placeholder="1.0"></el-input>
-              <el-button link class="active-btn" style="color: #3c58af">应用</el-button>
+              <el-input v-model="bid" :disabled="formData.useTmpl"
+                        clearable
+                        oninput="value=value.replace(/[^\d.]/g, '').replace(/\.{2,}/g, '.').replace('.', '$#$').replace(/\./g, '').replace('$#$', '.').replace(/^(\-)*(\d+)\.(\d\d).*$/, '$1$2.$3').replace(/^\./g, '')"
+                        min="0"
+                        max="100"
+                        placeholder="1.0"
+                        style="width: 150px"
+              ></el-input>
+              <el-button :disabled="formData.useTmpl" class="active-btn" link style="color: #3c58af"
+                         @click="handleApply">应用
+              </el-button>
             </div>
-            <TimerBidTable
-              :data="formData.rule.conditions"
-              @click="formRef.clearValidate('rule.conditions')"
-              :disabled="formData.useTmpl" />
           </div>
         </el-form-item>
       </el-form>
+      <TimerBidTable
+          ref="tableRef"
+          :data="formData.rule.conditions"
+          :disabled="formData.useTmpl"
+          @click="formRef.clearValidate('rule.conditions')" />
     </el-card>
 
+    <el-dialog
+        v-model="submitDialogVisible"
+        title="保存"
+        width= 30%
+        align-center
+    >
+      <div>
+        <el-radio-group v-model="selectedOption">
+          <!-- 将每个radio按钮包裹在div中,并使用样式使其独占一行 -->
+          <div style="display: block;">
+            <el-radio :label="1">仅应用于当前广告活动</el-radio>
+          </div>
+          <div style="display: block;">
+            <el-radio :label="2">应用于当前活动且保存为模板</el-radio>
+          </div>
+        </el-radio-group>
+      </div>
+      <div v-if="selectedOption === 2">
+        <el-form  :model="form" :rules="rules" ref="formRef" label-width="auto">
+          <el-form-item label="模板名称" prop="templateName" class="custom-form-item">
+            <el-input v-model="form.templateName" placeholder="请输入不大于150个字符的字符" maxlength="150" />
+          </el-form-item>
+        </el-form>
+      </div>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="submitDialogVisible = false">取消</el-button>
+          <el-button type="primary" @click="submit">
+            保存
+          </el-button>
+        </div>
+      </template>
+    </el-dialog>
+
     <div class="auto-page-foot">
       <el-button style="width: 200px" @click="cancel">取消</el-button>
-      <el-button style="width: 200px" type="primary" @click="submit">提交</el-button>
+      <el-button style="width: 200px" type="primary" @click="submitDialogVisible = true">提交</el-button>
     </div>
   </div>
 </template>
@@ -168,6 +235,12 @@ function handleClose() {
   transition: all 0.3s; /* 添加过渡效果 */
 }
 
+.active-btn:disabled {
+  color: #c0c4cc !important;
+  cursor: not-allowed;
+  /* pointer-events: none; !* 禁用点击事件 *! */
+}
+
 .custom-title-icon {
   padding-right: 10px;
 }
@@ -195,4 +268,16 @@ function handleClose() {
   display: block;
   max-width: 100%;
 }
+
+.el-radio-group {
+  display: inline-flex;
+  font-size: 0;
+  flex-direction: column;
+  align-items: flex-start;
+}
+
+.custom-form-item {
+  flex-direction: column;
+}
+
 </style>

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

@@ -1,20 +1,59 @@
 <template>
-  <div>
+  <div class="mx-5">
     <div class="asj-h2">分时调价</div>
-    <el-form :model="formData" label-position="top" style="margin-top: 20px" ref="formRef">
-      <el-form-item prop="name" :rules="{ required: true, message: '必填项', trigger: 'blur' }">
+    <div class="mt-3.5">
+      规则执行时区: PDT
+      <div>
+        <el-tag v-if="isVisible" class="custom-tag" closable color="#e7edf4" @close="handleClose">
+          <template #default>
+            <div class="tag-content">
+              <strong>自动化分时规则:</strong>
+              <p>
+                1.
+                应用分时调价后,如需手动修改竞价,只能在此操作。在亚马逊后台或其他第三方系统进行的调价操作,竞价将会被当前时段的自动化执行结果覆盖。
+              </p>
+              <p>2. 广告活动开启分时调价,规则的修改将在下一个整点生效。</p>
+            </div>
+          </template>
+        </el-tag>
+      </div>
+    </div>
+    <el-form ref="formRef" :model="formData" label-position="top" style="margin-top: 20px">
+      <el-form-item :rules="{ required: true, message: '必填项', trigger: 'blur' }" prop="name">
         <template #label>
           <span class="asj-h3">模板名称</span>
         </template>
         <el-input v-model="formData.name" style="width: 30%"></el-input>
       </el-form-item>
-      <el-form-item prop="rule.conditions" :rules="[{ validator: checkConditions, trigger: 'xxx' }]">
+      <el-form-item :rules="[{ validator: checkConditions, trigger: 'xxx' }]" prop="rule.conditions">
         <template #label>
           <span class="asj-h3">设置竞价</span>
         </template>
-        <TimerBidTable :data="formData.rule.conditions" @click="formRef.clearValidate('rule.conditions')" />
+        <div class="flex flex-col">
+          <div class="flex gap-2 my-2">
+            <el-select v-model="timeRange">
+              <el-option v-for="item in timeRangeOptions" :key="item.value" :label="item.label" :value="item.value" />
+            </el-select>
+            <el-select v-model="schedule">
+              <el-option v-for="item in scheduleOptions" :key="item.value" :label="item.label" :value="item.value" />
+            </el-select>
+            <el-input v-model="bid"
+                      clearable
+                      oninput="value=value.replace(/[^\d.]/g, '').replace(/\.{2,}/g, '.').replace('.', '$#$').replace(/\./g, '').replace('$#$', '.').replace(/^(\-)*(\d+)\.(\d\d).*$/, '$1$2.$3').replace(/^\./g, '')"
+                      placeholder="1.0"
+                      style="width: 150px"
+            ></el-input>
+            <el-button class="active-btn" link style="color: #3c58af"
+                       @click="handleApply">应用
+            </el-button>
+          </div>
+        </div>
       </el-form-item>
     </el-form>
+    <TimerBidTable
+        ref="tableRef"
+        :data="formData.rule.conditions"
+        @click="formRef.clearValidate('rule.conditions')" />
     <div class="auto-page-foot">
       <el-button style="width: 200px" @click="cancel">取消</el-button>
       <el-button style="width: 200px" type="primary" @click="submitForm">提交</el-button>
@@ -23,52 +62,132 @@
 </template>
 
 <script lang="ts" setup>
-import { ref, onMounted, Ref } from 'vue'
-import TimerBidTable from '/@/components/TimerBidTable/index.vue'
+/**
+ * @Name: timer-bid.vue
+ * @Description: 自动化规则模板-分时调价
+ * @Author: xinyan
+ */
+import { ref, onMounted, Ref } from 'vue';
+import TimerBidTable from '/@/components/TimerBidTable/index.vue';
+import { userFormData } from '/@/views/components/auto/auto-campaigns/common';
 
 interface Props {
-  mode: string
-  data: AutoTemplate
-  submitFormData: Function
+  mode: string;
+  data: AutoTemplate;
+  submitFormData: Function;
 }
-const props = defineProps<Props>()
-const emits = defineEmits(['refresh'])
 
-const formRef = ref()
+const props = defineProps<Props>();
+const emits = defineEmits(['refresh']);
+
+const formRef = ref();
 const formData = ref(props.data)
+
+const timeRange = ref('Option1');
+const schedule = ref('Option1');
+const bid = ref('1.0');
+const tableRef = ref(null);
+
+const timeRangeOptions = [
+  {
+    value: 'Option1',
+    label: '24小时: 00:00-23:59',
+  },
+  {
+    value: 'Option2',
+    label: '凌晨: 00:00-06:59',
+  },
+  {
+    value: 'Option3',
+    label: '上午: 7:00-11:59',
+  },
+  {
+    value: 'Option4',
+    label: '工作时: 9:00-16:59',
+  },
+  {
+    value: 'Option5',
+    label: '下午: 12:00-16:59',
+  },
+  {
+    value: 'Option6',
+    label: '晚上: 17:00-20:59',
+  },
+  {
+    value: 'Option7',
+    label: '深夜: 21:00-23:59',
+  },
+];
+
+const scheduleOptions = [
+  {
+    value: 'Option1',
+    label: '每一天',
+  },
+  {
+    value: 'Option2',
+    label: '仅在工作日',
+  },
+  {
+    value: 'Option3',
+    label: '仅在周末',
+  },
+];
+const isVisible = ref(true);
+
 if (props.mode === 'add') {
   for (let i = 0; i < 7; i++) {
-    const tmp = []
+    const tmp = [];
     for (let j = 0; j < 24; j++) {
-      tmp.push(0)
+      tmp.push(0);
     }
-    formData.value.rule.conditions.push(tmp)
+    formData.value.rule.conditions.push(tmp);
   }
 }
 
+function handleClose() {
+  isVisible.value = false;
+}
+
+const handleApply = () => {
+  if (tableRef.value) {
+    tableRef.value.applyBid(timeRange.value, schedule.value, parseFloat(bid.value));
+  }
+};
+
 const checkConditions = (rule: any, value: any, callback: any) => {
   for (const bidList of formData.value.rule.conditions) {
     for (const val of bidList) {
       if (val > 0) {
-        return callback()
+        return callback();
       }
     }
   }
-  callback(new Error('请先设置竞价!'))
-}
+  callback(new Error('请先设置竞价!'));
+};
 const submitForm = async () => {
   formRef.value.validate(async (valid: any) => {
     if (valid) {
-      await props.submitFormData()
-      emits('refresh')
+      await props.submitFormData();
+      emits('refresh');
     } else {
-      console.log('验证失败')
+      console.log('验证失败');
     }
-  })
-}
+  });
+};
 const cancel = () => {
-  emits('refresh')
-}
+  emits('refresh');
+};
 </script>
 
-<style scoped></style>
+<style scoped>
+.custom-tag {
+  height: auto;
+  padding: 8px 8px 8px 16px;
+  color: #505968;
+  border-color: #abbbd8;
+  align-items: flex-start !important;
+  white-space: normal;
+  line-height: 1.5;
+}
+</style>

+ 6 - 0
src/views/components/auto/target-select.vue

@@ -5,6 +5,7 @@
  * @Author: Cheney
  */
 import AdGroupSelect from '/@/views/components/ad-group-select/index.vue';
+import { watch } from 'vue';
 
 interface Props {
   mode: string;
@@ -13,6 +14,11 @@ interface Props {
   campaignId: string;
 }
 const props = defineProps<Props>();
+
+watch(()=>props.data.campaignAd, (val)=>{
+  console.log(11, props.data.campaignAd);
+})
+
 </script>
 
 <template>

+ 9 - 0
src/views/efTools/automation/api.ts

@@ -40,3 +40,12 @@ export function DelObj(id: DelReq) {
     data: { id },
   })
 }
+
+//关联广告活动
+export function getRelationCampaign(query) {
+  return request({
+    url: '/api/ad_manage/template/relation_campaign_list/',
+    method: 'GET',
+    params: query,
+  })
+}

+ 223 - 0
src/views/efTools/automation/components/adActivityDialog.vue

@@ -0,0 +1,223 @@
+<script setup lang="ts">
+/**
+ * @Name: adActivityDialog.vue
+ * @Description:广告关联活动弹窗
+ * @Author: xinyan
+ */
+import { inject, onMounted, Ref, ref } from 'vue';
+import { getRelationCampaign } from '/@/views/efTools/automation/api';
+
+const dialogVisible = inject<Ref>('isDialogVisible')
+const searchAdCampaign = ref('');
+const selectedCampaignType = ref('');
+const selectedAdGroup = ref('');
+const selectedStatus = ref('');
+const selectedActivityTag = ref('');
+const currentPage = ref('');
+const total = ref('');
+const pageSize = ref(20);
+const loading = ref(false)
+const handleSizeChange = (size) => {
+  pageSize.value = size;
+  fetchAdCampaign(); // 调用 fetchAdCampaign 重新获取数据
+};
+
+const handleCurrentChange = (newPage) => {
+  currentPage.value = newPage;
+  loading.value = true;
+  fetchAdCampaign();
+  loading.value = false;
+};
+
+const campaignType = [
+  {value: 'SB', label: 'SB'},
+  {value: 'SP', label: 'SP'}
+];
+
+const adGroups = [
+  {value: 'Group1', label: 'Group1'},
+  {value: 'Group2', label: 'Group2'}
+];
+
+const campaignStatus = [
+  {value: 'active', label: 'Active'},
+  {value: 'inactive', label: 'Inactive'}
+];
+
+const activityTags = [
+  {value: 'Tag1', label: 'Tag1'},
+  {value: 'Tag2', label: 'Tag2'}
+];
+
+const adCampaignName = ref([]);
+
+async function fetchAdCampaign() {
+  try{
+    const resp = await getRelationCampaign({
+      profileId: 3006125408623189,
+      templateId:49,
+      campaignName: "",
+      portfolioId:"",
+      campaignStatus:"",
+      campaignType:"sp",
+      page: currentPage.value,
+      limit: pageSize.value,
+    });
+    adCampaignName.value = resp.data;
+    total.value = resp.total;
+    currentPage.value = resp.page;
+  }catch (error) {
+    console.error('Error fetching task data:', error);
+  }
+}
+
+const selectedAds = ref([]);
+
+const handleSelectionChange = (selection) => {
+  selectedAds.value = selection;
+  console.log('Selected ads:', selectedAds.value);
+};
+
+const confirm = () => {
+};
+
+const removeSelectedAd = (index) => {
+  selectedAds.value.splice(index, 1);
+};
+
+const removeAllSelectedAds = () => {
+  selectedAds.value = [];
+};
+
+const headerCellStyle = (args) => {
+  if (args.rowIndex === 0) {
+    return {
+      backgroundColor: 'rgba(245, 245, 245, 0.9)',
+    }
+  }
+}
+
+onMounted(()=>{
+  fetchAdCampaign();
+});
+
+</script>
+
+<template>
+  <el-dialog
+      class="custom-dialog"
+      v-model="dialogVisible"
+      title="关联广告活动"
+      width="1158px"
+      style="border-radius: 10px;"
+  >
+    <div style="display: flex;" class="custom-border">
+      <div style="width: 50%;">
+        <el-input v-model="searchAdCampaign" placeholder="请输入广告活动" style="width: 100%;"></el-input>
+        <div class="custom-inline">
+          <el-select v-model="selectedCampaignType" placeholder="选择广告类型">
+            <el-option v-for="item in campaignType"
+                       :key="item.value"
+                       :label="item.label"
+                       :value="item.value"
+            ></el-option>
+          </el-select>
+
+          <el-select v-model="selectedAdGroup" placeholder="广告组合" style="margin-bottom: 10px;">
+            <el-option
+                v-for="item in adGroups"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+            ></el-option>
+          </el-select>
+
+          <el-select v-model="selectedStatus" placeholder="状态" style="margin-bottom: 10px;">
+            <el-option
+                v-for="item in campaignStatus"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+            ></el-option>
+          </el-select>
+
+          <el-select v-model="selectedActivityTag" placeholder="活动标签">
+            <el-option
+                v-for="item in activityTags"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+            ></el-option>
+          </el-select>
+        </div>
+        <el-table
+            :data="adCampaignName"
+            style="width: 100%;"
+            height="400"
+            v-loading="loading"
+            @selection-change="handleSelectionChange"
+            :header-cell-style="headerCellStyle"
+        >
+          <el-table-column label="广告活动名称" prop="campaignName"></el-table-column>
+          <el-table-column type="selection" width="55"></el-table-column>
+        </el-table>
+        <el-pagination
+            v-model:current-page="currentPage"
+            :page-size="pageSize"
+            :page-sizes="[10, 25, 50]"
+            :total="total"
+            layout="total, prev, pager, next"
+            @size-change="handleSizeChange"
+            @current-change="handleCurrentChange"
+        ></el-pagination>
+      </div>
+
+      <div style="flex: 1; padding-left: 20px;">
+        <h3>已选择({{ selectedAds.length }})</h3>
+        <el-table
+            :data="selectedAds"
+            height="484"
+            style="width: 100%; margin-top: 20px;"
+            :header-cell-style="headerCellStyle"
+        >
+          <el-table-column label="广告活动" prop="campaignName"></el-table-column>
+          <el-table-column
+              label="操作"
+              width="100"
+          >
+            <template #header>
+              <el-button type="danger" size="normal" link @click="removeAllSelectedAds">删除全部</el-button>
+            </template>
+            <template #default="scope">
+              <el-button type="text" @click="removeSelectedAd(scope.$index)">删除</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+    </div>
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button @click="dialogVisible = false">取消</el-button>
+        <el-button type="primary" @click="confirm">确定</el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+
+<style scoped>
+.SP {
+  background-color: orange;
+  color: white;
+  padding: 2px 4px;
+  border-radius: 3px;
+  margin-right: 8px;
+}
+
+.SB {
+  background-color: blue;
+  color: white;
+  padding: 2px 4px;
+  border-radius: 3px;
+  margin-right: 8px;
+}
+</style>

+ 11 - 8
src/views/efTools/automation/crud.tsx

@@ -5,7 +5,7 @@ import { TemplateType } from '../utils/enum'
 
 export const createCrudOptions = function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
 
-  const { editTmpl } = context
+  const { editTmpl, showDialog } = context;
 
   const pageRequest = async (query: UserPageQuery) => {
     return await api.GetList(query)
@@ -53,10 +53,10 @@ export const createCrudOptions = function ({ crudExpose, context }: CreateCrudOp
           	type: 'text',
           	// show: hasPermissions('dictionary:Update'),
             order: 1,
-          	tooltip: {
-          		placement: 'top',
-          		content: '编辑',
-          	},
+            tooltip: {
+              placement: 'top',
+              content: '编辑',
+            },
             click: (ctx: any) => {
               editTmpl(ctx.row)
             }
@@ -67,9 +67,12 @@ export const createCrudOptions = function ({ crudExpose, context }: CreateCrudOp
             type: 'text',
             order: 2,
             tooltip: {
-          		placement: 'top',
-          		content: '关联广告活动',
-          	}
+              placement: 'top',
+              content: '关联广告活动',
+            },
+            click: (ctx: any) => {
+              showDialog(); // 调用传入的上下文中的 showDialog 函数
+            }
           },
           remove: {
             iconRight: 'Delete',

+ 182 - 72
src/views/efTools/automation/index.vue

@@ -1,48 +1,70 @@
 <template>
-  <fs-page class="fs-page-custom">
-    <fs-crud ref="crudRef" v-bind="crudBinding">
-      <template #actionbar-right>
-        <SelectBotton btn-title="新建模板" :options="TemplateType" @click="createTmpl"></SelectBotton>
+  <div class="mx-3 mt-3" style="display: flex; gap: 14px;">
+    <el-input v-model="templateList" :prefix-icon="Search" placeholder="快速查询" style="width: 240px" @change=""></el-input>
+    <el-select v-model="templateType" placeholder="Select" style="width: 240px">
+      <el-option
+          v-for="item in TemplateType"
+          :key="item.value"
+          :label="item.label"
+          :value="item.value"
+      />
+    </el-select>
+  </div>
+  <el-card class="mx-3 my-3">
+    <vxe-grid v-bind="gridOptions" v-on="gridEvents">
+      <template #toolbar_buttons>
+        <SelectBotton :options="TemplateType" btn-title="新建模板" @click="createTmpl"></SelectBotton>
       </template>
-    </fs-crud>
-  </fs-page>
-
-  <el-drawer v-model="showDrawer" :title="mode === 'add' ? '新建模板' : '编辑模板'" size="70%" :destroy-on-close="true" :close-on-click-modal="false">
+      <template #operate="{ row }">
+        <el-button icon="Edit" type="text" @click="editTmpl(row)"></el-button>
+        <el-button icon="SetUp" type="text" @click="showDialog"></el-button>
+        <el-button icon="Delete" type="text" @click=""></el-button>
+      </template>
+    </vxe-grid>
+  </el-card>
+  <el-drawer v-model="showDrawer" :close-on-click-modal="false" :destroy-on-close="true"
+             :title="mode === 'add' ? '新建模板' : '编辑模板'"
+             size="70%">
     <div style="padding: 0 15px">
       <component
-        :is="dyComponents[formData.rule.type]"
-        :mode="mode"
-        :data="formData"
-        @refresh="refreshTable"
-        :submitFormData="submitFormData"></component>
+          :is="dyComponents[formData.rule.type]"
+          :data="formData"
+          :mode="mode"
+          :submitFormData="submitFormData"
+          @refresh="refreshTable"></component>
     </div>
   </el-drawer>
+  <AdActivityDialog v-model:visible="isDialogVisible" />
 </template>
 
 <script lang="ts" setup>
-import { onMounted, ref, Ref, watch } from 'vue'
-import { FsPage, useFs } from '@fast-crud/fast-crud'
-import { createCrudOptions } from './crud'
-import * as api from './api'
-import { TemplateType } from '../utils/enum'
-import SelectBotton from '/@/components/select-button/index.vue'
-import TimerBidTmpl from '/@/views/components/auto/auto-templates/timer-bid.vue'
-import TimerBudgetTmpl from '/@/views/components/auto/auto-templates/timer-budget.vue'
-import SwitchCampaignTmpl from '/@/views/components/auto/auto-templates/switch-campaign.vue'
-import TargetRuleTmpl from '/@/views/components/auto/auto-templates/target-rule.vue'
-import SearchTermTmpl from '/@/views/components/auto/auto-templates/search-term.vue'
-import NegKeywordTmpl from '/@/views/components/auto/auto-templates/neg-keyword.vue'
+import { onMounted, provide, reactive, ref, Ref } from 'vue';
+import { Search } from '@element-plus/icons-vue';
+import { TemplateType } from '../utils/enum';
+import { GetList } from '/@/views/efTools/automation/api';
+import SelectBotton from '/@/components/select-button/index.vue';
+import TimerBidTmpl from '/@/views/components/auto/auto-templates/timer-bid.vue';
+import TimerBudgetTmpl from '/@/views/components/auto/auto-templates/timer-budget.vue';
+import SwitchCampaignTmpl from '/@/views/components/auto/auto-templates/switch-campaign.vue';
+import TargetRuleTmpl from '/@/views/components/auto/auto-templates/target-rule.vue';
+import SearchTermTmpl from '/@/views/components/auto/auto-templates/search-term.vue';
+import NegKeywordTmpl from '/@/views/components/auto/auto-templates/neg-keyword.vue';
+import AdActivityDialog from './components/adActivityDialog.vue';
+import { AddObj, UpdateObj } from './api';
 
-const dyComponents = {
-  1: TimerBidTmpl,
-  2: TimerBudgetTmpl,
-  3: SwitchCampaignTmpl,
-  4: TargetRuleTmpl,
-  5: SearchTermTmpl,
-  6: NegKeywordTmpl
-}
-const mode = ref('')
-const showDrawer = ref(false)
+const isDialogVisible = ref(false);
+
+const showDialog = () => {
+  isDialogVisible.value = true;
+};
+provide('isDialogVisible',isDialogVisible)
+//查询
+const templateList = ref('');
+const templateType = ref('');
+
+//创建,编辑
+const mode = ref('');
+const showDrawer = ref(false);
 
 const formData: Ref<AutoTemplate> = ref({
   name: '',
@@ -56,13 +78,26 @@ const formData: Ref<AutoTemplate> = ref({
     weekdays: [],
     conditions: [],
   },
-})
+});
 
-const createTmpl = (val: number) => {
-  mode.value = 'add'
+const dyComponents = {
+  1: TimerBidTmpl,
+  2: TimerBudgetTmpl,
+  3: SwitchCampaignTmpl,
+  4: TargetRuleTmpl,
+  5: SearchTermTmpl,
+  6: NegKeywordTmpl,
+};
+
+const refreshTable = () => {
+  showDrawer.value = false;
+  getList();
+};
 
-  delete formData.value.id
-  formData.value.name = ''
+const createTmpl = (val: number) => {
+  mode.value = 'add';
+  delete formData.value.id;
+  formData.value.name = '';
   formData.value.rule = {
     type: val,
     campaignType: '',
@@ -72,46 +107,121 @@ const createTmpl = (val: number) => {
     setTime: '',
     weekdays: [],
     conditions: [],
-  }
-  console.log(formData.value)
-  showDrawer.value = true
-}
+  };
+  //console.log(formData.value);
+  showDrawer.value = true;
+};
+
 const editTmpl = (row: any) => {
-  mode.value = 'edit'
-  // console.log(50, row)
-  formData.value.id = row.id
-  formData.value.name = row.name
-  formData.value.rule = row.rule
-
-  // formData.value.rule.id = row.rule.id
-  // formData.value.rule.type = row.rule.type
-  // formData.value.rule.campaignType = row.rule.campaignType
-  // formData.value.rule.campaignAd = row.rule.campaignAd
-  // formData.value.rule.action = row.rule.action
-  // formData.value.rule.activeModel = row.rule.activeModel
-  // formData.value.rule.setTime = row.rule.setTime
-  // formData.value.rule.weekdays = row.rule.weekdays
-  // formData.value.rule.conditions = row.rule.conditions
-
-  showDrawer.value = true
-}
+  mode.value = 'edit';
+  formData.value.id = row.id;
+  formData.value.name = row.name;
+  formData.value.rule = row.rule;
+  showDrawer.value = true;
+};
 
 const submitFormData = async () => {
   if (mode.value === 'add') {
-    await api.AddObj(formData.value)
+    await AddObj(formData.value);
   } else if (mode.value === 'edit') {
-    await api.UpdateObj(formData.value)
+    await UpdateObj(formData.value);
+  }
+  refreshTable();
+};
+
+//表格配置
+const gridOptions = reactive({
+  border: 'inner',
+  height: 900,
+  align: null,
+  loading: false,
+  rowConfig: {
+    isHover: true,
+  },
+  columnConfig: {
+    resizable: true,
+  },
+  pagerConfig: {
+    enabled: true,
+    total: 20,
+    currentPage: 1,
+    pageSize: 20,
+    pageSizes: [10, 20, 30],
+  },
+  columns: [
+    {field: 'id', title: 'ID'},
+    {field: 'name', title: '模板名称'},
+    {field: 'rule.type', title: '模板类型', formatter: ({cellValue}) => getTemplateTypeLabel(cellValue)},
+    {field: 'campaignNumber', title: '广告活动数量'},
+    {field: 'creator_username', title: '创建人'},
+    {field: 'modifier_username', title: '修改人'},
+    {title: '操作', width: 120, slots: {default: 'operate'}},
+  ],
+  toolbarConfig: {
+    slots: {
+      buttons: 'toolbar_buttons',
+    },
+  },
+  data: [],
+});
+
+const gridEvents = {
+  pageChange({currentPage, pageSize}) {
+    if (gridOptions.pagerConfig) {
+      gridOptions.pagerConfig.currentPage = currentPage;
+      gridOptions.pagerConfig.pageSize = pageSize;
+      getList();
+    }
+  },
+};
+
+async function getList() {
+  try {
+    gridOptions.loading = true;
+    const response = await GetList({
+      page: gridOptions.pagerConfig.currentPage,
+      limit: gridOptions.pagerConfig.pageSize,
+    });
+    gridOptions.data = response.data.map(item => ({
+      ...item,
+      rule: {
+        ...item.rule,
+        typeLabel: getTemplateTypeLabel(item.rule.type),
+      },
+    }));
+    console.log(response.data);
+    gridOptions.pagerConfig.total = response.total;
+  } catch (error) {
+    console.error('Error fetching task data:', error);
+  } finally {
+    gridOptions.loading = false;
   }
 }
 
-const refreshTable = () => {
-  showDrawer.value = false
-  crudExpose.doRefresh()
+function getTemplateTypeLabel(type: number) {
+  const template = TemplateType.find(t => t.value === type);
+  return template ? template.label : '';
 }
-const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: { editTmpl } })
-onMounted(async () => {
-  crudExpose.doRefresh()
-})
+
+onMounted(() => {
+  getList();
+});
 </script>
 
-<style scoped></style>
+<style>
+.custom-inline {
+  display: flex;
+  justify-content: space-around;
+  margin: 12px 0;
+  gap: 4px;
+}
+
+.custom-dialog .el-dialog__header {
+  height: 60px;
+  line-height: 60px;
+  padding: 0 24px;
+  background-color: #fff;
+  border-bottom: 1px solid #e5e6eb;
+  border-radius: 10px 10px 0 0;
+}
+</style>