Browse Source

完善单个广告活动信息展示

guojing_wu 1 năm trước cách đây
mục cha
commit
00528b6786

+ 1 - 0
src/components/DateRangePicker/index.vue

@@ -14,6 +14,7 @@
       :clearable="false"
       :popper-options="{placement: props.popperPlacement}"
       @change="changedValue"
+      style="border-radius: 0;"
     />
   </div>
 </template>

+ 6 - 0
src/theme/app.scss

@@ -330,6 +330,10 @@ body,
 
 .fs-page-custom {
 	position: initial !important;
+
+	.fs-search-col >* {
+		margin-left: 0 !important;
+	}
 }
 
 .asj-tabs {
@@ -408,3 +412,5 @@ body,
 		padding-left: 0 !important;
 	}
 }
+
+

+ 2 - 1
src/types/views.d.ts

@@ -369,7 +369,8 @@ declare interface SpCampaign {
 	targetingType?: string,
 	state?: string,
 	dynBidStrategy?: string,
-	portfolio?: Portfolio
+	portfolioName?: string
+	servingStatus?: string
 }
 
 declare type SpAdGroup = {

+ 55 - 48
src/views/adManage/portfolios/api.ts

@@ -1,73 +1,80 @@
-import { request } from '/@/utils/service';
-import { AddReq, DelReq, EditReq, InfoReq, UserPageQuery } from '@fast-crud/fast-crud';
+import { request } from '/@/utils/service'
+import { AddReq, DelReq, EditReq, InfoReq, UserPageQuery } from '@fast-crud/fast-crud'
 
-export const apiPrefix = '/api/ad_manage/portfolios/';
+export const apiPrefix = '/api/ad_manage/portfolios/'
 export function GetList(query: UserPageQuery) {
-    return request({
-        url: apiPrefix,
-        method: 'get',
-        params: query,
-    })
+	return request({
+		url: apiPrefix,
+		method: 'get',
+		params: query,
+	})
+}
+export function GetAllPortfolios() {
+	return request({
+		url: apiPrefix + 'select_list',
+		method: 'get',
+		params: { limit: 999 },
+	})
 }
 export function GetObj(id: InfoReq) {
-    return request({
-        url: apiPrefix + id,
-        method: 'get',
-    });
+	return request({
+		url: apiPrefix + id,
+		method: 'get',
+	})
 }
 
 export function AddObj(obj: AddReq) {
-    return request({
-        url: apiPrefix,
-        method: 'post',
-        data: obj,
-    });
+	return request({
+		url: apiPrefix,
+		method: 'post',
+		data: obj,
+	})
 }
 
 export function UpdateObj(obj: EditReq) {
-    return request({
-        url: apiPrefix + obj.id + '/',
-        method: 'put',
-        data: obj,
-    });
+	return request({
+		url: apiPrefix + obj.id + '/',
+		method: 'put',
+		data: obj,
+	})
 }
 
 export function DelObj(id: DelReq) {
-    return request({
-        url: apiPrefix + id + '/',
-        method: 'delete',
-        data: { id },
-    });
+	return request({
+		url: apiPrefix + id + '/',
+		method: 'delete',
+		data: { id },
+	})
 }
 
 export function getCardData(query: UserPageQuery) {
-    return request({
-        url: apiPrefix + "report/amount",
-        method: 'GET',
-        params: query
-    })
+	return request({
+		url: apiPrefix + 'report/amount',
+		method: 'GET',
+		params: query,
+	})
 }
 
 export function getLineData(query: UserPageQuery) {
-    return request({
-        url: apiPrefix + "report/trend/daily",
-        method: 'GET',
-        params: query
-    })
+	return request({
+		url: apiPrefix + 'report/trend/daily',
+		method: 'GET',
+		params: query,
+	})
 }
 
 export function getLineWeekData(query: UserPageQuery) {
-    return request({
-        url: apiPrefix + "report/trend/weekly",
-        method: 'GET',
-        params: query
-    })
+	return request({
+		url: apiPrefix + 'report/trend/weekly',
+		method: 'GET',
+		params: query,
+	})
 }
 
 export function getLineMonthData(query: UserPageQuery) {
-    return request({
-        url: apiPrefix + "report/trend/monthly",
-        method: 'GET',
-        params: query
-    })
-}
+	return request({
+		url: apiPrefix + 'report/trend/monthly',
+		method: 'GET',
+		params: query,
+	})
+}

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

