浏览代码

完成广告活动-广告结构页面开发;修改mCard组件和TextSelector的@change暴露的newVal和oldVal顺序

WanGxC 1 年之前
父节点
当前提交
ff9f018fa7

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

@@ -116,4 +116,4 @@ const shortcuts = [
 
 <style scoped>
 
-</style>
+</style>

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

@@ -30,7 +30,7 @@ interface Props {
 const props = defineProps<Props>()
 const emits = defineEmits(["update:modelValue", "change-metric"])
 const metric = ref(props.modelValue)
-const changeMetric = (oldVal: string, newVal: string) => {
+const changeMetric = ( newVal: string, oldVal: string) => {
   emits('update:modelValue', newVal)
   emits('change-metric', oldVal, newVal)
 }

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

@@ -34,7 +34,7 @@ const handleCommand = (command: string) => {
   const oldVal = data.value
   data.value = command
   emits('update:modelValue', command)
-  emits('change', oldVal, command)
+  emits('change', command, oldVal)
 }
 
 </script>

+ 11 - 9
src/components/echartsComponents/PieBarChart.vue

@@ -27,6 +27,12 @@ import { onMounted, ref } from "vue"
 import * as echarts from "echarts"
 import TextSelector from '/@/components/TextSelector/index.vue'
 
+let props = defineProps({
+    pieBarChartData: {
+        type: Object,
+    }
+})
+
 let pieChart = ref()
 let barChart = ref()
 const pie = ref()
@@ -106,14 +112,14 @@ function setChartData() {
                 //   }
                 // },
                 barWidth: '30%',
-                data: [15, 24, 21, 26, 34],
+                data: props.pieBarChartData.barData[0],
                 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)' },
                     ]),
-                    //柱状图圆角
+                    // 柱状图圆角
                     borderRadius: [15, 15, 0, 0],
                 },
             },
@@ -121,14 +127,14 @@ function setChartData() {
                 name: '数据2',
                 type: 'bar',
                 barWidth: '30%',
-                data: [10, 16, 28, 21, 30],
+                data: props.pieBarChartData.barData[1],
                 yAxisIndex: 1,
                 itemStyle: {
                     color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                         { offset: 0, color: '#ebb14d' },
                         { offset: 1, color: 'rgba(111, 209, 206, 0.1)' },
                     ]),
-                    //柱状图圆角
+                    // 柱状图圆角
                     borderRadius: [15, 15, 0, 0],
                 },
             },
@@ -169,11 +175,7 @@ function setChartData() {
                         show: true
                     }
                 },
-                data: [
-                    { value: 1048, name: 'Search Engine' },
-                    { value: 484, name: 'Union Ads' },
-                    { value: 300, name: 'Video Ads' }
-                ]
+                data: props.pieBarChartData.pieData
             }
         ]
     }

+ 14 - 15
src/views/adManage/sb/campaigns/index.vue

@@ -15,10 +15,10 @@
                         <BarLineChart ref="barLine" :barLineData="barLineData"/>
                     </el-tab-pane>
                     <el-tab-pane label="广告结构">
-                        <PieBarChart ref="pieBar"/>
+                        <PieBarChart ref="pieBar" :pieBarChartData="pieBarChartData"/>
                     </el-tab-pane>
                     <el-tab-pane label="散点透视">
-                        <ScatterChart ref="scatter"/>
+                        <!--<ScatterChart ref="scatter"/>-->
                     </el-tab-pane>
                 </el-tabs>
             </template>
@@ -27,23 +27,22 @@
 </template>
 
 <script setup>
-import { ref, onMounted, reactive, inject } from 'vue'
+import { ref, onMounted, inject, nextTick } from 'vue'
 import { useFs, FsPage } from '@fast-crud/fast-crud'
 import { createCrudOptions } from './crud'
 import BarLineChart from '/@/components/echartsComponents/BarLineChart.vue'
 import PieBarChart from '/@/components/echartsComponents/PieBarChart.vue'
 import ScatterChart from '/@/components/echartsComponents/ScatterChart.vue'
 import MetricsCards from "/@/components/MetricsCards/index.vue"
-import { nextTick } from "process"
 
 const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: {} })
 
