Ver Fonte

feat(adManage): 新增 ASIN 跑词功能

- 添加 ASIN 跑词和 ASIN 跑词(词组)两个新标签页
- 实现 ASIN 跑词数据的获取和展示
- 优化广告组详情页面布局
WanGxC há 7 meses atrás
pai
commit
b01f3a9a65

+ 2 - 2
.env.development

@@ -4,8 +4,8 @@ ENV='development'
 
 # 本地环境接口地址
 # VITE_API_URL = 'http://127.0.0.1:8000'
-#VITE_API_URL='http://192.168.1.225/'
- VITE_API_URL='http://192.168.1.25:8080/'
+VITE_API_URL='http://192.168.1.225/'
+# VITE_API_URL='http://192.168.1.25:8080/'
 # VITE_API_URL = 'http://amzads.zositechc.cn'
 
 # 是否启用按钮权限

+ 11 - 0
src/views/adManage/sp/campaigns/campaignDetail/adGroups/adGroupDetail/asinWord/api.ts

@@ -0,0 +1,11 @@
+import { request } from '/@/utils/service';
+import { UserPageQuery, AddReq, DelReq, EditReq, InfoReq } from '@fast-crud/fast-crud';
+
+export const apiPrefix = '/api/ad_manage/spcampaigns/asin_word/';
+export function GetList(query: UserPageQuery) {
+	return request({
+		url: apiPrefix + 'split/',
+		method: 'get',
+		params: query,
+	})
+}

+ 181 - 0
src/views/adManage/sp/campaigns/campaignDetail/adGroups/adGroupDetail/asinWord/crud.tsx