@@ -0,0 +1,14 @@
+import { request } from '/@/utils/service'
+import { LocationQueryValue } from 'vue-router'
+// import { UserPageQuery, AddReq, DelReq, EditReq, InfoReq } from '@fast-crud/fast-crud';
+// import XEUtils from 'xe-utils';
+
+export const apiPrefix = '/api/ad_manage/spcampaigndetail/'
+
+export function GetObj(campaignId: LocationQueryValue | LocationQueryValue[]) {
+	return request({
+		url: apiPrefix + 'head/',
+		method: 'get',
+		params: { campaignId },
+	})
+}

+ 20 - 0
src/views/adManage/sp/campaigns/campaignDetail/budget/api.ts

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

+ 57 - 0
src/views/adManage/sp/campaigns/campaignDetail/budget/crud.tsx

@@ -0,0 +1,57 @@
+import * as api from './api'
+import { dict, UserPageQuery, compute, CreateCrudOptionsProps, CreateCrudOptionsRet } from '@fast-crud/fast-crud'
+import { BaseColumn } from '/@/views/adManage/utils/commonTabColumn.js'
+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)
+	}
+
+	return {
+		crudOptions: {
+			table: {
+				// height: 800,
+			},
+			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: {
+				
+			},
+		},
+	}
+}

+ 44 - 0
src/views/adManage/sp/campaigns/campaignDetail/budget/index.vue

@@ -0,0 +1,44 @@
+<template>
+  <fs-page class="fs-page-custom">
+    <fs-crud ref="crudRef" v-bind="crudBinding">
+      <template #search-left>
+        <DateRangePicker v-model="dateRange"></DateRangePicker>
+      </template>
+      <template #header-middle>
+        <LineChart :query="queryParams"/>
+      </template>
+    </fs-crud>
+  </fs-page>
+</template>
+
+<script lang="ts" setup>
+import { ref, onMounted } from 'vue'
+import { useFs, FsPage } from '@fast-crud/fast-crud'
+import { LocationQueryValue } from 'vue-router'
+import { usePublicData } from '/@/stores/publicData'
+import { storeToRefs } from 'pinia'
+import { createCrudOptions } from './crud'
+import LineChart from './lineChart.vue'
+import DateRangePicker from '/@/components/DateRangePicker/index.vue'
+
+const publicData = usePublicData()
+const { dateRange } = storeToRefs(publicData)
+interface Props {
+  campaignId: LocationQueryValue | LocationQueryValue[]
+}
+const props = defineProps<Props>()
+const queryParams = ref({
+  campaignId: props.campaignId,
+  dateRange
+})
+const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: queryParams })
+
+// onMounted(async () => {
+// 	crudExpose.doRefresh()
+// })
+
+</script>
+
+<style scoped>
+
+</style>

+ 116 - 0
src/views/adManage/sp/campaigns/campaignDetail/budget/lineChart.vue

