Bläddra i källkod

✨ 新增根据sku搜索过滤商品功能

WanGxC 1 år sedan
förälder
incheckning
20cba55711

+ 1 - 0
src/views/adManage/sp/campaigns/api.ts

@@ -2,6 +2,7 @@ import { request } from '/@/utils/service'
 import { UserPageQuery, AddReq, DelReq, EditReq, InfoReq } from '@fast-crud/fast-crud'
 
 export const apiPrefix = '/api/ad_manage/spcampaigns/'
+
 export function GetList(query: UserPageQuery) {
   return request({
     url: apiPrefix + 'list',

+ 11 - 0
src/views/adManage/sp/campaigns/index.vue

@@ -11,6 +11,15 @@ import DataTendencyChart from '/@/views/adManage/sp/chartComponents/dataTendency
 import { getCardData, getLineData, getLineMonthData, getLineWeekData } from './api'
 import { BaseColumn } from '/@/views/adManage/utils/commonTabColumn.js'
 import DataCompare from '/@/components/dataCompare/index.vue'
+import emitter from '../../../../utils/emitter'
+
+
+emitter.on('PopoverFilter-allSkus', (data: any) => {
+  searchItem.value = data.allSkus.value
+  searchType.value = data.searchType.value
+})
+const searchItem = ref([])
+const searchType = ref('')
 
 const tabActiveName = ref('dataTendency')
 const shopInfo = useShopInfo()
@@ -20,6 +29,8 @@ const { profile } = storeToRefs(shopInfo)
 const queryParams = ref({
   profileId: profile.value.profile_id,
   dateRange,
+  searchItem,
+  searchType
 })
 const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: queryParams })
 const router = useRouter()

+ 112 - 31
src/views/adManage/sp/components/PopoverFilter.vue

@@ -1,42 +1,62 @@
 <script setup lang="ts">
-import { Search } from '@element-plus/icons-vue'
-import { inject, onBeforeUnmount, onMounted, Ref, ref } from 'vue'
+import { Connection, Picture as IconPicture, Search } from '@element-plus/icons-vue'
+import { inject, onBeforeUnmount, onMounted, Ref, ref, watch } from 'vue'
 import { getProductline } from '../api'
 import PopoverFilterTable from './PopoverFilterTable.vue'
 import emitter from '/@/utils/emitter'
 
+const profile = <Ref>inject('profile')
+const activeName = ref('search')
+const searchInput = ref('')
+const options = ref<{ productlineId: number; productlineName: string }[]>([])
+const textarea = ref('')
+const activeNames = ref([])
+const productLineSelect = ref('')
+// 用于存储从 PopoverFilterTable 组件传来的数据
+const receiveData = ref([])
+// 用于存储已经添加的 parentAsin,避免重复添加
+const parentAsinsSet = ref(new Set<string>())
+const allSkus = ref<string[]>([])
+const searchType = ref('')
+
 // 点击复选框就会触发, 用于处理从 PopoverFilterTable 组件传来的数据
 emitter.on('PopoverFilterTable-tableData', (data: any) => {
-  // 过滤出 parentAsin 和 sku 都不在 parentAsinsSet 中的数据,避免重复添加
-  const uniqueData = data.filter((item: any) => !parentAsinsSet.value.has(item.parentAsin + item.sku))
+  // 过滤出 parentAsin 和 sku 都不在 parentAsinsSet 和 allSkus 中的数据,避免重复添加
+  const uniqueData = data.filter(
+    (item: any) => !parentAsinsSet.value.has(item.parentAsin + item.sku) && !allSkus.value.includes(item.sku)
+  )
   // 将过滤后的数据添加到 receiveData 中
   receiveData.value.push(...uniqueData)
-  // 将新添加的 parentAsin 和 sku 添加到 parentAsinsSet 中
-  uniqueData.forEach((item: any) => parentAsinsSet.value.add(item.parentAsin + item.sku))
+  // 将新添加的 parentAsin 和 sku 添加到 parentAsinsSet 和 allSkus 中
+  uniqueData.forEach((item: any) => {
+    parentAsinsSet.value.add(item.parentAsin + item.sku)
+    allSkus.value.push(item.sku)
+  })
 })
 
-// 删除指定 parentAsin 的数据
-emitter.on('PopoverFilterTable-needDelete', (parentAsinToDelete: string) => {
-  // 遍历 receiveData,找到 parentAsin 匹配的项
+emitter.on('PopoverFilterTable-needDeleteBySku', (skuToDelete: string) => {
+  // 遍历 receiveData,找到 sku 匹配的项
   receiveData.value = receiveData.value.reduce((acc: any[], item: any) => {
-    if (item.parentAsin !== parentAsinToDelete) {
+    if (item.sku !== skuToDelete) {
       acc.push(item)
     } else {
-      // 从 parentAsinsSet 中删除该 parentAsin 和 sku 的组合
+      // 从 parentAsinsSet 和 allSkus 中删除该 parentAsin 和 sku 的组合
       parentAsinsSet.value.delete(item.parentAsin + item.sku)
+      allSkus.value = allSkus.value.filter((sku) => sku !== item.sku)
     }
     return acc
   }, [])
 })
 
-emitter.on('PopoverFilterTable-needDeleteBySku', (skuToDelete: string) => {
-  // 遍历 receiveData,找到 sku 匹配的项
+emitter.on('PopoverFilterTable-needDelete', (parentAsinToDelete: string) => {
+  // 遍历 receiveData,找到 parentAsin 匹配的项
   receiveData.value = receiveData.value.reduce((acc: any[], item: any) => {
-    if (item.sku !== skuToDelete) {
+    if (item.parentAsin !== parentAsinToDelete) {
       acc.push(item)
     } else {
-      // 从 parentAsinsSet 中删除该 parentAsin 和 sku 的组合
+      // 从 parentAsinsSet 和 allSkus 中删除该 parentAsin 和 sku 的组合
       parentAsinsSet.value.delete(item.parentAsin + item.sku)
+      allSkus.value = allSkus.value.filter((sku) => sku !== item.sku)
     }
     return acc
   }, [])
@@ -47,19 +67,15 @@ emitter.on('TopFilter', (value: any) => {
   if (!value.isVisible) {
     resetReceiveData()
   }
+  console.log(value.productFilterSelect)
+  searchType.value = value.productFilterSelect?.value
 })
 
-const profile = <Ref>inject('profile')
-const activeName = ref('search')
-const searchInput = ref('')
-const options = ref<{ productlineId: number; productlineName: string }[]>([])
-const textarea = ref('')
-const activeNames = ref([])
-const productLineSelect = ref('')
-// 用于存储从 PopoverFilterTable 组件传来的数据
-const receiveData = ref([])
-// 用于存储已经添加的 parentAsin,避免重复添加
-const parentAsinsSet = ref(new Set<string>())
+emitter.on('TopFilter-confirm', (value: any) => {
+  value.confirm && emitter.emit('PopoverFilter-allSkus', { allSkus, searchType });
+  emitter.emit('PopoverFilter-sendSearchItem', allSkus)
+  resetReceiveData()
+})
 
 // 根据 parentAsin 对 receiveData 数据进行分组
 function groupByParentAsin(receiveData: { parentAsin: string; asin: string; sku: string }[]) {
@@ -76,6 +92,7 @@ function groupByParentAsin(receiveData: { parentAsin: string; asin: string; sku:
 function resetReceiveData() {
   receiveData.value = []
   parentAsinsSet.value.clear()
+  allSkus.value = []
 }
 
 // 获取产品线数据
@@ -130,9 +147,9 @@ onBeforeUnmount(() => {
         <div class="my-auto ml-2">已添加:</div>
         <el-button link @click="resetReceiveData" class="mr-2" style="color: #3569d6">全部删除</el-button>
       </div>
-      <div class="demo-collapse">
+      <div class="demo-collapse px-1.5">
         <el-scrollbar height="550px">
-          <el-collapse v-model="activeNames">
+          <el-collapse v-model="activeNames" style="border: none">
             <el-collapse-item
               v-for="(items, parentAsin) in groupByParentAsin(receiveData)"
               :key="parentAsin"
@@ -142,9 +159,49 @@ onBeforeUnmount(() => {
                 <span>{{ parentAsin }}</span>
               </template>
               <div v-for="item in items" :key="item.asin">
-                ASIN: {{ item.asin }}
-                <br />
-                SKU: {{ item.sku }}
+                <div style="display: flex; align-items: center">
+                  <el-image
+                    class="w-14 h-14 mr-1 border rounded"
+                    style="min-width: 56px; min-height: 56px"
+                    v-if="item.Image"
+                    :src="item.Image"
+                    alt=""
+                    fit="contain" />
+                  <el-image v-else class="w-12 h-12 mr-1 border rounded">
+                    <template #error>
+                      <div class="image-slot">
+                        <el-icon>
+                          <icon-picture />
+                        </el-icon>
+                      </div>
+                    </template>
+                  </el-image>
+                  <div>
+                    <el-tooltip class="box-item" effect="dark" :content="item.Title" placement="top-start">
+                      <div class="font-medium text-black display-line">{{ item.Title }}</div>
+                    </el-tooltip>
+                    <div>
+                      <span class="text-black font-semibold">{{ item.price }}</span>
+                      <span class="text-gray-300 mx-1">|</span>
+                      <span>{{ item.quantity }}</span>
+                    </div>
+                    <el-tooltip offset="0" :show-arrow="false" effect="dark" :content="item.sku" placement="top-end">
+                      <div class="display-line">
+                        ASIN:<span class="text-black">{{ item.asin }}</span>
+                        <el-link
+                          :href="item.amazonUrl"
+                          target="_blank"
+                          :disabled="!item.amazonUrl"
+                          :underline="false"
+                          :icon="Connection"
+                          :style="{ marginLeft: '2px', marginBottom: '2px', color: item.amazonUrl ? '#3a83f7' : '#c0c4cc' }">
+                        </el-link>
+                        <span class="text-gray-300 mx-1">|</span>
+                        SKU:<span class="text-black">{{ item.sku }}</span>
+                      </div>
+                    </el-tooltip>
+                  </div>
+                </div>
               </div>
             </el-collapse-item>
           </el-collapse>
@@ -160,4 +217,28 @@ onBeforeUnmount(() => {
   overflow: hidden;
   margin-left: 10px;
 }
+
+.display-line {
+  overflow: hidden;
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-line-clamp: var(--line-clamp);
+  /* white-space: pre-wrap; */
+  --line-clamp: 1;
+}
+
+.image-slot {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  width: 65px;
+  height: 65px;
+  background: var(--el-fill-color-light);
+  color: var(--el-text-color-secondary);
+  font-size: 30px;
+}
+
+.image-slot el-icon {
+  font-size: 30px;
+}
 </style>

+ 10 - 2
src/views/adManage/sp/components/PopoverFilterTable.vue

@@ -10,11 +10,14 @@ emitter.on('TopFilter', (value: any) => {
     searchType = value.productFilterSelect.value
     updateGridColumnField()
   } else {
-    gridOptions.data = []
-    gridOptionsRight.data = []
+    resetSelected()
   }
 })
 
+emitter.on('TopFilter-confirm', () => {
+  resetSelected()
+})
+
 const profile = <Ref>inject('profile')
 const parentLoading = ref(false)
 const rightLoading = ref(false)
@@ -187,6 +190,11 @@ async function handleRightScroll(event: any) {
   }
 }
 
+function resetSelected() {
+  gridOptions.data = []
+  gridOptionsRight.data = []
+}
+
 // 切换搜索类型时,更新右侧表格字段
 function updateGridColumnField() {
   // 直接映射现有的columns,只修改需要改变的部分

+ 25 - 3
src/views/adManage/sp/components/TopFilter.vue

@@ -1,6 +1,6 @@
 <script setup lang="ts">
 import { CloseBold } from '@element-plus/icons-vue'
-import { computed, onMounted, ref } from 'vue'
+import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
 import PopoverFilter from './PopoverFilter.vue'
 import PopoverFilterParent from './PopoverFilterParent.vue'
 import { getProductSelect } from '../api'
@@ -8,9 +8,22 @@ import emitter from '/@/utils/emitter'
 
 const isVisible = ref(false)
 const productFilterInput = ref('')
+const inputPlaceholder = ref('请选择推广商品')
 const productFilterSelect = ref('')
 const productFilterOptions = ref([])
 
+emitter.on('PopoverFilter-sendSearchItem', (data: any) => {
+  if (data.value.length === 1) {
+    // 如果数组只有一个元素,直接使用该元素的值作为占位符
+    inputPlaceholder.value = data.value[0]
+  } else if (data.value.length === 0) {
+    inputPlaceholder.value = '请选择推广商品'
+  } else if (data.value.length > 1) {
+    // 如果数组有多于一个元素,使用第一个元素并注明还有多少其他元素
+    inputPlaceholder.value = `${data.value[0]} +${data.value.length - 1}`
+  }
+})
+
 async function fetchProductSelect() {
   try {
     const response = await getProductSelect()
@@ -31,6 +44,11 @@ function handleClose() {
   emitter.emit('TopFilter', isVisible)
 }
 
+function handleConfirm() {
+  isVisible.value = false
+  emitter.emit('TopFilter-confirm', { confirm: true })
+}
+
 const currentComponent = computed(() => {
   switch (productFilterSelect.value) {
     case 'pAsin':
@@ -46,13 +64,17 @@ const currentComponent = computed(() => {
 onMounted(() => {
   fetchProductSelect()
 })
+
+onBeforeUnmount(() => {
+  emitter.all.clear()
+})
 </script>
 
 <template>
   <div style="max-width: 350px">
     <el-popover :visible="isVisible" placement="bottom-start" :width="1200">
       <template #reference>
-        <el-input v-model="productFilterInput" @click="handleOpen" style="width: 350px" placeholder="请选择推广商品">
+        <el-input v-model="productFilterInput" @click="handleOpen" style="width: 350px" :placeholder="inputPlaceholder">
           <template #prepend>
             <el-select v-model="productFilterSelect" placeholder="Select" style="width: 100px">
               <el-option v-for="item in productFilterOptions" :key="item.value" :label="item.label" :value="item.value" />
@@ -69,7 +91,7 @@ onMounted(() => {
       <component :is="currentComponent"></component>
       <div class="flex justify-end mt-2">
         <el-button @click="handleClose">取消</el-button>
-        <el-button type="primary" color="#3c58af">应用</el-button>
+        <el-button type="primary" color="#3c58af" @click="handleConfirm">应用</el-button>
       </div>
     </el-popover>
   </div>