-const barLineData = inject('barLineData')
-
 onMounted(() => {
     crudExpose.doRefresh()
 })
 
+let barLineData= inject('barLineData')
+let pieBarChartData = inject('pieBarChartData')
 const pieBar = ref()
 const barLine = ref()
 const scatter = ref()
@@ -61,15 +60,15 @@ const changeTab = () => {
 
 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%' },
+    {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%'},
 ])
 
 function changeMetric() {

+ 24 - 14
src/views/adManage/sb/index.vue

@@ -10,16 +10,15 @@
                     <campaigns ref="campaignsRef"/>
                 </el-tab-pane>
                 <el-tab-pane label="关键词" :lazy="true">
-                    <keywords ref="keywordsRef"/>
+                    <!--<keywords ref="keywordsRef"/>-->
                 </el-tab-pane>
                 <el-tab-pane label="商品投放" :lazy="true">
 
                 </el-tab-pane>
                 <el-tab-pane label="搜索词" :lazy="true">
-                    <SearchTerm ref="searchTermRef"/>
+                    <!--<SearchTerm ref="searchTermRef"/>-->
                 </el-tab-pane>
                 <el-tab-pane label="广告位" :lazy="true">
-                    testtesttest
                 </el-tab-pane>
             </el-tabs>
         </div>
@@ -50,6 +49,7 @@ function changeTab() {
         keywordsRef.value.resizeTabChart()
     })
 }
+
 // 提供柱线图数据
 let barLineData = reactive({
     xData: ['2023-10-18', '2023-10-19', '2023-10-20', '2023-10-21', '2023-10-22', '2023-10-23', '2023-10-24'],
@@ -59,18 +59,28 @@ let barLineData = reactive({
 })
 provide('barLineData', barLineData)
 
+// 提供饼图和柱状图的数据
+let pieBarChartData = reactive({
+    xData: ['2023-10-18', '2023-10-19', '2023-10-20', '2023-10-21', '2023-10-22', '2023-10-23', '2023-10-24'],
+    barData: [[10, 16, 28, 21, 30], [6, 12, 17, 21, 25]],
+    pieData: [{ value: 1048, name: 'Search Engine' },
+        { value: 484, name: 'Union Ads' },
+        { value: 300, name: 'Video Ads' }]
+})
+provide('pieBarChartData', pieBarChartData)
+
 </script>
 
 <style>
-    .public-search {
-        display: flex;
-        gap: 3px;
-        padding-bottom: 3px;
-        position: sticky;
-        top: 0;
-        z-index: 10;
-        width: 100%;
-        background-color: #f8f8f8;
-        box-shadow: 0 0 0 rgba(51, 89, 181, 0.16);
-    }
+.public-search {
+    display: flex;
+    gap: 3px;
+    padding-bottom: 3px;
+    position: sticky;
+    top: 0;
+    z-index: 10;
+    width: 100%;
+    background-color: #f8f8f8;
+    box-shadow: 0 0 0 rgba(51, 89, 181, 0.16);
+}
 </style>

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

@@ -56,3 +56,11 @@ export function getLineData(query: UserPageQuery) {
         params: query
     })
 }
+
+export function getAdStructureData(query) {
+    return request({
+        url: apiPrefix + "structure/",
+        method: 'GET',
+        params: query
+    })
+}

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

@@ -1,7 +1,7 @@
 <template>
   <div class="asj-container">
     <div class="asj-detail-header">
-      <span style="font-size: x-large; font-weight: bold; color: #0f1111;margin: 5px;"> 
+      <span style="font-size: x-large; font-weight: bold; color: #0f1111;margin: 5px;">
         <span> {{ campaignInfo.campaignName }}</span>
       </span>
       <div class="asj-detail-info">