@@ -0,0 +1,116 @@
+<template>
+  <el-card v-loading="loading" shadow="never" style="margin-bottom: 5px; border-radius:0;">
+    <div style="height: 350px;" ref="chartRef"></div>
+  </el-card>
+</template>
+
+<script lang="ts" setup>
+import { ref,onMounted, onBeforeUnmount, watch, computed } from 'vue'
+import * as echarts from 'echarts'
+import { GetLineList } from './api'
+import { parseQueryParams } from '/@/views/adManage/utils/tools.js'
+
+interface Props {
+  query: any
+}
+const props = defineProps<Props>()
+const chartRef = ref()
+let chartObj:any
+const loading = ref(true)
+const queryParams = computed(() => parseQueryParams(props.query))
+
+const resizeChart = () => { chartObj.resize() }
+const addResize = () => { window.addEventListener('resize', resizeChart) }
+const removeResize = () => { window.removeEventListener('resize', resizeChart) }
+onMounted(() => {
+  addResize()
+  setTimeout(() => { initLine() }, 0)
+})
+onBeforeUnmount(() => {
+	if(chartObj) {
+		chartObj.dispose()
+    chartObj = null
+	}
+  removeResize()
+})
+
+const initLine = async () => {
+  chartObj = echarts.init(chartRef.value)
+  const option = {
+    dataset: {
+      source: []
+    },
+    tooltip: {
+      trigger: 'axis',
+      axisPointer: {
+        label: {
+          backgroundColor: '#6a7985'
+        }
+      }
+    },
+    grid: { top: 30, bottom: 30, left: 30, right: 30 },
+    xAxis: {
+      type: 'category'
+    },
+    yAxis: {
+      type: 'value',
+      name: '预算',
+      axisLine: {
+        show: true,
+				lineStyle: { color: '#0085ff' }
+      },
+    },
+    series: [
+      {
+        type: 'line',
+        encode: {
+          x: 'date',
+          y: 'campaignBudgetAmount'
+        },
+        smooth: true,
+        symbol: 'circle',
+        symbolSize: 4,
+        lineStyle: { width: 2 },
+        itemStyle: {
+          color: '#0085ff',
+          borderColor: '#0085ff'
+        },
+        areaStyle: {
+          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+            { offset: 0, color: '#0085ff93' },
+            { offset: 1, color: '#0085ff03' },
+          ]),
+        },
+      }
+    ]
+  }
+  const items = await getDataset()
+  option.dataset.source = items
+  chartObj.setOption(option)
+  loading.value = false
+}
+const getDataset = async () => {
+  const resp = await GetLineList(queryParams.value)
+  return resp.data
+}
+watch(
+  props.query,
+  async () => {
+    loading.value = true
+
+    const dataset = await getDataset()
+    chartObj.setOption({
+      dataset: {
+        source: dataset
+      }
+    })
+
+    loading.value = false
+  },
+  { deep: true }
+)
+</script>
+
+<style scoped>
+
+</style>

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

@@ -5,28 +5,28 @@
         <span> {{ campaignInfo.campaignName }}</span>
       </span>
       <div class="asj-detail-info">
-        <span>状态:{{ campaignInfo.state }}</span>
-        <span>预算:${{ campaignInfo.budget }}</span>
+        <span>状态:{{ campaignInfo.state }} ({{ campaignInfo.servingStatus }})</span>
+        <span>预算:{{ profile.currency_symbol + campaignInfo.budget }} | {{ campaignInfo.budgetType }}</span>
         <span>投放类型:{{ campaignInfo.targetingType }}</span>
         <span>投放日期:{{ campaignInfo.startDate }} ~ {{ campaignInfo.endDate ?? '无结束日期' }}</span>
-        <span>广告组合:{{ campaignInfo?.portfolio?.name }}</span>
-        <span>竞价策略:{{ campaignInfo.dynBidStrategy }}</span>
+        <span>广告组合:{{ campaignInfo?.portfolioName }}</span>
+        <span>竞价策略:{{ getEnumLabel(dynBidStrategyEnum, campaignInfo.dynBidStrategy) }}</span>
       </div>
     </div>
     <el-tabs type="border-card" class="asj-detail-tabs" v-model="tabActiveName">
       <el-tab-pane label="广告组" name="adGroup">
         <AdGroups :campaignId="route.query.campaignId" v-if="tabActiveName==='adGroup'"></AdGroups>
       </el-tab-pane>
-      <el-tab-pane label="预算" :lazy="true">
-        预算
+      <el-tab-pane label="预算" name="budget">
+        <Budget :campaignId="route.query.campaignId" v-if="tabActiveName==='budget'"></Budget>
       </el-tab-pane>
-      <el-tab-pane label="自动化" :lazy="true">
+      <el-tab-pane label="自动化" name="automation">
         自动化
       </el-tab-pane>
       <el-tab-pane label="广告位" name="placement">
         <Placement :campaignId="route.query.campaignId" v-if="tabActiveName==='placement'"/>
       </el-tab-pane>
