Pārlūkot izejas kodu

🌈 style: 代码重置

WanGxC 1 gadu atpakaļ
vecāks
revīzija
d4eee7f1e6

+ 24 - 0
src/views/adManage/sd/campaigns/CreateCampaigns/api/index.ts

@@ -107,4 +107,28 @@ export function postCustomOperation(body) {
       method: 'post',
       data: body,
   })
+}
+export function uploadFile(obj) {
+  return request({
+      url: '/api/ad_manage/assets/upload/',
+      method: 'post',
+      data: obj,
+      headers: {
+        'Content-Type': 'multipart/form-data'
+      }
+  })
+}
+export function checkAsset(obj) {
+  return request({
+      url: '/api/ad_manage/assets/checkasset/',
+      method: 'post',
+      data: obj,
+  })
+}
+export function postCreative(obj) {
+  return request({
+      url: '/api/ad_manage/sdcreative/create/',
+      method: 'post',
+      data: obj,
+  })
 }

+ 326 - 28
src/views/adManage/sd/campaigns/CreateCampaigns/component/Creativity.vue

@@ -5,39 +5,145 @@
         <span class="custom-card-icon">|</span>
         <span class="custom-card-Text">创意</span>
       </div>
-      <div style="display: flex;">
+      <div class="main-container">
         <div class="left-container">
           <p class="left-part-title">请选择您想要自定义商品广告的方式</p>
