Selaa lähdekoodia

Merge remote-tracking branch 'origin/test' into test

# Conflicts:
#	src/views/adManage/sp/index.vue
WanGxC 1 vuosi sitten
vanhempi
commit
8582df7929

+ 47 - 19
src/components/MetricsCards/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="metrics-cards">
+  <div class="metrics-cards" v-loading="loading">
     <MCard
      v-model="info.metric"
      :metric-items="allMetricItems"
@@ -11,45 +11,59 @@
 </template>
 
 <script lang="ts" setup>
-import { ref, withDefaults, Ref, onBeforeMount, watch, computed,ComputedRef } from 'vue'
+import { ref, Ref, onBeforeMount, watch, onMounted, computed } from 'vue'
 import MCard from './mCard.vue'
+import XEUtils from 'xe-utils';
 
-interface ModelData {
-  metric: string,
-  color: string
-}
 interface Props {
-  modelValue: ModelData[],
+  modelValue: ShowMetric[],
   metricItems: MetricData[],
-  colors?: string[]
 }
 const colorsMap: { [key: string]: boolean } = {}
-const props = withDefaults(defineProps<Props>(), { colors: () => ["aqua", "orange", "blue"] })
+const props = defineProps<Props>()
 const emits = defineEmits(['change', 'update:modelValue'])
 const allMetricItems = ref(props.metricItems)
 const selectedMetric = ref(props.modelValue)
 const displayMetrics: Ref<{metric:string, color?: string}[]> = ref([])
 
-onBeforeMount(()=> {
-  for (const color of props.colors) {
-    colorsMap[color] = false
+const metricMap = computed(():{[key: string]: string} => {
+  const tmp:{[key: string]: string} = {}
+  for (const info of allMetricItems.value) {
+    tmp[info.value] = info.label
   }
-  const tmp:{[key: string]: boolean} = {}
+  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 })
-    tmp[info.metric] = true
+    dup[info.metric] = true
+    if (info.color) {
+      colorsMap[info.color] = true
+    }
   }
   for (const info of allMetricItems.value) {
-    if (info.disabled && !tmp[info.value]) { displayMetrics.value.push({ metric: info.value }) }
+    if (info.disabled && !dup[info.value]) { displayMetrics.value.push({ metric: info.value }) }
   }
 })
 
 const getColor = () => {
   for (const [k,v] of Object.entries(colorsMap)) {
-    if (!v) return k
+    if (!v) {
+      colorsMap[k] = true
+      return k
+    }
   }
   return ""
 }
