From 3827a9e669b32210b35c9f2897f0e56bc1cbccba Mon Sep 17 00:00:00 2001 From: zxl <763096477@qq.com> Date: 星期五, 26 九月 2025 09:14:14 +0800 Subject: [PATCH] 订单页面统计图 --- manager/src/views/statistics/order.vue | 471 +++++++++++++++++++++++++++++++++++++++++---------- manager/src/api/orderStatistics.jsx | 14 + 2 files changed, 391 insertions(+), 94 deletions(-) diff --git a/manager/src/api/orderStatistics.jsx b/manager/src/api/orderStatistics.jsx index 533d95f..9be17b4 100644 --- a/manager/src/api/orderStatistics.jsx +++ b/manager/src/api/orderStatistics.jsx @@ -7,3 +7,17 @@ params: param }) } +export const getOrderCount = (param) =>{ + return service({ + url:"/lmk/statistics/orderCount", + method: "GET", + params: param + }) +} +export const getViewAndCompletionRateCount = (param) =>{ + return service({ + url:"/lmk/statistics/viewAndCompletionRateCount", + method: "GET", + params: param + }) +} diff --git a/manager/src/views/statistics/order.vue b/manager/src/views/statistics/order.vue index 08a7ff6..17fb7a6 100644 --- a/manager/src/views/statistics/order.vue +++ b/manager/src/views/statistics/order.vue @@ -5,66 +5,74 @@ <affixTime @selected="clickBreadcrumb" /> </Card> </Affix> -<!-- <Card class="card">--> -<!-- <div class="my-chart-container">--> -<!-- <!– 鏁版嵁姒傝鍗$墖 –>--> -<!--<!– <div class="stats-cards">–>--> -<!--<!– <div class="stat-card">–>--> -<!--<!– <div class="stat-header">–>--> -<!--<!– <span class="stat-title">鎬绘祻瑙堥噺</span>–>--> -<!--<!– <i class="fa fa-eye stat-icon"></i>–>--> -<!--<!– </div>–>--> -<!--<!– <div class="stat-value">{{ totalPv }}</div>–>--> -<!--<!– <div class="stat-trend positive">–>--> -<!--<!– <i class="fa fa-arrow-up"></i> 12.5% 杈冧笂鏈�–>--> -<!--<!– </div>–>--> -<!--<!– </div>–>--> + <Card class="card"> + <div class="chart-wrapper"> + <div class="chart-header"> + <h2>PV/UV 瓒嬪娍鍥�</h2> + </div> + <div ref="chartDom" class="chart-container"></div> + </div> + </Card> + <Card class="card"> + <div class="my-chart-container"> + <div class="chart-wrapper" style="height: 800px"> + <div class="chart-header"> + <h2>鍟嗗搧/瑙嗛娴忚閲忓畬鎾巼 瓒嬪娍鍥�</h2> + </div> + <div class="button-group-wrapper"> + <!-- 绗竴缁勶細鍟嗗搧/瑙嗛锛堥潬宸︼級 --> + <ButtonGroup> + <Button + :type="currentType === 'goods' ? 'primary' : 'default'" + @click="handleTypeChange('goods')" + > + 鍟嗗搧 + </Button> + <Button + :type="currentType === 'video' ? 'primary' : 'default'" + @click="handleTypeChange('video')" + > + 瑙嗛 + </Button> + </ButtonGroup> -<!--<!– <div class="stat-card">–>--> -<!--<!– <div class="stat-header">–>--> -<!--<!– <span class="stat-title">骞冲潎鏃ユ祻瑙堥噺</span>–>--> -<!--<!– <i class="fa fa-calendar stat-icon"></i>–>--> -<!--<!– </div>–>--> -<!--<!– <div class="stat-value">{{ avgDailyPv }}</div>–>--> -<!--<!– <div class="stat-trend positive">–>--> -<!--<!– <i class="fa fa-arrow-up"></i> 8.3% 杈冧笂鏈�–>--> -<!--<!– </div>–>--> -<!--<!– </div>–>--> + <!-- 绗簩缁勶細鍓�10/鍓�20/鍓�30锛堥潬鍙筹級 --> + <ButtonGroup> + <Button + :type="currentLimit === 10 ? 'success' : 'default'" + @click="handleLimitChange(10)" + > + 鍓�10 + </Button> + <Button + :type="currentLimit === 20 ? 'success' : 'default'" + @click="handleLimitChange(20)" + > + 鍓�20 + </Button> + <Button + :type="currentLimit === 30 ? 'success' : 'default'" + @click="handleLimitChange(30)" + > + 鍓�30 + </Button> + </ButtonGroup> + </div> + <div ref="viewPrintChartDom" class="view-chart-container"></div> + </div> + </div> + </Card> + <Card class="card"> + <div class="my-chart-container"> + <div class="chart-wrapper"> + <div class="chart-header"> + <h2>璁㈠崟澧為暱 瓒嬪娍鍥�</h2> + </div> + <div ref="orderCountChartDom" class="chart-container"></div> + </div> + </div> + </Card> -<!--<!– <div class="stat-card">–>--> -<!--<!– <div class="stat-header">–>--> -<!--<!– <span class="stat-title">鏈�楂樺崟鏃ユ祻瑙堥噺</span>–>--> -<!--<!– <i class="fa fa-trophy stat-icon"></i>–>--> -<!--<!– </div>–>--> -<!--<!– <div class="stat-value">{{ maxDailyPv }}</div>–>--> -<!--<!– <div class="stat-trend">{{ maxPvDate }}</div>–>--> -<!--<!– </div>–>--> -<!--<!– </div>–>--> - -<!-- <!– 鍥捐〃鍖哄煙 –>--> -<!-- <div class="chart-wrapper">--> -<!-- <div class="chart-header">--> -<!-- <h2>PV/UV 瓒嬪娍鍥�</h2>--> -<!-- </div>--> -<!-- <div ref="chartDom" class="chart-container"></div>--> -<!-- </div>--> - -<!-- <!– 鏁版嵁鏇存柊鏃堕棿 –>--> -<!--<!– <div class="update-time">–>--> -<!--<!– 鏁版嵁鏇存柊鏃堕棿: {{ updateTime }}–>--> -<!--<!– </div>–>--> -<!-- </div>--> -<!-- </Card>--> -<!-- <Card class="card">--> -<!-- <div class="my-chart-container">--> -<!-- <div class="chart-wrapper">--> -<!-- <div class="chart-header">--> -<!-- <h2>璁㈠崟澧為暱 瓒嬪娍鍥�</h2>--> -<!-- </div>--> -<!-- <div ref="orderCount-chartDom" class="chart-container"></div>--> -<!-- </div>--> -<!-- </div>--> -<!-- </Card>--> <Card class="card"> <div> <h4>浜ゆ槗姒傚喌</h4> @@ -263,7 +271,7 @@ import refundRow from "./order/refundOrder"; import affixTime from "@/components/affix-time"; import * as echarts from 'echarts'; -import {pvUvData} from "../../api/orderStatistics"; +import {pvUvData,getOrderCount,getViewAndCompletionRateCount} from "../../api/orderStatistics"; export default { components: { orderRow, refundRow, affixTime }, @@ -273,7 +281,9 @@ // 鍥捐〃瀹炰緥 chart: null, //pvuv orderCountChart:null, //璁㈠崟鏃ヨ秼鍔� - + viewPrintChart:null, + currentType:"goods", + currentLimit:10, // 缁熻鏁版嵁 orderOrRefund: 1, // 璁㈠崟杩樻槸閫�鍗� @@ -592,26 +602,63 @@ }, }, methods: { + getDates(param){ + const dates = []; + const today = new Date(); + let days = 1; + + // 纭畾澶╂暟閫昏緫涓嶅彉 + if (param.searchType === "TODAY") { + days = 1; + } else if (param.searchType === "YESTERDAY") { + days = 1; + } else if (param.searchType === "LAST_SEVEN") { + days = 7; + } else if (param.searchType === "LAST_THIRTY") { + days = 30; + } + + // 鐢熸垚鏃ユ湡鏁扮粍閫昏緫涓嶅彉 + for (let i = days - 1; i >= 0; i--) { + const date = new Date(today); + date.setDate(today.getDate() - i); + dates.push(this.formatDate(date, 'MM-dd')); + } + return dates; + }, + //------------- puvu handleResize() { if (this.chart) { this.chart.resize() } + if(this.viewPrintChart){ + this.viewPrintChart.resize() + } + if (this.orderCountChart){ + this.orderCountChart.resize() + } }, initChart(){ this.chart = echarts.init(this.$refs.chartDom) + this.viewPrintChart = echarts.init(this.$refs.viewPrintChartDom) + this.orderCountChart = echarts.init(this.$refs.orderCountChartDom) + this.updateChartData(this.orderParams) + + this.updateOrderCountChartDate(this.orderParams) + + let form = {...this.orderParams}; + form.currentType = this.currentType; + form.currentLimit = this.currentLimit; + this.updateViewAndCompletionRateData(form) }, // 鏇存柊鍥捐〃鏁版嵁 async updateChartData(param) { // 鐢熸垚鏃ユ湡鍜孭V鏁版嵁 - const { dates, pvData ,uvData} = await this.generateChartData(param) - console.log(dates, pvData ,uvData) - // 鏇存柊缁熻鏁版嵁 - - + const { pvData ,uvData} = await this.generateChartData(param) // 璁剧疆鍥捐〃閰嶇疆 - this.chart.setOption(this.getChartOption(dates, pvData, uvData)) + this.chart.setOption(this.getChartOption(this.getDates(param), pvData, uvData)) }, // 鑾峰彇鍥捐〃閰嶇疆椤� // 鍥捐〃閰嶇疆椤癸紙鎭㈠鍘熷棰滆壊锛� @@ -745,29 +792,8 @@ }; }, // 鐢熸垚pv/uv鍥捐〃鏁版嵁 - async generateChartData(param) { // 1. 澹版槑涓篴sync鍑芥暟 - const dates = []; - const today = new Date(); - let days = 1; - - // 纭畾澶╂暟閫昏緫涓嶅彉 - if (param.searchType === "TODAY") { - days = 1; - } else if (param.searchType === "YESTERDAY") { - days = 1; - } else if (param.searchType === "LAST_SEVEN") { - days = 7; - } else if (param.searchType === "LAST_THIRTY") { - days = 30; - } - - // 鐢熸垚鏃ユ湡鏁扮粍閫昏緫涓嶅彉 - for (let i = days - 1; i >= 0; i--) { - const date = new Date(today); - date.setDate(today.getDate() - i); - dates.push(this.formatDate(date, 'MM-dd')); - } - + async generateChartData(param) { + // 1. 澹版槑涓篴sync鍑芥暟 // 2. 浣跨敤await绛夊緟鎺ュ彛杩斿洖锛岀‘淇濇暟鎹幏鍙栧悗鍐嶇户缁� let pvData = []; let uvData = []; @@ -783,18 +809,250 @@ } // 3. 姝ゆ椂pvData鍜寀vData宸茶鎺ュ彛鏁版嵁濉厖锛屽啀杩斿洖 - return { dates, pvData, uvData }; + return { pvData, uvData }; }, //------------- //-------------璁㈠崟鏃ヨ秼鍔� + async updateOrderCountChartDate(param){ + const { orderCountData } = await this.generateOrderCountChartData(param) + this.orderCountChart.setOption(this.getOrderCountChartOption(this.getDates(param),orderCountData)) + }, + async generateOrderCountChartData(param){ + let orderCountData = []; + try { + const res = await getOrderCount(param); + if (res.code === 200) { + orderCountData = res.data; + } + } catch (error) { + console.error("鎺ュ彛璋冪敤澶辫触", error); + } + return { orderCountData }; + }, + getOrderCountChartOption(dates, orderCountDate) { + return { + tooltip: { + trigger: 'axis', + backgroundColor: 'rgba(255, 255, 255, 0.9)', + borderColor: '#eee', + borderWidth: 1, + textStyle: { color: '#333' }, + // 淇1锛歍ooltip 鍐呭涓庘�滆鍗曢噺鈥濅富棰樺尮閰嶏紝绠�鍖栭�昏緫 + formatter: (params) => { + const date = params[0].name; + const orderCount = params[0].value || 0; // 鐩存帴鍙栧敮涓�绯诲垪鏁版嵁 + return `<div class="font-medium">${date}</div> + <div>璁㈠崟閲�: <span style="color: #00b42a; font-weight: bold">${orderCount.toLocaleString()}</span></div>`; + }, + }, + legend: { + data: ['璁㈠崟閲�'], + top: 0, + textStyle: { color: '#666' } + }, + grid: { + left: '3%', + right: '4%', + bottom: '3%', + containLabel: true, + top: '20%' // 浼樺寲1锛氬鍔犻《閮ㄩ棿璺濓紝閬垮厤涓巐egend閲嶅彔 + }, + xAxis: { + type: 'category', + data: dates, + axisLine: { lineStyle: { color: '#eee' } }, + axisTick: { show: false }, + axisLabel: { interval: 'auto', rotate: 0, color: '#86909C' }, + splitLine: { show: false } + }, + yAxis: { + type: 'value', + axisLine: { show: false }, + axisTick: { show: false }, + axisLabel: { color: '#86909C', formatter: '{value}' }, + splitLine: { lineStyle: { color: '#f2f3f5' } }, + min: 0 // 姝g‘锛氳鍗曢噺涓嶈兘涓鸿礋锛屽浐瀹氭渶灏忓�间负0 + }, + series: [ + { + name: '璁㈠崟閲�', + type: 'line', + data: orderCountDate, + symbol: 'circle', + symbolSize: 6, + emphasis: { + symbolSize: 8, + showSymbol: true + }, + lineStyle: { + width: 3, + color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [ + { offset: 0, color: '#00b42a' }, + { offset: 1, color: '#72c140' } + ]), + cap: 'round', // 绔偣鍦嗚锛屼紭鍖栬瑙� + join: 'round', // 鎷愯鍦嗚锛屼紭鍖栬瑙� + miterLimit: 3 + }, + itemStyle: { + color: '#00b42a', + borderColor: '#fff', + borderWidth: 0 // 淇2锛氫笌娉ㄩ噴涓�鑷达紝鏄剧ず鐧借壊杈规锛堥伩鍏嶇偣涓庤儗鏅瀺鍚堬級 + }, + areaStyle: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { offset: 0, color: 'rgba(0, 180, 42, 0.2)' }, + { offset: 1, color: 'rgba(0, 180, 42, 0)' } + ]) + }, + smooth: true, + showSymbol: true // 鏄剧ず鎵�鏈夋暟鎹偣锛屼究浜庢煡鐪嬪叿浣撴暟鍊� + } + ], + animation: true, + animationDuration: 1500, + animationEasing: 'cubicOut' // 缂撳姩鏁堟灉锛屼紭鍖栧姩鐢绘祦鐣呭害 + }; + }, + //------------- +//-------------娴忚閲忥紝瀹屾挱鐜囷紝 + handleLimitChange(limit) { + if (this.currentLimit !== limit) { + this.currentLimit = limit + let from = {...this.orderParams} + from.currentLimit = this.currentLimit; + from.currentType = this.currentType; + this.updateViewAndCompletionRateData(from) // 閲嶆柊鍔犺浇鏁版嵁 + } + }, + handleTypeChange(type) { + if (this.currentType !== type){// 閬垮厤閲嶅鐐瑰嚮 + this.currentType = type // 鏇存柊褰撳墠绫诲瀷 + let from = {...this.orderParams} + from.currentLimit = this.currentLimit; + from.currentType = this.currentType; + this.updateViewAndCompletionRateData(from) // 閲嶆柊鍔犺浇鏁版嵁 + } + + }, + async updateViewAndCompletionRateData(param) { + // 鐢熸垚鏃ユ湡鍜屾瘡鏃ヨ鍗曢噺鏁版嵁 + const { xData,yData ,rateData} = await this.generateViewAndCompletionRateChartData(param) + // 鏇存柊缁熻鏁版嵁 + // 璁剧疆鍥捐〃閰嶇疆( + this.viewPrintChart.setOption(this.getViewAndCompletionRateChartOption( xData,yData,rateData)); + }, + async generateViewAndCompletionRateChartData(param){ + let xData = []; + let yData = []; + let rateData =[]; + try { + const res = await getViewAndCompletionRateCount(param); // 绛夊緟鎺ュ彛鍝嶅簲 + if (res.code === 200) { + xData = res.data.xData; + yData = res.data.yData + rateData = res.data.rateData; + } + } catch (error) { + console.error("鎺ュ彛璋冪敤澶辫触", error); + + } + return { xData,yData,rateData} + }, + getViewAndCompletionRateChartOption(xData, yData, rateData) { + // 鍏煎ECharts瀹炰緥寮曠敤锛堟牴鎹」鐩幆澧冮�夋嫨this.$echarts鎴栧叏灞�echarts锛� + let isVideoType = this.currentType === "video" + const tooltipFormatter = (params) => { + let content = `${params[0].name}<br/>娴忚娆℃暟: ${params[0].value} 娆; + if (this.currentType === 'video') { + const rate = rateData?.[params[0].dataIndex] ?? 0; + content += `<br/>瀹屾挱鐜�: ${rate}%`; + } + return content; + }; + + return { + title: { + text: isVideoType ? '瑙嗛娴忚閲�&瀹屾挱鐜囩粺璁�' : '鍟嗗搧娴忚閲忕粺璁�', // 瑙嗛鏍囬鍔犫�滃畬鎾巼鈥� + left: 'center', + textStyle: { fontSize: 16, fontWeight: 'normal', color: '#333' }, + subtext: `鎸�${isVideoType ? '瑙嗛' : '鍟嗗搧'}鍒嗙被锛圱op${this.currentLimit}锛塦, + subtextStyle: { fontSize: 12, color: '#666' } + }, + tooltip: { + trigger: 'axis', + axisPointer: { type: 'shadow' }, + formatter:tooltipFormatter + }, + grid: { + left: '5%', // 瑙嗛绫诲瀷宸︾Щ锛岀粰瀹屾挱鐜囨爣绛剧暀绌洪棿 + right: '10%', + bottom: '0', + top: '5%', + containLabel: true + }, + xAxis: { + type: 'value', + name: '娴忚娆℃暟', + nameGap:100, + nameTextStyle: { color: '#666', fontSize: 12 }, + axisLine: { show: false }, + axisLabel: { formatter: '{value}', color: '#666', fontSize: 12 }, + splitLine: { lineStyle: { color: '#f5f5f5' } }, + min: 0 + }, + yAxis: { + type: 'category', + data: yData, + axisLine: { lineStyle: { color: '#ddd' } }, + axisLabel: { color: '#666', fontSize: 12, interval: 0 }, // 寮哄埗鏄剧ず鎵�鏈夋爣绛� + splitLine: { show: false } + }, + series: [ + { + name: isVideoType ? '娴忚閲�&瀹屾挱鐜�' : '娴忚閲�', + type: 'bar', + data: xData, + itemStyle: { + color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [ + { offset: 0, color: '#409eff' }, + { offset: 1, color: '#69b1ff' } + ]), + borderRadius: [0, 4, 4, 0] // 妯悜鏌卞瓙鍙充晶鍦嗚 + }, + barWidth: isVideoType ? '30%' : '40%', // 瑙嗛绫诲瀷鏌卞瓙鍙樼獎锛岄伩鍏嶆爣绛炬嫢鎸� + label: { + show: true, + position: 'right', // 鏍囩鍦ㄦ煴瀛愬彸渚� + color: '#333', + fontSize: 12, + // 鏍囩鍐呭锛氳棰戠被鍨嬫樉绀衡�滄祻瑙堥噺+瀹屾挱鐜団�濓紝鍟嗗搧绫诲瀷鍙樉绀烘祻瑙堥噺 + formatter: function(params) { + const viewCount = params.value; + if (isVideoType) { + const rate = rateData[params.dataIndex] || 0; // 鍏滃簳绌哄�� + // 鎹㈣鏄剧ず锛岄伩鍏嶆í鍚戞嫢鎸� + return `${viewCount} 娆n瀹屾挱鐜�: ${rate}%`; + } + return `${viewCount} 娆; + }.bind(this) // 缁戝畾this锛岀‘淇濊兘璁块棶鍒� isVideoType 鍜� rateData + }, + emphasis: { + itemStyle: { + color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [ + { offset: 0, color: '#3a86ff' }, + { offset: 1, color: '#5a9dff' } + ]) + } + } + } + ] + }; + }, //------------- - - - - formatDate(date) { const month = date.getMonth() + 1; // 鏈堜唤浠�0寮�濮嬶紝闇�+1 @@ -863,6 +1121,12 @@ //鏇存柊琛ㄦ牸 this.updateChartData(this.orderParams) + this.updateOrderCountChartDate(this.orderParams) + + let form = {...this.orderParams}; + form.currentType = this.currentType; + form.currentLimit = this.currentLimit; + this.updateViewAndCompletionRateData(form) }, // 瀹炰緥鍖栬鍗曟瑙� @@ -928,6 +1192,21 @@ }; </script> <style scoped lang="scss"> +.button-group-wrapper { + display: flex; + justify-content: space-between; /* 宸﹀彸涓ょ瀵归綈 */ + align-items: center; /* 鍨傜洿灞呬腑锛堥伩鍏嶆寜閽珮搴︿笉涓�鑷村鑷撮敊浣嶏級 */ + width: 100%; /* 蹇呴』鎾戞弧鐖跺鍣紝鍚﹀垯 justify-content: space-between 鏃犳晥 */ + margin-bottom: 20px; /* 涓庡浘琛ㄤ繚鎸侀棿璺� */ + flex-wrap: wrap; /* 灏忓睆骞曡嚜鍔ㄦ崲琛岋紙閬垮厤鎸夐挳鎸ゅ帇锛� */ + gap: 12px; /* 鎹㈣鏃朵袱缁勬寜閽殑涓婁笅闂磋窛 */ +} + +/* 鍥捐〃瀹瑰櫒锛氫繚鎸佸浐瀹氶珮搴� */ +.chart-wrapper { + width: 100%; + height: 500px; +} .active { color: $theme_color; position: relative; @@ -1248,6 +1527,10 @@ // color: #fff; //} +.view-chart-container { + width: 100%; + height: 662px; +} .chart-container { width: 100%; height: 400px; -- Gitblit v1.8.0