WanGxC 1 жил өмнө
parent
commit
86476bd371

+ 268 - 146
src/views/adManage/sp/campaigns/CreateCampaigns/index.vue

@@ -100,7 +100,7 @@
                 <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
                   <el-tab-pane label="搜索" name="first">
                     <div style="margin-bottom: 10px">
-                      <el-input v-model="searchInp" placeholder="Please input" class="input-with-select" @change="inpChange" clearable >
+                      <el-input v-model="searchInp" placeholder="Please input" class="input-with-select" @change="inpChange" clearable>
                         <template #prepend>
                           <el-select v-model="select" style="width: 100px" @change="selChange">
                             <el-option label="名称" value="name" />
@@ -127,26 +127,26 @@
                       <el-table-column type="selection" width="50" />
                       <el-table-column prop="asin" label="ASIN" width="538">
                         <template #default="scope">
-                          <div style="display: flex; align-items: center;">
-                            <div style=" margin-right: 8px; line-height: normal;">
+                          <div style="display: flex; align-items: center">
+                            <div style="margin-right: 8px; line-height: normal">
                               <el-image class="img-box" :src="scope.row.image_link" />
                             </div>
                             <div>
                               <el-tooltip class="box-item" effect="dark" :content="scope.row.title" placement="top">
-                              <div class="single-line">{{ scope.row.title ? scope.row.title : '--' }}</div>
-                            </el-tooltip>
-                            <div class="data-color">
-                              <span style="font-weight: 500; color: rgb(30, 33, 41);">${{ scope.row.price ? scope.row.price : '--' }}</span>
-                              <span style="margin: 0 5px; color: #cacdd4;">|</span>
-                              <span style="color: #6d7784;">{{ scope.row.quantity }}</span>
+                                <div class="single-line">{{ scope.row.title ? scope.row.title : '--' }}</div>
+                              </el-tooltip>
+                              <div class="data-color">
+                                <span style="font-weight: 500; color: rgb(30, 33, 41)">${{ scope.row.price ? scope.row.price : '--' }}</span>
+                                <span style="margin: 0 5px; color: #cacdd4">|</span>
+                                <span style="color: #6d7784">{{ scope.row.quantity }}</span>
+                              </div>
+                              <span>
+                                ASIN: <span class="data-color" style="margin-right: 8px">{{ scope.row.asin ? scope.row.asin : '--' }}</span>
+                              </span>
+                              <span>
+                                SKU: <span class="data-color">{{ scope.row.sku ? scope.row.sku : '--' }}</span>
+                              </span>
                             </div>
-                            <span>
-                              ASIN: <span class="data-color" style="margin-right: 8px;">{{ scope.row.asin ? scope.row.asin : '--' }}</span>
-                            </span>
-                            <span>
-                              SKU: <span class="data-color">{{ scope.row.sku ? scope.row.sku : '--' }}</span>
-                            </span>
-                            </div>      
                           </div>
                         </template>
                       </el-table-column>
@@ -170,7 +170,7 @@
                   <el-tab-pane label="输入" name="second">
                     <el-input
                       v-model="textarea"
-                      :rows="15"
+                      :rows="20"
                       type="textarea"
                       placeholder="请输入ASIN,多个ASIN使用逗号、空格或换行符分隔。"
                       maxlength="11000" />
@@ -180,7 +180,7 @@
                     <el-row :gutter="12" style="margin-top: 50px">
                       <el-col :span="12">
                         <el-card class="card-box" shadow="never" style="border: none; background-color: #e3f0de; height: 50px">
-                          <div style="line-height: 15px">Always</div>
+                          <div style="line-height: 15px">成功添加:</div>
                           <div style="line-height: 15px">
                             <el-icon style="color: #8fc47d; font-size: 25px"><SuccessFilled /></el-icon>
                           </div>
@@ -188,7 +188,7 @@
                       </el-col>
                       <el-col :span="12">
                         <el-card class="card-box" shadow="never" style="border: none; background-color: #fbe6e3; height: 50px">
