Преглед изворни кода

完成sp单个广告活动的广告位

guojing_wu пре 1 година
родитељ
комит
6c6afdba04

+ 7 - 1
src/components/MetricsCards/mCard.vue

@@ -9,7 +9,7 @@
         <Top :class="colorClass" v-if="isBoost"/>
         <Bottom :class="colorClass" v-else/>
       </el-icon>
-      <span :class="colorClass">{{ selectedData?.gapVal }}</span>
+      <span :class="colorClass">{{ formatGapVal(selectedData?.gapVal) }}</span>
     </div>
   </el-card>
 </template>
@@ -49,6 +49,12 @@ const isBoost = computed(():boolean => {
 })
 const colorClass = computed((): "green"|"red" => isBoost.value ? "green": "red")
 
+const formatGapVal = (gapVal: number | undefined) => {
+  if (gapVal) {
+    return (gapVal * 100).toFixed(2) + '%'
+  }
+}
+
 </script>
 
 <style scoped>

+ 1 - 0
src/components/shopSelector/types.ts

@@ -6,5 +6,6 @@ export interface Profile {
 	advertiser_id: string,
 	country_code: string,
 	currency_code: string,
+	currency_symbol: string,
 	marketplace_str_id: string
 }

+ 3 - 3
src/stores/publicData.ts

@@ -1,16 +1,16 @@
 import { defineStore } from 'pinia'
 import { ref, Ref } from 'vue'
 import XEUtils from 'xe-utils'
+import { Session } from '/@/utils/storage'
 
 export const usePublicData = defineStore('publicData', () => {
-  const data: any = ref({
-    dateRange: []  // 筛选条件的时间范围
-  })
+  const data: any = ref(Session.get('publicData') ?? {})
 
   function updateData(obj: any) {
     XEUtils.objectEach(obj, (val, key) => {
       data.value[key] = val
     })
+    Session.set('publicData', data.value)
   }
 
   return { data, updateData }

+ 2 - 0
src/stores/shopInfo.ts

@@ -14,6 +14,7 @@ export const useShopInfo = defineStore('shopInfo', () => {
     advertiser_id: "",
     country_code: "",
     currency_code: "",
+    currency_symbol: "",
     marketplace_str_id: ""
   })
 
@@ -25,6 +26,7 @@ export const useShopInfo = defineStore('shopInfo', () => {
     profile.value.advertiser_id = obj.advertiser_id
     profile.value.country_code = obj.country_code
     profile.value.currency_code = obj.currency_code
+    profile.value.currency_symbol = obj.currency_symbol
     profile.value.marketplace_str_id = obj.marketplace_str_id
     Session.set('shopInfo', profile.value);
   }

+ 14 - 5
src/views/adManage/sp/campaigns/campaignDetail/index.vue

@@ -17,11 +17,19 @@
       <el-tab-pane label="广告组">
         <AdGroups :campaignId="route.query.campaignId"></AdGroups>
       </el-tab-pane>
-      <el-tab-pane label="预算" :lazy="true"></el-tab-pane>
-      <el-tab-pane label="自动化" :lazy="true"></el-tab-pane>
-      <el-tab-pane label="广告位" :lazy="true"></el-tab-pane>
-      <el-tab-pane label="否定投放" :lazy="true"></el-tab-pane>
-      <el-tab-pane label="操作日志" :lazy="true"></el-tab-pane>
+      <el-tab-pane label="预算" :lazy="true">
+        预算
+      </el-tab-pane>
+      <el-tab-pane label="自动化" :lazy="true">
+        自动化
+      </el-tab-pane>
+      <el-tab-pane label="广告位" :lazy="true">
+        <Placement :campaignId="route.query.campaignId" />
+      </el-tab-pane>
+      <el-tab-pane label="否定投放" :lazy="true">
+        否定投放
+      </el-tab-pane>
+      <!-- <el-tab-pane label="操作日志" :lazy="true"></el-tab-pane> -->
     </el-tabs>
   </div>
 </template>
@@ -30,6 +38,7 @@
 import { ref, onMounted, onBeforeMount, Ref } from 'vue'
 import AdGroups from '/@/views/adManage/sp/adGroups/index.vue'
 import { useRoute, useRouter } from 'vue-router'
+import Placement from './placement/index.vue'
 
 import { GetObj } from '../api'
 

+ 12 - 0
src/views/adManage/sp/campaigns/campaignDetail/placement/api.ts

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

+ 71 - 0
src/views/adManage/sp/campaigns/campaignDetail/placement/crud.tsx

@@ -0,0 +1,71 @@
+import * as api from './api'
+import { UserPageQuery, CreateCrudOptionsProps, CreateCrudOptionsRet } from '@fast-crud/fast-crud'
+import { inject } from 'vue'
+import { BaseColumn } from '/@/views/adManage/utils/commonTabColumn.js'
+import XEUtils from 'xe-utils'
+
+
+export const createCrudOptions = function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
+	const { fetchData } = context
+
+	//权限判定
+	const hasPermissions = inject('$hasPermissions');
+
+	return {
+		crudOptions: {
+			table: {
+			},
+			container: {
+        fixedHeight: false
+      },
+			actionbar: {
+				show: false,
+				buttons: {
+					add: {
+						show: false
+					}
+				}
+			},
+			search: {
+				show: true,
+				buttons: {
+					search: {
+						show: false
+					},
+					reset: {
+						show: false
+					}
+				}
+			},
+			toolbar: {
+        buttons: {
+					search: {
+						show: true
+					},
+					compact: {
+						show: false
+					},
+					refresh: {
+						click: async () => fetchData()
+					}
+				}
+			},
+			pagination: {
+				show: false
+			},
+			rowHandle: {
+        show: false
+      },
+			columns: {
+        placementClassification: {
+          title: '广告位',
+          column: {
+            width: '200px',
+						fixed: 'left'
+          }
+        },
+        ...BaseColumn
+			}
+		}
+	}
+}

+ 94 - 0
src/views/adManage/sp/campaigns/campaignDetail/placement/index.vue

@@ -0,0 +1,94 @@
+<template>
+  <fs-page class="fs-page-custom" v-loading='loading'>
+    <fs-crud ref="crudRef" v-bind="crudBinding">
+      <template #search-left>
+        <DateRangePicker v-model="dateRange" :timezone="shopInfo.profile.time_zone" style="margin-bottom: 5px;"></DateRangePicker>
+      </template>
+      <template v-for="field of Object.keys(BaseColumn)" #[`cell_${field}`]="scope">
+        <p>{{ scope.row[field] }}</p>
+        <el-popover
+          class="box-item"
+          effect="dark"
+          :width="260">
+          <template #reference>
+            <p :class="scope.row[`gap${field}`] > 0 ? 'green' : 'red'" v-show="showCompare">
+              <el-icon v-show="scope.row[field]">
+                <Top v-if="scope.row[`gap${field}`] > 0"/>
+                <Bottom v-else/>
+              </el-icon>
+              <span>{{ scope.row[`gap${field}`] }}%</span>
+            </p>
+          </template>
+          <p>对比周期:{{ placementData.compare_date[0] }} ~ {{ placementData.compare_date[1] }}</p>
+          <p>对比值:{{ scope.row[`prev${field}`] }}</p>
+        </el-popover>
+      </template>
+      <template #toolbar-left>
+        <div>
+          <span>数据对比 </span>
+          <el-switch v-model="showCompare" size="small" />
+        </div>
+      </template>
+    </fs-crud>
+  </fs-page>
+</template>
+
+<script lang="ts" setup>
+import { ref, onMounted, Ref, watch } from 'vue'
+import { useFs, FsPage } from '@fast-crud/fast-crud'
+import { createCrudOptions } from './crud'
+import { usePublicData } from '/@/stores/publicData'
+import { useShopInfo } from '/@/stores/shopInfo'
+import DateRangePicker from '/@/components/DateRangePicker/index.vue'
+import { GetList } from './api'
+import { BaseColumn } from '/@/views/adManage/utils/commonTabColumn.js'
+
+defineOptions({
+  name: "Placement"
+})
+const publicData = usePublicData()
+const shopInfo = useShopInfo()
+const dateRange: Ref<string[]> = ref(publicData.data.dateRange)
+const props = defineProps({
+  campaignId: { type: String }
+})
+const loading = ref(true)
+const placementData = ref({items: [], compare_date: []})
+
+const showCompare = ref(false)
+const fetchData = async () => {
+  loading.value = true
+  const resp = await GetList({ 
+    campaignId: props.campaignId,
+    date__gte: dateRange.value[0],
+    date__lte: dateRange.value[1]
+  })
+  placementData.value = resp.data
+  crudExpose.setTableData(placementData.value.items)
+  loading.value = false
+}
+
+const context = { fetchData }
+
+const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context })
+onMounted(async () => {
+  await fetchData()
+})
+
+
+
+watch(
+  dateRange, 
+  async () => await fetchData()
+)
+
+</script>
+
+<style scoped>
+.red {
+  color: red;
+}
+.green {
+  color: #1cbc0e;
+}
+</style>