-          <div class="demo-collapse">
-            <el-collapse v-model="activeNames" @change="handleCollapseChange" style="border: none;">
-              <el-collapse-item title="徽标" name="logo">
-                <div>
-                  Consistent with real life: in line with the process and logic of real life, and comply with languages and habits that the users are
-                  used to;
-                </div>
-                <div>
-                  Consistent within interface: all elements should be consistent, such as: design style, icons and texts, position of elements, etc.
-                </div>
-              </el-collapse-item>
-              <el-collapse-item title="标题" name="title">
-                <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-item title="图片" name="image">
-                <div>Simplify the process: keep operating process simple and intuitive;</div>
-                <div>Definite and clear: enunciate your intentions clearly so that the users can quickly understand and make decisions;</div>
-                <div>
-                  Easy to identify: the interface should be straightforward, which helps the users to identify and frees them from memorizing and
-                  recalling.
-                </div>
-              </el-collapse-item>
-            </el-collapse>
-          </div>
+          <el-scrollbar height="640px">
+            <div class="demo-collapse">
+              <el-collapse v-model="activeNames" @change="handleCollapseChange" style="border: none">
+                <el-collapse-item title="徽标" name="logo">
+                  <div style="display: flex; margin-bottom: 5px">
+                    <p style="font-weight: 700; color: #1d2129; margin-right: 8px">品牌标识</p>
+                    <el-switch v-model="isOpenLogo" size="small" />
+                  </div>
+                  <el-upload
+                    v-model:file-list="fileList"
+                    :on-change="changeFile"
+                    v-loading="upLoading"
+                    :on-remove="handleRemove"
+                    action="#"
+                    accept=".png, .jpg"
+                    :limit="1"
+                    list-type="picture-card"
+                    :auto-upload="false">
+                    <el-icon><Plus /></el-icon>
+                    <template #file="{ file }">
+                      <div>
+                        <img class="el-upload-list__item-thumbnail" :src="file.url" alt="" />
+                        <span class="el-upload-list__item-actions">
+                          <span class="el-upload-list__item-preview" @click="handlePictureCardPreview(file)">
+                            <el-icon><zoom-in /></el-icon>
+                          </span>
+                          <span v-if="!disabled" class="el-upload-list__item-delete" @click="handleRemove(file)">
+                            <el-icon><Delete /></el-icon>
+                          </span>
+                        </span>
+                      </div>
+                    </template>
+                    <template #tip>
+                      <div style="margin-top: 10px">
+                        <div style="display: flex; align-items: center; justify-content: space-between">
+                          <span style="line-height: 17px; font-weight: 600; color: #1e2128">徽标要求</span>
+                          <!-- <el-button type="primary" :icon="Picture" @click="openDialog">从素材库中选择</el-button> -->
+                        </div>
+                        <div class="introduce-item">1、图片大小: 至少600x100像素</div>
+                        <div class="introduce-item">2、文件大小: 小于1MB</div>
+                        <div style="display: flex; justify-content: space-between">
+                          <span class="introduce-item">3、文件格式: PNG 或 JPG</span>
+                          <span style="margin-left: 25px; position: relative">
+                            <el-icon size="14" style="position: absolute; left: -14px; top: 6px"><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-dialog v-model="dialogVisible">
+                    <img w-full :src="dialogImageUrl" alt="Preview Image" />
+                  </el-dialog>
+                </el-collapse-item>
+                <el-collapse-item title="标题" name="title">
+                  <template #title style="position: relative">
+                    <span>标题</span>
+
+                    <el-icon size="14" style="position: absolute; right: 85px"><Link /></el-icon>
+                    <el-link
+                      type="primary"
+                      href="https://advertising.amazon.com/resources/ad-policy/creative-acceptance#editorialguidelines"
+                      target="_blank"
+                      :underline="false"
+                      style="position: absolute; right: 30px">
+                      查看政策
+                    </el-link>
+                  </template>
+                  <div style="display: flex">
+                    <el-switch v-model="isOpenTitle" style="margin-right: 10px" />
+                    <el-input v-model="titleInp" maxlength="50" show-word-limit placeholder="Please input" type="text" />
+                  </div>
+                </el-collapse-item>
+                <el-collapse-item title="图片" name="image">
+                  <div style="display: flex; margin-bottom: 5px">
+                    <p style="font-weight: 700; color: #1d2129; margin-right: 8px">添加图片</p>
+                    <el-switch v-model="isOpenPicture" size="small" />
+                  </div>
+                  <el-upload
+                    v-model:file-list="pictureFile"
+                    :on-change="changePicture"
+                    v-loading="pictureLoading"
+                    :on-remove="handleRemovePicture"
+                    action="#"
+                    accept=".png, .jpeg, .gif"
+                    :limit="1"
+                    list-type="picture-card"
+                    :auto-upload="false">
+                    <el-icon><Plus /></el-icon>
+                    <template #file="{ file }">
+                      <div>
+                        <img class="el-upload-list__item-thumbnail" :src="file.url" alt="" />
+                        <span class="el-upload-list__item-actions">
+                          <span class="el-upload-list__item-preview" @click="handlePictureCardPreview(file)">
+                            <el-icon><zoom-in /></el-icon>
+                          </span>
+                          <span v-if="!disabled" class="el-upload-list__item-delete" @click="handleRemove(file)">
+                            <el-icon><Delete /></el-icon>
+                          </span>
+                        </span>
+                      </div>
+                    </template>
+                    <template #tip>
+                      <div style="margin-top: 10px">
+                        <div style="display: flex; align-items: center; justify-content: space-between">
+                          <span style="line-height: 17px; font-weight: 600; color: #1e2128">徽标要求</span>
+                          <!-- <el-button type="primary" :icon="Picture" @click="openDialog">从素材库中选择</el-button> -->
+                        </div>
+                        <div class="introduce-item">1、图片大小: 至少 1200x628 像素</div>
+                        <div class="introduce-item">2、文件大小: 小于5MB</div>
+                        <div class="introduce-item">3、文件格式: PNG, JPEG 或GIF</div>
+                        <div class="introduce-item">4、没有在图片上添加文字, 图形或徽标</div>
+                      </div>
+                    </template>
+                  </el-upload>
+                  <!-- 预览弹窗 -->
+                  <el-dialog v-model="dialogVisible">
+                    <img w-full :src="dialogImageUrl" alt="Preview Image" />
+                  </el-dialog>
+                </el-collapse-item>
+              </el-collapse>
+            </div>
+          </el-scrollbar>
         </div>
         <div class="right-container">
           <div class="preview-title-line">
             <p class="right-part-title">广告预览</p>
             <el-select></el-select>
+            <el-button style="margin-left: 10px">保存</el-button>
           </div>
         </div>
       </div>
@@ -46,14 +152,192 @@
 </template>
 
 <script setup lang="ts">
-import { ref } from 'vue'
+import { ref, inject, Ref, onMounted, watch } from 'vue'
+import { Delete, Picture, Plus, ZoomIn } from '@element-plus/icons-vue'
+import type { UploadFile } from 'element-plus'
+import { ElMessage } from 'element-plus'
+import { uploadFile, checkAsset, postCreative } from '../api/index'
+import { useShopInfo } from '/@/stores/shopInfo'
+import { storeToRefs } from 'pinia'
+import emitter from '/@/utils/emitter'
+
+const respAdGroupId = inject<Ref>('respAdGroupId')
+const shopInfo = useShopInfo()
+const { profile } = storeToRefs(shopInfo)
 
 // 折叠面板相关
 const activeNames = ref([''])
 
 function handleCollapseChange(val: string[]) {
-  console.log(val)
+  // console.log(val)
+}
+
+// logo相关
+const fileList = ref([])
+const upLoading = ref(false)
+const disabled = ref(false)
+const dialogVisible = ref(false)
+const dialogImageUrl = ref('')
+const centerDialogVisible = ref(false)
+
+function changeFile(file: UploadFile) {
+  handleUpload(file)
+}
+
+function handleRemove(file: UploadFile) {
+  fileList.value = []
 }