-      <el-tab-pane label="否定投放" :lazy="true">
+      <el-tab-pane label="否定投放" name="negative">
         否定投放
       </el-tab-pane>
       <!-- <el-tab-pane label="操作日志" :lazy="true"></el-tab-pane> -->
@@ -39,16 +39,23 @@ import { ref, onMounted, onBeforeMount, Ref } from 'vue'
 import { useRoute, useRouter } from 'vue-router'
 import AdGroups from './adGroups/index.vue'
 import Placement from './placement/index.vue'
+import Budget from './budget/index.vue'
+import { getEnumLabel } from '/@/views/adManage/utils/tools.js'
+import { dynBidStrategyEnum, spCampaignServingStatusEnum } from '/@/views/adManage/utils/enum.js'
+import { useShopInfo } from '/@/stores/shopInfo'
+// import { usePublicData } from '/@/stores/publicData'
+import { storeToRefs } from 'pinia'
 
-import { GetObj } from '../api'
+import { GetObj } from './api'
 
-const router = useRouter()
+const shopInfo = useShopInfo()
+const { profile } = storeToRefs(shopInfo)
 const route = useRoute()
 const campaignInfo: Ref<SpCampaign> = ref({})
 const tabActiveName = ref('adGroup')
 
 onMounted(async () => {
-  const resp = await GetObj(route.query.id)
+  const resp = await GetObj(route.query.campaignId)
   campaignInfo.value = resp.data
 })
 

+ 1 - 6
src/views/adManage/sp/campaigns/campaignDetail/placement/crud.tsx

@@ -1,6 +1,4 @@
-import * as api from './api'
-import { UserPageQuery, CreateCrudOptionsProps, CreateCrudOptionsRet } from '@fast-crud/fast-crud'
-import { inject } from 'vue'
+import { CreateCrudOptionsProps, CreateCrudOptionsRet } from '@fast-crud/fast-crud'
 import { BaseColumn } from '/@/views/adManage/utils/commonTabColumn.js'
 import { spCampaignPlacementEnum } from '/@/views/adManage/utils/enum'
 import XEUtils from 'xe-utils'
@@ -9,9 +7,6 @@ import XEUtils from 'xe-utils'
 export const createCrudOptions = function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
 	const { fetchData } = context
 