+ 33 - 0
src/views/adManage/utils/commonTabColumn.ts

@@ -3,66 +3,99 @@ export const BaseColumn = {
     title: '曝光量',
     form: {
       show: false
+    },
+    column:{
+      align: 'right'
     }
   },
   Click: {
     title: '点击量',
     form: {
       show: false
+    },
+    column:{
+      align: 'right'
     }
   },
   CTR: {
     title: '点击率',
     form: {
       show: false
+    },
+    column:{
+      align: 'right'
     }
   },
   Spend: {
     title: '花费',
     form: {
       show: false
+    },
+    column:{
+      align: 'right'
     }
   },
   CPC: {
     title: '点击成本',
     form: {
       show: false
+    },
+    column:{
+      align: 'right'
     }
   },
   TotalPurchases: {
     title: '订单量',
     form: {
       show: false
+    },
+    column:{
+      align: 'right'
     }
   },
   TotalUnitOrdered: {
     title: '销量',
     form: {
       show: false
+    },
+    column:{
+      align: 'right'
     }
   },
   TotalSales: {
     title: '销售额',
     form: {
       show: false
+    },
+    column:{
+      align: 'right'
     }
   },
   ACOS: {
     title: 'ACOS',
     form: {
       show: false
+    },
+    column:{
+      align: 'right'
     }
   },
   ROAS: {
     title: 'ROAS',
     form: {
       show: false
+    },
+    column:{
+      align: 'right'
     }
   },
   CPA: {
     title: '订单成本',
     form: {
       show: false
+    },
+    column:{
+      align: 'right'
     }
   }
 }