Explorar el Código

feat<自动化规则>:1.修改条件组件中SymbolOptionsList的label为符号;
2。广告管理-自动化:保存规则后监控formData.value变化,能获取到最新RuleStatusButton,当存在规则时,按钮不被禁用;
3.效率工具-自动化规则:已存在关联广告添加新广告时逻辑修改;

xinyan hace 6 meses
padre
commit
7e1f637401

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

@@ -266,7 +266,7 @@ watch(
               @mouseover="handleMouseMove(week, hour)"
               @mouseup="handleMouseUp">
             <span class="cell-text"> {{
-                info.value ? Number(info.value).toFixed(2) : ''
+                Number(info.value).toFixed(2)
               }} </span>
           </td>
         </tr>

+ 166 - 152
src/components/TimerBudgetTable/index.vue

@@ -35,56 +35,64 @@
     <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 class="calendar-body">
-          <template v-for="(hoursList, week) in items">
-            <tr>
-              <th class="td-normal">{{ WeekMap[week] }}</th>
-              <td
-                class="un-selected"
+        <template v-for="(hoursList, week) in items">
+          <tr>
+            <th class="td-normal">{{ WeekMap[week] }}</th>
+            <td
                 v-for="(info, hour) in hoursList"
                 :key="hour"
+                :style="getTdStyle(info)"
+                class="un-selected"
                 @mousedown="handleMouseDown(week, hour, $event)"
                 @mouseover="handleMouseMove(week, hour)"
-                @mouseup="handleMouseUp"
-                :style="getTdStyle(info)">
-                {{ getCellText(info) }}
-                <el-icon v-if="info.type !== 'FixBudget'" style="display: inline-block; padding-top: 2px">
-                  <Top v-if="info.type === 'UpPercent' || info.type === 'UpNumber'" />
-                  <Bottom v-if="info.type === 'DownPercent' || info.type === 'DownNumber'" />
-                </el-icon>
-              </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">
+              {{ getCellText(info) }}
+              <el-icon v-if="info.type !== 'FixBudget'" style="display: inline-block; padding-top: 2px">
+                <Top v-if="info.type === 'UpPercent' || info.type === 'UpNumber'" />
+                <Bottom v-if="info.type === 'DownPercent' || info.type === 'DownNumber'" />
+              </el-icon>
+            </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>
     </div>
 
-    <el-dialog v-model="dialogVisible" :close-on-click-modal="false" title="编辑" width="30%" :before-close="closeDialog" :append-to-body="true">
-      <el-form :model="formData" ref="formRef" :inline="true">
-        <el-form-item prop="type">
-          <el-select v-model="formData.type" @change="changeKind" style="width: 250px">
-            <el-option v-for="item in KindEnum" :key="item.value" :label="item.label" :value="item.value" />
-          </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 ? '%' : ''" maxlength="111111"></InputFloat>
-        </el-form-item>
+    <el-dialog v-model="dialogVisible" :append-to-body="true" :before-close="closeDialog" :close-on-click-modal="false"
+               title="编辑" width="520px">
+      <el-form ref="formRef" :inline="true" :model="formData">
+        <el-row  :gutter="20">
+          <el-col :span="16">
+            <el-form-item prop="type">
+              <el-select v-model="formData.type" style="width: 280px" @change="changeKind">
+                <el-option v-for="item in KindEnum" :key="item.value" :label="item.label" :value="item.value" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item v-if="formData.type !== ''" :rules="{ validator: checkValue, trigger: 'blur' }" prop="value">
+              <InputFloat v-model="formData.value" :prefix="isNumber ? '$' : ''" :suffix="!isNumber ? '%' : ''"
+                          maxlength="111111"></InputFloat>
+            </el-form-item>
+          </el-col>
+        </el-row>
       </el-form>
       <template #footer>
         <div class="dialog-footer">
@@ -97,24 +105,27 @@
 </template>
 
 <script lang="ts" setup>
-import { ref, onMounted, watch, Ref } from 'vue'
-import InputFloat from '/@/components/input-float/index.vue'
-import XEUtils from 'xe-utils'
+import { ref, Ref, watch } from 'vue';
+import InputFloat from '/@/components/input-float/index.vue';
+import XEUtils from 'xe-utils';
+
 
 interface Props {
-  data: { value: string; type: string }[][]
-  disabled?: boolean
+  data: { value: string; type: string }[][];
+  disabled?: boolean;
 }
+
 interface FormData {
-  type: string
-  value: string
+  type: string;
+  value: string;
 }
-const props = defineProps<Props>()
 
-const mouseDown = ref(false)
-const startRowIndex = ref(0)
-const startColIndex = ref(0)
-const items = ref([])
+const props = defineProps<Props>();
+
+const mouseDown = ref(false);
+const startRowIndex = ref(0);
+const startColIndex = ref(0);
+const items = ref([]);
 const WeekMap = {
   0: '星期一',
   1: '星期二',
@@ -123,9 +134,9 @@ const WeekMap = {
   4: '星期五',
   5: '星期六',
   6: '星期日',
-}
-const dialogVisible = ref(false)
-const selectedItems = ref({})
+};
+const dialogVisible = ref(false);
+const selectedItems = ref({});
 
 const KindEnum = [
   { label: '无需调整预算', value: '' },
@@ -134,193 +145,193 @@ const KindEnum = [
   { label: '基于原始预算升高(百分比)', value: 'UpPercent', color: '#11acf5' },
   { label: '基于原始预算降低(数值)', value: 'DownNumber', color: '#3fd4cf' },
   { label: '基于原始预算升高(数值)', value: 'UpNumber', color: '#3fd4cf' },
-]
+];
 
-const formData: Ref<FormData> = ref({ type: 'FixBudget', value: '1.00' })
-const isNumber = ref(true)
-const formRef = ref()
+const formData: Ref<FormData> = ref({ type: 'FixBudget', value: '1.00' });
+const isNumber = ref(true);
+const formRef = ref();
 
 const checkValue = (rule: any, value: string, callback: any) => {
   if (formData.value.type === 'FixBudget') {
     if (XEUtils.toNumber(value) < 1) {
-      return new Error('固定预算必须大于1')
+      return new Error('固定预算必须大于1');
     }
   } else {
     if (XEUtils.toNumber(value) <= 0) {
-      return new Error('数值必须大于0')
+      return new Error('数值必须大于0');
     }
   }
-}
+};
 
 for (let i = 0; i < 7; i++) {
-  selectedItems.value[i] = []
-  const tmp = []
+  selectedItems.value[i] = [];
+  const tmp = [];
   for (let j = 0; j < 24; j++) {
-    let type = ''
-    let value = ''
+    let type = '';
+    let value = '';
     if (props.data.length !== 0) {
-      type = props.data[i][j].type
-      value = props.data[i][j].value
+      type = props.data[i][j].type;
+      value = props.data[i][j].value;
     }
-    tmp.push({ type, value })
+    tmp.push({ type, value });
   }
-  items.value.push(tmp)
+  items.value.push(tmp);
 }
 
 const getCellBackgroundColor = (row: any) => {
-  if (row.selected) return '#ccdbff'
-  if (row.type) return KindEnum.find((item) => item.value === row.type).color
-  return ''
-}
+  if (row.selected) return '#ccdbff';
+  if (row.type) return KindEnum.find((item) => item.value === row.type).color;
+  return '';
+};
 
 const getTdStyle = (info: any) => {
   if (props.disabled) {
-    let backgroundColor = ''
+    let backgroundColor = '';
     if (info.type) {
-      backgroundColor = KindEnum.find((item) => item.value === info.type).color
+      backgroundColor = KindEnum.find((item) => item.value === info.type).color;
     } else {
-      backgroundColor = '#fff'
+      backgroundColor = '#fff';
     }
-    return { cursor: 'not-allowed', background: backgroundColor }
+    return { cursor: 'not-allowed', background: backgroundColor };
   }
-  return { background: getCellBackgroundColor(info) }
-}
+  return { background: getCellBackgroundColor(info) };
+};
 
 watch(
-  () => props.data,
-  () => {
-    // console.log(191, props.data)
-    if (props.data.length === 0) {
+    () => props.data,
+    () => {
+      // console.log(191, 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({ type: '', value: '' });
+          }
+          props.data.push(tmp);
+        }
+      }
       for (let i = 0; i < 7; i++) {
-        const tmp = []
         for (let j = 0; j < 24; j++) {
-          tmp.push({ type: '', value: '' })
+          items.value[i][j].type = props.data[i][j].type;
+          items.value[i][j].value = props.data[i][j].value;
         }
-        props.data.push(tmp)
       }
-    }
-    for (let i = 0; i < 7; i++) {
-      for (let j = 0; j < 24; j++) {
-        items.value[i][j].type = props.data[i][j].type
-        items.value[i][j].value = props.data[i][j].value
-      }
-    }
-  },
-  { deep: true, immediate: true }
-)
+    },
+    { deep: true, immediate: true }
+);
 
 const changeKind = () => {
   if (formData.value.type === 'DownPercent' || formData.value.type === 'UpPercent') {
-    isNumber.value = false
+    isNumber.value = false;
   } else {
-    isNumber.value = true
+    isNumber.value = true;
   }
-  formRef.value.clearValidate('value')
-}
+  formRef.value.clearValidate('value');
+};
 
 const getCellText = (row: any) => {
-  if (row.type === 'DownPercent' || row.type === 'UpPercent') return row.value + '%'
-  if (row.value) return '$' + row.value
-  return ''
-}
+  if (row.type === 'DownPercent' || row.type === 'UpPercent') return row.value + '%';
+  if (row.value) return '$' + row.value;
+  return '';
+};
 
 const handleMouseDown = (rowIndex: number, colIndex: number, event: any) => {
-  if (props.disabled) return
+  if (props.disabled) return;
   if (event.button === 0) {
-    mouseDown.value = true
-    startRowIndex.value = rowIndex
-    startColIndex.value = colIndex
-    items.value[rowIndex][colIndex].selected = true
-    selectedItems.value[rowIndex].push(colIndex)
+    mouseDown.value = true;
+    startRowIndex.value = rowIndex;
+    startColIndex.value = colIndex;
+    items.value[rowIndex][colIndex].selected = true;
+    selectedItems.value[rowIndex].push(colIndex);
   }
-}
+};
 
 const handleMouseUp = (event: any) => {
-  if (props.disabled) return
+  if (props.disabled) return;
   if (event.button === 0) {
-    mouseDown.value = false
-    startColIndex.value = 0
-    startRowIndex.value = 0
-    dialogVisible.value = true
+    mouseDown.value = false;
+    startColIndex.value = 0;
+    startRowIndex.value = 0;
+    dialogVisible.value = true;
   }
-}
+};
 
 const handleMouseMove = (rowIndex: number, colIndex: number) => {
-  if (props.disabled) return
+  if (props.disabled) return;
   if (mouseDown.value) {
-    selectCell(rowIndex, colIndex)
+    selectCell(rowIndex, colIndex);
   }
-}
+};
 
 const selectCell = (rowIndex: number, colIndex: number) => {
-  if (props.disabled) return
-  const rowStart = Math.min(startRowIndex.value, rowIndex)
-  const rowEnd = Math.max(startRowIndex.value, rowIndex)
-  const cellStart = Math.min(startColIndex.value, colIndex)
-  const cellEnd = Math.max(startColIndex.value, colIndex)
+  if (props.disabled) return;
+  const rowStart = Math.min(startRowIndex.value, rowIndex);
+  const rowEnd = Math.max(startRowIndex.value, rowIndex);
+  const cellStart = Math.min(startColIndex.value, colIndex);
+  const cellEnd = Math.max(startColIndex.value, colIndex);
 
   for (let i = rowStart; i <= rowEnd; i++) {
     for (let j = cellStart; j <= cellEnd; j++) {
-      items.value[i][j].selected = true
-      selectedItems.value[i].push(j)
+      items.value[i][j].selected = true;
+      selectedItems.value[i].push(j);
     }
   }
-}
+};
 
 const submitBid = () => {
   if (formData.value.type === '') {
     for (const row of Object.keys(selectedItems.value)) {
       for (const col of selectedItems.value[row]) {
-        props.data[row][col].type = ''
-        props.data[row][col].value = ''
+        props.data[row][col].type = '';
+        props.data[row][col].value = '';
       }
     }
   } else {
     for (const row of Object.keys(selectedItems.value)) {
       for (const col of selectedItems.value[row]) {
-        props.data[row][col].type = formData.value.type
-        props.data[row][col].value = formData.value.value
+        props.data[row][col].type = formData.value.type;
+        props.data[row][col].value = formData.value.value;
       }
     }
   }
-  clearSelectedItems()
-  clearCellBackgroundColor()
-  dialogVisible.value = false
-}
+  clearSelectedItems();
+  clearCellBackgroundColor();
+  dialogVisible.value = false;
+};
 
 const cancelBid = () => {
-  clearSelectedItems()
-  clearCellBackgroundColor()
-  dialogVisible.value = false
-}
+  clearSelectedItems();
+  clearCellBackgroundColor();
+  dialogVisible.value = false;
+};
 
 const closeDialog = (done: Function) => {
-  cancelBid()
-  done()
-}
+  cancelBid();
+  done();
+};
 
 const clearCellBackgroundColor = () => {
   for (const hoursList of items.value) {
     for (const info of hoursList) {
-      info.selected = false
+      info.selected = false;
     }
   }
-}
+};
 const clearSelectedItems = () => {
   for (var i = 0; i < 7; i++) {
-    selectedItems.value[i] = []
+    selectedItems.value[i] = [];
   }
-}
+};
 const resetAllBid = () => {
   for (let i = 0; i < 7; i++) {
     for (let j = 0; j < 24; j++) {
-      items.value[i][j].value = 0
-      items.value[i][j].selected = false
-      props.data[i][j].type = ''
-      props.data[i][j].value = ''
+      items.value[i][j].value = 0;
+      items.value[i][j].selected = false;
+      props.data[i][j].type = '';
+      props.data[i][j].value = '';
     }
   }
-}
+};
 </script>
 
 <style lang="scss" scoped>