@@ -0,0 +1,181 @@
+import * as api from './api';
+import { CreateCrudOptionsProps, CreateCrudOptionsRet, UserPageQuery } from '@fast-crud/fast-crud';
+import { inject } from 'vue';
+import { parseQueryParams } from '/@/views/adManage/utils/tools.js';
+import XEUtils from 'xe-utils';
+
+
+export const createCrudOptions = function({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
+  const pageRequest = async (query: UserPageQuery) => {
+    const params = parseQueryParams(context.value);
+    XEUtils.assign(query, params);
+    return await api.GetList(query);
+  };
+
+  //权限判定
+  const hasPermissions = inject('$hasPermissions');
+
+  return {
+    crudOptions: {
+      table: {},
+      container: {
+        fixedHeight: false
+      },
+      actionbar: {
+        show: false
+      },
+      search: {
+        show: true,
+        buttons: {
+          search: {
+            show: false
+          },
+          reset: {
+            show: false
+          }
+        }
+      },
+      // toolbar: {
+      //   buttons: {
+      //     search: {
+      //       show: true,
+      //     },
+      //     compact: {
+      //       show: false,
+      //     },
+      //   },
+      // },
+      request: {
+        pageRequest
+      },
+      rowHandle: {
+        show: false
+      },
+      columns: {
+        searchTerm: {
+          title: '搜索词',
+          column: {
+            width: '200px',
+            fixed: 'left'
+          }
+        },
+        Impression: {
+          title: '曝光量',
+          column: {
+            align: 'center'
+          }
+        },
+        Click: {
+          title: '点击量',
+          column: {
+            align: 'center'
+          }
+        },
+        Spend: {
+          title: '花 费',
+          column: {
+            align: 'center'
+          }
+        },
+        TotalPurchases: {
+          title: '订单数',
+          column: {
+            align: 'center'
+          }
+        },
+        TotalSales: {
+          title: '花 费',
+          column: {
+            align: 'center'
+          }
+        },
+        TotalUnitOrdered: {
+          title: '销 量',
+          column: {
+            align: 'center'
+          }
+        },
+        TotalSalesSameSKU: {
+          title: '推广商品销售额',
+          column: {
+            width: '180',
+            align: 'center'
+          }
+        },
+        TotalSalesOtherSKU: {
+          title: '其他商品销售额',
+          column: {
+            width: '180',
+            align: 'center'
+          }
+        },
+        TotalPurchasesSameSKU: {
+          title: '推广商品订单数',
+          column: {
+            width: '180',
+            align: 'center'
+          }
+        },
+        TotalPurchasesOtherSKU: {
+          title: '其他商品订单数',
+          column: {
+            width: '180',
+            align: 'center'
+          }
+        },
+        TotalUnitOrderedSameSKU: {
+          title: '推广商品销量',
+          column: {
+            width: '180',
+            align: 'center'
+          }
+        },
+        TotalUnitOrderedOtherSKU: {
+          title: '其它商品销量',
+          column: {
+            width: '180',
+            align: 'center'
+          }
+        },
+        CPC: {
+          title: '点击成本',
+          column: {
+            width: '130',
+            align: 'center'
+          }
+        },
+        CTR: {
+          title: '点击率',
+          column: {
+            align: 'center'
+          }
+        },
+        PurchasesRate: {
+          title: '转化率',
+          column: {
+            align: 'center'
+          }
+        },
+        ACOS: {
+          title: 'ACOS',
+          column: {
+            align: 'center'
+          }
+        },
+        ROAS: {
+          title: 'ROAS',
+          column: {
+            align: 'center'
+          }
+        },
+        CPA: {
+          title: '订单成本',
+          column: {
+            width: '130',
+            align: 'center'
+          }
+        }
+      }
+    }
+  };
+};

+ 68 - 0
src/views/adManage/sp/campaigns/campaignDetail/adGroups/adGroupDetail/asinWord/index.vue

@@ -0,0 +1,68 @@
+<script lang="ts" setup>
+/**
+ * @Name: index.vue
+ * @Description:
+ * @Author: Cheney
+ */
+
+import { BaseColumn } from '/@/views/adManage/utils/commonTabColumn';
+import DateRangePicker from '/@/components/DateRangePicker/index.vue';
+import DataCompare from '/@/components/dataCompare/index.vue';
+import { FsPage, useFs } from '@fast-crud/fast-crud';
+import { createCrudOptions } from './crud';
+import { onMounted, ref } from 'vue';
+import { storeToRefs } from 'pinia';
+import { usePublicData } from '/@/stores/publicData';
+import { LocationQueryValue } from 'vue-router';
+
+
+interface Props {
+  adGroupId: LocationQueryValue | LocationQueryValue[];
+}
+
+const props = defineProps<Props>();
+
+const publicData = usePublicData();
+const { dateRange } = storeToRefs(publicData);
+const queryParams = ref({
+  adGroupId: props.adGroupId,
+  dateRange
+});
+
+const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: queryParams });
+
+onMounted(() => {
+  crudExpose.doRefresh();
+});
+</script>
+
+<template>
+  <fs-page class="fs-page-custom">
+    <fs-crud ref="crudRef" v-bind="crudBinding">
+      <!--<template #search-left>-->
+      <!--  <DateRangePicker v-model="dateRange"></DateRangePicker>-->
+      <!--</template>-->
+
+      <!--<template v-for="field of Object.keys(BaseColumn)" #[`cell_${field}`]="scope">-->
+      <!--  <DataCompare-->
+      <!--      :field="field"-->
+      <!--      :value="scope.row[field]"-->
+      <!--      :prev-val="scope.row[`prev${field}`]"-->
+      <!--      :gap-val="scope.row[`gap${field}`]"-->
+      <!--      :date-range="dateRange"-->
+      <!--      :show-compare="showCompare"-->
+      <!--  />-->
+      <!--</template>-->
+      <!--<template #toolbar-left>-->
+      <!--  <div class="campare-switch">-->
+      <!--    <span>数据对比 </span>-->
+      <!--    <el-switch v-model="showCompare" size="small" />-->
+      <!--  </div>-->
+      <!--</template>-->
+    </fs-crud>
+  </fs-page>
+</template>
+
+<style scoped>
+
+</style>

+ 11 - 0
src/views/adManage/sp/campaigns/campaignDetail/adGroups/adGroupDetail/asinWordGroup/api.ts