+
+function handlePictureCardPreview(file: UploadFile) {
+  dialogImageUrl.value = file.url!
+  dialogVisible.value = true
+}
+// 文件上传相关
+const brandEntityId = ref('')
+let brandLogoAssetID = ''
+let brandLogoAssetVersion = ''
+let brandLogoCrop = {}
+const isOpenLogo = ref(false)
+
+async function handleUpload(file: UploadFile) {
+  const formData = new FormData()
+  formData.append('file', file.raw)
+  formData.append('profile_id', profile.value.profile_id)
+  formData.append('brandEntityId', brandEntityId.value)
+  formData.append('assetType', 'IMAGE')
+  formData.append('assetSubTypeList', JSON.stringify(['LOGO']))
+  upLoading.value = true
+  try {
+    const response = await uploadFile(formData)
+    brandLogoAssetVersion = response.data.versionId
+    const fileName = response.data.file_name
+    const obj = {
+      profile_id: profile.value.profile_id,
+      file_name: fileName,
+    }
+    const resp = await checkAsset(obj)
+    brandLogoAssetID = resp.data.assetId
+
+    const { width, height } = resp.data.fileMetadata
+    brandLogoCrop = {
+      width,
+      height,
+      top: 0,
+      left: 0,
+    }
+    if (resp.data.checkresult == 'success') {
+      ElMessage({ message: '上传成功', type: 'success' })
+    } else {
+      ElMessage.error('上传失败')
+    }
+  } catch (error) {
+    console.error('上传失败:', error)
+  } finally {
+    upLoading.value = false
+  }
+}
+
+function openDialog() {
+  centerDialogVisible.value = true
+  // getAssetsData()
+}
+
+// title相关
+const titleInp = ref('')
+const isOpenTitle = ref(false)
+
+// 图片相关
+const pictureFile = ref([])
+const pictureLoading = ref(false)
+const isOpenPicture = ref(false)
+let pictureAssetVersion = ''
+let pictureAssetID = ''
+
+function changePicture(file: UploadFile) {
+  handleUploadPicture(file)
+}
+
+function handleRemovePicture(file: UploadFile) {
+  fileList.value = []
+}
+
+async function handleUploadPicture(file: UploadFile) {
+  const formData = new FormData()
+  formData.append('file', file.raw)
+  formData.append('profile_id', profile.value.profile_id)
+  formData.append('brandEntityId', brandEntityId.value)
+  formData.append('assetType', 'IMAGE')
+  formData.append('assetSubTypeList', JSON.stringify(['LOGO']))
+  upLoading.value = true
+  try {
+    const response = await uploadFile(formData)
+    pictureAssetVersion = response.data.versionId
+    const fileName = response.data.file_name
+    const obj = {
+      profile_id: profile.value.profile_id,
+      file_name: fileName,
+    }
+    const resp = await checkAsset(obj)
+    pictureAssetID = resp.data.assetId
+
+    const { width, height } = resp.data.fileMetadata
+    brandLogoCrop = {
+      width,
+      height,
+      top: 0,
+      left: 0,
+    }
+    if (resp.data.checkresult == 'success') {
+      ElMessage({ message: '上传成功', type: 'success' })
+    } else {
+      ElMessage.error('上传失败')
+    }
+  } catch (error) {
+    console.error('上传失败:', error)
+  } finally {
+    upLoading.value = false
+  }
+}
+
+const createLoading = ref(false)
+
+async function createCreativity() {
+  createLoading.value = true
+  const obj = {
+    profile_id: profile.value.profile_id,
+    adGroupId: respAdGroupId.value,
+    properties_logo: isOpenLogo.value,
+    properties_head: isOpenTitle.value,
+    properties_custom: isOpenPicture.value,
+    headline: '',
+    brandLogo_assetId: '',
+    brandLogo_assetVersion: '',
+    brandLogo_croppingCoordinates: brandLogoCrop,
+    contentType: '',
+    rectCustomImage_assetId: '',
+    rectCustomImage_assetVersion: '',
+    squareCustomImage_assetId: '',
+    squareCustomImage_assetVersion: '',
+  }
+  try {
+    const response = await postCreative(obj)
+    if (response.data.creative_state == 'success') {
+      ElMessage({ message: '创建成功', type: 'success' })
+    } else {
+      ElMessage.error('上传失败')
+    }
+  } catch (error) {
+    console.error('error:', error)
+  } finally {
+    createLoading.value = false
+  }
+}
+
+onMounted(() => {
+  emitter.on('send-brandEntityId', (value: any) => {
+    brandEntityId.value = value.brandEntityId[0].brandEntityId
+  })
+})
 </script>
 
 <style scoped>