@@ -376,6 +387,7 @@ table {
       line-height: 32px;
       min-width: 40px;
       color: #fff;
+
       &:hover {
         background: #ccdbff;
         cursor: pointer;
@@ -393,9 +405,11 @@ table {
     font-size: 13px;
     margin-top: 7px;
   }
+
   .fr {
     float: right;
   }
+
   .middle {
     float: center;
   }

+ 1 - 1
src/components/conditionBuilder/condition-group2.vue

@@ -38,7 +38,7 @@
               style="width: 80px"
               v-show="conditionInfo.symbol !== 'in' && conditionInfo.symbol !== 'not_in'">
               <el-option label="总计" value="sum"></el-option>
-              <el-option label="均值" value="avg"></el-option>
+              <!--<el-option label="均值" value="avg"></el-option>-->
             </el-select>
             <el-select v-model="conditionInfo.symbol" style="width: 120px">
               <el-option v-for="info in getSymbolOptions(conditionInfo.dataType)" :label="info.label" :value="info.value" :key="info.value">

+ 7 - 7
src/components/conditionBuilder/utils.ts

@@ -2,13 +2,13 @@ import XEUtils from 'xe-utils'
 
 export const useSymbolOptions = (candidateFields: CandidateField[]) => {
   const SymbolOptionsList = [
-    { label: '大于', value: 'gt' },
-    { label: '大于等于', value: 'gte' },
-    { label: '小于', value: 'lt' },
-    { label: '小于等于', value: 'lte' },
-    { label: '等于', value: 'eq' },
-    { label: '范围内', value: 'between' },
-    { label: '范围外', value: 'not_between' },
+    { label: '≤', value: 'lte' },
+    { label: '<', value: 'lt' },
+    { label: '=', value: 'eq' },
+    { label: '≥', value: 'gte' },
+    { label: '>', value: 'gt' },
+    // { label: '范围内', value: 'between' },
+    // { label: '范围外', value: 'not_between' },
     // { label: '包含', value: 'in' },
     // { label: '不包含', value: 'not_in' }
   ]

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

@@ -27,12 +27,12 @@ const props = defineProps<Props>();
 const campaignType = 'sp';
 const activeTab = ref(1);
 const RuleStatusButton = ref({
-  '1': 0,
-  '2': 0,
-  '3': 0,
-  '4': 0,
-  '5': 0,
-  '6': 0,
+  '1': '-',
+  '2': '-',
+  '3': '-',
+  '4': '-',
+  '5': '-',
+  '6': '-',
 })
 
 const baseData = ref({
@@ -42,6 +42,17 @@ const baseData = ref({
   ruleType: activeTab,
 });
 
+function initData() {
+  RuleStatusButton.value ={1: '-', 2: '-', 3: '-', 4: '-', 5: '-', 6: '-'}
+}
+
+function handleSwitchClick(event, tabIndex) {
+  const newValue = RuleStatusButton[tabIndex] === 1 ? 1 : 0;
+  if (RuleStatusButton[tabIndex] !== '-') {
+    changeStatus(newValue, tabIndex);
+  }
+}
+
 async function changeStatus(newStatus: number, tabIndex: string) {
   const body = {
     ...baseData.value,
@@ -52,10 +63,6 @@ async function changeStatus(newStatus: number, tabIndex: string) {
     const response = await postCampaignStatus(body);
     if (response.code === 2000) {
       ElMessage.success('更新状态成功');
-      // const resp = await getCampaignRuleInfo(baseData.value);
-      // RuleStatusButton.value = resp.data[0].RuleStatusButton;
-    } else if (response.code == 5000) {
-      ElMessage.warning(`${ response.data.description }`);
     } else {
       ElMessage.error('状态更新失败');
     }
@@ -63,7 +70,8 @@ async function changeStatus(newStatus: number, tabIndex: string) {
     console.log('error:', error);
   }
 }
-function updateRuleStatusButton(newValue) {
+
+async function updateRuleStatusButton(newValue) {
   if (newValue !== undefined) {
     RuleStatusButton.value = { ...RuleStatusButton.value, ...newValue }
   } else {
@@ -79,17 +87,17 @@ async function refresh(tab: number) {
 }
 
 onMounted(async () => {
-  // await initData();
+  initData(); // 确保初始化
 });
 </script>
 
 <template>
-  <el-tabs v-model="activeTab" tab-position="left" @tab-change="changeTab">
+  <el-tabs v-model="activeTab" tab-position="left">
     <el-tab-pane :name="1" label="分时调价">
       <template #label>
         <div class="tab-label">
           <el-switch v-model="RuleStatusButton['1']" :active-value="1" :disabled="RuleStatusButton['1'] === '-'"
-                     :inactive-value="0" size="small" @change="(val) => changeStatus(val, '1')" @click.stop="">
+                     :inactive-value="0" size="small" @click="handleSwitchClick($event, '1')" @click.stop="">
           </el-switch>
           <span>分时调价</span>
         </div>
@@ -100,61 +108,61 @@ onMounted(async () => {
       <template #label>
         <div class="tab-label">
           <el-switch v-model="RuleStatusButton['2']" :active-value="1" :disabled="RuleStatusButton['2'] === '-'"
-                     :inactive-value="0" size="small" @change="(val) => changeStatus(val, '2')" @click.stop="">
+                     :inactive-value="0" size="small" @click="handleSwitchClick($event, '2')" @click.stop="">
           </el-switch>
           <span>分时预算</span>
         </div>
       </template>
-      <TimerBudget v-if="activeTab === 2" :RuleStatusButton="RuleStatusButton" :data="baseData" @refresh="refresh(2)" />
+      <TimerBudget v-if="activeTab === 2" :RuleStatusButton="RuleStatusButton" :data="baseData" @refresh="refresh(2)" @updateRuleStatusButton="updateRuleStatusButton"/>
     </el-tab-pane>
     <el-tab-pane :name="3" label="开启/暂停广告活动">
       <template #label>
         <div class="tab-label">
           <el-switch v-model="RuleStatusButton['3']" :active-value="1" :disabled="RuleStatusButton['3'] === '-'"
-                     :inactive-value="0" size="small" @change="(val) => changeStatus(val, '3')" @click.stop="">
+                     :inactive-value="0" size="small" @click="handleSwitchClick($event, '3')" @click.stop="">
           </el-switch>
           <span>开启/暂停广告活动</span>
         </div>
       </template>
       <SwitchCampaign v-if="activeTab === 3" :RuleStatusButton="RuleStatusButton" :data="baseData"
-                      @refresh="refresh(3)" />
+                      @refresh="refresh(3)" @updateRuleStatusButton="updateRuleStatusButton"/>
     </el-tab-pane>
     <el-tab-pane :name="4" label="定向规则" v-if="targetingType !== 'AUTO'">
       <template #label>
         <div class="tab-label">
           <el-switch v-model="RuleStatusButton['4']" :active-value="1" :disabled="RuleStatusButton['4'] === '-'"
-                     :inactive-value="0" size="small" @change="(val) => changeStatus(val, '4')" @click.stop="">
+                     :inactive-value="0" size="small" @click="handleSwitchClick($event, '4')" @click.stop="">
           </el-switch>
           <span>定向规则</span>
         </div>
       </template>
       <TargetRule v-if="activeTab === 4" :RuleStatusButton="RuleStatusButton" :data="baseData"
-                  @refresh="refresh(4)"></TargetRule>
+                  @refresh="refresh(4)" @updateRuleStatusButton="updateRuleStatusButton"></TargetRule>
     </el-tab-pane>
     <el-tab-pane :name="5" label="添加搜索词" v-if="targetingType !== 'AUTO'">
       <template #label>
         <div class="tab-label">
           <el-switch v-model="RuleStatusButton['5']" :active-value="1" :disabled="RuleStatusButton['5'] === '-'"
-                     :inactive-value="0" size="small" @change="(val) => changeStatus(val, '5')" @click.stop="">
+                     :inactive-value="0" size="small" @click="handleSwitchClick($event, '5')" @click.stop="">
           </el-switch>
           <span>添加搜索词</span>
         </div>
       </template>
       <SearchTermRule v-if="activeTab === 5" :RuleStatusButton="RuleStatusButton" :data="baseData"
-                      @refresh="refresh(5)">
+                      @refresh="refresh(5)" @updateRuleStatusButton="updateRuleStatusButton">
       </SearchTermRule>
     </el-tab-pane>
     <el-tab-pane :name="6" label="添加否定词">
       <template #label>
         <div class="tab-label">
           <el-switch v-model="RuleStatusButton['6']" :active-value="1" :disabled="RuleStatusButton['6'] === '-'"
-                     :inactive-value="0" size="small" @change="(val) => changeStatus(val, '6')" @click.stop="">
+                     :inactive-value="0" size="small" @click="handleSwitchClick($event, '6')" @click.stop="">
           </el-switch>
           <span>添加否定词</span>
         </div>
       </template>
       <NegKeywordRule v-if="activeTab === 6" :RuleStatusButton="RuleStatusButton" :data="baseData"
-                      @refresh="refresh(6)">
+                      @refresh="refresh(6)" @updateRuleStatusButton="updateRuleStatusButton">
       </NegKeywordRule>
     </el-tab-pane>
   </el-tabs>

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

@@ -56,7 +56,7 @@ onMounted(async () => {
         </div>
         <div>
           <span class="label">广告组合:</span>
-          <span class="value">{{ campaignInfo?.portfolioName }}</span>
+          <span class="value">{{ campaignInfo?.portfolioName || '--' }}</span>
         </div>
         <div>
           <span class="label">竞价策略:</span>

+ 6 - 7
src/views/components/auto/auto-campaigns/common.ts

@@ -31,13 +31,12 @@ export const userFormData = (props: Props) => {
     },
     RuleStatusButton: props.RuleStatusButton,
   })
-  const ruleStatusButton = ref({})
   const initData = async () => {
     const resp = await api.getCampaignRuleInfo(props.data)
     const info = resp.data[0]
     if (info) {
-      ruleStatusButton.value = info.RuleStatusButton || {}
-      delete info['RuleStatusButton']
+      // ruleStatusButton.value = info.RuleStatusButton || {}
+      // delete info['RuleStatusButton']
       formData.value = info
       if (info.template) {
         formData.value.useTmpl = true
@@ -65,8 +64,8 @@ export const userFormData = (props: Props) => {
       delete body.rule['modifier_name']
       delete body.rule.id
     }
-    console.log('body', body);
-    // await api.saveCampaignRule(body)
+    await api.saveCampaignRule(body)
+    console.log("=>(common.ts:68) body", body);
   }
 
   watch(
@@ -77,9 +76,9 @@ export const userFormData = (props: Props) => {
     { deep: true }
   )
 
-  onMounted(async () => {
+  onBeforeMount(async () => {
     await initData()
   })
 
-  return { formData, submitFormData ,ruleStatusButton}
+  return { formData, submitFormData }
 }

+ 5 - 1
src/views/components/auto/auto-campaigns/neg-keyword.vue

@@ -26,8 +26,8 @@ interface Props {
 }
 
 const props = defineProps<Props>();
+const emits = defineEmits(['refresh', 'updateRuleStatusButton']);
 
-const emits = defineEmits(['refresh']);
 const formRef = ref();
 const searchTermAddRef = ref();
 const condiBuilderRef = ref();
@@ -56,6 +56,10 @@ async function handleSubmit() {
     }
   });
 }
+
+watch(() => formData.value, (newData) => {
+  emits('updateRuleStatusButton', newData.RuleStatusButton);
+});
 </script>
 
 <template>

+ 6 - 1
src/views/components/auto/auto-campaigns/search-term.vue

@@ -27,7 +27,8 @@ interface Props {
 const props = defineProps<Props>();
 
 
-const emits = defineEmits(['refresh']);
+const emits = defineEmits(['refresh', 'updateRuleStatusButton']);
+
 const formRef = ref();
 const searchTermAddRef = ref();
 const searchTermBidRef = ref();
@@ -62,6 +63,10 @@ async function handleSubmit() {
     }
   });
 }
+
+watch(() => formData.value, (newData) => {
+  emits('updateRuleStatusButton', newData.RuleStatusButton);
+});
 </script>
 
 <template>

+ 32 - 35
src/views/components/auto/auto-campaigns/switch-campaign.vue

@@ -13,6 +13,7 @@ import FreqSetting from '../freq-setting.vue';
 import SaveRuleDialog from '/@/views/components/auto/auto-campaigns/save-rule-dialog.vue';
 import { ElMessage } from 'element-plus';
 
+
 interface Props {
   data: {
     campaignId: string;
@@ -24,7 +25,8 @@ interface Props {
 }
 
 const props = defineProps<Props>();
-const emits = defineEmits(['refresh']);
+const emits = defineEmits(['refresh', 'updateRuleStatusButton']);
+
 const formRef = ref();
 const condiBuilderRef = ref();
 const { formData, submitFormData } = userFormData(props);
@@ -39,7 +41,7 @@ const condidateFields = [
   { label: '转化率', value: 'cr', suffix: '%' },
   { label: '单次点击费用', value: 'cpc', prefix: '$' },
 ];
-const defaultTime = new Date()
+const defaultTime = new Date();
 
 function disabledDate(date) {
   return date < new Date().setHours(0, 0, 0, 0);
@@ -47,23 +49,23 @@ function disabledDate(date) {
 
 // 限制小时
 const disabledHour = () => {
-  const arrs = []
+  const arrs = [];
   for (let i = 0; i < 24; i++) {
     if (new Date().getHours() <= i) continue;
-    arrs.push(i)
+    arrs.push(i);
   }
   return arrs;
-}
+};
 
 // 限制分
 const disabledMinute = () => {
-  const arrs = []
+  const arrs = [];
   for (let i = 0; i < 60; i++) {
     if (new Date().getMinutes() <= i) continue;
-    arrs.push(i)
+    arrs.push(i);
   }
   return arrs;
-}
+};
 
 function addConditions() {
   if (formData.value.rule.conditions.length === 0) {
@@ -73,6 +75,7 @@ function addConditions() {
 
 async function validateConditionsForm() {
   const validList = await condiBuilderRef.value.validate();
+  console.log('=>(switch-campaign.vue:77) validList', validList);
   return !validList.includes(false);
 }
 
@@ -89,8 +92,8 @@ function cancel() {
 async function handleSubmit() {
   const valid2 = await validateConditionsForm();
   formRef.value.validate(async (valid: any) => {
-    if (!valid || !valid2) return;
-
+    const actionState = formData.value.rule.action.state;
+    if (!valid  || (actionState.includes('paused') && !valid2)) return;
     if (formData.value.rule.action.state.length === 0) return;
 
     const selectedTime = new Date(formData.value.rule.action.setTime).setSeconds(0, 0);;
@@ -111,27 +114,21 @@ async function handleSubmit() {
   });
 }
 
-// watch(() => formData.value.useTmpl, (newValue) => {
-//   if (!newValue) {
-//     // clearForm();
-//   }
-// });
-//
-// function clearForm() {
-//   formData.value.rule.action.state = [];
-//   formData.value.rule.action.setTime = '';
-//   formData.value.rule.conditions = [];
-// }
+watch(() => formData.value, (newData) => {
+  emits('updateRuleStatusButton', newData.RuleStatusButton);
+});
+
 </script>
 
 <template>
   <div class="mx-5">
-    <div class="asj-h2">广告活动</div>
+    <div class="asj-h2">开启/暂停广告活动</div>
     <SelectTmpl :data="formData" />
     <el-card class="mt-3">
-      <FreqSetting :rule="formData.rule" :disabled="formData.useTmpl" />
+      <FreqSetting :disabled="formData.useTmpl" :rule="formData.rule" />
       <el-divider />
-      <el-form :model="formData" label-position="top" style="margin-top: 20px" ref="formRef" :disabled="formData.useTmpl">
+      <el-form ref="formRef" :disabled="formData.useTmpl" :model="formData" label-position="top"
+               style="margin-top: 20px">
         <div class="asj-h3">
           <span class="custom-title-icon"></span>
           操作
@@ -141,18 +138,18 @@ async function handleSubmit() {
             <el-checkbox label="enabled">开始</el-checkbox>
             <div v-show="formData.rule.action.state.includes('enabled')" style="display: block; margin: 10px 0">
               <el-form-item
-                prop="rule.action.setTime"
-                :rules="[{ required: formData.rule.action.state.includes('enabled'), message: '必填项', trigger: 'blur' }]">
+                  :rules="[{ required: formData.rule.action.state.includes('enabled'), message: '必填项', trigger: 'blur' }]"
+                  prop="rule.action.setTime">
                 <el-date-picker
                     v-model="formData.rule.action.setTime"
-                    type="datetime"
-                    format="YYYY-MM-DD HH:mm"
-                    time-format="HH:mm"
-                    value-format="YYYY-MM-DD HH:mm"
+                    :default-time="defaultTime"
                     :disabled-date="disabledDate"
                     :disabled-hours="disabledHour"
                     :disabled-minutes="disabledMinute"
-                    :default-time="defaultTime"
+                    format="YYYY-MM-DD HH:mm"
+                    time-format="HH:mm"
+                    type="datetime"
+                    value-format="YYYY-MM-DD HH:mm"
                 />
               </el-form-item>
             </div>
@@ -165,10 +162,10 @@ async function handleSubmit() {
       </el-form>
       <div v-show="formData.rule.action.state.includes('paused')">
         <conditionBuilder
-          :data="formData.rule.conditions"
-          :candidate-fields="condidateFields"
-          ref="condiBuilderRef"
-          :disabled="formData.useTmpl" />
+            ref="condiBuilderRef"
+            :candidate-fields="condidateFields"
+            :data="formData.rule.conditions"
+            :disabled="formData.useTmpl" />
       </div>
     </el-card>
 

+ 9 - 3
src/views/components/auto/auto-campaigns/target-rule.vue

@@ -12,6 +12,7 @@ import FreqSetting from '../freq-setting.vue';
 import { userFormData } from './common';
 import TargetRuleSetting from '../target-rule-setting.vue';
 import SaveRuleDialog from '/@/views/components/auto/auto-campaigns/save-rule-dialog.vue';
+import { ElMessage } from 'element-plus';
 
 
 interface Props {
@@ -25,7 +26,8 @@ interface Props {
 }
 
 const props = defineProps<Props>();
-const emits = defineEmits(['refresh']);
+const emits = defineEmits(['refresh', 'updateRuleStatusButton']);
+
 const formRef = ref();
 const ruleSettingRef = ref();
 const { formData, submitFormData } = userFormData(props);
@@ -33,7 +35,7 @@ const submitDialogVisible = ref(false);
 
 const submitForm = async () => {
   await submitFormData();
-  ELMessage.success('保存成功');
+  ElMessage.success('保存成功');
   emits('refresh');
 };
 
@@ -55,6 +57,10 @@ async function handleSubmit() {
     }
   });
 }
+
+watch(() => formData.value, (newData) => {
+  emits('updateRuleStatusButton', newData.RuleStatusButton);
+});
 </script>
 
 <template>
@@ -69,7 +75,7 @@ async function handleSubmit() {
           <el-divider />
           <!-- 生效对象 -->
           <TargetSelect
-              :campaign-id="data.campaignId"
+              :campaignInfo="data"
               :data="formData.rule"
               :useTmpl="formData.useTmpl"
               mode="auto"></TargetSelect>

+ 14 - 11
src/views/components/auto/auto-campaigns/timer-bid.vue

@@ -10,7 +10,8 @@ import TimerBidTable from '/@/components/TimerBidTable/index.vue';
 import SelectTmpl from './select-tmpl.vue';
 import { userFormData } from './common';
 import SaveRuleDialog from '/@/views/components/auto/auto-campaigns/save-rule-dialog.vue';
-import { ElMessage } from 'element-plus'
+import { ElMessage } from 'element-plus';
+
 
 interface Props {
   data: {
@@ -24,10 +25,10 @@ interface Props {
 }
 
 const props = defineProps<Props>();
-const emits = defineEmits(['refresh','updateRuleStatusButton']);
+const emits = defineEmits(['refresh', 'updateRuleStatusButton']);
 
 const formRef = ref();
-const { formData, submitFormData, ruleStatusButton } = userFormData(props)
+const { formData, submitFormData } = userFormData(props);
 
 const tableRef = ref(null);
 const timeRange = ref('Option1');
@@ -88,10 +89,6 @@ async function submit() {
   emits('refresh');
 }
 
-function cancel() {
-  emits('refresh');
-}
-
 async function handleSubmit() {
   formRef.value.validate(async (valid: boolean) => {
     if (!valid) {
@@ -106,6 +103,10 @@ async function handleSubmit() {
   });
 }
 
+function cancel() {
+  emits('refresh');
+}
+
 function handleClose() {
   isVisible.value = false;
 }
@@ -127,14 +128,16 @@ function handleBidChange(value: string) {
 
 const handleApply = () => {
   validateBid(bid.value);
+  const bidValue = bid.value === '' ? 0 : parseFloat(bid.value);
   if (!bidError.value && tableRef.value) {
-    tableRef.value.applyBid(timeRange.value, schedule.value, parseFloat(bid.value));
+    tableRef.value.applyBid(timeRange.value, schedule.value, bidValue);
   }
 };
 
-watch(ruleStatusButton, (newValue) => {
-  emits('updateRuleStatusButton', newValue)
-}, { deep: true })
+watch(() => formData.value, (newData) => {
+  emits('updateRuleStatusButton', newData.RuleStatusButton);
+});
+
 </script>
 
 <template>

+ 8 - 2
src/views/components/auto/auto-campaigns/timer-budget.vue

@@ -24,7 +24,8 @@ interface Props {
 }
 
 const props = defineProps<Props>();
-const emits = defineEmits(['refresh']);
+const emits = defineEmits(['refresh', 'updateRuleStatusButton']);
+
 const formRef = ref();
 const { formData, submitFormData } = userFormData(props);
 
@@ -54,7 +55,7 @@ function handleSubmit() {
       return;
     } else {
       if (formData.value.useTmpl) {
-        await submit();
+        await submitForm();
       } else {
         submitDialogVisible.value = true;
       }
@@ -65,6 +66,11 @@ function handleSubmit() {
 function cancel() {
   emits('refresh');
 }
+
+watch(() => formData.value, (newData) => {
+  emits('updateRuleStatusButton', newData.RuleStatusButton);
+});
+
 </script>
 
 <template>

+ 1 - 1
src/views/components/auto/auto-campaigns/view-target-rules.vue

@@ -33,7 +33,7 @@ let selectedAds = ref([]);
 const dialogVisible = ref(false);
 const SelectTargetVisible = ref(false);
 
-const selectedTargetedRow = ref(null);
+const selectedTargetedRow = ref();
 
 const selectedColumns = [
   {

+ 43 - 33
src/views/components/auto/target-rule-setting.vue

@@ -30,19 +30,19 @@ const candidateFields = [
   { label: '广告订单数', value: 'order' },
   { label: '广告销售额', value: 'sale', prefix: '$' },
   { label: 'ACOS', value: 'acos', suffix: '%' },
-  {
-    label: '定向匹配方式',
-    value: 'matchType',
-    type: 'array',
-    options: [
-      { label: '关键词-精确', value: 'exect' },
-      { label: '关键词-广泛', value: 'broad' },
-      { label: '关键词-词组', value: 'phrase' },
-      { label: '商品-品类', value: 'category' },
-      { label: '商品-单个商品', value: 'asin' },
-    ],
-  },
-  { label: '关键词名称', value: 'keywords', type: 'array' },
+  // {
+  //   label: '定向匹配方式',
+  //   value: 'matchType',
+  //   type: 'array',
+  //   options: [
+  //     { label: '关键词-精确', value: 'exect' },
+  //     { label: '关键词-广泛', value: 'broad' },
+  //     { label: '关键词-词组', value: 'phrase' },
+  //     { label: '商品-品类', value: 'category' },
+  //     { label: '商品-单个商品', value: 'asin' },
+  //   ],
+  // },
+  // { label: '关键词名称', value: 'keywords', type: 'array' },
 ];
 
 const isVisible = ref(true);
@@ -69,9 +69,24 @@ const maxRuleNumber = computed(() => {
   return ret;
 });
 
-
-watch(() => props.rule, (newRule) => {
-  ruleInfo = newRule.conditions[0].action;
+onBeforeMount(() => {
+  watch(() => props.rule, (newRule) => {
+    ruleInfo = newRule.conditions[0].action;
+    actionModel.value = newRule.conditions.map(condition => condition.action.baseType + '-' + condition.action.numType);
+    if (!actionModel.value) {
+      props.rule.campaignType = 'sp';
+      props.rule.activeModel = 'campaign';
+      addRule('increase', -1);
+    }
+  });
+  // 已有数据
+  if (props.rule.id) {
+    actionModel.value = props.rule.conditions.map(condition => condition.action.baseType + '-' + condition.action.numType);
+  } else {
+    props.rule.campaignType = 'sp';
+    props.rule.activeModel = 'campaign';
+    addRule('increase', -1);
+  }
 });
 
 function checkFloat(rule: any, value: any, callback: any) {
@@ -82,19 +97,19 @@ function checkFloat(rule: any, value: any, callback: any) {
   }
 }
 
-function checkMinMax(rule: any, value: any, callback: any) {
-  if (XEUtils.toNumber(value) <= 0) {
-    callback(new Error('请输入大于0的数值!'));
-  } else {
-    callback();
-  }
-}
+// function checkMinMax(rule: any, value: any, callback: any) {
+//   if (XEUtils.toNumber(value) <= 0) {
+//     callback(new Error('请输入大于0的数值!'));
+//   } else {
+//     callback();
+//   }
+// }
 
-function addRule(actionType: string, index: number = -1) {
+async function addRule(actionType: string, index: number = -1) {
   const field = candidateFields[0].value;
   const symbol = getSymbolOptions(field)[0].value;
   const rule = {
-    action: { set: '', baseType: '', max: '', min: '', numType: 'ratio' },
+    action: { set: '', baseType: 'bid', max: '', min: '', numType: 'ratio' },
     actionType: actionType,
     conditions: [
       {
@@ -137,19 +152,14 @@ function addRule(actionType: string, index: number = -1) {
   }
 }
 
-if (props.rule.conditions.length === 0) {
-  props.rule.campaignType = 'sp';
-  props.rule.activeModel = 'campaign';
-  console.log('actionModel.value',actionModel.value);
-  addRule('increase', -1);
-}
-
 function delRule(actionType: string, index: number) {
   props.rule.conditions.splice(index, 1);
   if (actionType === 'increase') {
     maxIsDisabled.value.splice(index, 1);
+    actionModel.value.splice(index, 1);
   } else if (actionType === 'decrease') {
     minIsDisabled.value.splice(index, 1);
+    actionModel.value.splice(index, 1);
   }
 }
 
@@ -353,7 +363,7 @@ defineExpose({ validateForm });
       <div v-for="(info, index) in rule.conditions" :key="info.actionType + info.ordering">
         <el-row>
           <el-col :span="20">
-            <el-card body-style="padding: 12px 10px;" class="rule-setting-item" draggable="true" shadow="hover">
+            <el-card body-style="padding: 12px 10px;" class="rule-setting-item" shadow="hover">
               {{ RuleNameMap[info.actionType] }} - 规则{{ info.ordering }}
               <span v-if="info.actionType === 'increase' || info.actionType === 'decrease'">
                  {{

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

@@ -14,17 +14,17 @@ interface Props {
   mode: string;
   data: AutoRule;
   useTmpl?: boolean;
-  campaignId: string;
+  campaignInfo: any;
 }
 
 const props = defineProps<Props>();
 const dialogVisible = ref(false);
-const checkTarget = ref(null);
+const checkTarget = ref();
 
 function handleSelectTarget() {
   checkTarget.value = {
-    profileId:3006125408623189,
-    campaignId:483046146089241,
+    profileId:props.campaignInfo.profileId,
+    campaignId:props.campaignInfo.campaignId,
   }
   dialogVisible.value = true;
 }

+ 7 - 1
src/views/efTools/automation/components/adActivityDialog.vue

@@ -314,10 +314,16 @@ function handleSelectTarget(row) {
 function handleConfirm({ campaignInfo, targetType }) {
   if (!selectedTargetedRow.value) return;
 
-  const parentCampaign = gridOptions.data.find(campaign =>
+  let parentCampaign = gridOptions.data.find(campaign =>
       campaign.campaignGroupInfo.some(group => group.adGroupId === selectedTargetedRow.value.adGroupId)
   );
 
+  if (!parentCampaign) {
+    parentCampaign = selectedAds.value.find(campaign =>
+        campaign.campaignGroupInfo.some(group => group.adGroupId === selectedTargetedRow.value.adGroupId)
+    );
+  }
+
   if (parentCampaign) {
     // 更新子节点(广告组)的信息
     const group = parentCampaign.campaignGroupInfo.find(group => group.adGroupId === selectedTargetedRow.value.adGroupId);