@@ -0,0 +1,11 @@
+import { request } from '/@/utils/service';
+import { UserPageQuery, AddReq, DelReq, EditReq, InfoReq } from '@fast-crud/fast-crud';
+
+export const apiPrefix = '/api/ad_manage/spcampaigns/asin_word/';
+export function GetList(query: UserPageQuery) {
+	return request({
+		url: apiPrefix,
+		method: 'get',
+		params: query,
+	})
+}

+ 181 - 0
src/views/adManage/sp/campaigns/campaignDetail/adGroups/adGroupDetail/asinWordGroup/crud.tsx

@@ -0,0 +1,181 @@
+import * as api from './api';
+import { CreateCrudOptionsProps, CreateCrudOptionsRet, UserPageQuery } from '@fast-crud/fast-crud';
+import { inject } from 'vue';
+import { parseQueryParams } from '/@/views/adManage/utils/tools.js';
+import XEUtils from 'xe-utils';
+
+
+export const createCrudOptions = function({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
+  const pageRequest = async (query: UserPageQuery) => {
+    const params = parseQueryParams(context.value);
+    XEUtils.assign(query, params);
+    return await api.GetList(query);
+  };
+
+  //权限判定
+  const hasPermissions = inject('$hasPermissions');
+
+  return {
+    crudOptions: {
+      table: {},
+      container: {
+        fixedHeight: false
+      },
+      actionbar: {
+        show: false
+      },
+      search: {
+        show: true,
+        buttons: {
+          search: {
+            show: false
+          },
+          reset: {
+            show: false
+          }
+        }
+      },
+      // toolbar: {
+      //   buttons: {
+      //     search: {
+      //       show: true,
+      //     },
+      //     compact: {
+      //       show: false,
+      //     },
+      //   },
+      // },
+      request: {
+        pageRequest
+      },
+      rowHandle: {
+        show: false
+      },
+      columns: {
+        searchTerm: {
+          title: '搜索词',
+          column: {
+            width: '200px',
+            fixed: 'left'
+          }
+        },
+        Impression: {
+          title: '曝光量',
+          column: {
+            align: 'center'
+          }
+        },
+        Click: {
+          title: '点击量',
+          column: {
+            align: 'center'
+          }
+        },
+        Spend: {
+          title: '花 费',
+          column: {
+            align: 'center'
+          }
+        },
+        TotalPurchases: {
+          title: '订单数',
+          column: {
+            align: 'center'
+          }
+        },
+        TotalSales: {
+          title: '花 费',
+          column: {
+            align: 'center'
+          }
+        },
+        TotalUnitOrdered: {
+          title: '销 量',
+          column: {
+            align: 'center'
+          }
+        },
+        TotalSalesSameSKU: {
+          title: '推广商品销售额',
+          column: {
+            width: '180',
+            align: 'center'
+          }
+        },
+        TotalSalesOtherSKU: {
+          title: '其他商品销售额',
+          column: {
+            width: '180',
+            align: 'center'
+          }
+        },
+        TotalPurchasesSameSKU: {
+          title: '推广商品订单数',
+          column: {
+            width: '180',
+            align: 'center'
+          }
+        },
+        TotalPurchasesOtherSKU: {
+          title: '其他商品订单数',
+          column: {
+            width: '180',
+            align: 'center'
+          }
+        },
+        TotalUnitOrderedSameSKU: {
+          title: '推广商品销量',
+          column: {
+            width: '180',
+            align: 'center'
+          }
+        },
+        TotalUnitOrderedOtherSKU: {
+          title: '其它商品销量',
+          column: {
+            width: '180',
+            align: 'center'
+          }
+        },
+        CPC: {
+          title: '点击成本',
+          column: {
+            width: '130',
+            align: 'center'
+          }
+        },
+        CTR: {
+          title: '点击率',
+          column: {
+            align: 'center'
+          }
+        },
+        PurchasesRate: {
+          title: '转化率',
+          column: {
+            align: 'center'
+          }
+        },
+        ACOS: {
+          title: 'ACOS',
+          column: {
+            align: 'center'
+          }
+        },
+        ROAS: {
+          title: 'ROAS',
+          column: {
+            align: 'center'
+          }
+        },
+        CPA: {
+          title: '订单成本',
+          column: {
+            width: '130',
+            align: 'center'
+          }
+        }
+      }
+    }
+  };
+};

+ 68 - 0
src/views/adManage/sp/campaigns/campaignDetail/adGroups/adGroupDetail/asinWordGroup/index.vue

@@ -0,0 +1,68 @@
+<script lang="ts" setup>
+/**
+ * @Name: index.vue
+ * @Description:
+ * @Author: Cheney
+ */
+
+import { BaseColumn } from '/@/views/adManage/utils/commonTabColumn';
+import DateRangePicker from '/@/components/DateRangePicker/index.vue';
+import DataCompare from '/@/components/dataCompare/index.vue';
+import { FsPage, useFs } from '@fast-crud/fast-crud';
+import { createCrudOptions } from './crud';
+import { onMounted, ref } from 'vue';
+import { storeToRefs } from 'pinia';
+import { usePublicData } from '/@/stores/publicData';
+import { LocationQueryValue } from 'vue-router';
+
+
+interface Props {
+  adGroupId: LocationQueryValue | LocationQueryValue[];
+}
+
+const props = defineProps<Props>();
+
+const publicData = usePublicData();
+const { dateRange } = storeToRefs(publicData);
+const queryParams = ref({
+  adGroupId: props.adGroupId,
+  dateRange
+});
+
+const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: queryParams });
+
+onMounted(() => {
+  crudExpose.doRefresh();
+});
+</script>
+
+<template>
+  <fs-page class="fs-page-custom">
+    <fs-crud ref="crudRef" v-bind="crudBinding">
+      <!--<template #search-left>-->
+      <!--  <DateRangePicker v-model="dateRange"></DateRangePicker>-->
+      <!--</template>-->
+
+      <!--<template v-for="field of Object.keys(BaseColumn)" #[`cell_${field}`]="scope">-->
+      <!--  <DataCompare-->
+      <!--      :field="field"-->
+      <!--      :value="scope.row[field]"-->
+      <!--      :prev-val="scope.row[`prev${field}`]"-->
+      <!--      :gap-val="scope.row[`gap${field}`]"-->
+      <!--      :date-range="dateRange"-->
+      <!--      :show-compare="showCompare"-->
+      <!--  />-->
+      <!--</template>-->
+      <!--<template #toolbar-left>-->
+      <!--  <div class="campare-switch">-->
+      <!--    <span>数据对比 </span>-->
+      <!--    <el-switch v-model="showCompare" size="small" />-->
+      <!--  </div>-->
+      <!--</template>-->
+    </fs-crud>
+  </fs-page>
+</template>
+
+<style scoped>
+
+</style>

