Pārlūkot izejas kodu

更新部分组件和页面

WanGxC 1 gadu atpakaļ
vecāks
revīzija
324125ccfa

+ 18 - 5
src/components/echartsComponents/BarLineChart.vue

@@ -3,7 +3,7 @@
 </template>
 
 <script>
-import { onMounted, onBeforeUnmount, ref, } from 'vue'
+import { onMounted, onBeforeUnmount, ref, defineExpose  } from 'vue'
 import * as echarts from 'echarts'
 
 export default {
@@ -47,7 +47,7 @@ export default {
                     }
                 },
                 grid: {
-                    top: 70, right: 60, bottom: 30, left: 55,
+                    top: 70, right: 150, bottom: 30, left: 55,
 
                 },
                 xAxis: [
@@ -60,7 +60,7 @@ export default {
                 yAxis: [
                     {
                         type: 'value',
-                        // name: yTitle1,
+                        name: 'ACOS',
                         splitLine: {
                             show: true // 设置显示分割线
                         },
@@ -70,7 +70,20 @@ export default {
                     },
                     {
                         type: 'value',
-                        // name: yTitle2,
+                        name: '点击率',
+                        position: 'right',
+                        splitLine: {
+                            show: false
+                        },
+                        axisLabel: {
+                            formatter: '{value} 单位2'
+                        }
+                    },
+                    {
+                        type: 'value',
+                        position: 'right',
+                        offset: 100,
+                        name: '订单数',
                         splitLine: {
                             show: false
                         },
@@ -166,7 +179,7 @@ export default {
             }
         }
 
-        return {}
+        return {resizeChart}
     },
 
 }

+ 193 - 0
src/components/echartsComponents/PieBarChart.vue

@@ -0,0 +1,193 @@
+<template>
+    <div>
+        <el-row :gutter="5">
+            <el-col :span="8">
+                <div style="display: flex;">
+                    <!--<span>{{ modelValue }}</span>-->
+                    <TextSelector :modelValue="modelValue" :options="options" style="margin-top: 5px"/>
+                </div>
+
+                <div id="pie" style="height: 400px;"></div>
+            </el-col>
+            <el-col :span="16">
+                <div id="bar" style="height: 400px;"></div>
+            </el-col>
+        </el-row>
+    </div>
+</template>
+
+<script setup>
+import { onMounted, ref } from "vue"
+import * as echarts from "echarts"
+import TextSelector from '/@/components/TextSelector/index.vue'
+
+let pieChart = ref()
+let barChart = ref()
+
+onMounted(() => {
+    pieChart = echarts.init(document.getElementById('pie'))
+    barChart = echarts.init(document.getElementById('bar'))
+    setChartData()
+    window.addEventListener('resize', resizeChart)  // 监听窗口大小变化,调整图表大小
+    setTimeout(() => {
+        resizeChart()
+    }, 0)
+
+})
+
+function setChartData() {
+    // 柱状图配置
+    const option = {
+        tooltip: {
+            trigger: 'axis',
+            axisPointer: {
+                type: 'cross',
+                label: {
+                    backgroundColor: '#6a7985'
+                }
+            }
+        },
+        legend: {data: ['数据1', '数据2'],},
+        toolbox: {
+            feature: {
+                saveAsImage: { yAxisIndex: 'none' }
+            }
+        },
+        grid: {
+            top: 70, right: 60, bottom: 30, left: 55,
+
+        },
+        xAxis: [
+            {
+                type: 'category',
+                boundaryGap: true,
+                data: ['商品', '品类', '关键词-精准', '关键词-广泛', '关键词-词组'],
+            }
+        ],
+        yAxis: [
+            {
+                type: 'value',
+                name: '数据1',
+                axisLabel: {
+                    formatter: '{value} 单位1'
+                }
+            },
+            {
+                type: 'value',
+                name: '数据2',
+                splitLine: {
+                    show: false
+                },
+                axisLabel: {
+                    formatter: '{value} 单位2'
+                }
+            }
+        ],
+        series: [
+            {
+                name: '数据1',
+                type: 'bar',
+                // tooltip: {
+                //   valueFormatter: function (value) {
+                //     return value + ' ml';
+                //   }
+                // },
+                barWidth: '30%',
+                data: [2, 24, 21, 40, 51],
+                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],
+                },
+            },
+            {
+                name: '数据2',
+                type: 'bar',
+                barWidth: '30%',
+                data: [10, 20, 30, 40, 50],
+                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],
+                },
+            },
+        ],
+    }
+    barChart.setOption(option)
+    // 饼图配置
+    const option2 = {
+        tooltip: {
+            trigger: 'item'
+        },
+        series: [
+            {
+                name: 'Access From',
+                type: 'pie',
+                radius: ['40%', '70%'],
+                avoidLabelOverlap: false,
+                label: {
+                    show: false,
+                    position: 'center'
+                },
+                emphasis: {
+                    label: {
+                        show: true,
+                        fontSize: 40,
+                        fontWeight: 'bold'
+                    }
+                },
+                labelLine: {
+                    show: false
+                },
+                data: [
+                    { value: 1048, name: 'Search Engine' },
+                    { value: 735, name: 'Direct' },
+                    { value: 580, name: 'Email' },
+                    { value: 484, name: 'Union Ads' },
+                    { value: 300, name: 'Video Ads' }
+                ]
+            }
+        ]
+    }
+    pieChart.setOption(option2)
+    resizeChart()
+}
+
+function resizeChart() {
+    if (barChart) {
+        barChart.resize()
+        pieChart.resize()
+    }
+}
+
+defineExpose({ resizeChart })
+
+// 下拉框相关
+const options = [
+    {
+        value: 'Option1',
+        label: 'Option1',
+    },
+    {
+        value: 'Option2',
+        label: 'Option2',
+    },
+    {
+        value: 'Option3',
+        label: 'Option3',
+    }
+]
+const modelValue = ref(options[0].value)
+</script>
+
+<style scoped>
+
+</style>