-	//权限判定
-	const hasPermissions = inject('$hasPermissions');
-
 	return {
 		crudOptions: {
 			table: {

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

@@ -65,7 +65,6 @@ 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 { getCompareDate } from '/@/views/adManage/utils/tools.js'
 
 const tabActiveName = ref('dataTendency')
 const shopInfo = useShopInfo()
@@ -83,13 +82,10 @@ const showCompare = ref(false)
 onMounted(async () => {
 	crudExpose.doRefresh()
 })
-const compareDate = computed(() => {
-	return getCompareDate(dateRange.value)
-})
 const jumpGroup = (row: any) => {
 	router.push({
 		name: 'CampaignDetail',
-		query: { id: row.id, campaignId: row.campaignId, tagsViewName: row.campaignName },
+		query: { campaignId: row.campaignId, tagsViewName: row.campaignName },
 	})
 }
 

+ 3 - 3
src/views/adManage/sp/index.vue

@@ -30,7 +30,7 @@ import { ref, onBeforeMount, Ref, watch, provide } from 'vue'
 import { useShopInfo } from '/@/stores/shopInfo'
 import { usePublicData } from '/@/stores/publicData'
 import { storeToRefs } from 'pinia'
-import { GetList } from '/@/views/adManage/portfolios/api'
+import { GetAllPortfolios } from '/@/views/adManage/portfolios/api'
 import DateRangePicker from '/@/components/DateRangePicker/index.vue'
 import Campaigns from './campaigns/index.vue'
 import Keywords from './keywords/index.vue'
@@ -40,7 +40,7 @@ import AdvertisedProducts from './advertisedProducts/index.vue'
 import PurchasedOtherProducts from './purchasedOtherProducts/index.vue'
 import Placement from './placement/index.vue'
 
-const shopInfo = useShopInfo()
+// const shopInfo = useShopInfo()
 const publicData = usePublicData()
 const selectedPortfolios: Ref<string[]> = ref([])
 const portfolios: Ref<Portfolio[]> = ref([])
@@ -68,7 +68,7 @@ const tabsComponents: any = {
 provide('dateRange', dateRange)
 
 onBeforeMount(async () => {
-	const resp: APIResponseData = await GetList({ limit: 999 })
+	const resp: APIResponseData = await GetAllPortfolios()
 	portfolios.value = resp.data
 })
 

+ 0 - 4
src/views/adManage/sp/purchasedOtherProducts/index.vue

@@ -54,7 +54,6 @@ import { usePublicData } from '/@/stores/publicData'
 import { storeToRefs } from 'pinia'
 import { spCampaignPuchasedOtherProductsMetricsEnum } from '/@/views/adManage/utils/enum.js'
 import { SpCampaignPuchasedOtherProductsColumn } from '/@/views/adManage/utils/commonTabColumn.js'
-import { getCompareDate } from '/@/views/adManage/utils/tools.js'
 import DataCompare from '/@/components/dataCompare/index.vue'
 
 const tabActiveName = ref("dataTendency")
@@ -73,9 +72,6 @@ const queryParams = ref({
   dateRange
 })
 const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: queryParams })
-const compareDate = computed(() => {
-  return getCompareDate(dateRange.value)
-})
 
 onMounted(async () => {
 	crudExpose.doRefresh()

+ 0 - 4
src/views/adManage/sp/searchTerm/index.vue

@@ -48,7 +48,6 @@ import { useShopInfo } from '/@/stores/shopInfo'
 import { usePublicData } from '/@/stores/publicData'
 import { storeToRefs } from 'pinia'
 import { BaseColumn } from '/@/views/adManage/utils/commonTabColumn.js'
-import { getCompareDate } from '/@/views/adManage/utils/tools.js'
 import DataCompare from '/@/components/dataCompare/index.vue'
 
 const tabActiveName = ref("dataTendency")
@@ -63,9 +62,6 @@ const queryParams = ref({
 })
 const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: queryParams })
 
-const compareDate = computed(() => {
-  return getCompareDate(dateRange.value)
-})
 onMounted(async () => {
 	crudExpose.doRefresh()
 })

+ 26 - 0
src/views/adManage/utils/enum.ts

@@ -40,6 +40,32 @@ export const spCampaignPlacementEnum = [
   { label: '搜索结果的其余位置', value: 'rest_of_search' },
 ]
 
+export const spCampaignStateEnum = [
+  { label: '投放中', value: 'ENABLE' },
+  { label: '已暂停', value: 'PAUSED' },
+  { label: '已归档', value: 'ARCHIVED' },
+  // { label: '', value: 'ENABLING' },
+  // { label: '', value: 'USER_DELETED' },
+  { label: '其它', value: 'OTHER' },
+]
+
+export const spCampaignServingStatusEnum = [
+  { label: '投放中', value: 'CAMPAIGN_STATUS_ENABLED' },
+  { label: '已暂停', value: 'CAMPAIGN_PAUSED' },
+  { label: '已归档', value: 'CAMPAIGN_ARCHIVED' },
+  { label: '超出预算', value: 'CAMPAIGN_OUT_OF_BUDGET' },
+  // { label: '', value: '' },
+  // { label: '', value: '' },
+  // { label: '', value: '' },
+  // { label: '', value: '' },
+  // { label: '', value: '' },
+  // { label: '', value: '' },
+  // { label: '', value: '' },
+  // { label: '', value: '' },
+  // { label: '', value: '' },
+  // { label: '', value: '' }
+]
+
 export const metricMap = {
   'Spend': '花费',
   'TotalSales': '销售额',

+ 4 - 0
src/views/adManage/utils/tools.ts

@@ -63,3 +63,7 @@ export function parseQueryParams(body: any) {
     }
     return ret
 }
+
+export function getEnumLabel(enumObj: {label:string, value:string}[], value: any) {
+    return enumObj.find(item => item.value === value)?.label
+}