Quellcode durchsuchen

广告活动添加时间联动功能

guojing_wu vor 1 Jahr
Ursprung
Commit
d43f0a8c24

+ 1 - 1
.prettierrc.js

@@ -6,7 +6,7 @@ module.exports = {
 	// 使用制表符而不是空格缩进行
 	useTabs: true,
 	// 在语句末尾打印分号
-	semi: true,
+	semi: false,
 	// 使用单引号而不是双引号
 	singleQuote: true,
 	// 更改引用对象属性的时间 可选值"<as-needed|consistent|preserve>"

+ 27 - 20
src/components/MetricsCards/index.vue

@@ -1,8 +1,8 @@
 <template>
-  <div class="metrics-cards" v-loading="loading">
+  <div class="metrics-cards">
     <MCard
      v-model="info.metric"
-     :metric-items="allMetricItems"
+     :metric-items="props.metricItems"
      :color="info.color"
      v-for="info in displayMetrics"
      @change-metric="changedMetric"
@@ -22,31 +22,24 @@ interface Props {
 const colorsMap: { [key: string]: boolean } = {}
 const props = defineProps<Props>()
 const emits = defineEmits(['change', 'update:modelValue'])
-const allMetricItems = ref(props.metricItems)
+// const allMetricItems = ref(props.metricItems)
 const selectedMetric = ref(props.modelValue)
 const displayMetrics: Ref<{metric:string, color?: string}[]> = ref([])
 
 const metricMap = computed(():{[key: string]: string} => {
   const tmp:{[key: string]: string} = {}
-  for (const info of allMetricItems.value) {
+  for (const info of props.metricItems) {
     tmp[info.value] = info.label
   }
   return tmp
 })
-const loading = computed(() => {
-  return displayMetrics.value.length !== 6
-})
 onBeforeMount(()=> {
   const dup:{[key: string]: boolean} = {}
+  // 初始显示图线的三个维度
   for (const info of selectedMetric.value) {
     displayMetrics.value.push({ metric: info.metric, color: info.color })
     dup[info.metric] = true
-    if (info.color) {
-      colorsMap[info.color] = true
-    }
-  }
-  for (const info of allMetricItems.value) {
-    if (info.disabled && !dup[info.value]) { displayMetrics.value.push({ metric: info.value }) }
+    if (info.color) { colorsMap[info.color] = true }
   }
 })
 
@@ -65,7 +58,7 @@ const unsetColor = (color: string ) => {
   }
 }
 const changedMetric = (newVal: string, oldVal: string) => {
-  for (const info of allMetricItems.value) {
+  for (const info of props.metricItems) {
     if (info.value === newVal) {
       info.disabled = true 
     } else if (info.value === oldVal) {
@@ -117,14 +110,28 @@ watch(selectedMetric.value, () => {
 })
 
 watch(
-  allMetricItems.value,
+  props.metricItems,
   () => {
-    const tmp:{[key: string]: boolean} = {}
-    for (const info of displayMetrics.value) {
-      tmp[info.metric] = true
+    const dup:{[key: string]: boolean} = {}
+    for (const info of displayMetrics.value) { dup[info.metric] = true }
+    let needNum = 6 - displayMetrics.value.length
+    if (needNum > 0) {  
+      // 从所有维度中选择剩余
+      for (const info of props.metricItems) {
+        if (!dup[info.value]) {
+          displayMetrics.value.push({ metric: info.value })
+          dup[info.value] = true
+          needNum --
+          if (needNum === 0) break
+        }
+      }
     }
-    for (const info of allMetricItems.value) {
-      if (info.disabled && !tmp[info.value]) { displayMetrics.value.push({ metric: info.value }) }
+    for (const info of props.metricItems) {
+      if (dup[info.value]) {
+        info.disabled = true
+      } else {
+        info.disabled = false
+      }  
     }
   }
 )

+ 2 - 0
src/router/backEnd.ts

@@ -3,6 +3,7 @@ import { storeToRefs } from 'pinia';
 import pinia from '/@/stores/index';
 import { useUserInfo } from '/@/stores/userInfo';
 import { useShopInfo } from '/@/stores/shopInfo';
+import { usePublicData } from '/@/stores/publicData'
 import { useRequestOldRoutes } from '/@/stores/requestOldRoutes';
 import { Session } from '/@/utils/storage';
 import { NextLoading } from '/@/utils/loading';
@@ -47,6 +48,7 @@ export async function initBackEndControlRoutes() {
 	// https://gitee.com/lyt-top/vue-next-admin/issues/I5F1HP
 	await useUserInfo().setUserInfos();
 	await useShopInfo().initShopInfo();
+	usePublicData().initData();
 	// 获取路由菜单数据
 	const res = await getBackEndControlRoutes();
 

+ 16 - 8
src/stores/publicData.ts

@@ -1,18 +1,26 @@
 import { defineStore } from 'pinia'
 import { ref, Ref } from 'vue'
-import XEUtils from 'xe-utils'
 import { Session } from '/@/utils/storage'
+import { recentDaysRange } from '/@/views/adManage/utils/tools'
+import { useShopInfo } from './shopInfo'
 
 export const usePublicData = defineStore('publicData', () => {
-  const data: any = ref(Session.get('publicData') ?? {})
+  const dateRange: Ref<string[]> = ref([])
 
-  function updateData(obj: any) {
-    XEUtils.objectEach(obj, (val, key) => {
-      data.value[key] = val
-    })
-    Session.set('publicData', data.value)
+  function setDateRange(val: string[]) {
+    dateRange.value = val
+    Session.set('dateRange', val)
   }
 
-  return { data, updateData }
+  function initData() {
+    const dateRangeVal = Session.get('dateRange')
+    if (dateRangeVal) {
+      dateRange.value = dateRangeVal
+    } else {
+      setDateRange(recentDaysRange(useShopInfo().profile.time_zone, 7))
+    }
+  }
+
+  return { dateRange, initData, setDateRange }
 })
 

+ 5 - 0
src/types/pinia.d.ts

@@ -89,3 +89,8 @@ declare interface ThemeConfigState {
 		globalComponentSize: string;
 	};
 }
+
+declare interface publicData {
+	dateRange: string[],
+	[key:string]: any
+}

+ 1 - 1
src/views/adManage/sp/adGroups/index.vue

@@ -29,7 +29,7 @@ interface Props {
   campaignId: LocationQueryValue | LocationQueryValue[]
 }
 const props = defineProps<Props>()
-const dateRange: Ref<string[]> = ref(publicData.data.dateRange)
+const dateRange: Ref<string[]> = ref(publicData.dateRange)
 const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: { campaignId: props.campaignId } })
 
 onMounted(() => {

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

@@ -49,7 +49,7 @@ defineOptions({
 })
 const publicData = usePublicData()
 const shopInfo = useShopInfo()
-const dateRange: Ref<string[]> = ref(publicData.data.dateRange)
+const dateRange: Ref<string[]> = ref(publicData.dateRange)
 interface Props {
   campaignId: LocationQueryValue | LocationQueryValue[]
 }

+ 30 - 9
src/views/adManage/sp/campaigns/chartComponents/dataTendency.vue

@@ -1,6 +1,8 @@
 <template>
-	<MetricsCards v-model="metrics" :metric-items="metricsItems" @change="changeMetric"></MetricsCards>
-  <div style="height: 350px;" ref="chartRef"></div>
+  <div v-loading="loading">
+    <MetricsCards v-model="metrics" :metric-items="metricsItems" @change="changeMetric"></MetricsCards>
+    <div style="height: 350px;" ref="chartRef"></div>
+  </div>
 </template>
 
 <script lang="ts" setup>
@@ -12,15 +14,15 @@ import { spCampaignMetricsEnum } from '/@/views/adManage/utils/enum.js'
 import MetricsCards from '/@/components/MetricsCards/index.vue'
 import XEUtils from 'xe-utils'
 import { buildChartOpt } from '/@/views/adManage/utils/tools.js'
+import { usePublicData } from '/@/stores/publicData'
+import { storeToRefs } from 'pinia'
 
 defineOptions({
   name: "DataTendencyChart"
 })
 
-onBeforeMount(async () => {
-	await getMetricsItems()
-})
 onMounted(() => {
+  getMetricsItems()
 	initLine()
 	addResize()
 });
@@ -32,6 +34,7 @@ onBeforeUnmount(() => {
   removeResize()
 })
 
+const publicData = usePublicData()
 const metrics = ref([
   {metric: 'Impression', color: '#0085ff', 'label': '曝光量'},
   {metric: 'Click', color: '#3fd4cf', 'label': '点击量'},
@@ -177,23 +180,31 @@ const option: any = {
     }
   ]
 }
+const { dateRange } = storeToRefs(publicData)
+const loading = ref(true)
+
 const getDataset = async () => {
-	const resp = await getLineData({profile: shopInfo.profile.profile_id, start: '2023-11-01', end: '2023-11-04'})
+	const resp = await getLineData({profile: shopInfo.profile.profile_id, start: dateRange.value[0], end: dateRange.value[1]})
 	return resp.data
 }
 const initLine = async () => {
 	chartObj = echarts.init(chartRef.value)
 	const items = await getDataset()
 	option.dataset.source = items
+  XEUtils.arrayEach(metricsItems.value, info => {
+    option.legend.selected[info.label] = false
+  })
   for(const info of metrics.value) {
     option.legend.selected[info.label] = true
   }
 	chartObj.setOption(option)
+  loading.value = false
 }
 
 const getMetricsItems = async () => {
-	const resp = await getCardData({start: '2023-11-01', end: '2023-11-04', profile: shopInfo.profile.profile_id})
+	const resp = await getCardData({start: dateRange.value[0], end: dateRange.value[1], profile: shopInfo.profile.profile_id})
 	const data = resp.data
+  metricsItems.value.length = 0
 	XEUtils.arrayEach(spCampaignMetricsEnum, info => {
 		const tmp:MetricData = { 
 			label: info.label, 
@@ -201,10 +212,8 @@ const getMetricsItems = async () => {
 			metricVal: data[info.value],
 			gapVal: data[`gap${info.value}`],
 			preVal: data[`prev${info.value}`],
-			disabled: info.initShow ? true : false
 		}
 		metricsItems.value.push(tmp)
-    option.legend.selected[info.label] = false
 	})
 }
 
@@ -213,6 +222,18 @@ const changeMetric = () => {
   chartObj.setOption(opt)
 }
 
+watch(
+  dateRange, 
+  async () => {
+    loading.value = true
+    await getMetricsItems()
+    const items = await getDataset()
+    const opt = { dataset: { source: items } }
+    chartObj.setOption(opt)
+    loading.value = false
+  }
+)
+
 const resizeChart = () => { chartObj.resize() }
 const addResize = () => { window.addEventListener('resize', resizeChart) }
 const removeResize = () => { window.removeEventListener('resize', resizeChart) }

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

@@ -27,13 +27,12 @@
 			<template #cell_MissedSales="scope">
         {{ scope.row.MissedSalesLower ?? '0' }} ~ {{ scope.row.MissedSalesUpper ?? '0' }}
       </template>
-
 		</fs-crud>
 	</fs-page>
 </template>
 
 <script lang="ts" setup>
-import {ref, onMounted, Ref, nextTick, onBeforeMount, inject} from 'vue'
+import {ref, onMounted, Ref, nextTick, onBeforeMount} from 'vue'
 import { useFs, FsPage } from '@fast-crud/fast-crud';
 import { createCrudOptions } from './crud';
 import { useShopInfo } from '/@/stores/shopInfo'

+ 47 - 48
src/views/adManage/sp/index.vue

@@ -1,72 +1,71 @@
 <template>
-    <div class="asj-container">
-        <div class="public-search">
-            <DateRangePicker v-model="dateRange" :timezone="shopInfo.profile.time_zone"></DateRangePicker>
-            <el-select v-model="selectedPortfolios" placeholder="广告组合" clearable multiple>
-                <el-option v-for="info of portfolios" :label="info.name" :value="info.portfolioId"></el-option>
-            </el-select>
-        </div>
-        <el-tabs v-model="tabActiveName" class="asj-tabs" @tab-change="changeTab">
-            <el-tab-pane label="广告活动" name="campaigns">
-                <Campaigns ref="campaignsRef"/>
-            </el-tab-pane>
-            <el-tab-pane label="关键词投放" name="keywords" :lazy="true">
-                <Keywords ref="keywordsRef"/>
-            </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-tabs>
-    </div>
+	<div class="asj-container">
+		<div class="public-search">
+			<DateRangePicker v-model="dateRange" :timezone="shopInfo.profile.time_zone"></DateRangePicker>
+			<el-select v-model="selectedPortfolios" placeholder="广告组合" clearable multiple style="width: 400px;"
+				collapse-tags
+				collapse-tags-tooltip
+				:max-collapse-tags="3">
+				<el-option v-for="info of portfolios" :label="info.name" :value="info.portfolioId"></el-option>
+			</el-select>
+		</div>
+		<el-tabs v-model="tabActiveName" class="asj-tabs" @tab-change="changeTab">
+			<el-tab-pane label="广告活动" name="campaigns">
+				<Campaigns ref="campaignsRef" />
+			</el-tab-pane>
+			<el-tab-pane label="关键词投放" name="keywords" :lazy="true">
+				<Keywords ref="keywordsRef" />
+			</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-tabs>
+	</div>
 </template>
 
 <script lang="ts" setup>
 import DateRangePicker from '/@/components/DateRangePicker/index.vue'
 import Campaigns from './campaigns/index.vue'
 import Keywords from './keywords/index.vue'
-import {recentDaysRange} from '/@/views/adManage/utils/tools'
-import {ref, onBeforeMount, Ref, provide, watch, reactive} from 'vue'
-import {useShopInfo} from '/@/stores/shopInfo'
-import {usePublicData} from '/@/stores/publicData'
-import {GetList} from '/@/views/adManage/portfolios/api'
-import {nextTick} from 'process'
-import {getAdStructureData} from '/@/views/adManage/sp/campaigns/api'
-
+import { recentDaysRange } from '/@/views/adManage/utils/tools'
+import { ref, onBeforeMount, Ref, watch, provide } from 'vue'
+import { useShopInfo } from '/@/stores/shopInfo'
+import { usePublicData } from '/@/stores/publicData'
+import { GetList } from '/@/views/adManage/portfolios/api'
+import { nextTick } from 'process'
+import { storeToRefs } from 'pinia'
 
 const shopInfo = useShopInfo()
 const publicData = usePublicData()
 const selectedPortfolios: Ref<string[]> = ref([])
 const portfolios: Ref<Portfolio[]> = ref([])
-const dateRange: Ref<string[]> = ref(['2023-11-01', '2023-11-04'])
+const { dateRange } = storeToRefs(publicData)
 const tabActiveName = ref('campaigns')
 const keywordsRef = ref()
 const campaignsRef = ref()
 
-publicData.updateData({dateRange: dateRange.value})
 provide('dateRange', dateRange)
 
 onBeforeMount(async () => {
-    console.log(shopInfo.profile)
-    // dateRange.value = recentDaysRange(shopInfo.profile.time_zone, 7)
-
-    const resp: APIResponseData = await GetList({limit: 999})
-    portfolios.value = resp.data
+	const resp: APIResponseData = await GetList({ limit: 999 })
+	portfolios.value = resp.data
 })
 const changeTab = () => {
-    nextTick(() => {
-        campaignsRef.value.resizeTabChart()
-        keywordsRef.value.resizeTabChart()
-    })
+	nextTick(() => {
+		campaignsRef.value.resizeTabChart()
+		keywordsRef.value.resizeTabChart()
+	})
 }
-watch(
-        dateRange,
-        () => {
-            publicData.updateData({dateRange: dateRange.value})
-        }
-)
-
+publicData.$subscribe((mutation, state) => {
+	// console.log(mutation)
+	// console.log(state.dateRange)
+	publicData.setDateRange(state.dateRange)
+})
 </script>
 
-<style>
-
-</style>
+<style></style>

+ 6 - 6
src/views/adManage/utils/enum.ts

@@ -1,10 +1,10 @@
 export const spCampaignMetricsEnum = [
-  {label: '曝光量', value: 'Impression', initShow: true},
-  {label: '点击量', value: 'Click', initShow: true},
-  {label: '花费', value: 'Spend', initShow: true},
-  {label: '订单量', value: 'TotalPurchases', initShow: true},
-  {label: '销售额', value: 'TotalSales', initShow: true},
-  {label: '销量', value: 'TotalUnitOrdered', initShow: true},
+  {label: '曝光量', value: 'Impression'},
+  {label: '点击量', value: 'Click'},
+  {label: '花费', value: 'Spend'},
+  {label: '订单量', value: 'TotalPurchases'},
+  {label: '销售额', value: 'TotalSales'},
+  {label: '销量', value: 'TotalUnitOrdered'},
   {label: '点击率', value: 'CTR'},
   {label: '点击成本', value: 'CPC'},
   {label: '转化率', value: 'PurchasesRate'},