+ 74 - 0
src/components/echartsComponents/ScatterChart.vue

@@ -0,0 +1,74 @@
+<template>
+    <div>
+        <div id="scatter" style="height: 400px;"></div>
+    </div>
+</template>
+
+<script setup>
+import { onBeforeUnmount, onMounted, ref } from "vue"
+import * as echarts from "echarts"
+
+let scatterChart = ref()
+onMounted(() => {
+    scatterChart = echarts.init(document.getElementById('scatter'))
+    setChartData()
+    window.addEventListener('resize', resizeChart)  // 监听窗口大小变化,调整图表大小
+    setTimeout(() => {
+        resizeChart()
+    },0)
+})
+onBeforeUnmount(() => {
+    window.removeEventListener('resize', resizeChart)   // 在组件销毁前移除事件监听,避免内存泄漏
+})
+
+function setChartData() {
+    const option = {
+        xAxis: {},
+        yAxis: {},
+        series: [
+            {
+                symbolSize: 20,
+                data: [
+                    [10.0, 8.04],
+                    [8.07, 6.95],
+                    [13.0, 7.58],
+                    [9.05, 8.81],
+                    [11.0, 8.33],
+                    [14.0, 7.66],
+                    [13.4, 6.81],
+                    [10.0, 6.33],
+                    [14.0, 8.96],
+                    [12.5, 6.82],
+                    [9.15, 7.2],
+                    [11.5, 7.2],
+                    [3.03, 4.23],
+                    [12.2, 7.83],
+                    [2.02, 4.47],
+                    [1.05, 3.33],
+                    [4.05, 4.96],
+                    [6.03, 7.24],
+                    [12.0, 6.26],
+                    [12.0, 8.84],
+                    [7.08, 5.82],
+                    [5.02, 5.68]
+                ],
+                type: 'scatter'
+            }
+        ]
+    }
+    scatterChart.setOption(option)
+}
+
+function resizeChart() {
+    if (scatterChart) {
+        scatterChart.resize()
+    }
+}
+defineExpose({ resizeChart })
+
+
+</script>
+
+<style scoped>
+
+</style>

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