@@ -46,4 +46,4 @@ onMounted(async () => {
 
 <style lang="scss">
 
-</style>
+</style>

+ 487 - 33
src/views/adManage/sp/campaigns/chartComponents/adStruct.vue

@@ -1,55 +1,509 @@
 <template>
-    <div style="height: 500px;" ref="lineRef"></div>
+    <div v-loading="loading">
+        <el-row :gutter="5">
+            <el-col :span="8">
+                <div>
+                    <TextSelector v-model="modelValue" :options="pieOptions" @change="changePie" style="margin-top: 5px"/>
+                </div>
+                <div ref="pie" style="height: 500px;"></div>
+            </el-col>
+            <el-col :span="16">
+                <div style="margin-left: 40%">
+                    <span style="background: #3a83f7; width: 18px; height: 10px; margin-top: 8px; display: inline-block; border-radius: 3px;"></span>
+                    <TextSelector v-model="barModelValue1" :options="barOptions1" @change="changeBarOne" style="margin-top: 5px; margin-left: 8px;"/>
+                    <span style="background: #f19a37; width: 18px; height: 10px; margin-top: 8px; margin-left: 20px; display: inline-block; border-radius: 3px;"></span>
+                    <TextSelector v-model="barModelValue2" :options="barOptions2" @change="changeBarTwo" style="margin-top: 5px; margin-left: 8px;"/>
+                </div>
+                <div ref="bar" style="height: 500px;"></div>
+            </el-col>
+        </el-row>
+    </div>
 </template>
 
-<script lang="ts" setup>
-import {ref, onMounted, onBeforeUnmount} from 'vue'
-import * as echarts from 'echarts'
+<script setup>
+import { onMounted, ref, inject } from "vue"
+import * as echarts from "echarts"
+import TextSelector from '/@/components/TextSelector/index.vue'
+import { getAdStructureData } from "/@/views/adManage/sp/campaigns/api"
 
-defineOptions({
-    name: 'AdStructChart'
+let pieChart = ref()
+let barChart = ref()
+const pie = ref()
+const bar = ref()
+const loading = ref(true)
+
+let dateRange = inject('dateRange')
+console.log('dateRange', dateRange.value)
+
+// 下拉框相关
+const pieOptions = [
+    {
+        value: 'Spend',
+        label: '花费',
+    },
+    {
+        value: 'TotalSales',
+        label: '销售额',
+    },
+    {
+        value: 'TotalPurchases',
+        label: '订单数',
+    },
+    {
+        value: 'TotalUnitOrdered',
+        label: '销量',
+    },
+    {
+        value: 'Impression',
+        label: '曝光量',
+    },
+    {
+        value: 'Click',
+        label: '点击量',
+    },
+]
+const metricMap = {
+    'Spend': '花费',
+    'TotalSales': '销售额',
+    'TotalPurchases': '订单数',
+    'TotalUnitOrdered': '销量',
+    'Impression': '曝光量',
+    'Click': '点击量',
+}
+let modelValue = ref(pieOptions[0].value)
+
+const barOptions1 = [
+    {
+        value: 'ACOS',
+        label: 'ACOS',
+    },
+    {
+        value: 'ROAS',
+        label: 'ROAS',
+    },
+    {
+        value: 'Spend',
+        label: '花费',
+        units: '$',
+    },
+    {
+        value: 'TotalSales',
+        label: '销售额',
+    },
+    {
+        value: 'TotalPurchases',
+        label: '订单数',
+    },
+    {
+        value: 'TotalUnitOrdered',
+        label: '销量',
+    },
+    {
+        value: 'CPC',
+        label: '点击成本'
+    },
+    {
+        value: 'CPA',
+        label: '订单成本'
+    },
+    {
+        value: 'Impression',
+        label: '曝光量',
+    },
+    {
+        value: 'Click',
+        label: '点击量',
+    },
+    {
+        value: 'qwe',
+        label: '点击率'
+    },
+    {
+        value: '转化率',
+        label: '转化率'
+    },
+    {
+        value: 'TotalSalesSameSKU',
+        label: '推广商品销售额'
+    },
+    {
+        value: 'TotalSalesOtherSKU',
+        label: '其他商品销售额'
+    },
+    {
+        value: 'TotalPurchasesSameSKU',
+        label: '推广商品订单数'
+    },
+    {
+        value: 'TotalPurchasesOtherSKU',
+        label: '其他商品订单数'
+    },
+    {
+        value: 'TotalUnitOrderedSameSKU',
+        label: '推广商品销量'
+    },
+    {
+        value: 'TotalUnitOrderedOtherSKU',
+        label: '其他商品销量'
+    },
+    {
+        value: 'TopOfSearchImpressionShare',
+        label: '搜索结果顶部展示份额'
+    },
+]
+let barModelValue1 = ref(barOptions1[0].value)
+
+const barOptions2 = [
+    {
+        value: 'ACOS',
+        label: 'ACOS',
+    },
+    {
+        value: 'ROAS',
+        label: 'ROAS',
+    },
+    {
+        value: 'Spend',
+        label: '花费',
+        units: '$',
+    },
+    {
+        value: 'TotalSales',
+        label: '销售额',
+    },
+    {
+        value: 'TotalPurchases',
+        label: '订单数',
+    },
+    {
+        value: 'TotalUnitOrdered',
+        label: '销量',
+    },
+    {
+        value: 'CPC',
+        label: '点击成本'
+    },
+    {
+        value: 'CPA',
+        label: '订单成本'
+    },
+    {
+        value: 'Impression',
+        label: '曝光量',
+    },
+    {
+        value: 'Click',
+        label: '点击量',
+    },
+    {
+        value: 'qwe',
+        label: '点击率'
+    },
+    {
+        value: '转化率',
+        label: '转化率'
+    },
+    {
+        value: 'TotalSalesSameSKU',
+        label: '推广商品销售额'
+    },
+    {
+        value: 'TotalSalesOtherSKU',
+        label: '其他商品销售额'
+    },
+    {
+        value: 'TotalPurchasesSameSKU',
+        label: '推广商品订单数'
+    },
+    {
+        value: 'TotalPurchasesOtherSKU',
+        label: '其他商品订单数'
+    },
+    {
+        value: 'TotalUnitOrderedSameSKU',
+        label: '推广商品销量'
+    },
+    {
+        value: 'TotalUnitOrderedOtherSKU',
+        label: '其他商品销量'
+    },
+    {
+        value: 'TopOfSearchImpressionShare',
+        label: '搜索结果顶部展示份额'
+    },
+]
+let barModelValue2 = ref(barOptions2[2].value)
+
+onMounted(async () => {
+    barChart = echarts.init(bar.value)
+    pieChart = echarts.init(pie.value)
+
+    window.addEventListener('resize', resizeChart)  // 监听窗口大小变化,调整图表大小
+    setTimeout(() => {
+        resizeChart()
+    }, 0)
+
+    await initPieBarData()
+    initChart()
 })
 
-let chartObj: any
-const lineRef = ref()
-const resizeChart = () => {
-    chartObj.resize()
+// 获取总数据
+let allData = null
+
+async function setAdStructureData() {
+    allData = await getAdStructureData({ start: dateRange.value[0], end: dateRange.value[1], profile: '3006125408623189' })
+    console.log('allData.data', allData.data)
+    return allData.data
+}
+
+// 饼图总数据和柱状图总数据
+let pieData = null
+let barData = null
+let pieBarData = null
+// 柱状图初始数据
+let ACOSList
+let SpendList
+let ClassificationList
+let classificationMapList
+
+async function initPieBarData() {
+    pieBarData = await setAdStructureData()
+    pieData = [
+        { value: pieBarData.pie_data[0].Spend, name: '自动' },
+        { value: pieBarData.pie_data[1].Spend, name: '手动' },
+    ]
+    barData = pieBarData.line_data
+    // 柱状图初始化数据
+    ACOSList = barData.map(item => item.ACOS)
+    SpendList = barData.map(item => item.Spend)
+    ClassificationList = barData.map(item => item.Classification)
+    const classificationMap = {
+        'BROAD': '关键词-广泛',
+        'category': '品类',
+        'EXACT': '关键词-精准',
+        'asin': '商品',
+        'PHRASE': '关键词-词组',
+        'close-match': '紧密匹配',
+        'loose-match': '广泛匹配',
+        'substitutes': '同类商品',
+        'complements': '关联商品'
+    }
+    classificationMapList = ClassificationList.map(item => classificationMap[item])
+    console.log(ClassificationList)
+    loading.value = false
 }
-const addResize = () => {
-    window.addEventListener('resize', resizeChart)
+
+// 重置图像
+let flag = ref()
+let barFlag = ref()
+let barFlag2 = ref()
+let option
+let option2
+
+function changePie(newValue) {
+    modelValue.value = newValue
+    flag.value = modelValue.value
+    option2.series[0].data = [
+        { value: pieBarData.pie_data[0][flag.value], name: '自动' },
+        { value: pieBarData.pie_data[1][flag.value], name: '手动' },
+    ]
+    // pieChart.clear() // 清除当前饼图的配置
+    // option2.series[0].data = newPieData // 确保更新的是数组中的正确位置
+    // pieChart.setOption(option2, true) // 使用 true 强制合并选项
+    pieChart.setOption(option2)
 }
-const removeResize = () => {
-    window.removeEventListener('resize', resizeChart)
+
+function changeBarOne(newValue) {
+    barModelValue1.value = newValue
+    barFlag.value = barModelValue1.value
+    const barValues = []
+    try {
+        for (let i = 0; i < barData.length; i++) {
+            const value = barData[i][barFlag.value]
+            barValues.push(value)
+        }
+        // barChart.clear()
+        option.series[0].data = barValues
+        barChart.setOption(option)
+    } catch (error) {
+        console.log(error)
+    }
 }
 
-onMounted(() => {
-    initLine()
-    addResize()
-})
-onBeforeUnmount(() => {
-    if (chartObj) {
-        chartObj.dispose()
-        chartObj = null
+function changeBarTwo(newValue) {
+    barModelValue2.value = newValue
+    barFlag2.value = barModelValue2.value
+    const barValues = []
+    try {
+        for (let i = 0; i < barData.length; i++) {
+            const value = barData[i][barFlag2.value]
+            barValues.push(value)
+        }
+        // barChart.clear()
+        option.series[1].data = barValues
+        barChart.setOption(option)
+    } catch (error) {
+        console.log(error)
     }
-    removeResize()
-})
-const initLine = () => {
-    chartObj = echarts.init(lineRef.value)
-    const option = {
-        xAxis: {
-            data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
+}
+
+// 初始化图表
+function initChart() {
+    // 柱状图配置
+    option = {
+        tooltip: {
+            trigger: 'axis',
+            axisPointer: {
+                type: 'cross',
+                label: {
+                    backgroundColor: '#6a7985'
+                }
+            }
+        },
+        // legend: {data: ['数据1', '数据2'],},
+        toolbox: {
+            feature: {
+                saveAsImage: { yAxisIndex: 'none' }
+            }
+        },
+        grid: {
+            top: 55, right: 60, bottom: 55, left: 55,
+
         },
-        yAxis: {},
+        xAxis: [
+            {
+                type: 'category',
+                boundaryGap: true,
+                data: classificationMapList,
+                axisLabel: {
+                    rotate: 30, // 将标签旋转45度
+                    fontSize: 12
+                },
+            },
+        ],
+        yAxis: [
+            {
+                type: 'value',
+                // name: '数据1',
+                // axisLabel: {
+                //     formatter: '{value} %'
+                // },
+                axisLine: {
+                    show: true,
+                    lineStyle: {
+                        color: '#3a83f7' // 第一个 Y 轴的颜色
+                    }
+                }
+            },
+            {
+                type: 'value',
+                // name: '数据2',
+                splitLine: {
+                    show: false
+                },
+                // axisLabel: {
+                //     formatter: '{value} 单位2'
+                // },
+                axisLine: {
+                    show: true,
+                    lineStyle: {
+                        color: '#f19a37' // 第一个 Y 轴的颜色
+                    }
+                }
+            }
+        ],
         series: [
             {
+                // name: '数据1',
                 type: 'bar',
-                data: [23, 24, 18, 25, 27, 28, 25]
+                barWidth: '15%',
+                data: ACOSList,
+                yAxisIndex: 0,
+                itemStyle: {
+                    color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+                        { offset: 0, color: '#3a83f7' },
+                        { offset: 1, color: 'rgb(111, 209, 206)' },
+                    ]),
+                    // 柱状图圆角
+                    borderRadius: [15, 15, 0, 0],
+                },
+            },
+            {
+                // name: '数据2',
+                type: 'bar',
+                barWidth: '15%',
+                data: SpendList,
+                yAxisIndex: 1,
+                itemStyle: {
+                    color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+                        { offset: 0, color: '#f19a37' },
+                        { offset: 1, color: 'rgb(234,207,135)' },
+                    ]),
+                    // 柱状图圆角
+                    borderRadius: [15, 15, 0, 0],
+                },
+            },
+        ],
+    }
+    barChart.setOption(option)
+    // 饼图配置
+    option2 = {
+        tooltip: {
+            trigger: 'item',
+        },
+        series: [
+            {
+                // name: modelValue.value,
+                type: 'pie',
+                radius: ['20%', '40%'],
+                avoidLabelOverlap: false,
+                itemStyle: {
+                    // borderRadius: 10,
+                    borderWidth: 1, // 设置边框的宽度
+                    borderColor: '#fff', // 将边框颜色设置为白色或图表背景颜色
+                },
+                emphasis: {
+                    label: {
+                        show: true,
+                        // fontSize: 40,
+                        fontWeight: 'bold',
+                    }
+                },
+                label: {
+                    show: true,
+                    position: 'outside', // 标签显示在外侧
+                    // formatter: `{b}\n{b|${metricMap[modelValue.value]}:{c}}\n{d}%`, // 标签文本格式器
+                    formatter: (params) => {
+                        return params.name + '\n' + '{b|' + metricMap[modelValue.value] + ':}' + '{b|' + params.data.value + '}' + '\n' + params.percent + '%'
+                    },
+                    rich: {
+                        b: {
+                            color: '#4C5058',
+                            fontSize: 15,
+                            fontWeight: 'bold',
+                            lineHeight: 33
+                        },
+                    }
+                },
+                labelLine: {
+                    normal: {
+                        show: true
+                    }
+                },
+                data: pieData
             }
         ]
     }
-    chartObj.setOption(option)
+    pieChart.setOption(option2)
+    resizeChart()
+}
+
+function resizeChart() {
+    barChart.resize()
+    pieChart.resize()
 }
-defineExpose({resizeChart})
+
+defineExpose({ resizeChart })
 
 </script>
 

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

@@ -33,7 +33,7 @@
 </template>
 
 <script lang="ts" setup>
-import { ref, onMounted, Ref, nextTick, onBeforeMount } from 'vue';
+import {ref, onMounted, Ref, nextTick, onBeforeMount, inject} from 'vue'
 import { useFs, FsPage } from '@fast-crud/fast-crud';
 import { createCrudOptions } from './crud';
 import { useShopInfo } from '/@/stores/shopInfo'
@@ -70,8 +70,9 @@ const jumpGroup = (row: any) => {
 	})
 }
 
+
 defineExpose({ resizeTabChart })
 </script>
 
 <style lang="scss">
-</style>
+</style>

+ 38 - 37
src/views/adManage/sp/index.vue

@@ -1,35 +1,36 @@
 <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 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>
-    <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, 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'
+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'
 
 
 const shopInfo = useShopInfo()
@@ -37,7 +38,7 @@ 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 tabActiveName = ref("campaigns")
+const tabActiveName = ref('campaigns')
 const keywordsRef = ref()
 const campaignsRef = ref()
 
@@ -45,23 +46,23 @@ 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})
-  }
+        dateRange,
+        () => {
+            publicData.updateData({dateRange: dateRange.value})
+        }
 )
 
 </script>

+ 108 - 108
src/views/adManage/sp/keywords/crud.tsx

@@ -1,114 +1,114 @@
 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 { BaseColumn } from '/@/views/adManage/utils/commonTabColumn.js'
+import {dict, UserPageQuery, AddReq, DelReq, EditReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet} from '@fast-crud/fast-crud'
+import {inject, nextTick, ref} from 'vue'
+import {BaseColumn} from '/@/views/adManage/utils/commonTabColumn.js'
 
 
-export const createCrudOptions = function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
-	const pageRequest = async (query: UserPageQuery) => {
-		return await api.GetList(query);
-	};
-	const editRequest = async ({ form, row }: EditReq) => {
-		form.id = row.id;
-		return await api.UpdateObj(form);
-	};
-	const delRequest = async ({ row }: DelReq) => {
-		return await api.DelObj(row.id);
-	};
-	const addRequest = async ({ form }: AddReq) => {
-		return await api.AddObj(form);
-	};
+export const createCrudOptions = function ({crudExpose, context}: CreateCrudOptionsProps): CreateCrudOptionsRet {
+    const pageRequest = async (query: UserPageQuery) => {
+        return await api.GetList(query)
+    }
+    const editRequest = async ({form, row}: EditReq) => {
+        form.id = row.id
+        return await api.UpdateObj(form)
+    }
+    const delRequest = async ({row}: DelReq) => {
+        return await api.DelObj(row.id)
+    }
+    const addRequest = async ({form}: AddReq) => {
+        return await api.AddObj(form)
+    }
 
-	//权限判定
-	const hasPermissions = inject('$hasPermissions');
+    //权限判定
+    const hasPermissions = inject('$hasPermissions')
 
-	return {
-		crudOptions: {
-			table: {
-				height: 600
-			},
-			container: {
-        fixedHeight: false
-      },
-			actionbar: {
-				show: true,
-				buttons: {
-					add: {
-						show: false
-					}
-				}
-			},
-			search: {
-				show: false
-			},
-			toolbar: {
-        buttons: {
-					search: {
-						show: true
-					},
-					compact: {
-						show: false
-					}
-				}
-			},
-			request: {
-				pageRequest,
-				addRequest,
-				editRequest,
-				delRequest,
-			},
-			rowHandle: {
-				fixed: 'right',
-				width: 80,
-				buttons: {
-					view: {
-						show: false,
-					},
-					edit: {
-						iconRight: 'Edit',
-						type: 'text',
-            text: null
-						// show: hasPermissions('dictionary:Update'),
-					},
-					remove: {
-						iconRight: 'Delete',
-						type: 'text',
-            text: null
-						// show: hasPermissions('dictionary:Delete'),
-					},
-				},
-			},
-			columns: {
-        keywordText: {
-          title: '关键词'
-        },
-				matchType: {
-					title: '匹配类型',
-					type: 'dict-select',
-					search: {
-						show: true
-					},
-					dict: dict({
-						data: [
-							{ value: 'BROAD', label: '广泛匹配' },
-							{ value: 'PHRASE', label: '词组匹配' },
-							{ value: 'EXACT', label: '精准匹配' },
-						]
-					})
-				},
-				state: {
-					title: '状态'
-				},
-				bid: {
-					title: '出价'
-				},
-				"campaign": {
-					title: '广告活动'
-				},
-				"adGroup": {
-					title: '广告组'
-				}
-			}
-		}
-	}
+    return {
+        crudOptions: {
+            table: {
+                height: 600
+            },
+            container: {
+                fixedHeight: false
+            },
+            actionbar: {
+                show: true,
+                buttons: {
+                    add: {
+                        show: false
+                    }
+                }
+            },
+            search: {
+                show: false
+            },
+            toolbar: {
+                buttons: {
+                    search: {
+                        show: true
+                    },
+                    compact: {
+                        show: false
+                    }
+                }
+            },
+            request: {
+                pageRequest,
+                addRequest,
+                editRequest,
+                delRequest,
+            },
+            rowHandle: {
+                fixed: 'right',
+                width: 80,
+                buttons: {
+                    view: {
+                        show: false,
+                    },
+                    edit: {
+                        iconRight: 'Edit',
+                        type: 'text',
+                        text: null
+                        // show: hasPermissions('dictionary:Update'),
+                    },
+                    remove: {
+                        iconRight: 'Delete',
+                        type: 'text',
+                        text: null
+                        // show: hasPermissions('dictionary:Delete'),
+                    },
+                },
+            },
+            columns: {
+                keywordText: {
+                    title: '关键词'
+                },
+                matchType: {
+                    title: '匹配类型',
+                    type: 'dict-select',
+                    search: {
+                        show: true
+                    },
+                    dict: dict({
+                        data: [
+                            {value: 'BROAD', label: '广泛匹配'},
+                            {value: 'PHRASE', label: '词组匹配'},
+                            {value: 'EXACT', label: '精准匹配'},
+                        ]
+                    })
+                },
+                state: {
+                    title: '状态'
+                },
+                bid: {
+                    title: '出价'
+                },
+                'campaign': {
+                    title: '广告活动'
+                },
+                'adGroup': {
+                    title: '广告组'
+                }
+            }
+        }
+    }
 }