+const unsetColor = (color: string ) => {
+  if (XEUtils.has(colorsMap, color)) {
+    colorsMap[color] = false
+  }
+}
 const changedMetric = (oldVal: string, newVal: string) => {
   for (const info of allMetricItems.value) {
     if (info.value === newVal) {
@@ -61,6 +75,7 @@ const changedMetric = (oldVal: string, newVal: string) => {
   const index = selectedMetric.value.findIndex( info => info.metric === oldVal)
   if (index > -1) {
     selectedMetric.value[index].metric = newVal
+    selectedMetric.value[index].label = metricMap.value[newVal]
     emits('update:modelValue', selectedMetric.value)
     emits('change', selectedMetric.value)
   }
@@ -71,16 +86,16 @@ const clickCard = (metric: string) => {
     if (selectedMetric.value.length <= 1 ) return
     const tmp = selectedMetric.value[index]
     selectedMetric.value.splice(index, 1)
-    colorsMap[tmp.color] = false
+    unsetColor(tmp.color)
     emits('update:modelValue', selectedMetric.value)
     emits('change', selectedMetric.value)
   } else {  // 不存在则添加
     if (selectedMetric.value.length === 3) { 
       selectedMetric.value[2].metric = metric
+      selectedMetric.value[2].label = metricMap.value[metric]
     } else {
       const color = getColor()
-      colorsMap[color] = true
-      selectedMetric.value.push({ metric: metric, color: color})
+      selectedMetric.value.push({ metric: metric, color: color, label: metricMap.value[metric]})
     }
     emits('update:modelValue', selectedMetric.value)
     emits('change', selectedMetric.value)
@@ -101,6 +116,19 @@ watch(selectedMetric.value, () => {
   }
 })
 
+watch(
+  allMetricItems.value,
+  () => {
+    const tmp:{[key: string]: boolean} = {}
+    for (const info of displayMetrics.value) {
+      tmp[info.metric] = true
+    }
+    for (const info of allMetricItems.value) {
+      if (info.disabled && !tmp[info.value]) { displayMetrics.value.push({ metric: info.value }) }
+    }
+  }
+)
+
 </script>
 
 <style scoped>

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

@@ -6,10 +6,10 @@
     <div class="metric-pre">
       <span>{{ selectedData?.preVal }}&nbsp;&nbsp;</span>
       <el-icon>
-        <!-- <Bottom class="green"/> -->
-        <Top class="green"/>
+        <Top :class="colorClass" v-if="isBoost"/>
+        <Bottom :class="colorClass" v-else/>
       </el-icon>
-      <span class="green">{{ selectedData?.gapVal }}</span>
+      <span :class="colorClass">{{ selectedData?.gapVal }}</span>
     </div>
   </el-card>
 </template>
@@ -44,6 +44,10 @@ const boardTopStyle = computed(() => {
   if (props.color) { style_["border-top-color"] = props.color }
   return style_
 })
+const isBoost = computed(():boolean => {
+  return (selectedData.value?.gapVal ?? -1) > 0
+})
+const colorClass = computed((): "green"|"red" => isBoost.value ? "green": "red")
 
 </script>
 

+ 1 - 1
src/components/TextSelector/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <el-dropdown class="el-dropdown-link" @command="handleCommand" trigger="click">
+  <el-dropdown class="el-dropdown-link" @command="handleCommand" trigger="click" placement="bottom-start">
     <span @click.stop>
       {{ displayLabel }}
       <el-icon>

+ 268 - 0
src/components/echartsComponents/dataTendency.vue

@@ -0,0 +1,268 @@
+<template>
+  <div ref="chartRef" :style="{height:height, width:width}"></div>
+  <p>{{ props.showMetrics }}</p>
+</template>
+
+<script lang="ts" setup>
+import { ref, onMounted, onBeforeUnmount, watch } from 'vue'
+import * as echarts from 'echarts'
+import XEUtils from 'xe-utils'
+
+defineOptions({
+  name: 'DataTendencyChart'
+})
+interface Props {
+  dataset: {[key: string]: any}[],
+  showMetrics: ShowMetric[],
+  width: string,
+  height: string
+}
+
+const props = withDefaults(defineProps<Props>(), { width: "100%", height: "500px" })
+const chartRef = ref()
+let chartObj:any
+const resizeChart = () => { chartObj.resize() }
+const addResize = () => { window.addEventListener('resize', resizeChart) }
+const removeResize = () => { window.removeEventListener('resize', resizeChart) }
+const option: {[key: string]: any} = {
+  dataset: {
+    source: props.dataset
+  },
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'cross',
+      label: {
+        backgroundColor: '#6a7985'
+      }
+    }
+  },
+  legend: {
+    selected: {},  // 控制显隐
+    show: false
+  },
+  grid: {
+    top: 50, right: 150, bottom: 30, left: 55,
+  },
+  xAxis: {
+    type: 'time'
+  },
+  yAxis: [
+    {
+      type: 'value',
+      name: '',
+      splitLine: {
+        show: true // 设置显示分割线
+      },
+      // axisLabel: {
+      //   formatter: '{value}'
+      // },
+      axisLine: {
+        show: true
+      },
+      show: false
+    },
+    {
+      type: 'value',
+      name: '',
+      position: 'right',
+      splitLine: {
+        show: false
+      },
+      // axisLabel: {
+      //   formatter: '{value} 单位2'
+      // },
+      axisLine: {
+        show: true
+      },
+      show: false
+    },
+    {
+      type: 'value',
+      position: 'right',
+      offset: 80,
+      name: '',
+      splitLine: {
+        show: false
+      },
+      // axisLabel: {
+      //   formatter: '{value} 单位3'
+      // },
+      axisLine: {
+        show: true
+      },
+      show: false
+    }
+  ],
+  series: [
+    {
+      name: '',
+      type: 'bar',
+      encode: {
+        x: 'date',
+        y: ''
+      },
+      // tooltip: {
+      //   valueFormatter: function (value) {
+      //     return value + ' ml';
+      //   }
+      // },
+      barWidth: '20px',
+      yAxisIndex: 0,
+      itemStyle: {
+        // color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+        //     { offset: 0, color: 'rgba(111, 209, 206, 0.8)' },
+        //     { offset: 1, color: 'rgba(111, 209, 206, 0.1)' },
+        // ]),
+        color: '',
+        //柱状图圆角
+        borderRadius: [15, 15, 0, 0],
+      }
+    },
+    {
+      name: '',
+      type: 'line',
+      encode: {
+        x: 'date',
+        y: ''
+      },
+      symbolSize: 6,
+      symbol: 'circle',
+      smooth: true,
+      yAxisIndex: 1,
+      // lineStyle: { color: '#fe9a8b' },
+      itemStyle: { color: '#fe9a8b', borderColor: '#fe9a8b' },
+      areaStyle: {
+        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+          { offset: 0, color: '#fe9a8bb3' },
+          { offset: 1, color: '#fe9a8b03' },
+        ]),
+      },
+    },
+    {
+      name: '',
+      type: 'line',
+      encode: {
+        x: 'date',
+        y: ''
+      },
+      symbolSize: 6,
+      symbol: 'circle',
+      smooth: true,
+      yAxisIndex: 2,
+      // lineStyle: { color: '#9E87FF' },
+      itemStyle: { color: '#9E87FF', borderColor: '#9E87FF' },
+      areaStyle: {
+        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+          { offset: 0, color: '#9E87FFb3' },
+          { offset: 1, color: '#9E87FF03' },
+        ]),
+      },
+      emphasis: {
+        itemStyle: {
+          color: {
+            type: 'radial',
+            x: 0.5,
+            y: 0.5,
+            r: 0.5,
+            colorStops: [
+              { offset: 0, color: '#9E87FF' },
+              { offset: 0.4, color: '#9E87FF' },
+              { offset: 0.5, color: '#fff' },
+              { offset: 0.7, color: '#fff' },
+              { offset: 0.8, color: '#fff' },
+              { offset: 1, color: '#fff' },
+            ],
+          },
+          borderColor: '#9E87FF',
+          borderWidth: 2,
+        },
+      }
+    }
+  ]
+}
+
+onMounted(() => {
+	initLine()
+	addResize()
+})
+onBeforeUnmount(() => {
+	if(chartObj) {
+		chartObj.dispose()
+    chartObj = null
+	}
+  removeResize()
+})
+watch(
+  props.showMetrics,
+  () => {
+    // const option: any = {
+    //   legend: {
+    //     selected: {},
+    //     yAxis: [
+    //       {name: '', show: false},
+    //       {name: '', show: false},
+    //       {name: '', show: false}
+    //     ],
+    //     series: [
+    //       {name: '', encode: {y: ''}, itemStyle: {color: ''}},
+    //       {name: '', encode: {y: ''}, itemStyle: {color: ''}},
+    //       {name: '', encode: {y: ''}, itemStyle: {color: ''}}
+    //     ]
+    //   } 
+    // }
+    const tmp:{[key: string]: boolean} = {}
+    for (const info of props.showMetrics) { tmp[info.metric] = true }
+    for (const key of XEUtils.keys(option.legend.selected)) {
+      if (XEUtils.has(tmp, key)) {
+        option.legend.selected[key] = true
+      } else {
+        option.legend.selected[key] = false
+      }
+    }
+    
+    for (const [metricInfo, yInfo, sInfo] of XEUtils.zip(props.showMetrics, option.yAxis, option.series)) {
+      if (metricInfo) {
+        yInfo.name = metricInfo.label
+        yInfo.show = true
+
+        sInfo.name = metricInfo.label
+        sInfo.encode.y = metricInfo.metric
+        sInfo.itemStyle.color = metricInfo.color
+        
+      } else {
+        yInfo.show = false
+      }
+    }
+
+    console.log(option)
+    
+    chartObj.setOption(option)
+  }
+)
+
+const initLine = () => {
+	chartObj = echarts.init(chartRef.value)
+	
+  const tmp:{[key: string]: boolean} = {}
+  for (const info of props.showMetrics) { tmp[info.metric] = true }
+  option.legend.selected = tmp
+
+  props.showMetrics.forEach((info, index) => {
+    option.yAxis[index].name = info.label
+    option.yAxis[index].show = true
+
+    option.series[index].name = info.label
+    option.series[index].encode.y = info.metric
+    option.series[index].itemStyle.color = info.color
+  })
+  console.log(option)
+	chartObj.setOption(option)
+}
+
+defineExpose({resizeChart})
+
+</script>
+
+<style scoped>
+</style>