-                          <div style="line-height: 15px">Never</div>
+                          <div style="line-height: 15px">未成功添加:</div>
                           <div style="line-height: 15px">
                             <el-icon style="color: #e3918d; font-size: 25px"><CircleCloseFilled /></el-icon>
                           </div>
@@ -202,7 +202,7 @@
                 <el-card class="box-card" shadow="never">
                   <template #header>
                     <div class="card-header">
-                      <span style="font-weight: 550; font-size: 15px; color: #1f2128;">已添加: {{ addedData.length }}</span>
+                      <span style="font-weight: 550; font-size: 15px; color: #1f2128">已添加: {{ addedData.length }}</span>
                       <el-button class="button" text @click="delAll">全部删除</el-button>
                     </div>
                   </template>
@@ -219,37 +219,39 @@
                     @selection-change="handleAddedChange">
                     <el-table-column type="selection" width="50" />
                     <el-table-column prop="asin" label="ASIN" width="538">
-                        <template #default="scope">
-                          <div style="display: flex; align-items: center;">
-                            <div style=" margin-right: 8px; line-height: normal;">
-                              <el-image class="img-box" :src="scope.row.image_link" />
-                            </div>
-                            <div>
-                              <el-tooltip class="box-item" effect="dark" :content="scope.row.title" placement="top">
+                      <template #default="scope">
+                        <div style="display: flex; align-items: center">
+                          <div style="margin-right: 8px; line-height: normal">
+                            <el-image class="img-box" :src="scope.row.image_link" />
+                          </div>
+                          <div>
+                            <el-tooltip class="box-item" effect="dark" :content="scope.row.title" placement="top">
                               <div class="single-line">{{ scope.row.title ? scope.row.title : '--' }}</div>
                             </el-tooltip>
                             <div class="data-color">
-                              <span style="font-weight: 500; color: rgb(30, 33, 41);">${{ scope.row.price ? scope.row.price : '--' }}</span>
-                              <span style="margin: 0 5px; color: #cacdd4;">|</span>
-                              <span style="color: #6d7784;">{{ scope.row.quantity }}</span>
+                              <span style="font-weight: 500; color: rgb(30, 33, 41)">${{ scope.row.price ? scope.row.price : '--' }}</span>
+                              <span style="margin: 0 5px; color: #cacdd4">|</span>
+                              <span style="color: #6d7784">{{ scope.row.quantity }}</span>
                             </div>
-                            <span>ASIN: 
-                              <span class="data-color" style="margin-right: 8px;">{{ scope.row.asin ? scope.row.asin : '--' }}</span>
+                            <span
+                              >ASIN:
+                              <span class="data-color" style="margin-right: 8px">{{ scope.row.asin ? scope.row.asin : '--' }}</span>
                             </span>
-                            <span>SKU: 
+                            <span
+                              >SKU:
                               <span class="data-color">{{ scope.row.sku ? scope.row.sku : '--' }}</span>
                             </span>
-                            </div>      
                           </div>
-                        </template>
-                      </el-table-column>
+                        </div>
+                      </template>
+                    </el-table-column>
                     <el-table-column prop="name" label="Name" width="120" align="right">
                       <template #header>
                         <el-button type="primary" size="normal" link @click="handleDel">删除已选中</el-button>
                       </template>
                       <template #default="scope">
-                          <el-button type="primary" size="small" @click="delSingle(scope)" text>删除</el-button>
-                        </template>
+                        <el-button type="primary" size="small" @click="delSingle(scope)" text>删除</el-button>
+                      </template>
                     </el-table-column>
                   </el-table>
                 </div>
@@ -257,6 +259,87 @@
             </div>
           </el-form-item>
 