@@ -1,6 +1,6 @@
 <template>
     <div>
-        <div class="mt-4" style="margin-bottom: 5px">
+        <div class="mt-1" style="margin-bottom: 5px">
             <el-input
                     v-model="input3"
                     placeholder="快速查询"

+ 22 - 0
src/stores/chartData/line.ts

@@ -0,0 +1,22 @@
+import {defineStore} from 'pinia'
+import {reactive} from 'vue'
+
+export const useLineStore = defineStore('line', () => {
+    let chartData = reactive({
+        xData: [1, 2, 3, 4, 5, 6, 7],
+        yData1: [5, 6, 7, 8, 9, 10, 11],
+        yData2: [14, 15, 12, 16, 15, 13, 14.5]
+    })
+
+    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'],
+        barData: [12, 13.4, 12.5, 16, 14.5, 15.6, 12.3],
+        yData1: [5, 6, 7, 8, 9, 10, 11],
+        yData2: [14, 15, 12, 16, 15, 13, 14.5]
+    })
+
+    return {
+        chartData,
+        barLineData
+    }
+})

+ 1 - 1
src/views/adManage/sb/campaigns/api.ts

@@ -2,7 +2,7 @@ import { request } from '/@/utils/service';
 import { PageQuery, AddReq, DelReq, EditReq, InfoReq } from '@fast-crud/fast-crud';
 import XEUtils from 'xe-utils';
 
-export const apiPrefix = '/api/ad_manage/spCampaigns/';
+export const apiPrefix = 'api/ad_manage/sbcampaigns/';
 export function GetList(query: PageQuery) {
     return request({
         url: apiPrefix,

+ 144 - 139
src/views/adManage/sb/campaigns/crud.tsx

@@ -1,146 +1,151 @@
 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'
 import {useRouter} from 'vue-router'
 
-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 hasPermissions = inject('$hasPermissions');
+    }
+    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)
+    }
 
-	// todo 点击新建广告活动进行路由跳转(还有问题)
-	const router = useRouter()
-	function goCreate() {
-		router.push('/createcampaigns')
-	}
+    //权限判定
+    const hasPermissions = inject('$hasPermissions')
 
-	return {
-		crudOptions: {
-			table: {
-				height: 800
-			},
-			container: {
-        fixedHeight: false
-      },
-			actionbar: {
-				show: true,
-				buttons: {
-					add: {
-						text: 'xxx',
-						show: false
-					},
-					create: {
-						text: '新建广告活动',
-						type: "primary",
-						show: true,
-						click() {
-							goCreate()
-						}
-					}
-				}
-			},
-			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: {
-        name: {
-          title: '广告活动',
-          column: {
-            width: '150px'
-          },
-					search: {
-						show: true,
-						component: {
-							props: {
-								clearable: true
-							}
-						}
-					},
-					form: {
-						rules: [{required: true, message:'必填项'}]
-					}
-        },
-				targetingType: {
-					title: '投放类型',
-					type: 'dict-select',
-					search: {
-						show: true
-					},
-					dict: dict({
-						data: [
-							{ value: 'AUTO', label: '自动' },
-							{ value: 'MANUAL', label: '手动' },
-						]
-					})
-				},
-				state: {
-					title: '状态'
-				},
-				startDate: {
-					title: '开始日期'
-				},
-				endDate: {
-					title: '结束日期'
-				},
-				budget: {
-					title: '预算'
-				},
-				portfolio: {
-					title: '广告组合'
-				},
-        ...BaseColumn
-			}
-		}
-	}
+    // todo 点击新建广告活动进行路由跳转(还有问题)
+    const router = useRouter()
+
+    function goCreate() {
+        router.push('/createcampaigns')
+    }
+
+    return {
+        crudOptions: {
+            table: {
+                height: 800
+            },
+            container: {
+                fixedHeight: false
+            },
+            actionbar: {
+                show: true,
+                buttons: {
+                    add: {
+                        text: 'xxx',
+                        show: false
+                    },
+                    create: {
+                        text: '新建广告活动',
+                        type: 'primary',
+                        show: true,
+                        click() {
+                            goCreate()
+                        }
+                    }
+                }
+            },
+            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: {
+                campaignName: {
+                    title: '广告活动',
+                    column: {
+                        width: '150px'
+                    },
+                    search: {
+                        show: true,
+                        component: {
+                            props: {
+                                clearable: true
+                            }
+                        }
+                    },
+                    form: {
+                        rules: [{required: true, message: '必填项'}]
+                    }
+                },
+                // targetingType: {
+                // 	title: '投放类型',
+                // 	type: 'dict-select',
+                // 	search: {
+                // 		show: true
+                // 	},
+                // 	dict: dict({
+                // 		data: [
+                // 			{ value: 'AUTO', label: '自动' },
+                // 			{ value: 'MANUAL', label: '手动' },
+                // 		]
+                // 	})
+                // },
+                state: {
+                    title: '状态'
+                },
+                state: {
+                    title: '竞价'
+                },
+                startDate: {
+                    title: '开始日期'
+                },
+                endDate: {
+                    title: '结束日期'
+                },
+                portfolio: {
+                    title: '广告组合'
+                },
+                budget: {
+                    title: '预算'
+                },
+                ...BaseColumn
+            }
+        }
+    }
 }