+ 9 - 0
src/views/adManage/sp/campaigns/campaignDetail/adGroups/adGroupDetail/index.vue

@@ -42,6 +42,12 @@
         <el-tab-pane label="否定商品" name="tab3">
           <NegProduct v-if="tabActiveName === 'tab3'" :adGroupId="route.query.adGroupId">否定商品</NegProduct>
         </el-tab-pane>
+        <el-tab-pane label="ASIN跑词" name="asinWord">
+          <AsinWord v-if="tabActiveName === 'asinWord'" :adGroupId="route.query.adGroupId" />
+        </el-tab-pane>
+        <el-tab-pane label="ASIN跑词(词组)" name="asinWordGroup">
+          <AsinWordGroup v-if="tabActiveName === 'asinWordGroup'" :adGroupId="route.query.adGroupId" />
+        </el-tab-pane>
       </template>
       <template v-else>
         <el-tab-pane label="关键词" name="tab2">
@@ -73,6 +79,8 @@ import ManualTarget from './manualTarget/index.vue'
 import NegProduct from './negProduct/index.vue'
 import NegKeyword from './negKeyword/index.vue'
 import NegTarget from './negTarget/index.vue'
+import AsinWord from './asinWord/index.vue'
+import AsinWordGroup from './asinWordGroup/index.vue'
 
 const tabActiveName = ref('adProducts')
 const shopInfo = useShopInfo()
@@ -82,6 +90,7 @@ const adGroupInfo: Ref<SpAdGroup> = ref({})
 
 onMounted(async () => {
   const resp = await GetObj(route.query.adGroupId)
+  console.log("(index.vue: 89)=> resp", resp);
   adGroupInfo.value = resp.data
 })
 

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

