Browse Source

完成关键词-数据趋势的数据展示和广告结构的数据展示;

WanGxC 1 năm trước cách đây
mục cha
commit
f3a49866f7

+ 2 - 2
src/utils/service.ts

@@ -16,7 +16,7 @@ import { getBaseURL } from './baseUrl';
 function createService() {
 	// 创建一个 axios 实例
 	const service = axios.create({
-		timeout: 30000,
+		timeout: 60000,
 		headers: {
 			'Content-Type': 'application/json;charset=utf-8',
 		},
@@ -172,7 +172,7 @@ function createRequestFunction(service: any) {
 			headers: {
 				'Content-Type': get(config, 'headers.Content-Type', 'application/json'),
 			},
-			timeout: 30000,
+			timeout: 60000,
 			baseURL: getBaseURL(),
 			data: {},
 		};

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

@@ -276,6 +276,7 @@ async function initPieBarData() {
     // 柱状图初始化数据
     ACOSList = barData.map(item => item.ACOS)
     SpendList = barData.map(item => item.Spend)
+    // 将x轴映射为中文
     ClassificationList = barData.map(item => item.Classification)
     const classificationMap = {
         'BROAD': '关键词-广泛',
@@ -289,7 +290,6 @@ async function initPieBarData() {
         'complements': '关联商品'
     }
     classificationMapList = ClassificationList.map(item => classificationMap[item])
-    console.log(ClassificationList)
     loading.value = false
 }
 
@@ -425,7 +425,7 @@ function initChart() {
                         { offset: 1, color: 'rgb(111, 209, 206)' },
                     ]),
                     // 柱状图圆角
-                    borderRadius: [15, 15, 0, 0],
+                    borderRadius: [6, 6, 6, 6],
                 },
             },
             {
@@ -440,7 +440,7 @@ function initChart() {
                         { offset: 1, color: 'rgb(234,207,135)' },
                     ]),
                     // 柱状图圆角
-                    borderRadius: [15, 15, 0, 0],
+                    borderRadius: [6, 6, 6, 6],
                 },
             },
         ],

+ 9 - 1
src/views/adManage/sp/keywords/api.ts

@@ -10,7 +10,7 @@ export function GetList(query: UserPageQuery) {
         params: query,
     })
 }
-export function GetObj(id: InfoReq) {
+export function GetObj(id: any) {
     return request({
         url: apiPrefix + id + "/",
         method: 'get',
@@ -56,3 +56,11 @@ export function getLineData(query: UserPageQuery) {
         params: query
     })
 }
+
+export function getAdStructureData(query) {
+    return request({
+        url: apiPrefix + "structure/",
+        method: 'GET',
+        params: query
+    })
+}

+ 397 - 0
src/views/adManage/sp/keywords/chartComponents/adStruct.vue

@@ -0,0 +1,397 @@
+<template>
+    <div v-loading="loading">
+        <el-row :gutter="5">
+            <el-col :span="24">
+                <div style="margin-left: 45%">
+                    <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: 400px;"></div>
+            </el-col>
+        </el-row>
+    </div>
+</template>
+
+<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/keywords/api"
+
+let barChart = ref()
+const bar = ref()
+const loading = ref(true)
+
+let dateRange = inject('dateRange')
+
+// 下拉框相关
+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)
+
+    window.addEventListener('resize', resizeChart)  // 监听窗口大小变化,调整图表大小
+    setTimeout(() => {
+        resizeChart()
+    }, 0)
+
+    await initBarData()
+    initChart()
+})
+
+// 获取总数据
+let resp = null
+
+async function setAdStructureData() {
+    resp = await getAdStructureData({ start: dateRange.value[0], end: dateRange.value[1], profile: '3006125408623189' })
+    console.log('resp.data', resp.data)
+    return resp.data
+}
+
+// 饼图总数据和柱状图总数据
+let barData = null
+let allData = null
+// 柱状图初始数据
+let ACOSList
+let SpendList
+let matchTypeList
+let matchTypeMapList
+
+async function initBarData() {
+    allData = await setAdStructureData()
+    barData = allData
+    // 柱状图初始化数据
+    ACOSList = barData.map(item => item.ACOS)
+    SpendList = barData.map(item => item.Spend)
+    // 将x轴映射为中文
+    matchTypeList = barData.map(item => item.matchType)
+    const matchTypeMap = {
+        'BROAD': '关键词-广泛',
+        'category': '品类',
+        'EXACT': '关键词-精准',
+        'asin': '商品',
+        'PHRASE': '关键词-词组',
+        'close-match': '紧密匹配',
+        'loose-match': '广泛匹配',
+        'substitutes': '同类商品',
+        'complements': '关联商品'
+    }
+    matchTypeMapList = matchTypeList.map(item => matchTypeMap[item])
+    loading.value = false
+}
+
+// 重置图像
+let barFlag = ref()
+let barFlag2 = ref()
+let option
+let option2
+
+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)
+    }
+}
+
+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)
+    }
+}
+
+// 初始化图表
+function initChart() {
+    // 柱状图配置
+    option = {
+        tooltip: {
+            trigger: 'axis',
+            axisPointer: {
+                type: 'cross',
+                label: {
+                    backgroundColor: '#6a7985'
+                }
+            }
+        },
+        // legend: {data: ['数据1', '数据2'],},
+        toolbox: {
+            feature: {
+                saveAsImage: { yAxisIndex: 'none' }
+            }
+        },
+        grid: {
+            top: 50, right: 60, bottom: 50, left: 60,
+
+        },
+        xAxis: [
+            {
+                type: 'category',
+                boundaryGap: true,
+                data: matchTypeMapList,
+                // 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',
+                barWidth: '5%',
+                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: [6, 6, 6, 6],
+                },
+            },
+            {
+                // name: '数据2',
+                type: 'bar',
+                barWidth: '5%',
+                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: [6, 6, 6, 6],
+                },
+            },
+        ],
+    }
+    barChart.setOption(option)
+    resizeChart()
+}
+
+function resizeChart() {
+    barChart.resize()
+}
+
+defineExpose({ resizeChart })
+
+</script>
+
+<style scoped>
+
+</style>