+ 24 - 18
src/views/adManage/sb/campaigns/index.vue

@@ -2,10 +2,18 @@
     <fs-page class="fs-page-custom">
         <fs-crud ref="crudRef" v-bind="crudBinding">
             <template #header-middle>
-                <SearchInput/>
                 <el-card style="height: 500px;margin-bottom: 5px;" shadow="hover">
-                    <BarLineChart :barLineData="barLineData"/>
+
                     <!--<line-chart :chartData="chartData"/>-->
+                    <el-tabs type="border-card" @click="clickFn">
+                        <el-tab-pane label="数据趋势">
+                            <BarLineChart ref="barLine" :barLineData="barLineData"/>
+                        </el-tab-pane>
+                        <el-tab-pane label="广告结构">
+                            <PieBarChart ref="pieBar"/>
+                        </el-tab-pane>
+                        <el-tab-pane label="散点透视"><ScatterChart ref="scatter"/></el-tab-pane>
+                    </el-tabs>
                 </el-card>
 
             </template>
@@ -13,14 +21,15 @@
     </fs-page>
 </template>
 
-<script lang="ts" setup>
+<script setup>
 import {ref, onMounted, defineAsyncComponent, reactive} from 'vue'
 import {useFs, FsPage} from '@fast-crud/fast-crud'
 import {createCrudOptions} from './crud'
 import BarLineChart from '/@/components/echartsComponents/BarLineChart.vue'
-import LineChart from '/@/components/echartsComponents/LineChart.vue'
 import {useLineStore} from '/@/stores/chartData/line'
 import SearchInput from '/@/components/searchInput/index.vue'
+import PieBarChart from '/@/components/echartsComponents/PieBarChart.vue'
+import ScatterChart from '/@/components/echartsComponents/ScatterChart.vue'
 
 
 const {crudBinding, crudRef, crudExpose} = useFs({createCrudOptions, context: {}})