+          <div class="column-item">
+            <p style="color: #606266; font-weight: 450">自动定向</p>
+            <el-radio-group v-model="ruleForm.autoRedirect" @change="changeBid">
+              <div style="display: flex">
+                <el-radio label="defaultBid">设置默认出价</el-radio>
+                <el-form-item prop="defaultBidInp">
+                  <el-input v-model="ruleForm.defaultBidInp" label="ruleForm.defaultBidInp" style="width: 200px">
+                    <template #prepend>$</template>
+                  </el-input>
+                </el-form-item>
+              </div>
+              <div>
+                <el-radio label="targetBid">按目标组设置出价</el-radio>
+              </div>
+            </el-radio-group>
+          </div>
+
+          <el-card v-if="showCard" class="box-card">
+            <div>
+              <div style="color: #8e9095">
+                <span>目标群体</span>
+                <span class="suggested-bid-item">建议竞价</span>
+                <span>竞价</span>
+              </div>
+              <div style="display: flex">
+                <el-switch v-model="ruleForm.closeMatch" size="small" active-text="紧密匹配" />
+                <span class="suggested-bid-item">--</span>
+                <el-form-item prop="closeMatchInp">
+                  <el-input :disabled="!ruleForm.closeMatch" v-model="ruleForm.closeMatchInp" placeholder="Please input" class="bid-input">
+                    <template #prepend>$</template>
+                  </el-input>
+                </el-form-item>
+              </div>
+              <div>
+                <div style="display: flex">
+                  <el-switch v-model="ruleForm.broadMatch" size="small" active-text="广泛匹配" />
+                  <span class="suggested-bid-item">--</span>
+                  <el-form-item prop="broadMatchInp">
+                    <el-input :disabled="!ruleForm.broadMatch" v-model="ruleForm.broadMatchInp" placeholder="Please input" class="bid-input">
+                      <template #prepend>$</template>
+                    </el-input>
+                  </el-form-item>
+                </div>
+              </div>
+              <div>
+                <div style="display: flex">
+                  <el-switch v-model="ruleForm.similarProducts" size="small" active-text="同类商品" />
+                  <span class="suggested-bid-item">--</span>
+                  <el-form-item prop="similarProductsInp">
+                    <el-input
+                      :disabled="!ruleForm.similarProducts"
+                      v-model="ruleForm.similarProductsInp"
+                      placeholder="Please input"
+                      class="bid-input">
+                      <template #prepend>$</template>
+                    </el-input>
+                  </el-form-item>
+                </div>
+              </div>
+              <div>
+                <div style="display: flex">
+                  <el-switch v-model="ruleForm.relatedProducts" size="small" active-text="关联商品" />
+                  <span class="suggested-bid-item">--</span>
+                  <el-form-item prop="relatedProductsInp">
+                    <el-input
+                      :disabled="!ruleForm.relatedProducts"
+                      v-model="ruleForm.relatedProductsInp"
+                      placeholder="Please input"
+                      class="bid-input">
+                      <template #prepend>$</template>
+                    </el-input>
+                  </el-form-item>
+                </div>
+              </div>
+            </div>
+          </el-card>
+
+          <el-form-item label="手动" v-if="ruleForm.type === 'manual'">
+            <el-card>1233</el-card>
+          </el-form-item>
+
           <br />
           <el-form-item>
             <el-button type="primary" @click="submitForm(ruleFormRef)">Create</el-button>
@@ -269,7 +352,7 @@
 </template>
 
 <script lang="ts" setup>
-  import { onMounted, reactive, ref, computed } from 'vue'
+  import { onMounted, reactive, ref, computed, watch } from 'vue'
   import { useRoute } from 'vue-router'
   import type { FormInstance, FormRules, TabsPaneContext } from 'element-plus'
   import { Search } from '@element-plus/icons-vue'
@@ -280,25 +363,27 @@
   import axios from 'axios'
   import { request } from '/@/utils/service'
 
-
   const router = useRouter()
   const route = useRoute()
   const shopInfo = useShopInfo()
-  const publicData = usePublicData()
-  const { dateRange } = storeToRefs(publicData)
   const { profile } = storeToRefs(shopInfo)
-  const queryParams = ref({
-    profileId: profile.value.profile_id,
-    dateRange,
-  })
   const loading = ref(true)
   const fullTableData = ref([]) // 表格数据