+ 83 - 22
src/views/adManage/sp/keywords/crud.tsx

@@ -1,11 +1,15 @@
 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 {dynBidStrategyEnum} from '/@/views/adManage/utils/enum.js'
 
 
 export const createCrudOptions = function ({crudExpose, context}: CreateCrudOptionsProps): CreateCrudOptionsRet {
     const pageRequest = async (query: UserPageQuery) => {
+        query['profile'] = context['profileId']
+        query['start'] = context['start']
+        query['end'] = context['end']
         return await api.GetList(query)
     }
     const editRequest = async ({form, row}: EditReq) => {
@@ -25,7 +29,7 @@ export const createCrudOptions = function ({crudExpose, context}: CreateCrudOpti
     return {
         crudOptions: {
             table: {
-                height: 600
+                height: 800
             },
             container: {
                 fixedHeight: false
@@ -35,6 +39,14 @@ export const createCrudOptions = function ({crudExpose, context}: CreateCrudOpti
                 buttons: {
                     add: {
                         show: false
+                    },
+                    create: {
+                        text: '新建广告活动',
+                        type: 'primary',
+                        show: true,
+                        click() {
+
+                        }
                     }
                 }
             },
@@ -79,35 +91,84 @@ export const createCrudOptions = function ({crudExpose, context}: CreateCrudOpti
                 },
             },
             columns: {
-                keywordText: {
-                    title: '关键词'
+                id: {
+                    title: 'ID',
+                    column: {
+                        show: false
+                    },
+                    form: {
+                        show: false
+                    }
                 },
-                matchType: {
-                    title: '匹配类型',
-                    type: 'dict-select',
+                keywordText: {
+                    title: '关键词',
+                    column: {
+                        width: '200px',
+                        fixed: 'left'
+                    },
                     search: {
-                        show: true
+                        show: true,
+                        component: {
+                            props: {
+                                clearable: true
+                            }
+                        }
                     },
-                    dict: dict({
-                        data: [
-                            {value: 'BROAD', label: '广泛匹配'},
-                            {value: 'PHRASE', label: '词组匹配'},
-                            {value: 'EXACT', label: '精准匹配'},
-                        ]
-                    })
                 },
                 state: {
                     title: '状态'
                 },
-                bid: {
-                    title: '出价'
+                campaignName: {
+                    title: '广告活动名称',
+                    column: {
+                        width: '200px',
+                        fixed: 'left'
+                    },
+                    search: {
+                        show: true,
+                        component: {
+                            props: {
+                                clearable: true
+                            }
+                        }
+                    },
+                    form: {
+                        rules: [{required: true, message: '必填项'}]
+                    }
+                },
+                adGroupName: {
+                    title: '广告组名称',
                 },
-                'campaign': {
-                    title: '广告活动'
+                suggestedBudget: {
+                    title: '建议竞价',
+                    form: {
+                        show: false
+                    }
                 },
-                'adGroup': {
-                    title: '广告组'
-                }
+                bid: {title: '出价'},
+                '标签': {},
+                Impression: {
+                    title: '曝光量'
+                },
+                '搜索结果顶部展示份额': {},
+                Click: {
+                    title: '点击量'
+                },
+                CTR: {
+                    title: '点击率'
+                },
+                Spend: {
+                    title: '花费'
+                },
+                CPC: {title: '点击成本'},
+                TotalPurchases: {title: '订单数'},
+                TotalSales: {title: '销售额'},
+                TotalUnitOrdered: {title: '销量'},
+                PurchasesRate: {title: '转化率'},
+                ACOS: {title: 'ACOS'},
+                ROAS: {title: 'ROAS'},
+                CPA: {title: '订单成本'},
+                ...BaseColumn
             }
         }
     }

+ 15 - 17
src/views/adManage/sp/keywords/index.vue

@@ -7,7 +7,7 @@
 						<DataTendencyChart ref="dataTendencyRef"/>
 					</el-tab-pane>
 					<el-tab-pane label="广告结构" name="adStruct" :lazy="true">
-						<!-- <AdStructChart ref="adStructChartRef" /> -->
+						 <AdStructChart ref="adStructChartRef" />
 					</el-tab-pane>
 					<el-tab-pane label="散点视图" name="scatterView" :lazy="true"></el-tab-pane>
 				</el-tabs>
@@ -17,46 +17,44 @@
 </template>
 
 <script lang="ts" setup>
-import { ref, onMounted, onBeforeUnmount, watch,nextTick, onActivated } from 'vue';
+import { ref, onMounted, onBeforeUnmount, watch,nextTick, onActivated, inject } from 'vue';
 import { useFs, FsPage } from '@fast-crud/fast-crud';
 import { createCrudOptions } from './crud';
 import { useRoute, useRouter } from 'vue-router'
 import DataTendencyChart from './chartComponents/dataTendency.vue'
-// import AdStructChart from './chartComponents/adStruct.vue'
+import {useShopInfo} from '/@/stores/shopInfo'
+import AdStructChart from './chartComponents/adStruct.vue'
 
 const tabActiveName = ref("dataTendency")
-const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: {} });
+const shopInfo = useShopInfo()
+const dateRange = inject('dateRange')
+const start = dateRange.value[0]
+const end = dateRange.value[1]
+const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: { profileId: shopInfo.profile.profile_id, start: start, end: end } });
 
 const route = useRoute()
 const router = useRouter()
 const adStructChartRef = ref()
 const dataTendencyRef = ref()
 
+console.log(111, dateRange.value)
+
 onMounted(() => {
 	crudExpose.doRefresh();
 })
 
 const resizeTabChart = () => {
 	if (tabActiveName.value === "dataTendency") {
-		dataTendencyRef.value.resizeChart()
+        dataTendencyRef.value.resizeChart()
 	} else if (tabActiveName.value === "adStruct"){
-		adStructChartRef.value.resizeChart()
+        adStructChartRef.value.resizeChart()
 	}
-	// dataTendencyRef.value.resizeChart()
-	// adStructChartRef.value.resizeChart()
-} 
+}
 const changeTab = () => {
 	nextTick(() => {
 		resizeTabChart()
 	})
 }
-
-// const jumpGroup = (row: any) => {
-// 	router.push({
-// 		name: 'CampaignDetail',
-// 		query: { id: row.id, campaignId: row.campaignId, tagsViewName: row.campaignName },
-// 	})
-// }
 defineExpose({ resizeTabChart })
 </script>
 
@@ -68,4 +66,4 @@ defineExpose({ resizeTabChart })
 	}
 }
 
-</style>
+</style>