@@ -72,8 +356,17 @@ function handleCollapseChange(val: string[]) {
   color: #306cd7;
   font-size: 26px;
 }
+.main-container {
+  display: flex;
+  border: 1px solid #e5e7eb;
+  height: 700px;
+  margin-bottom: 20px;
+  border-radius: 6px;
+}
 .left-container {
   width: 50%;
+  padding: 10px;
+  border-right: 1px solid #e5e7eb;
 }
 .left-part-title {
   color: #4e5969;
@@ -94,4 +387,9 @@ function handleCollapseChange(val: string[]) {
   font-weight: 700;
   line-height: 32px;
 }
+.introduce-item {
+  line-height: 17px;
+  font-size: 12px;
+  color: #88909b;
+}
 </style>

+ 6 - 12
src/views/adManage/sd/campaigns/CreateCampaigns/component/PromoteProduct.vue

@@ -96,7 +96,7 @@
           <template #header>
             <div class="card-header">
               <span style="font-weight: 550; font-size: 15px; color: #1f2128">已添加: {{ addedTableData.length }}</span>
-              <el-button class="button" type="danger" text bg @click="delAllGoods">全部删除</el-button>
+              <el-button class="button" type="danger" text @click="delAllProduct">全部删除</el-button>
             </div>
           </template>
           <div class="card-body"></div>
@@ -243,15 +243,13 @@ function delSingleGoods(scope) {
   const index = addedTableData.value.findIndex((item) => item.sku === scope.row.sku)
   if (index !== -1) {
     addedTableData.value.splice(index, 1)
-    console.log('Item removed successfully.')
   } else {
     console.log('Item not found.')
   }
 }
 
-function delAllGoods() {
-  addedTableData.value = []
-  // addedTableData.value.splice(0, addedTableData.value.length)
+function delAllProduct() {
+  addedTableData.value.splice(0, addedTableData.value.length)
 }
 
 // 删除第二个table中已经选中的项
@@ -272,7 +270,6 @@ function inpChange(e) {
 }
 
 function selChange(e) {
-  console.log('e', e)
   const value = e
   if (leftSelect.value === 'asin' && searchInp.value) {
     loading.value = true
@@ -312,8 +309,7 @@ function isItemInList(item, list) {
 // 监听商品右侧表格已添加的数据并转化数据格式
 let firstAsin = ''
 watch(
-  addedTableData,
-  (newValue, oldValue) => {
+  addedTableData, (newValue, oldValue) => {
     newValue.forEach((item) => {
       if (!isItemInList(item, addedAdsTableItems.value)) {
         addedAdsTableItems.value.push({ sku: item.sku, asin: item.asin })
@@ -321,8 +317,9 @@ watch(
         emitter.emit('send-firstAsin', firstAsin)
       }
     })
+    emitter.emit('send-tableData', addedTableData.value)
   },
-  { deep: true }
+  { deep: true, immediate: true }
 )
 
 async function createAds() {
@@ -383,9 +380,6 @@ function headerCellStyle(args) {
 
 onMounted(() => {
   setTableData()
-  // emitter.on('respAdGroupId', (value: any)=>{
-  //   respAdGroupId.value = value
-  // })
 })
 </script>
 

+ 4 - 4
src/views/adManage/sd/campaigns/CreateCampaigns/index.vue

@@ -3,8 +3,7 @@
     <AdCampaign @send-campaign="getCampaign" @send-targetType="getTargetType"></AdCampaign>
     <AdGroup @send-groupId="getGroupId"></AdGroup>
     <component :is="currentComponent"></component>
-    <!-- <Creativity v-if="product.length !== 0"></Creativity> -->
-    <Creativity></Creativity>
+    <Creativity v-if="product.length !== 0"></Creativity>
   </div>
 </template>
 
@@ -17,6 +16,7 @@ import CustomTarget from './component/CustomTarget.vue'
 import Creativity from './component/Creativity.vue'
 import emitter from '/@/utils/emitter'
 
+
 const respCampaignId = ref('')
 const respCampaignName = ref('')
 const respAdGroupId = ref('')
@@ -52,8 +52,8 @@ function getGroupId(data) {
 }
 
 // 若有商品被添加显示创意
-const product = ref('')
-emitter.on('send-firstAsin', (value: any) => {
+const product = ref([])
+emitter.on('send-tableData', (value: any) => {
   product.value = value
 })