+ 18 - 0
src/stores/publicData.ts

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

+ 3 - 3
src/stores/themeConfig.ts

@@ -64,7 +64,7 @@ export const useThemeConfig = defineStore('themeConfig', {
 			// 是否开启菜单手风琴效果
 			isUniqueOpened: true,
 			// 是否开启固定 Header
-			isFixedHeader: false,
+			isFixedHeader: true,
 			// 初始化变量,用于更新菜单 el-scrollbar 的高度,请勿删除
 			isFixedHeaderChange: false,
 			// 是否开启经典布局分割菜单(仅经典布局生效)
@@ -111,7 +111,7 @@ export const useThemeConfig = defineStore('themeConfig', {
 			 */
 			// Tagsview 风格:可选值"<tags-style-one|tags-style-four|tags-style-five>",默认 tags-style-five
 			// 定义的值与 `/src/layout/navBars/tagsView/tagsView.vue` 中的 class 同名
-			tagsStyle: 'tags-style-five',
+			tagsStyle: 'tags-style-one',
 			// 主页面切换动画:可选值"<slide-right|slide-left|opacitys>",默认 slide-right
 			animation: 'slide-right',
 			// 分栏高亮风格:可选值"<columns-round|columns-card>",默认 columns-round
@@ -141,7 +141,7 @@ export const useThemeConfig = defineStore('themeConfig', {
 			// 网站副标题(登录页顶部文字)
 			globalViceTitle: 'DVAdmin',
 			// 网站副标题(登录页顶部文字)
-			globalViceTitleMsg: '企业级快速开发平台',
+			globalViceTitleMsg: '广告管理系统',
 			// 默认初始语言,可选值"<zh-cn|en|zh-tw>",默认 zh-cn
 			globalI18n: 'zh-cn',
 			// 默认全局组件大小,可选值"<large|'default'|small>",默认 'large'

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

@@ -341,10 +341,16 @@ declare interface MetricOptions {
   disabled?: boolean
 }
 
+declare interface ShowMetric {
+	label: string,
+	metric: string,
+	color: string
+}
+
 declare interface MetricData extends MetricOptions {
   metricVal: string,
-  preVal?: string,
-  gapVal?: string
+  preVal?: number,
+  gapVal?: number
 }
 
 declare interface Portfolio {

+ 1 - 1
src/utils/service.ts

@@ -172,7 +172,7 @@ function createRequestFunction(service: any) {
 			headers: {
 				'Content-Type': get(config, 'headers.Content-Type', 'application/json'),
 			},
-			timeout: 5000,
+			timeout: 10000,
 			baseURL: getBaseURL(),
 			data: {},
 		};

+ 18 - 3
src/views/adManage/sp/adGroups/api.ts

@@ -1,9 +1,8 @@
 import { request } from '/@/utils/service';
-import { PageQuery, AddReq, DelReq, EditReq, InfoReq } from '@fast-crud/fast-crud';
-import XEUtils from 'xe-utils';
+import { UserPageQuery, AddReq, DelReq, EditReq, InfoReq } from '@fast-crud/fast-crud';
 
 export const apiPrefix = '/api/ad_manage/spgroups/';
-export function GetList(query: PageQuery) {
+export function GetList(query: UserPageQuery) {
     return request({
         url: apiPrefix,
         method: 'get',
@@ -40,3 +39,19 @@ export function DelObj(id: DelReq) {
         data: { id },
     });
 }
+
+export function getCardData(query: UserPageQuery) {
+    return request({
+        url: apiPrefix + "total/",
+        method: 'GET',
+        params: query
+    })
+}
+
+export function getLineData(query: UserPageQuery) {
+    return request({
+        url: apiPrefix + "daily/",
+        method: 'GET',
+        params: query
+    })
+}

+ 111 - 0
src/views/adManage/sp/adGroups/chartComponents/adGroup.vue

@@ -0,0 +1,111 @@
+<template>
+  <MetricsCards v-model="metrics" :metric-items="metricItems" @change="changeMetric"></MetricsCards>
+  <div style="height: 500px;" ref="chartRef"></div>
+</template>
+
+<script lang="ts" setup>
+import { ref,onBeforeMount,onMounted,onBeforeUnmount,inject, Ref } from 'vue'
+import MetricsCards from '/@/components/MetricsCards/index.vue'
+import { useShopInfo } from '/@/stores/shopInfo'
+import * as echarts from 'echarts'
+import XEUtils from 'xe-utils'
+import { getLineData, getCardData } from '../api'
+import { spCampaignMetricsEnum } from '/@/views/adManage/utils/enum.js'
+
+defineOptions({name: 'AdGroupChart'})
+
+const shopInfo = useShopInfo()
+const metrics = ref([
+  {metric: 'Impression', color: 'aqua', 'label': '曝光量'},
+  {metric: 'Click', color: 'blue', 'label': '点击量'},
+  {metric: 'Spend', color: 'orange', 'label': '花费'},
+])
+const metricItems: Ref<MetricData[]> = ref([])
+let chartObj:any
+const chartRef = ref()
+const dateRange: string[] = inject('dateRange', [])
+
+onBeforeMount(async () => {
+	await getMetricItems()
+})
+onMounted(() => {
+	initLine()
+	addResize()
+})
+onBeforeUnmount(() => {
+	if(chartObj) {
+		chartObj.dispose()
+    chartObj = null
+	}
+  removeResize()
+})
+
+const getMetricItems = async () => {
+	const resp = await getCardData({start: dateRange[0], end: dateRange[1], profile: shopInfo.profile.profile_id})
+	const data = resp.data
+	XEUtils.arrayEach(spCampaignMetricsEnum, info => {
+		const tmp: MetricData = { 
+			label: info.label, 
+			value: info.value,
+			metricVal: data[info.value],
+			gapVal: data[`gap${info.value}`],
+			preVal: data[`prev${info.value}`],
+			disabled: info.initShow ? true : false
+		}
+		metricItems.value.push(tmp)
+	})
+}
+const getDataset = async () => {
+	const resp = await getLineData({profile: shopInfo.profile.profile_id, start: dateRange[0], end: dateRange[1]})
+	return resp.data
+}
+const initLine = async () => {
+	chartObj = echarts.init(chartRef.value)
+	
+  const option: any = {
+    dataset: {
+      source: []
+    },
+    tooltip: {
+      trigger: 'axis',
+      axisPointer: {
+        // type: 'cross',
+        label: {
+          backgroundColor: '#6a7985'
+        }
+      }
+    },
+    legend: {
+      selected: {},  // 控制显隐
+      show: false
+    },
+    grid: {
+      top: 50, right: 150, bottom: 30, left: 55,
+    },
+    xAxis: {
+      type: 'time'
+    },
+    yAxis: [],
+    series: []
+  }
+
+	const items = await getDataset()
+	option.dataset.source = items
+
+	
+	// chartObj.setOption(option)
+}
+const changeMetric = () => {
+
+}
+
+const resizeChart = () => { chartObj.resize() }
+const addResize = () => { window.addEventListener('resize', resizeChart) }
+const removeResize = () => { window.removeEventListener('resize', resizeChart) }
+
+// defineExpose({resizeChart})
+</script>
+
+<style scoped>
+
+</style>

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

@@ -5,7 +5,7 @@
         <DateRangePicker v-model="dateRange" timezone="America/Los_Angeles" style="margin-bottom: 5px;"></DateRangePicker>
       </template>
       <template #header-middle>
-        <MetricsCards v-model="metrics" :metric-items="options" @change="changeMetric"></MetricsCards>
+        <AdGroupChart/>
       </template>
       <template #cell_adGroupName="scope">
         <el-link type="primary" :underline="false" @click="jumpAds(scope.row)">{{ scope.row.adGroupName }}</el-link>
@@ -18,15 +18,17 @@
 import { Ref, ref, onMounted } from 'vue'
 import { useFs, FsPage } from '@fast-crud/fast-crud';
 import DateRangePicker from '/@/components/DateRangePicker/index.vue'
-import MetricsCards from '/@/components/MetricsCards/index.vue'
 import { createCrudOptions } from './crud';
 import { useRoute, useRouter } from 'vue-router'
+import AdGroupChart from './chartComponents/adGroup.vue'
+import { usePublicData } from '/@/stores/publicData'
 
+const publicData = usePublicData()
 const router = useRouter()
 const props = defineProps({
   campaignId: { type: String, required: true }
 })
-const dateRange: Ref<string[]> = ref([])
+const dateRange: Ref<string[]> = ref(publicData.data.dateRange)
 const metrics = ref([{metric: 'ACOS', color: 'blue'}])
 const options = ref([
   {label: 'ACOS', value: 'ACOS', metricVal: "18.00%", preVal: '20.15%', gapVal: '-2.00%', disabled:true},

+ 19 - 3
src/views/adManage/sp/campaigns/api.ts

@@ -1,16 +1,16 @@
 import { request } from '/@/utils/service';
-import { PageQuery, AddReq, DelReq, EditReq, InfoReq } from '@fast-crud/fast-crud';
+import { UserPageQuery, AddReq, DelReq, EditReq, InfoReq } from '@fast-crud/fast-crud';
 import XEUtils from 'xe-utils';
 
 export const apiPrefix = '/api/ad_manage/spcampaigns/';
-export function GetList(query: PageQuery) {
+export function GetList(query: UserPageQuery) {
     return request({
         url: apiPrefix,
         method: 'get',
         params: query,
     })
 }
-export function GetObj(id: InfoReq) {
+export function GetObj(id: any) {
     return request({
         url: apiPrefix + id + "/",
         method: 'get',
@@ -40,3 +40,19 @@ export function DelObj(id: DelReq) {
         data: { id },
     });
 }
+
+export function getCardData(query: UserPageQuery) {
+    return request({
+        url: apiPrefix + "total/",
+        method: 'GET',
+        params: query
+    })
+}
+
+export function getLineData(query: UserPageQuery) {
+    return request({
+        url: apiPrefix + "daily/",
+        method: 'GET',
+        params: query
+    })
+}

+ 136 - 23
src/views/adManage/sp/campaigns/chartComponents/dataTendency.vue

@@ -1,21 +1,24 @@
 <template>
-  <div style="height: 500px;" ref="lineRef"></div>
+	<MetricsCards v-model="metrics" :metric-items="metricsItems" @change="changeMetric"></MetricsCards>
+  <div style="height: 500px;" ref="chartRef"></div>
 </template>
 
 <script lang="ts" setup>
-import { ref,onMounted, onBeforeUnmount } from 'vue'
+import { ref,onMounted, onBeforeUnmount, Ref, onBeforeMount, watch, computed, inject } from 'vue'
 import * as echarts from 'echarts'
+import { useShopInfo } from '/@/stores/shopInfo'
+import { getLineData, getCardData } from '../api'
+import { spCampaignMetricsEnum } from '/@/views/adManage/utils/enum.js'
+import MetricsCards from '/@/components/MetricsCards/index.vue'
+import XEUtils from 'xe-utils'
 
 defineOptions({
   name: "DataTendencyChart"
 })
 
-let chartObj:any
-const lineRef = ref()
-const resizeChart = () => { chartObj.resize() }
-const addResize = () => { window.addEventListener('resize', resizeChart) }
-const removeResize = () => { window.removeEventListener('resize', resizeChart) }
-
+onBeforeMount(async () => {
+	await getMetricsItems()
+})
 onMounted(() => {
 	initLine()
 	addResize()
@@ -27,26 +30,136 @@ onBeforeUnmount(() => {
 	}
   removeResize()
 })
-const initLine = () => {
-	chartObj = echarts.init(lineRef.value)
-	const option = {
-		xAxis: {
-			data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
-		},
-		yAxis: {},
-		series: [
-			{
-				type: 'bar',
-				data: [23, 24, 18, 25, 27, 28, 25]
-			}
-		]
-	}
+
+let chartObj:any
+const chartRef = ref()
+const dateRange: string[] = inject('dateRange', [])
+const shopInfo = useShopInfo()
+// 初始显示指标,长度必须为3
+const metrics = ref([  
+  {metric: 'Impression', color: '#3fd4cf', 'label': '曝光量'},
+  {metric: 'Click', color: '#0085ff', 'label': '点击量'},
+  {metric: 'Spend', color: '#ff9500', 'label': '花费'},
+])
+const metricsItems: Ref<MetricData[]> = ref([])
+
+const getDataset = async () => {
+	const resp = await getLineData({profile: shopInfo.profile.profile_id, start: dateRange[0], end: dateRange[1]})
+	return resp.data
+}
+const initLine = async () => {
+	chartObj = echarts.init(chartRef.value)
+	
+  const option: any = {
+    dataset: {
+      source: []
+    },
+    tooltip: {
+      trigger: 'axis',
+      axisPointer: {
+        // type: 'cross',
+        label: {
+          backgroundColor: '#6a7985'
+        }
+      }
+    },
+    legend: {
+      selected: {},  // 控制显隐
+      show: false
+    },
+    grid: {
+      top: 50, right: 150, bottom: 30, left: 55,
+    },
+    xAxis: {
+      type: 'time'
+    },
+    yAxis: [],
+    series: []
+  }
+	const items = await getDataset()
+	option.dataset.source = items
+
+  const opt = buildOption()
+  option.series = opt.series
+  option.yAxis = opt.yAxis
+	
 	chartObj.setOption(option)
 }
+const getMetricsItems = async () => {
+	const resp = await getCardData({start: dateRange[0], end: dateRange[1], profile: shopInfo.profile.profile_id})
+	const data = resp.data
+	XEUtils.arrayEach(spCampaignMetricsEnum, info => {
+		const tmp:MetricData = { 
+			label: info.label, 
+			value: info.value,
+			metricVal: data[info.value],
+			gapVal: data[`gap${info.value}`],
+			preVal: data[`prev${info.value}`],
+			disabled: info.initShow ? true : false
+		}
+		metricsItems.value.push(tmp)
+	})
+}
+const buildOption = () => {
+  const opt:any = {
+    yAxis: [],
+    series: []
+  }
+  XEUtils.arrayEach(metrics.value, (info, index) => {
+    const tmp:any = {
+      type: 'value',
+      name: info.label,
+      position: 'left',
+      splitLine: {
+        show: false // 设置显示分割线
+      },
+      axisLine: {
+        show: true,
+				lineStyle: {
+					color: info.color
+				}
+      },
+      show: true
+    }
+    if (index > 0) {
+      tmp["position"] = "right"
+      if (index === 2) { tmp["offset"] = 80 }
+    }
+    opt.yAxis.push(tmp)
+    opt.series.push({
+      name: info.label,
+      type: 'line',
+      encode: {
+        x: 'date',
+        y: info.metric
+      },
+      symbolSize: 6,
+      symbol: 'circle',
+      smooth: true,
+      yAxisIndex: index,
+      itemStyle: { color: info.color, borderColor: info.color },
+    })
+  })
+  return opt
+}
+const changeMetric = () => {
+  const opt = buildOption()
+  chartObj.setOption(opt, { replaceMerge: ['yAxis', 'series'] })
+}
+const resizeChart = () => { chartObj.resize() }
+const addResize = () => { window.addEventListener('resize', resizeChart) }
+const removeResize = () => { window.removeEventListener('resize', resizeChart) }
+
 defineExpose({resizeChart})
 
 </script>
 
 <style scoped>
-
+.metrics-cards {
+  display: flex;
+  justify-content: space-between;
+  align-items: flex-start;
+  gap: 12px;
+  width: 100%;
+}
 </style>

+ 266 - 0
src/views/adManage/sp/campaigns/chartComponents/dataTendency2.vue

@@ -0,0 +1,266 @@
+<template>
+	<MetricsCards v-model="metrics" :metric-items="metricsItems" @change="changeMetric"></MetricsCards>
+  <div style="height: 500px;" ref="chartRef"></div>
+</template>
+
+<script lang="ts" setup>
+import { ref,onMounted, onBeforeUnmount, Ref, onBeforeMount, watch, computed } from 'vue'
+import * as echarts from 'echarts'
+import { useShopInfo } from '/@/stores/shopInfo'
+import { getLineData, getCardData } from '../api'
+import { spCampaignMetricsEnum } from '/@/views/adManage/utils/enum.js'
+import MetricsCards from '/@/components/MetricsCards/index.vue'
+import XEUtils from 'xe-utils'
+
+defineOptions({
+  name: "DataTendencyChart"
+})
+
+onBeforeMount(async () => {
+	await getMetricsItems()
+})
+onMounted(() => {
+	initLine()
+	addResize()
+});
+onBeforeUnmount(() => {
+	if(chartObj) {
+		chartObj.dispose()
+    chartObj = null
+	}
+  removeResize()
+})
+
+const metrics = ref([
+  {metric: 'Impression', color: '#0085ff', 'label': '曝光量'},
+  {metric: 'Click', color: '#3fd4cf', 'label': '点击量'},
+  {metric: 'Spend', color: '#ff9500', 'label': '花费'},
+])
+const shopInfo = useShopInfo()
+const metricsItems: Ref<MetricData[]> = ref([])
+const metricLabelMap: any = {}
+let chartObj:any
+const chartRef = ref()
+const option: any = {
+  dataset: {
+    source: []
+  },
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      label: {
+        backgroundColor: '#6a7985'
+      }
+    }
+  },
+  legend: {
+    selected: {},  // 控制显隐
+    show: false
+  },
+  grid: {
+    top: 50, right: 150, bottom: 30, left: 55,
+  },
+  xAxis: {
+    type: 'category'
+  },
+  yAxis: [
+    {
+      id: 0,
+      type: 'value',
+      name: '曝光量',
+      splitLine: {
+        show: true // 设置显示分割线
+      },
+      axisLine: {
+        show: true,
+				lineStyle: {
+					color: '#0085ff'
+				}
+      },
+      show: true
+    },
+    {
+      id: 1,
+      type: 'value',
+      name: '点击量',
+      position: 'right',
+      splitLine: {
+        show: false
+      },
+      axisLine: {
+        show: true,
+				lineStyle: {
+					color: '#3fd4cf'
+				}
+      },
+      show: true
+    },
+    {
+      id: 2,
+      type: 'value',
+      position: 'right',
+      offset: 90,
+      name: '花费',
+      splitLine: {
+        show: false
+      },
+      axisLine: {
+        show: true,
+				lineStyle: {
+					color: '#ff9500'
+				}
+      },
+      show: true
+    }
+  ],
+  series: [
+    {
+      id: 0,
+      name: '曝光量',
+      type: 'bar',
+      encode: {
+        x: 'date',
+        y: 'Impression'
+      },
+      barWidth: '20px',
+      yAxisIndex: 0,
+      itemStyle: {
+        color: '#0085ff',
+        borderRadius: [10, 10, 0, 0],
+      }
+    },
+    {
+      id: 1,
+      name: '点击量',
+      type: 'line',
+      encode: {
+        x: 'date',
+        y: 'Click'
+      },
+      symbolSize: 6,
+      symbol: 'circle',
+      smooth: true,
+      yAxisIndex: 1,
+      itemStyle: { color: '#3fd4cf', borderColor: '#3fd4cf' },
+      areaStyle: {
+        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+          { offset: 0, color: '#3fd4cf53' },
+          { offset: 1, color: '#3fd4cf03' },
+        ]),
+      },
+      emphasis: {
+        focus:'series'
+      }
+    },
+    {
+      id: 2,
+      name: '花费',
+      type: 'line',
+      encode: {
+        x: 'date',
+        y: 'Spend'
+      },
+      symbolSize: 6,
+      symbol: 'circle',
+      smooth: true,
+      yAxisIndex: 2,
+      itemStyle: { color: '#ff9500', borderColor: '#ff9500' },
+      areaStyle: {
+        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+          { offset: 0, color: '#ff950053' },
+          { offset: 1, color: '#ff950003' },
+        ]),
+      },
+      emphasis: {
+        focus:'series'
+      }
+    }
+  ]
+}
+const getDataset = async () => {
+	const resp = await getLineData({profile: shopInfo.profile.profile_id, start: '2023-11-01', end: '2023-11-04'})
+	return resp.data
+}
+const initLine = async () => {
+	chartObj = echarts.init(chartRef.value)
+	
+	const items = await getDataset()
+	option.dataset.source = items
+	
+  for(const info of metrics.value) {
+    option.legend.selected[info.label] = true
+  }
+
+	console.log(option)
+	chartObj.setOption(option)
+}
+
+
+const getMetricsItems = async () => {
+	const resp = await getCardData({start: '2023-11-01', end: '2023-11-04', profile: shopInfo.profile.profile_id})
+	const data = resp.data
+	XEUtils.arrayEach(spCampaignMetricsEnum, info => {
+		metricLabelMap[info.value] = info.label
+		const tmp:MetricData = { 
+			label: info.label, 
+			value: info.value,
+			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
+	})
+}
+
+const changeMetric = () => {
+  const tmp: any = {}
+  const opt:any = {
+    legend: {selected: {}},
+    yAxis: [],
+    series: []
+  }
+  for (const info of metrics.value) { tmp[info.color] = info }
+  for (const info of option.series) {
+    const color = info.itemStyle.color
+    const metricInfo = tmp[color]
+    if (metricInfo) {
+      opt.series.push({
+        id: info.id,
+        name: metricInfo.label, 
+        encode: {y: metricInfo.metric},
+      })
+      opt.yAxis.push({id: info.id, name: metricInfo.label, show: true})
+    } else {
+      opt.yAxis.push({id: info.id, show: false})
+    }
+  }
+  for (const label of Object.keys(option.legend.selected)) {
+    if (XEUtils.findIndexOf(metrics.value, info => info.label === label) === -1) {
+      opt.legend.selected[label] = false
+    } else {
+      opt.legend.selected[label] = true
+    }
+  }
+  chartObj.setOption(opt)
+}
+
+const resizeChart = () => { chartObj.resize() }
+const addResize = () => { window.addEventListener('resize', resizeChart) }
+const removeResize = () => { window.removeEventListener('resize', resizeChart) }
+
+
+defineExpose({resizeChart})
+
+</script>
+
+<style scoped>
+.metrics-cards {
+  display: flex;
+  justify-content: space-between;
+  align-items: flex-start;
+  gap: 12px;
+  width: 100%;
+}
+</style>

+ 70 - 5
src/views/adManage/sp/campaigns/crud.tsx

@@ -1,13 +1,13 @@
 import * as api from './api'
 import { dict, UserPageQuery, AddReq, DelReq, EditReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet } from '@fast-crud/fast-crud'
-import { inject, nextTick, ref } from 'vue'
+import { inject } from 'vue'
 import { BaseColumn } from '/@/views/adManage/utils/commonTabColumn.js'
-// import { useShopInfo } from '/@/stores/shopInfo'
+import { dynBidStrategyEnum } from '/@/views/adManage/utils/enum.js'
 
 
 export const createCrudOptions = function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
 	const pageRequest = async (query: UserPageQuery) => {
-		query["profile_id"] = context['query']["profile_id"]
+		query["profile"] = context["profileId"]
 		return await api.GetList(query);
 	};
 	const editRequest = async ({ form, row }: EditReq) => {
@@ -89,10 +89,20 @@ export const createCrudOptions = function ({ crudExpose, context }: CreateCrudOp
 				},
 			},
 			columns: {
+				id: {
+					title: 'ID',
+					column: {
+						show: false
+					},
+					form: {
+						show: false
+					}
+				},
         campaignName: {
           title: '广告活动',
           column: {
-            width: '200px'
+            width: '200px',
+						fixed: 'left'
           },
 					search: {
 						show: true,
@@ -122,6 +132,19 @@ export const createCrudOptions = function ({ crudExpose, context }: CreateCrudOp
 				state: {
 					title: '状态'
 				},
+				dynBidStrategy: {
+					title: '竞价策略',
+					form: {
+						show: false,
+					},
+					column: {
+						width: '160px'
+					},
+					type: 'dict-select',
+					dict: dict({
+						data: dynBidStrategyEnum
+					})
+				},
 				startDate: {
 					title: '开始日期',
 					column: {
@@ -137,9 +160,51 @@ export const createCrudOptions = function ({ crudExpose, context }: CreateCrudOp
 				budget: {
 					title: '预算'
 				},
-				"portfolio.name": {
+				portfolioName: {
 					title: '广告组合'
 				},
+				suggestedBudget: {
+					title: '建议竞价',
+					form: {
+						show: false
+					}
+				},
+				percentTimeInBudget: {
+					title: '预算活跃均值',
+					column:{
+						minWidth: 150
+					},
+					form: {
+						show: false
+					}
+				},
+				MissedImpressions: {
+					title: '预计错过的曝光',
+					form: {
+						show: false
+					},
+					column:{
+						width: 180
+					},
+				},
+				MissedClicks: {
+					title: '预计错过的点击',
+					form: {
+						show: false
+					},
+					column:{
+						width: 180
+					},
+				},
+				MissedSales: {
+					title: '预计错过的销售',
+					form: {
+						show: false
+					},
+					column:{
+						width: 180
+					},
+				},
         ...BaseColumn
 			}
 		}

+ 20 - 23
src/views/adManage/sp/campaigns/index.vue

@@ -4,7 +4,6 @@
 			<template #header-middle>
 				<el-tabs v-model="tabActiveName" class="chart-tabs" type="border-card" @tab-change="changeTab">
 					<el-tab-pane label="数据趋势" name="dataTendency">
-						<MetricsCards v-model="metrics" :metric-items="options" @change="changeMetric"></MetricsCards>
 						<DataTendencyChart ref="dataTendencyRef"></DataTendencyChart>
 					</el-tab-pane>
 					<el-tab-pane label="广告结构" name="adStruct" :lazy="true">
@@ -13,45 +12,46 @@
 					<el-tab-pane label="散点视图" name="scatterView" :lazy="true"></el-tab-pane>
 				</el-tabs>
 			</template>
+			<template #cell_percentTimeInBudget="scope">
+        <el-progress :percentage="scope.row.percentTimeInBudget > 0 ? scope.row.percentTimeInBudget * 100: 0" />
+      </template>
 			<template #cell_campaignName="scope">
         <el-link type="primary" :underline="false" @click="jumpGroup(scope.row)">{{ scope.row.campaignName }}</el-link>
       </template>
+			<template #cell_MissedImpressions="scope">
+        {{ scope.row.MissedImpressionsLower ?? '0' }} ~ {{ scope.row.MissedImpressionsUpper ?? '0' }}
+      </template>
+			<template #cell_MissedClicks="scope">
+        {{ scope.row.MissedClicksLower ?? '0' }} ~ {{ scope.row.MissedClicksUpper ?? '0' }}
+      </template>
+			<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, onBeforeUnmount, watch,nextTick, onActivated } 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'
 import { useRoute, useRouter } from 'vue-router'
-import MetricsCards from '/@/components/MetricsCards/index.vue'
 import AdStructChart from './chartComponents/adStruct.vue'
-import DataTendencyChart from './chartComponents/dataTendency.vue'
+import DataTendencyChart from './chartComponents/dataTendency2.vue'
+
 
 const tabActiveName = ref("dataTendency")
 const shopInfo = useShopInfo()
-const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: {query: { profile_id: shopInfo.profile.profile_id }} });
+const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: { profileId: shopInfo.profile.profile_id } });
 
-const metrics = ref([{metric: 'ACOS', color: 'blue'}])
-const options = ref([
-  {label: 'ACOS', value: 'ACOS', metricVal: "18.00%", preVal: '20.15%', gapVal: '-2.00%', disabled:true},
-  {label: '点击量', value: 'clicks', metricVal: "19.00%", preVal: '20.15%', gapVal: '-1.00%', disabled:true},
-  {label: '曝光量', value: 'impression', metricVal: "20.00%", preVal: '15.00%', gapVal: '5.00%', disabled:true},
-  {label: '转化率1', value: 'rate1', metricVal: "1.00%", preVal: '15.00%', gapVal: '5.00%', disabled:true},
-  {label: '转化率2', value: 'rate2', metricVal: "2.00%", preVal: '15.00%', gapVal: '5.00%', disabled:true},
-  {label: '转化率3', value: 'rate3', metricVal: "3.00%", preVal: '15.00%', gapVal: '5.00%', disabled:true},
-  {label: '转化率4', value: 'rate4', metricVal: "4.00%", preVal: '15.00%', gapVal: '5.00%'},
-  {label: '转化率5', value: 'rate5', metricVal: "5.00%", preVal: '15.00%', gapVal: '5.00%'},
-  {label: '转化率6', value: 'rate6', metricVal: "6.00%", preVal: '15.00%', gapVal: '5.00%'},
-])
 const adStructChartRef = ref()
 const dataTendencyRef = ref()
-const route = useRoute()
 const router = useRouter()
-onMounted(() => {
-	crudExpose.doRefresh();
+
+onMounted(async () => {
+	crudExpose.doRefresh()
 })
 
 const resizeTabChart = () => {
@@ -63,9 +63,6 @@ const changeTab = () => {
 		resizeTabChart()
 	})
 }
-const changeMetric = () => {
-	console.log(metrics.value)
-}
 const jumpGroup = (row: any) => {
 	router.push({
 		name: 'CampaignDetail',

+ 44 - 33
src/views/adManage/sp/index.vue

@@ -1,57 +1,68 @@
 <template>
-    <div class="asj-container">
-        <div class="public-search">
-            <DateRangePicker v-model="dateRange" timezone="America/Los_Angeles"></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 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>
 </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} from 'vue'
-import {useShopInfo} from '/@/stores/shopInfo'
-import {GetList} from '/@/views/adManage/portfolios/api'
-import {nextTick} from 'process'
+import { recentDaysRange } from '/@/views/adManage/utils/tools'
+import { ref, onBeforeMount, Ref, provide, watch } from 'vue'
+import { useShopInfo } from '/@/stores/shopInfo'
+import { usePublicData } from '/@/stores/publicData'
+import { GetList } from '/@/views/adManage/portfolios/api'
+import { nextTick } from 'process'
 
 
 const shopInfo = useShopInfo()
+const publicData = usePublicData()
 const selectedPortfolios: Ref<string[]> = ref([])
 const portfolios: Ref<Portfolio[]> = ref([])
-const dateRange: Ref<string[]> = ref([])
-const tabActiveName = ref('campaigns')
+const dateRange: Ref<string[]> = ref(['2023-11-01', '2023-11-04'])
+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)
+  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})
+  }
+)
 
 </script>
 

+ 0 - 1
src/views/adManage/sp/keywords/index.vue

@@ -4,7 +4,6 @@
 			<template #header-middle>
 				<el-tabs v-model="tabActiveName" class="chart-tabs" type="border-card" @tab-change="changeTab">
 					<el-tab-pane label="数据趋势" name="dataTendency">
-						<MetricsCards v-model="metrics" :metric-items="options" @change="changeMetric"></MetricsCards>
 						<DataTendencyChart ref="dataTendencyRef"/>
 					</el-tab-pane>
 					<el-tab-pane label="广告结构" name="adStruct" :lazy="true">

+ 11 - 11
src/views/adManage/utils/commonTabColumn.js → src/views/adManage/utils/commonTabColumn.ts

@@ -1,65 +1,65 @@
 export const BaseColumn = {
-  impressions: {
+  Impression: {
     title: '曝光量',
     form: {
       show: false
     }
   },
-  clicks: {
+  Click: {
     title: '点击量',
     form: {
       show: false
     }
   },
-  ctr: {
+  CTR: {
     title: '点击率',
     form: {
       show: false
     }
   },
-  spend: {
+  Spend: {
     title: '花费',
     form: {
       show: false
     }
   },
-  cpc: {
+  CPC: {
     title: '点击成本',
     form: {
       show: false
     }
   },
-  purchases: {
+  TotalPurchases: {
     title: '订单量',
     form: {
       show: false
     }
   },
-  unitsOrdered: {
+  TotalUnitOrdered: {
     title: '销量',
     form: {
       show: false
     }
   },
-  sales: {
+  TotalSales: {
     title: '销售额',
     form: {
       show: false
     }
   },
-  acos: {
+  ACOS: {
     title: 'ACOS',
     form: {
       show: false
     }
   },
-  roas: {
+  ROAS: {
     title: 'ROAS',
     form: {
       show: false
     }
   },
-  cpa: {
+  CPA: {
     title: '订单成本',
     form: {
       show: false

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

@@ -0,0 +1,26 @@
+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: 'CTR'},
+  {label: '点击成本', value: 'CPC'},
+  {label: '转化率', value: 'PurchasesRate'},
+  {label: 'ACOS', value: 'ACOS'},
+  {label: 'ROAS', value: 'ROAS'},
+  {label: '订单成本', value: 'CPA'},
+  {label: '推广商品销售额', value: 'TotalSalesSameSKU'},
+  {label: '其它商品销售额', value: 'TotalSalesOtherSKU'},
+  {label: '推广商品订单量', value: 'TotalPurchasesSameSKU'},
+  {label: '其它商品订单量', value: 'TotalPurchasesOtherSKU'},
+  {label: '推广商品销量', value: 'TotalUnitOrderedSameSKU'},
+  {label: '其它商品销量', value: 'TotalUnitOrderedOtherSKU'},
+]
+
+export const dynBidStrategyEnum = [
+  { label: '动态竞价-仅降低', value: 'LEGACY_FOR_SALES', color: '' },
+  { label: '动态竞价-提高和降低', value: 'AUTO_FOR_SALES', color: 'success' },
+  { label: '固定竞价', value: 'MANUAL', color: 'warning' }
+]