-  let addedData = ref([])   // 已添加的商品数据
-  let selections = []  // 添加选中的项
-  let addedSels = []  // 删除选中的项
+  let addedData = ref([]) // 已添加的商品数据
+  let selections = [] // 添加选中的项
+  let addedSels = [] // 删除选中的项
   const currentPage = ref() // 当前页
   const pageSize = ref(20) // 每页显示条目数
   const totalItems = ref() // 数据总量
+  const showCard = ref(false)
+
+  // 当单选按钮变化时更新showCard状态
+  function changeBid() {
+    console.log(ruleForm.autoRedirect)
+    showCard.value = ruleForm.autoRedirect === 'targetBid'
+  }
+  // 切换投放类型
+  function changeType() {}
 
   function setTableData(asin = '', sku = '') {
     return request({
@@ -311,12 +396,14 @@
         asin,
         sku,
       },
-      }).then((resp) => {
+    })
+      .then((resp) => {
         fullTableData.value = resp.data
         totalItems.value = resp.total
         currentPage.value = resp.page
         loading.value = false
-      }).catch((error) => {
+      })
+      .catch((error) => {
         console.error('Error fetching data:', error)
         loading.value = false
       })
@@ -341,8 +428,8 @@
   // 添加已选中的项
   function handleAdd() {
     // 过滤掉已经存在于addedData.value中的项
-    const newSelections = selections.filter(sel => 
-      !addedData.value.some(added => added.sku === sel.sku)  // 假设使用sku作为唯一标识
+    const newSelections = selections.filter(
+      (sel) => !addedData.value.some((added) => added.sku === sel.sku) // 假设使用sku作为唯一标识
     )
     // 如果有新的不重复项,加入到addedData.value中
     if (newSelections.length > 0) {
@@ -356,15 +443,13 @@
   }
   // 删除第二个table中已经选中的项
   function handleDel() {
-    addedData.value = addedData.value.filter(
-    (item) => !addedSels.includes(item)
-    )
+    addedData.value = addedData.value.filter((item) => !addedSels.includes(item))
     addedSels = []
   }
   function addSingle(scope) {
     console.log('scope', scope.row)
 
-    const isAlreadyAdded = addedData.value.some(item => item.sku === scope.row.sku)
+    const isAlreadyAdded = addedData.value.some((item) => item.sku === scope.row.sku)
     if (!isAlreadyAdded) {
       addedData.value.push(scope.row)
     } else {
@@ -372,7 +457,7 @@
     }
   }
   function delSingle(scope) {
-    const index = addedData.value.findIndex(item => item.sku === scope.row.sku)
+    const index = addedData.value.findIndex((item) => item.sku === scope.row.sku)
 
     if (index !== -1) {
       addedData.value.splice(index, 1)
@@ -403,22 +488,12 @@
     if (select.value === 'asin' && searchInp.value) {
       loading.value = true
       setTableData(value)
-    } else if (select.value === 'sku'  && searchInp.value) {
+    } else if (select.value === 'sku' && searchInp.value) {
       loading.value = true
       setTableData('', value)
     }
   }
 
-  // 修改表头样式
-  const headerCellStyle = (args) => {
-    // console.log('args', args)
-    if (args.rowIndex === 0) {
-      return {
-        backgroundColor: 'rgba(245, 245, 245, 0.9)',
-      }
-    }
-  }
-
   // const size = ref('default')
   // const labelPosition = ref('top')
   interface RuleForm {
@@ -435,6 +510,16 @@
     firstPage: string
     other: string
     adGroupName: string
+    autoRedirect: string
+    defaultBidInp: string
+    closeMatch: boolean
+    broadMatch: boolean
+    similarProducts: boolean
+    relatedProducts: boolean
+    closeMatchInp: string
+    broadMatchInp: string
+    similarProductsInp: string
+    relatedProductsInp: string
   }
 
   const formSize = ref('default')
@@ -454,8 +539,18 @@
     firstPage: '',
     other: '',
     adGroupName: '',
+    autoRedirect: 'defaultBid',
+    defaultBidInp: '',
+    closeMatch: true,
+    broadMatch: true,
+    similarProducts: true,
+    relatedProducts: true,
+    closeMatchInp: '',
+    broadMatchInp: '',
+    similarProductsInp: '',
+    relatedProductsInp: '',
   })
-  const rules = reactive<FormRules<RuleForm>>({
+  const rules = computed(()=>({
     name: [{ required: true, message: 'Please input Activity name', trigger: 'blur' }],
     adMix: [{ required: false, message: 'Please select Activity zone', trigger: 'change' }],
     count: [{ required: true, message: 'Please select Activity count', trigger: 'change' }],
@@ -471,8 +566,91 @@
     firstPage: [{ required: false, pattern: /^[0-9]{1,3}$/, message: '必须是0~900之间的整数百分比', trigger: 'change' }],
     other: [{ required: false, pattern: /^[0-9]{1,3}$/, message: '必须是0~900之间的整数百分比', trigger: 'change' }],
     adGroupName: [{ required: true, message: 'Please input Activity name', trigger: 'blur' }],
+    autoRedirect: [
+      { required: true, trigger: 'change' },
+      // {
+      //   validator: (rule, value, callback) => {
+      //     if (value === 'defaultBid') {
+      //       console.log(value)
+      //       const bid = parseFloat(ruleForm.defaultBidInp)
+      //       const budget = parseFloat(ruleForm.budget)
+      //       // 对 defaultBidInp 进行更细致的验证
+      //       if (isNaN(bid) || bid < 0.02 || bid > 1000) {
+      //         callback(new Error('默认出价必须在0.02到1000之间'))
+      //       } else if (bid >= budget) { // 确保默认出价小于预算
+      //         callback(new Error('默认出价必须小于预算'))
+      //       } else {
+      //         callback() // 通过验证
+      //       }
+      //     } else {
+      //       callback() // 如果没有选择 'defaultBid',则直接通过验证
+      //     }
+      //   },
+      //   trigger: 'blur' // 触发时机改为 'change' 以响应 radio 的变化
+      // }
+    ],
+    defaultBidInp: [
+      { required: true, message: '此项为必填项', trigger: 'blur' },
+      { validator: validateDefaultBidInp, trigger: 'blur' },
+    ],
+    // relatedProductsInp 的校验规则
+    relatedProductsInp: [
+      { required: ruleForm.relatedProducts, message: '此项为必填项', trigger: 'blur' },
+      {
+        validator: (rule, value, callback) => (ruleForm.relatedProducts ? checkBid(value, callback, 'relatedProductsInp') : callback()),
+        trigger: 'blur',
+      },
+    ],
+    // similarProductsInp 的校验规则
+    similarProductsInp: [
+      { required: ruleForm.similarProducts, message: '此项为必填项', trigger: 'blur' },
+      {
+        validator: (rule, value, callback) => (ruleForm.similarProducts ? checkBid(value, callback, 'similarProductsInp') : callback()),
+        trigger: 'blur',
+      },
+    ],
+    // broadMatchInp 的校验规则
+    broadMatchInp: [
+      { required: ruleForm.broadMatch, message: '此项为必填项', trigger: 'blur' },
+      { validator: (rule, value, callback) => (ruleForm.broadMatch ? checkBid(value, callback, 'broadMatchInp') : callback()), trigger: 'blur' },
+    ],
+    // closeMatchInp 的校验规则
+    closeMatchInp: [
+      { required: ruleForm.closeMatch, message: '此项为必填项', trigger: 'blur' },
+      { validator: (rule, value, callback) => (ruleForm.closeMatch ? checkBid(value, callback, 'closeMatchInp') : callback()), trigger: 'blur' },
+    ],
+  }))
+
+  // 1. 定义验证方法
+  function checkBid(value, callback, bidField) {
+    const bid = parseFloat(value)
+    const budget = parseFloat(ruleForm.budget)
+    if (isNaN(bid)) {
+      callback(new Error('请输入数字值'))
+    } else if (bid < 0.02 || bid > 1000) {
+      callback(new Error('值必须在0.02到1000之间'))
+    } else if (bid >= budget) {
+      callback(new Error('出价必须小于预算'))
+    } else {
+      callback() // 通过验证
+    }
+  }
+
+  const validateDefaultBidInp = (rule: any, value: any, callback: any) => {
+    if (ruleForm.autoRedirect === 'defaultBid') {
+      checkBid(value, callback, 'defaultBidInp')
+    }  else {
+      callback()
+    }
+  }
+
+  watch(() => ruleForm.autoRedirect, (newVal) => {
+    if (newVal !== 'defaultBid') {
+      ruleFormRef.value?.clearValidate('defaultBidInp')
+    }
   })
 
+
   async function submitForm(formEl: FormInstance | undefined) {
     if (!formEl) return
     await formEl.validate((valid, fields) => {
@@ -494,10 +672,6 @@
   //   label: `${idx + 1}`,
   // }))
 
-  function changeType() {
-    console.log(ruleForm.type)
-  }
-
   // 商品模块
   const activeName = ref('first')
 
@@ -511,77 +685,15 @@
   const textarea = ref('')
   const buttons = [{ type: 'primary', text: '添加' }] as const
 
-  // const pagedTableData = [
-  //   {
-  //     date: '2016-05-03',
-  //     name: 'Tom',
-  //     address: 'No. 189, Grove St, Los Angeles',
-  //   },
-  //   {
-  //     date: '2016-05-02',
-  //     name: 'Tom',
-  //     address: 'No. 189, Grove St, Los Angeles',
-  //   },
-  //   {
-  //     date: '2016-05-04',
-  //     name: 'Tom',
-  //     address: 'No. 189, Grove St, Los Angeles',
-  //   },
-  //   {
-  //     date: '2016-05-01',
-  //     name: 'Tom',
-  //     address: 'No. 189, Grove St, Los Angeles',
-  //   },
-  //   {
-  //     date: '2016-05-08',
-  //     name: 'Tom',
-  //     address: 'No. 189, Grove St, Los Angeles',
-  //   },
-  //   {
-  //     date: '2016-05-06',
-  //     name: 'Tom',
-  //     address: 'No. 189, Grove St, Los Angeles',
-  //   },
-  //   {
-  //     date: '2016-05-07',
-  //     name: 'Tom',
-  //     address: 'No. 189, Grove St, Los Angeles',
-  //   },
-  //   {
-  //     date: '2016-05-07',
-  //     name: 'Tom',
-  //     address: 'No. 189, Grove St, Los Angeles',
-  //   },
-  //   {
-  //     date: '2016-05-07',
-  //     name: 'Tom',
-  //     address: 'No. 189, Grove St, Los Angeles',
-  //   },
-  //   {
-  //     date: '2016-05-07',
-  //     name: 'Tom',
-  //     address: 'No. 189, Grove St, Los Angeles',
-  //   },
-  //   {
-  //     date: '2016-05-07',
-  //     name: 'Tom',
-  //     address: 'No. 189, Grove St, Los Angeles',
-  //   },
-  //   {
-  //     date: '2016-05-07',
-  //     name: 'Tom',
-  //     address: 'No. 189, Grove St, Los Angeles',
-  //   },
-  //   {
-  //     date: '2016-05-07',
-  //     name: 'Tom',
-  //     address: 'No. 189, Grove St, Los Angeles',
-  //   },
-  // ]
-
-  // 分页器相关状态
-
-  // 后端获取的完整数据
+  // 修改表头样式
+  const headerCellStyle = (args) => {
+    // console.log('args', args)
+    if (args.rowIndex === 0) {
+      return {
+        backgroundColor: 'rgba(245, 245, 245, 0.9)',
+      }
+    }
+  }
 
   onMounted(() => {
     setTableData()
@@ -592,7 +704,6 @@
   defineOptions({
     name: 'SpCreateCampaigns',
   })
-
 </script>
 
 <style lang="scss" scoped>
@@ -698,4 +809,15 @@
     border: 1px solid rgb(194, 199, 207);
     border-radius: 4px;
   }
+  .target-group-item {
+    margin-top: 15px;
+  }
+  .suggested-bid-item {
+    margin-left: 230px;
+    margin-right: 60px;
+  }
+  .bid-input {
+    width: 200px;
+    margin-left: 15px;
+  }
 </style>