@@ -29,23 +38,20 @@ const {crudBinding, crudRef, crudExpose} = useFs({createCrudOptions, context: {}
 const lineStore = useLineStore()
 let barLineData = lineStore.barLineData
 
-// let barLineData
-//
-// function initData() {
-//     barLineData = reactive({
-//         xData: ['2023-10-18', '2023-10-19', '2023-10-20', '2023-10-21', '2023-10-22', '2023-10-23', '2023-10-24'],
-//         barData: [12, 13.4, 12.5, 16, 14.5, 15.6, 12.3],
-//         yData1: [5, 6, 7, 8, 9, 10, 11],
-//         yData2: [14, 15, 12, 16, 15, 13, 14.5]
-//     })
-// }
-// initData()
-
-
-
 onMounted(() => {
     crudExpose.doRefresh()
 })
+
+const pieBar = ref(null)
+const barLine = ref(null)
+const scatter = ref(null)
+
+function clickFn() {
+    pieBar.value.resizeChart()
+    barLine.value.resizeChart()
+    scatter.value.resizeChart()
+}
+
 </script>
 
 <style scoped>

+ 23 - 18
src/views/adManage/sb/index.vue

@@ -1,19 +1,20 @@
 <template>
     <div class="ads-container">
         <div class="public-search">
-            <DateRangePicker timezone="America/Los_Angeles" @change="changeDateRange"></DateRangePicker>
+            <DateRangePicker v-model="dateRange" timezone="America/Los_Angeles" @change="changeDateRange"></DateRangePicker>
             <el-select v-model="portfolios" placeholder="广告组合"></el-select>
         </div>
-        <el-tabs>
-            <el-tab-pane label="广告活动">
-                <campaigns></campaigns>
-            </el-tab-pane>
-            <el-tab-pane label="关键词"></el-tab-pane>
-            <el-tab-pane label="商品投放"></el-tab-pane>
-            <el-tab-pane label="搜索词"></el-tab-pane>
-            <el-tab-pane label="广告位"></el-tab-pane>
-        </el-tabs>
-
+        <div>
+            <el-tabs class="topTabs">
+                <el-tab-pane label="广告活动">
+                    <campaigns></campaigns>
+                </el-tab-pane>
+                <el-tab-pane label="关键词" ></el-tab-pane>
+                <el-tab-pane label="商品投放"></el-tab-pane>
+                <el-tab-pane label="搜索词"></el-tab-pane>
+                <el-tab-pane label="广告位"></el-tab-pane>
+            </el-tabs>
+        </div>
     </div>
 </template>
 
@@ -23,6 +24,7 @@ import campaigns from './campaigns/index.vue'
 import {ref} from 'vue'
 
 const portfolios = ref([])
+const dateRange = ref([])
 
 function changeDateRange(val: string[]) {
     console.log(val)
@@ -40,19 +42,22 @@ function changeDateRange(val: string[]) {
         z-index: 10;
         width: 100%;
         background-color: #f8f8f8;
-        box-shadow: 0px 0px 0px rgba(51, 89, 181, 0.16);
+        box-shadow: 0 0 0 rgba(51, 89, 181, 0.16);
     }
 
-    :deep(.el-tabs__header.is-top) {
+    ::v-deep(.el-tabs__header) {
         background-color: #fff;
         position: sticky;
-        top: 32px;
-        z-index: 9;
-        box-shadow: 0px 0px 12px rgba(51, 89, 181, 0.16);
+        box-shadow: 0 0 12px rgba(51, 89, 181, 0.16);
     }
 
-    :deep(.el-tabs__nav) {
-        padding-left: 10px;
+    ::v-deep(.topTabs>.el-tabs__header .el-tabs__nav-scroll){
+        margin-left: 10px;
     }
 
+    ::v-deep(.topTabs>.el-tabs__header.is-top) {
+        position: sticky;
+        top: 35px;
+        z-index: 10;
+    }
 </style>

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

@@ -25,7 +25,7 @@ const portfolios = ref([])
 const dateRange = ref([])
 
 function changeDateRange(val: []) {
-  
+
 }
 
 </script>
@@ -40,16 +40,16 @@ function changeDateRange(val: []) {
   z-index: 10;
   width: 100%;
   background-color: #f8f8f8;
-  box-shadow: 0px 0px 0px rgba(51,89,181,0.16);
+  box-shadow: 0 0 0 rgba(51,89,181,0.16);
 }
 :deep(.el-tabs__header.is-top) {
   background-color: #fff;
   position: sticky;
   top: 32px;
   z-index: 9;
-  box-shadow: 0px 0px 12px rgba(51,89,181,0.16);
+  box-shadow: 0 0 12px rgba(51,89,181,0.16);
 }
 :deep(.el-tabs__nav) {
   padding-left: 10px;
 }
-</style>
+</style>