@@ -1,30 +1,31 @@
 <script lang="ts" setup>
-import {onMounted, ref, Ref} from 'vue'
-import {useRoute} from 'vue-router'
-import AdGroups from './adGroups/index.vue'
-import Placement from './placement/index.vue'
-import Budget from './budget/index.vue'
-import Automation from './automation/index.vue'
-import {getEnumLabel} from '/@/views/adManage/utils/tools.js'
-import {dynBidStrategyEnum} from '/@/views/adManage/utils/enum.js'
-import {useShopInfo} from '/@/stores/shopInfo'
+import { onMounted, ref, Ref } from 'vue';
+import { useRoute } from 'vue-router';
+import AdGroups from './adGroups/index.vue';
+import Placement from './placement/index.vue';
+import Budget from './budget/index.vue';
+import Automation from './automation/index.vue';
+import { getEnumLabel } from '/@/views/adManage/utils/tools.js';
+import { dynBidStrategyEnum } from '/@/views/adManage/utils/enum.js';
+import { useShopInfo } from '/@/stores/shopInfo';
 // import { usePublicData } from '/@/stores/publicData'
-import {storeToRefs} from 'pinia'
+import { storeToRefs } from 'pinia';
 
-import {GetObj} from './api'
+import { GetObj } from './api';
 
-const shopInfo = useShopInfo()
-const { profile } = storeToRefs(shopInfo)
-const route = useRoute()
-const campaignInfo: Ref<SpCampaign> = ref({})
-const tabActiveName = ref('adGroup')
 
-const campaignId = ref(route.query.campaignId)
+const shopInfo = useShopInfo();
+const { profile } = storeToRefs(shopInfo);
+const route = useRoute();
+const campaignInfo: Ref<SpCampaign> = ref({});
+const tabActiveName = ref('adGroup');
+
+const campaignId = ref(route.query.campaignId);
 
 onMounted(async () => {
-  const resp = await GetObj(route.query.campaignId)
-  campaignInfo.value = resp.data
-})
+  const resp = await GetObj(route.query.campaignId);
+  campaignInfo.value = resp.data;
+});
 
 
 </script>
@@ -62,22 +63,23 @@ onMounted(async () => {
         </div>
       </div>
     </div>
-    <el-tabs type="border-card" class="asj-detail-tabs" v-model="tabActiveName">
+    <el-tabs v-model="tabActiveName" class="asj-detail-tabs" type="border-card">
       <el-tab-pane label="广告组" name="adGroup">
-        <AdGroups :campaignId="campaignId" v-if="tabActiveName==='adGroup'"></AdGroups>
+        <AdGroups v-if="tabActiveName==='adGroup'" :campaignId="campaignId"></AdGroups>
       </el-tab-pane>
       <el-tab-pane label="预算" name="budget">
-        <Budget :campaignId="campaignId" v-if="tabActiveName==='budget'"></Budget>
+        <Budget v-if="tabActiveName==='budget'" :campaignId="campaignId"></Budget>
       </el-tab-pane>
       <el-tab-pane label="自动化" name="automation">
-        <Automation :campaignId="campaignId" :profileId="profile.profile_id" v-if="tabActiveName==='automation'"></Automation>
+        <Automation v-if="tabActiveName==='automation'" :campaignId="campaignId"
+                    :profileId="profile.profile_id"></Automation>
       </el-tab-pane>
       <el-tab-pane label="广告位" name="placement">
-        <Placement :campaignId="campaignId" v-if="tabActiveName==='placement'"/>
-      </el-tab-pane>
-      <el-tab-pane label="否定投放" name="negative">
-        否定投放
+        <Placement v-if="tabActiveName==='placement'" :campaignId="campaignId" />
       </el-tab-pane>
+      <!--<el-tab-pane label="否定投放" name="negative">-->
+      <!--  否定投放-->
+      <!--</el-tab-pane>-->
       <!-- <el-tab-pane label="操作日志" :lazy="true"></el-tab-pane> -->
     </el-tabs>
   </div>