Quellcode durchsuchen

✨ feat: 新增视频下的创意板块

WanGxC vor 1 Jahr
Ursprung
Commit
a7e391cb73

+ 0 - 1
src/views/adManage/sb/campaigns/CreateCampaigns/component/AdCampaign.vue

@@ -159,7 +159,6 @@ const adMixOptions = ref([])
 async function buildAdMix() {
   try {
     const response = await getAdMixSelect()
-    console.log('🚀 ~ buildAdMix ~ resp-->>', response)
     adMixOptions.value = response.data.map((option) => {
       return {
         value: option.portfolioId,

+ 22 - 10
src/views/adManage/sb/campaigns/CreateCampaigns/component/AdFormat.vue

@@ -53,12 +53,12 @@
                 status-icon>
                 <div style="display: flex; margin-top: 10px">
                   <el-form-item label="选择一个店铺" prop="shop" style="width: 48%; margin-right: 10px">
-                    <el-select style="width: 100%">
+                    <el-select v-model="flagshipStoreRuleForm.shop" clearable style="width: 100%">
                       <el-option v-for="item in shopOptions" :key="item.value" :label="item.label" :value="item.value" />
                     </el-select>
                   </el-form-item>
-                  <el-form-item label="选择一个页面" prop="page" style="width: 48%">
-                    <el-select style="width: 100%">
+                  <el-form-item label="选择一个页面" prop="page" clearable style="width: 48%">
+                    <el-select v-model="flagshipStoreRuleForm.page" style="width: 100%">
                       <el-option v-for="item in pageOptions" :key="item.value" :label="item.label" :value="item.value" />
                     </el-select>
                   </el-form-item>
@@ -113,7 +113,7 @@
 </template>
 
 <script setup lang="ts">
-import { ref, reactive } from 'vue'
+import { ref, reactive, defineEmits, watch } from 'vue'
 import type { FormInstance, FormRules } from 'element-plus'
 import ProductSetCommodity from '../component/ProductSetCommodity.vue'
 import VideoCommodity from '../component/VideoCommodity.vue'
@@ -147,12 +147,8 @@ const flagshipStoreRules2 = reactive<FormRules<flagshipStoreRuleForm2>>({
 
 const shopOptions = [
   {
-    value: '1',
-    label: '1',
-  },
-  {
-    value: '2',
-    label: '2',
+    value: 'zosi',
+    label: 'ZOSI',
   },
 ]
 const pageOptions = [
@@ -175,6 +171,22 @@ const focusShopOptions = [
     label: '2',
   },
 ]
+
+const emit = defineEmits(['update:adFormatRadio', 'update:arrivalsRadio', 'update:flagshipStoreShop'])
+
+// 监听 adFormatRadio 的变化并触发事件
+watch(adFormatRadio, (newValue) => {
+  emit('update:adFormatRadio', newValue)
+},{ immediate: true })
+
+watch(arrivalsRadio, (newValue) => {
+  emit('update:arrivalsRadio', newValue)
+},{ immediate: true })
+
+watch(() => flagshipStoreRuleForm.shop, (newValue) => {
+  emit('update:flagshipStoreShop', newValue)
+})
+
 </script>
 
 <style scoped>

+ 1 - 1
src/views/adManage/sb/campaigns/CreateCampaigns/component/KeywordTarget.vue

@@ -63,7 +63,7 @@
           </div>
         </el-card>
         <div style="display: flex; justify-content: space-around; padding-top: 0px">
-          <el-button type="primary" plain>保存</el-button>
+          <el-button type="primary" plain :disabled="!addedKeyWordsTableData.length">保存</el-button>
         </div>
       </div>
     </div>

+ 59 - 103
src/views/adManage/sb/campaigns/CreateCampaigns/component/NegativeGood.vue

@@ -1,55 +1,65 @@
 <template>
   <div prop="matchType" style="width: 100%; margin-top: 20px">
+    <el-divider content-position="left">
+      <span style="font-size: 18px; font-weight: 700">否定商品</span>
+    </el-divider>
     <div style="width: 100%; height: 600px; display: flex; border: 1px solid #e5e7ec; border-radius: 6px" v-loading="negativeGoodsLoading">
       <div style="width: 50%; border-right: 1px solid #e5e7ec">
-        <el-tabs v-model="negativeTabs" class="demo-tabs">
-          <el-tab-pane label="搜索" name="first">
-            <div style="margin-bottom: 10px">
-              <el-input placeholder="按ASIN搜索" v-model="negativeInput" @change="searchNegativeGoods" clearable />
-            </div>
-            <el-table
-              height="495"
-              style="width: 100%"
-              v-loading="loading"
-              :data="negativeTableData"
-              :header-cell-style="headerCellStyle"
-              :show-header="false">
-              <el-table-column prop="asin" label="商品">
-                <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>
-                      <span>
-                        ASIN: <span class="data-color" style="margin-right: 8px">{{ scope.row.asin ? scope.row.asin : '--' }}</span>
-                      </span>
-                    </div>
-                  </div>
-                </template>
-              </el-table-column>
-              <el-table-column prop="name" label="Name" width="120" align="right">
-                <template #header> </template>
-                <template #default="scope">
-                  <el-button type="primary" size="small" @click="addSingleNegativeGoods(scope)" text>添加</el-button>
-                </template>
-              </el-table-column>
-            </el-table>
+        <el-tabs v-model="topTabs" stretch>
+          <el-tab-pane label="排除商品" name="first">
+            <el-tabs v-model="negativeTabs" class="demo-tabs">
+              <el-tab-pane label="搜索" name="first">
+                <div style="margin-bottom: 10px">
+                  <el-input placeholder="按ASIN搜索" v-model="negativeInput" @change="searchNegativeGoods" clearable />
+                </div>
+                <el-table
+                  height="495"
+                  style="width: 100%"
+                  v-loading="loading"
+                  :data="negativeTableData"
+                  :header-cell-style="headerCellStyle"
+                  :show-header="false">
+                  <el-table-column prop="asin" label="商品">
+                    <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>
+                          <span>
+                            ASIN: <span class="data-color" style="margin-right: 8px">{{ scope.row.asin ? scope.row.asin : '--' }}</span>
+                          </span>
+                        </div>
+                      </div>
+                    </template>
+                  </el-table-column>
+                  <el-table-column prop="name" label="Name" width="120" align="right">
+                    <template #header> </template>
+                    <template #default="scope">
+                      <el-button type="primary" size="small" @click="addSingleNegativeGoods(scope)" text>添加</el-button>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </el-tab-pane>
+              <el-tab-pane label="输入" name="second">
+                <el-input
+                  v-model="negativeGoodsTextarea"
+                  :rows="17"
+                  type="textarea"
+                  placeholder="未完成"
+                  maxlength="11000"
+                  style="padding: 10px 10px" />
+                <div style="display: flex; flex-direction: row-reverse; margin-top: 10px">
+                  <el-button style="margin-right: 10px" type="primary" text bg @click="addNegativeGoods">添加</el-button>
+                </div>
+              </el-tab-pane>
+            </el-tabs>
           </el-tab-pane>
-          <el-tab-pane label="输入" name="second">
-            <el-input
-              v-model="negativeGoodsTextarea"
-              :rows="17"
-              type="textarea"
-              placeholder="未完成"
-              maxlength="11000"
-              style="padding: 10px 10px" />
-            <div style="display: flex; flex-direction: row-reverse; margin-top: 10px">
-              <el-button style="margin-right: 10px" type="primary" text bg @click="addNegativeGoods">添加</el-button>
-            </div>
+          <el-tab-pane label="排除品牌" name="second">
+
           </el-tab-pane>
         </el-tabs>
       </div>
@@ -116,6 +126,7 @@ const currentPage = ref() // 当前页
 const pageSize = ref(20) // 每页显示条目数
 const totalItems = ref() // 数据总量
 const negativeTabs = ref('first')
+const topTabs = ref('first')
 const loading = ref(false)
 const respCampaignId = inject<Ref>('respCampaignId')
 const respAdGroupId = inject<Ref>('respAdGroupId')
@@ -262,23 +273,6 @@ const headerCellStyle = (args) => {
 ::v-deep(.el-form--default.el-form--label-top .el-form-item .el-form-item__label) {
   font-weight: 500;
 }
-.column-item .el-radio-group {
-  display: inline-flex;
-  font-size: 0;
-  flex-direction: column;
-  align-items: flex-start;
-}
-.radio-description {
-  font-size: 12px;
-  color: #666;
-  margin-top: -18px;
-  margin-left: 22px;
-}
-.radio-description-2 {
-  font-size: 12px;
-  color: #666;
-  margin-top: -10px;
-}
 .column-margin-bottom label.el-radio.is-bordered {
   margin-bottom: 10px;
   padding: 35px;
@@ -287,17 +281,6 @@ const headerCellStyle = (args) => {
   margin-top: -18px;
   margin-left: -15px;
 }
-.gap-items {
-  display: flex;
-  justify-content: flex-start;
-  width: 100%;
-  margin-bottom: 20px;
-}
-.gap-item {
-  width: 200px;
-  margin-left: 30px;
-  color: #0b0d0d;
-}
 .demo-tabs > .el-tabs__content {
   padding: 52px;
   color: #6b778c;
@@ -305,7 +288,7 @@ const headerCellStyle = (args) => {
   font-weight: 600;
 }
 /* 广告组商品Tab栏 */
-::v-deep(.el-tabs__nav-scroll) {
+::v-deep(.demo-tabs .el-tabs__nav-scroll) {
   overflow: hidden;
   margin-left: 20px;
 }
@@ -358,18 +341,6 @@ div {
   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;
-}
-
 ::v-deep(.goods-orientation-tabs .el-tabs__nav-scroll) {
   margin-left: -20px !important;
 }
@@ -380,19 +351,4 @@ div {
   /* 商品定向Tab栏 */
   border-right: 0;
 }
-.custom-tree-node {
-  /* el-tree自定义样式 */
-  flex: 1;
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  font-size: 14px;
-  padding-right: 8px;
-}
-.dialog-head {
-  /* 弹窗样式 */
-  display: flex;
-  flex-direction: row;
-  justify-content: space-between;
-}
 </style>

+ 33 - 31
src/views/adManage/sb/campaigns/CreateCampaigns/component/ProductOrientation.vue

@@ -92,10 +92,9 @@
                   </el-form>
                   <template #footer>
                     <div style="display: flex; justify-content: space-between">
-                      <span v-loading="countLoadig"
-                        >定位到的商品数量:
-                        <span v-if="dialogForm.isCount == true">{{ commodityCount[0]?.min }} - {{ commodityCount[0]?.max }}</span></span
-                      >
+                      <span v-loading="countLoadig">定位到的商品数量:
+                        <span v-if="dialogForm.isCount == true">{{ commodityCount[0]?.min }} - {{ commodityCount[0]?.max }}</span>
+                      </span>
                       <span class="dialog-footer">
                         <el-button @click="visible = false">取消</el-button>
                         <el-button type="primary" @click="dialogFormSubmit">确定</el-button>
@@ -227,7 +226,7 @@
 </template>
 
 <script setup lang="ts">
-import { CSSProperties, Ref, inject, reactive, ref } from 'vue'
+import { CSSProperties, Ref, inject, onMounted, reactive, ref } from 'vue'
 import { useShopInfo } from '/@/stores/shopInfo'
 import { storeToRefs } from 'pinia'
 import { ElMessage } from 'element-plus'
@@ -255,6 +254,7 @@ const categoryBiddingTypeOptions = [
     label: '自定义竞价',
   },
 ]
+const categoryBidInput = ref('0.75')
 const singleGoodsBidSelect = ref('customBid')
 const singleGoodsBidTypeOptions = [
   {
@@ -281,7 +281,8 @@ const countLoadig = ref(false)
 const visible = ref(false)
 let dialogTitle = ref('')
 let categoryId = ref('')
-
+const dialogselectValue = ref('')
+let dialogOptions: any = ref([])
 const dialogForm: any = reactive({
   prices: {
     lowest: undefined,
@@ -322,6 +323,7 @@ async function validatePrices(rule, value) {
 }
 
 async function setProductOrientationData() {
+  productOrientationLoading.value = true
   try {
     const resp = await request({
       url: '/api/ad_manage/targetable/categories/',
@@ -450,22 +452,22 @@ function singleGoodsSearchChaneged() {
   setSearchTableData()
 }
 function addSingleSearch(scope) {
-  console.log('🚀 ~ addSingleSearch ~ scope-->>', scope)
+  console.log('🚀 ~ addSingleSearch ~ scope-->>', scope);
 
-  const typesToAdd = []
+  const typesToAdd = [];
   if (expand.value) {
-    typesToAdd.push('ASIN_EXPANDED_FROM')
+    typesToAdd.push('ASIN_EXPANDED_FROM');
   }
   if (accurate.value) {
-    typesToAdd.push('ASIN_SAME_AS')
+    typesToAdd.push('ASIN_SAME_AS');
   }
   const productTypeMap = {
     ASIN_EXPANDED_FROM: '扩展',
     ASIN_SAME_AS: '精确',
-  }
+  };
 
   typesToAdd.forEach((productType) => {
-    const isAlreadyAdded = productOrientationTableData.value.some((item) => item.sku === scope.row.sku && item.productType === productType)
+    const isAlreadyAdded = productOrientationTableData.value.some(item => item.sku === scope.row.sku && item.productType === productType);
 
     if (!isAlreadyAdded) {
       const newData = {
@@ -474,14 +476,15 @@ function addSingleSearch(scope) {
         sku: scope.row.sku,
         productType: productType,
         productTypeText: productTypeMap[productType],
-      }
-      productOrientationTableData.value.push(newData)
+      };
+      productOrientationTableData.value.push(newData);
     } else {
-      console.log(`${productType} item is already added.`)
+      console.log(`${productType} item is already added.`);
     }
-  })
+  });
 }
 
+
 let selectedLabels = ref([]) // 选中的label数组
 function dialogSelectChange(event) {
   console.log('🚀 ~ dialogSelectChange ~ event-->>', event)
@@ -556,24 +559,26 @@ function dialogFormSubmit() {
 
 // 定向按钮功能
 function orientate(node, data) {
-  console.log('🚀 ~ orientate ~ data-->>', data)
-  const exists = productOrientationTableData.value.some((item) => item.cid === data.cid)
+  console.log('🚀 ~ orientate ~ data-->>', data);
+  const exists = productOrientationTableData.value.some(item => item.cid === data.cid);
 
   if (!exists) {
     const newData = {
       type: 'c',
       classification: data.cna,
       classificationId: data.cid,
-    }
-    productOrientationTableData.value.push(newData)
+    };
+    productOrientationTableData.value.push(newData);
   }
 }
 
+
+
 let productTargetBidList = ref([])
 async function productTagetSave() {
   console.log('tableData', productOrientationTableData.value)
   // 检查是否存在 bid 为空的行
-  const hasEmptyBid = productOrientationTableData.value.some((row) => row.bid == null || row.bid === '')
+  const hasEmptyBid = productOrientationTableData.value.some(row => row.bid == null || row.bid === '')
   // 直接返回,不继续执行
   if (hasEmptyBid) {
     console.log('存在空的 bid,不发送请求')
@@ -591,7 +596,7 @@ async function productTagetSave() {
       adGroupId: respAdGroupId.value,
       campaignId: respCampaignId.value,
       expressionList: productOrientationTableData.value,
-      state: 'PAUSED',
+      state: "PAUSED"
     }
     const filteredRequestData = Object.fromEntries(Object.entries(requestData).filter(([_, v]) => v != null))
     const resp = await request({
@@ -619,15 +624,7 @@ async function productTagetSave() {
   productOrientationTableData.value = []
   productTargetBidList.value = []
 }
-// 点击表格选项触发事件
-function handleSelectionChange(selection) {
-  selections = selection
-}
-// 获取addedTable中已选中的项
-function handleAddedGoodsChange(selection) {
-  addedSels = selection
-}
-// 添加已选中的项
+
 function handleGoodsAdd() {
   // 过滤掉已经存在于addedData.value中的项
   const newSelections = selections.filter(
@@ -665,6 +662,11 @@ function changeKeyWordsTableHeader(args) {
     }
   }
 }
+
+onMounted(() => {
+  setProductOrientationData()
+})
+
 </script>
 
 <style lang="scss" scoped>

+ 228 - 0
src/views/adManage/sb/campaigns/CreateCampaigns/component/VideoCreativity1.vue

@@ -0,0 +1,228 @@
+<template>
+  <div class="customize-container">
+    <el-card body-style="padding: 20px 80px 0 80px;">
+      <div style="font-weight: 700; padding-bottom: 18px">
+        <span style="color: #306cd7; font-size: 26px">|</span>
+        <span style="font-size: 18px; padding-left: 5px">创意</span>
+      </div>
+      <el-form
+        ref="ruleFormRef"
+        :model="ruleForm"
+        :rules="rules"
+        label-width="120px"
+        class="demo-ruleForm"
+        size="default"
+        label-position="top"
+        status-icon>
+        <el-form-item label="广告名称" prop="name">
+          <el-input v-model="ruleForm.name" style="width: 50%" />
+        </el-form-item>
+        <el-form-item style="border: 1px solid #dddfe6; padding: 0 0 0 5px">
+          <div style="width: 50%; padding-left: 5px; border-right: 1px solid #dddfe6">
+            <el-scrollbar height="700px">
+              <el-collapse v-model="activeNames" @change="handleChange">
+                <el-collapse-item name="1">
+                  <template #title> <span style="color: #e47470; margin-right: 4px">*</span>品牌名称和徽标</template>
+                  <el-form-item prop="brandName">
+                    <el-input v-model="ruleForm.brandName" style="padding: 0 10px 5px 0"></el-input>
+                  </el-form-item>
+                  <el-upload
+                    class="upload-demo"
+                    drag
+                    action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
+                    multiple
+                    style="padding-right: 10px">
+                    <el-icon class="el-icon--upload"><upload-filled /></el-icon>
+                    <div class="el-upload__text">Drop file here or <em>click to upload</em></div>
+                    <template #tip>
+                      <div style="margin-top: 10px">
+                        <div style="display: flex; justify-content: space-between">
+                          <span class="el-upload__tip">jpg/png files with a size less than 500kb</span>
+                          <el-button type="primary" :icon="Picture">从素材库中选择</el-button>
+                        </div>
+                        <div class="introduce-item">1、图片大小: 400x400 像素或更大</div>
+                        <div class="introduce-item">2、文件大小: 1MB 或更小</div>
+                        <div class="introduce-item">3、文件格式: PNG 或 JPG</div>
+                        <div class="introduce-item">
+                          4、内容: 徽标必须填满图片或置于白色或透明背景上详细了解我们的徽标要求
+                          <span style="margin-left: 25px; position: relative;">
+                            <el-icon size="14" style="position: absolute; left: -14px; top: 1px"><Link /></el-icon>
+                            <el-link
+                              type="primary"
+                              :underline="false"
+                              href="https://advertising.amazon.com/resources/ad-policy/sponsored-ads-policies#brandlogo"
+                              target="_blank"
+                              >查看要求</el-link
+                            >
+                          </span>
+                        </div>
+                      </div>
+                    </template>
+                  </el-upload>
+                </el-collapse-item>
+                <el-collapse-item name="2">
+                  <template #title> <span style="color: #e47470; margin-right: 4px">*</span>视频</template>
+                  <div style="display: flex; align-items: center; justify-content: space-between">
+                    <span style="color: #1e2128; font-size: 15px; font-weight: 450">选择视频</span>
+                    <el-button type="primary" text>查看视频批准提示</el-button>
+                  </div>
+                  <div style="color: #666666; margin-bottom: 10px">
+                    保持视频简短并紧扣主题。视频会自动播放,因此请确保前 2
+                    秒极具吸引力,并且不依靠声音来传递信息。如果您在视频中使用了文字,请确保文字清晰易辨。字幕或音频必须与将展示您广告的区域相匹配。
+                  </div>
+                  <div class="upload-button-group">
+                    <el-upload
+                      v-model:file-list="fileList"
+                      class="upload-demo"
+                      action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
+                      multiple
+                      :on-preview="handlePreview"
+                      :on-remove="handleRemove"
+                      :before-remove="beforeRemove"
+                      :limit="3"
+                      :on-exceed="handleExceed">
+                      <el-button type="primary">上传文件</el-button>
+
+                      <template #tip>
+                        <div class="el-upload__tip">jpg/png files with a size less than 500KB.</div>
+                      </template>
+                    </el-upload>
+                    <el-button type="primary" :icon="Picture" style="margin-left: -120px" @click="handleSelect">从素材库中选择</el-button>
+                  </div>
+                  <div style="display: flex; align-items: center; justify-content: space-between">
+                    <span style="color: #1e2128; font-size: 15px; font-weight: 450">视频文件要求:</span>
+                    <el-button type="primary" text>了解更多</el-button>
+                  </div>
+
+                  <div>
+                    <span style="color: #1e2128; font-size: 13px; font-weight: 450">视频规格</span>
+                    <div class="introduce-item">1.纵横比:16:9</div>
+                    <div class="introduce-item">2.尺寸:1280 x 720 像素、1920 x 1080 像素或 3840 x 2160 像素</div>
+                    <div class="introduce-item">3.文件大小:500MB 或更小</div>
+                    <div class="introduce-item">4.文件格式:MP4 或 MOV</div>
+                    <div class="introduce-item">5.长度:6-45 秒</div>
+                    <div class="introduce-item">6.帧率:23.976、23.98、24、25、29.97 或 29.98 fps</div>
+                    <div class="introduce-item">7.比特率:1 Mbps 或更高</div>
+                    <div class="introduce-item">8.编解码器:H.264 或 H.265</div>
+                    <div class="introduce-item">9.配置文件:主配置文件或基线配置文件</div>
+                    <div class="introduce-item">10.视频流:仅为 1</div>
+                  </div>
+                  <div>
+                    <span style="color: #1e2128; font-size: 13px; font-weight: 450">音频规格</span>
+                    <div class="introduce-item">1.语言:必须与广告投放区域匹配</div>
+                    <div class="introduce-item">2.采样率:44.1 kHz 或更高</div>
+                    <div class="introduce-item">3.编解码器:PCM、AAC 或 MP3</div>
+                    <div class="introduce-item">4.比特率:96 kbps 或更高</div>
+                    <div class="introduce-item">5.格式:立体声或单声道</div>
+                    <div class="introduce-item">6.音频流:仅为 1</div>
+                  </div>
+                </el-collapse-item>
+
+                <el-collapse-item name="3">
+                  <template #title> <span style="color: #e47470; margin-right: 4px">*</span>商品</template>
+                  <el-button type="primary" :icon="Plus" :disabled="true">添加商品</el-button>
+                </el-collapse-item>
+                <el-collapse-item name="4">
+                  <template #title> <span style="color: #e47470; margin-right: 4px">*</span>标题</template>
+                  <el-form-item prop="title">
+                    <el-input v-model="ruleForm.title" maxlength="50" placeholder="请输入标题" show-word-limit style="padding: 0 10px 0 0"></el-input>
+                  </el-form-item>
+                </el-collapse-item>
+              </el-collapse>
+            </el-scrollbar>
+          </div>
+        </el-form-item>
+      </el-form>
+    </el-card>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { reactive, ref } from 'vue'
+import type { FormInstance, FormRules, UploadProps, UploadUserFile } from 'element-plus'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { Plus, Picture } from '@element-plus/icons-vue'
+
+interface RuleForm {
+  name: string
+  brandName: string
+  title: string
+}
+
+const ruleFormRef = ref<FormInstance>()
+const ruleForm = reactive<RuleForm>({
+  name: '视频 广告 - 1/15/2024 17:51:10.236',
+  brandName: '',
+  title: '',
+})
+
+const rules = reactive<FormRules<RuleForm>>({
+  name: [{ required: true, message: '请输入广告名称', trigger: 'blur' }],
+  brandName: [{ required: true, message: '请输入品牌名称', trigger: 'blur' }],
+  title: [{ required: true, message: '请输入标题', trigger: 'blur' }],
+})
+
+const submitForm = async (formEl: FormInstance | undefined) => {
+  if (!formEl) return
+  await formEl.validate((valid, fields) => {
+    if (valid) {
+      console.log('submit!')
+    } else {
+      console.log('error submit!', fields)
+    }
+  })
+}
+
+const activeNames = ref(['1'])
+const handleChange = (val: string[]) => {
+  console.log(val)
+}
+
+const fileList = ref<UploadUserFile[]>([
+  {
+    name: 'element-plus-logo.svg',
+    url: 'https://element-plus.org/images/element-plus-logo.svg',
+  },
+  {
+    name: 'element-plus-logo2.svg',
+    url: 'https://element-plus.org/images/element-plus-logo.svg',
+  },
+])
+
+const handleRemove: UploadProps['onRemove'] = (file, uploadFiles) => {
+  console.log(file, uploadFiles)
+}
+
+const handlePreview: UploadProps['onPreview'] = (uploadFile) => {
+  console.log(uploadFile)
+}
+
+const handleExceed: UploadProps['onExceed'] = (files, uploadFiles) => {
+  ElMessage.warning(`The limit is 3, you selected ${files.length} files this time, add up to ${files.length + uploadFiles.length} totally`)
+}
+
+const beforeRemove: UploadProps['beforeRemove'] = (uploadFile, uploadFiles) => {
+  return ElMessageBox.confirm(`Cancel the transfer of ${uploadFile.name} ?`).then(
+    () => true,
+    () => false
+  )
+}
+
+function handleSelect() {
+  // console.log()
+}
+</script>
+
+<style scoped>
+.customize-container {
+  margin-top: 10px;
+}
+.upload-button-group {
+  display: flex;
+}
+.introduce-item {
+  line-height: 17px;
+  font-size: 12px;
+  color: #88909b;
+}
+</style>

+ 182 - 0
src/views/adManage/sb/campaigns/CreateCampaigns/component/VideoCreativity2.vue

@@ -0,0 +1,182 @@
+<template>
+  <div class="customize-container">
+    <el-card body-style="padding: 20px 80px 0 80px;">
+      <div style="font-weight: 700; padding-bottom: 18px">
+        <span style="color: #306cd7; font-size: 26px">|</span>
+        <span style="font-size: 18px; padding-left: 5px">创意</span>
+      </div>
+      <el-form
+        ref="ruleFormRef"
+        :model="ruleForm"
+        :rules="rules"
+        label-width="120px"
+        class="demo-ruleForm"
+        size="default"
+        label-position="top"
+        status-icon>
+        <el-form-item label="广告名称" prop="name">
+          <el-input v-model="ruleForm.name" style="width: 50%" />
+        </el-form-item>
+        <el-form-item style="border: 1px solid #dddfe6;">
+          <div style="width: 50%; padding-left: 5px; border-right: 1px solid #dddfe6">
+            <el-scrollbar height="700px">
+            <el-collapse v-model="activeNames" @change="handleChange">
+              <el-collapse-item name="1">
+                <template #title> <span style="color: #e47470; margin-right: 4px">*</span>视频 </template>
+                <div>
+                  <div style="display: flex; align-items: center; justify-content: space-between">
+                    <span style="color: #1e2128; font-size: 15px; font-weight: 450">选择视频</span>
+                    <el-button type="primary" text>查看视频批准提示</el-button>
+                  </div>
+                  <div style="color: #666666; margin-bottom: 10px">
+                    保持视频简短并紧扣主题。视频会自动播放,因此请确保前 2
+                    秒极具吸引力,并且不依靠声音来传递信息。如果您在视频中使用了文字,请确保文字清晰易辨。字幕或音频必须与将展示您广告的区域相匹配。
+                  </div>
+                  <div class="upload-button-group">
+                    <el-upload
+                      v-model:file-list="fileList"
+                      class="upload-demo"
+                      action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
+                      multiple
+                      :on-preview="handlePreview"
+                      :on-remove="handleRemove"
+                      :before-remove="beforeRemove"
+                      :limit="3"
+                      :on-exceed="handleExceed">
+                      <el-button type="primary">上传文件</el-button>
+
+                      <template #tip>
+                        <div class="el-upload__tip">jpg/png files with a size less than 500KB.</div>
+                      </template>
+                    </el-upload>
+                    <el-button type="primary" :icon="Picture" style="margin-left: -120px" @click="handleSelect">从素材库中选择</el-button>
+                  </div>
+                </div>
+              </el-collapse-item>
+              <div style="display: flex; align-items: center; justify-content: space-between">
+                <span style="color: #1e2128; font-size: 15px; font-weight: 450">视频文件要求:</span>
+                <el-button type="primary" text>了解更多</el-button>
+              </div>
+              <div>
+                <span style="color: #1e2128; font-size: 13px; font-weight: 450">视频规格</span>
+                <div class="introduce-item">1.纵横比:16:9</div>
+                <div class="introduce-item">2.尺寸:1280 x 720 像素、1920 x 1080 像素或 3840 x 2160 像素</div>
+                <div class="introduce-item">3.文件大小:500MB 或更小</div>
+                <div class="introduce-item">4.文件格式:MP4 或 MOV</div>
+                <div class="introduce-item">5.长度:6-45 秒</div>
+                <div class="introduce-item">6.帧率:23.976、23.98、24、25、29.97 或 29.98 fps</div>
+                <div class="introduce-item">7.比特率:1 Mbps 或更高</div>
+                <div class="introduce-item">8.编解码器:H.264 或 H.265</div>
+                <div class="introduce-item">9.配置文件:主配置文件或基线配置文件</div>
+                <div class="introduce-item">10.视频流:仅为 1</div>
+              </div>
+              <div>
+                <span style="color: #1e2128; font-size: 13px; font-weight: 450">音频规格</span>
+                <div class="introduce-item">1.语言:必须与广告投放区域匹配</div>
+                <div class="introduce-item">2.采样率:44.1 kHz 或更高</div>
+                <div class="introduce-item">3.编解码器:PCM、AAC 或 MP3</div>
+                <div class="introduce-item">4.比特率:96 kbps 或更高</div>
+                <div class="introduce-item">5.格式:立体声或单声道</div>
+                <div class="introduce-item">6.音频流:仅为 1</div>
+              </div>
+              <hr style="margin-top: 8px;">
+              <el-collapse-item name="2">
+                <template #title> <span style="color: #e47470; margin-right: 4px">*</span>商品 </template>
+                <div>Operation feedback: enable the users to clearly perceive their operations by style updates and interactive effects;</div>
+                <div>Visual feedback: reflect current state by updating or rearranging elements of the page.</div>
+              </el-collapse-item>
+            </el-collapse>
+          </el-scrollbar>
+          </div>
+        </el-form-item>
+      </el-form>
+    </el-card>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { reactive, ref } from 'vue'
+import type { FormInstance, FormRules, UploadProps, UploadUserFile } from 'element-plus'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { Plus, Picture} from '@element-plus/icons-vue'
+
+interface RuleForm {
+  name: string
+}
+
+const ruleFormRef = ref<FormInstance>()
+const ruleForm = reactive<RuleForm>({
+  name: '视频 广告 - 1/15/2024 17:51:10.236',
+})
+
+const rules = reactive<FormRules<RuleForm>>({
+  name: [
+    { required: true, message: 'Please input Activity name', trigger: 'blur' },
+    { min: 3, max: 5, message: 'Length should be 3 to 5', trigger: 'blur' },
+  ],
+})
+
+const submitForm = async (formEl: FormInstance | undefined) => {
+  if (!formEl) return
+  await formEl.validate((valid, fields) => {
+    if (valid) {
+      console.log('submit!')
+    } else {
+      console.log('error submit!', fields)
+    }
+  })
+}
+
+const activeNames = ref(['1'])
+const handleChange = (val: string[]) => {
+  console.log(val)
+}
+
+const fileList = ref<UploadUserFile[]>([
+  {
+    name: 'element-plus-logo.svg',
+    url: 'https://element-plus.org/images/element-plus-logo.svg',
+  },
+  {
+    name: 'element-plus-logo2.svg',
+    url: 'https://element-plus.org/images/element-plus-logo.svg',
+  },
+])
+
+const handleRemove: UploadProps['onRemove'] = (file, uploadFiles) => {
+  console.log(file, uploadFiles)
+}
+
+const handlePreview: UploadProps['onPreview'] = (uploadFile) => {
+  console.log(uploadFile)
+}
+
+const handleExceed: UploadProps['onExceed'] = (files, uploadFiles) => {
+  ElMessage.warning(`The limit is 3, you selected ${files.length} files this time, add up to ${files.length + uploadFiles.length} totally`)
+}
+
+const beforeRemove: UploadProps['beforeRemove'] = (uploadFile, uploadFiles) => {
+  return ElMessageBox.confirm(`Cancel the transfer of ${uploadFile.name} ?`).then(
+    () => true,
+    () => false
+  )
+}
+
+function handleSelect() {
+  // console.log()
+}
+</script>
+
+<style scoped>
+.customize-container {
+  margin-top: 10px;
+}
+.upload-button-group {
+  display: flex;
+}
+.introduce-item {
+  line-height: 17px;
+  font-size: 12px;
+  color: #88909b;
+}
+</style>

+ 23 - 2
src/views/adManage/sb/campaigns/CreateCampaigns/index.vue

@@ -2,8 +2,13 @@
   <div class="page-container">
     <AdCampaign @update-campaign="handleCampaignUpdate"></AdCampaign>
     <AdGroup @update-group-id="handleGroupIdUpdate"></AdGroup>
-    <AdFormat></AdFormat>
+    <AdFormat @update:adFormatRadio="handleAdFormatRadioChange"
+      @update:arrivalsRadio="handleArrivalsRadioChange"
+      @update:flagshipStoreShop="handleFlagshipStoreShopChange"></AdFormat>
+      <VideoCreativity1 v-if="adFormatRadioValue === 'video' && arrivalsRadioValue === 'flagshipStore' && flagshipStoreShopValue === 'zosi' "></VideoCreativity1>
+    <VideoCreativity2 v-if="adFormatRadioValue === 'video' && arrivalsRadioValue === 'productDetailsPage'"></VideoCreativity2>
     <DeliveryType></DeliveryType>
+    <p>{{ adFormatRadioValue }} -- {{ arrivalsRadioValue }} -- {{ flagshipStoreShopValue }}</p>
   </div>
 </template>
 
@@ -13,11 +18,15 @@ import AdCampaign from './component/AdCampaign.vue'
 import AdGroup from './component/AdGroup.vue'
 import AdFormat from './component/AdFormat.vue'
 import DeliveryType from './component/DeliveryType.vue'
-
+import VideoCreativity1 from './component/VideoCreativity1.vue'
+import VideoCreativity2 from './component/VideoCreativity2.vue'
 
 const respCampaignId = ref('')
 const respCampaignName = ref('')
 const respAdGroupId = ref('')
+const adFormatRadioValue = ref('')
+const arrivalsRadioValue = ref('')
+const flagshipStoreShopValue = ref('')
 
 provide('respCampaignId', respCampaignId)
 provide('respCampaignName', respCampaignName)
@@ -30,6 +39,18 @@ const handleCampaignUpdate = (data) => {
 const handleGroupIdUpdate = (data) => {
   respAdGroupId.value = data.id
 }
+const handleAdFormatRadioChange = (newValue) => {
+  adFormatRadioValue.value = newValue // 更新 adFormatRadioValue
+  console.log('adFormatRadio changed in child component:', newValue)
+}
+const handleArrivalsRadioChange = (newValue) => {
+arrivalsRadioValue.value = newValue
+console.log(newValue)
+}
+const handleFlagshipStoreShopChange = (newValue) => {
+  flagshipStoreShopValue.value = newValue
+console.log(111, newValue)
+}
 </script>
 
 <style scoped>