| | |
| | | <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>–>--> |
| | | |
| | | <!--<!– <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>–>--> |
| | | |
| | | <!--<!– <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> |
| | |
| | | import orderRow from "./order/orderDetail"; |
| | | import refundRow from "./order/refundOrder"; |
| | | import affixTime from "@/components/affix-time"; |
| | | import * as echarts from 'echarts'; |
| | | import {pvUvData} from "../../api/orderStatistics"; |
| | | |
| | | export default { |
| | | components: { orderRow, refundRow, affixTime }, |
| | | |
| | | data() { |
| | | return { |
| | | // 图表实例 |
| | | chart: null, //pvuv |
| | | orderCountChart:null, //订单日趋势 |
| | | |
| | | // 统计数据 |
| | | |
| | | orderOrRefund: 1, // 订单还是退单 |
| | | total: 0, // 总数 |
| | | // 订单状态 |
| | |
| | | }, |
| | | }, |
| | | methods: { |
| | | //------------- puvu |
| | | handleResize() { |
| | | if (this.chart) { |
| | | this.chart.resize() |
| | | } |
| | | }, |
| | | initChart(){ |
| | | this.chart = echarts.init(this.$refs.chartDom) |
| | | this.updateChartData(this.orderParams) |
| | | }, |
| | | // 更新图表数据 |
| | | async updateChartData(param) { |
| | | // 生成日期和PV数据 |
| | | const { dates, pvData ,uvData} = await this.generateChartData(param) |
| | | console.log(dates, pvData ,uvData) |
| | | // 更新统计数据 |
| | | |
| | | |
| | | // 设置图表配置 |
| | | this.chart.setOption(this.getChartOption(dates, pvData, uvData)) |
| | | }, |
| | | // 获取图表配置项 |
| | | // 图表配置项(恢复原始颜色) |
| | | getChartOption(dates, pvData, uvData) { |
| | | return { |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | backgroundColor: 'rgba(255, 255, 255, 0.9)', |
| | | borderColor: '#eee', |
| | | borderWidth: 1, |
| | | textStyle: { color: '#333' }, |
| | | formatter: (params) => { |
| | | const date = params[0].name; |
| | | const pv = params.find(item => item.seriesName === '浏览量(PV)')?.value || 0; |
| | | const uv = params.find(item => item.seriesName === '独立访客(UV)')?.value || 0; |
| | | // 优化:添加换行符转义,避免潜在格式问题(可选,不影响功能) |
| | | return `<div class="font-medium">${date}</div> |
| | | <div>浏览量(PV): <span style="color: #165DFF; font-weight: bold">${pv.toLocaleString()}</span></div> |
| | | <div>独立访客(UV): <span style="color: #00b42a; font-weight: bold">${uv.toLocaleString()}</span></div>`; |
| | | }, |
| | | }, |
| | | legend: { |
| | | data: ['浏览量(PV)', '独立访客(UV)'], |
| | | top: 0, |
| | | textStyle: { color: '#666' } |
| | | }, |
| | | grid: { |
| | | left: '3%', |
| | | right: '4%', |
| | | bottom: '3%', |
| | | containLabel: true, |
| | | top: '15%' |
| | | }, |
| | | 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 |
| | | }, |
| | | series: [ |
| | | // PV折线(保留原始蓝色系,优化点线衔接) |
| | | { |
| | | name: '浏览量(PV)', |
| | | type: 'line', |
| | | data: pvData, |
| | | symbol: 'circle', |
| | | symbolSize: 6, // 保留原有点大小 |
| | | emphasis: { |
| | | symbolSize: 8, |
| | | showSymbol: true |
| | | }, |
| | | lineStyle: { |
| | | width: 3, // 保留原有线宽 |
| | | color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [ |
| | | { offset: 0, color: '#165DFF' }, // 原始PV主色 |
| | | { offset: 1, color: '#36CFC9' } // 原始渐变辅助色 |
| | | ]), |
| | | // 关键优化1:线条端点设为圆角,避免“切口”空白 |
| | | cap: 'round', |
| | | // 关键优化2:线条拐角设为圆角,避免衔接间隙 |
| | | join: 'round', |
| | | // 辅助:控制拐角圆角大小(与线宽匹配,避免溢出) |
| | | miterLimit: 3 |
| | | }, |
| | | itemStyle: { |
| | | color: '#165DFF', // 原始点颜色 |
| | | borderColor: '#fff', // 保留白色边框(增强层次感) |
| | | // 关键优化3:减小边框宽度,避免遮挡线条导致断层 |
| | | borderWidth: 0 // 从2调整为1.5 |
| | | }, |
| | | areaStyle: { |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { offset: 0, color: 'rgba(22, 93, 255, 0.2)' }, // 原始填充色 |
| | | { offset: 1, color: 'rgba(22, 93, 255, 0)' } |
| | | ]) |
| | | }, |
| | | smooth: true, |
| | | showSymbol: true, // 保留你设置的“默认显示所有点” |
| | | }, |
| | | // UV折线(保留原始绿色系,同PV优化逻辑) |
| | | { |
| | | name: '独立访客(UV)', |
| | | type: 'line', |
| | | data: uvData, |
| | | 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' }, // 原始UV主色 |
| | | { offset: 1, color: '#72c140' } // 原始渐变辅助色 |
| | | ]), |
| | | // 同PV优化:端点圆角+拐角圆角 |
| | | cap: 'round', |
| | | join: 'round', |
| | | miterLimit: 3 |
| | | }, |
| | | itemStyle: { |
| | | color: '#00b42a', // 原始点颜色 |
| | | borderColor: '#fff', // 保留白色边框 |
| | | // 同PV优化:减小边框宽度 |
| | | borderWidth: 0 // 从2调整为1.5 |
| | | }, |
| | | 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' |
| | | }; |
| | | }, |
| | | // 生成pv/uv图表数据 |
| | | async generateChartData(param) { // 1. 声明为async函数 |
| | | 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')); |
| | | } |
| | | |
| | | // 2. 使用await等待接口返回,确保数据获取后再继续 |
| | | let pvData = []; |
| | | let uvData = []; |
| | | try { |
| | | const res = await pvUvData(param); // 等待接口响应 |
| | | if (res.code === 200) { |
| | | pvData = res.data.pvData; |
| | | uvData = res.data.uvData; |
| | | } |
| | | } catch (error) { |
| | | console.error("接口调用失败", error); |
| | | // 可根据需求添加错误处理(如默认数据) |
| | | } |
| | | |
| | | // 3. 此时pvData和uvData已被接口数据填充,再返回 |
| | | return { dates, pvData, uvData }; |
| | | }, |
| | | //------------- |
| | | //-------------订单日趋势 |
| | | |
| | | |
| | | |
| | | //------------- |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | formatDate(date) { |
| | | const month = date.getMonth() + 1; // 月份从0开始,需+1 |
| | | const day = date.getDate(); |
| | | // 补零:如果是个位数,前面加0 |
| | | const formattedMonth = month < 10 ? `0${month}` : month; |
| | | const formattedDay = day < 10 ? `0${day}` : day; |
| | | return `${formattedMonth}-${formattedDay}`; |
| | | }, |
| | | |
| | | pageNumberChange(val){ |
| | | this.refundParams.pageNumber = val |
| | | this.getOrderList(); |
| | |
| | | this.refundParams = callback; |
| | | this.refundParams.pageNumber = 1 |
| | | this.refundParams.pageSize = 10 |
| | | |
| | | //更新表格 |
| | | this.updateChartData(this.orderParams) |
| | | }, |
| | | |
| | | // 实例化订单概览 |
| | |
| | | }, |
| | | |
| | | mounted() { |
| | | console.log('ECharts 是否存在:', typeof echarts !== 'undefined'); // 应输出 true |
| | | this.initChart(); |
| | | this.initBaseParams(); |
| | | window.addEventListener('resize', this.handleResize) |
| | | }, |
| | | }; |
| | | </script> |
| | |
| | | .card { |
| | | margin-bottom: 10px; |
| | | } |
| | | .my-chart-container { |
| | | padding: 20px; |
| | | background-color: #f9fafb; |
| | | } |
| | | |
| | | .stats-cards { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 20px; |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .stat-card { |
| | | flex: 1; |
| | | min-width: 250px; |
| | | background-color: #fff; |
| | | border-radius: 8px; |
| | | padding: 20px; |
| | | box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); |
| | | transition: transform 0.3s ease, box-shadow 0.3s ease; |
| | | } |
| | | |
| | | .stat-card:hover { |
| | | transform: translateY(-5px); |
| | | box-shadow: 0 10px 20px rgba(22, 93, 255, 0.1); |
| | | } |
| | | |
| | | .stat-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 15px; |
| | | } |
| | | |
| | | .stat-title { |
| | | color: #86909c; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .stat-icon { |
| | | color: #165dff; |
| | | font-size: 18px; |
| | | } |
| | | |
| | | .stat-value { |
| | | font-size: 28px; |
| | | font-weight: bold; |
| | | margin-bottom: 10px; |
| | | color: #1d2129; |
| | | } |
| | | |
| | | .stat-trend { |
| | | font-size: 13px; |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .stat-trend.positive { |
| | | color: #00b42a; |
| | | } |
| | | |
| | | .chart-wrapper { |
| | | background-color: #fff; |
| | | border-radius: 8px; |
| | | padding: 20px; |
| | | box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); |
| | | margin-bottom: 15px; |
| | | } |
| | | |
| | | .chart-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .chart-header h2 { |
| | | font-size: 18px; |
| | | font-weight: 600; |
| | | color: #1d2129; |
| | | } |
| | | |
| | | //.time-filters { |
| | | // display: flex; |
| | | // gap: 10px; |
| | | //} |
| | | |
| | | //.time-filters button { |
| | | // padding: 6px 12px; |
| | | // border-radius: 4px; |
| | | // border: none; |
| | | // background-color: #f2f3f5; |
| | | // color: #1d2129; |
| | | // font-size: 14px; |
| | | // cursor: pointer; |
| | | // transition: all 0.2s ease; |
| | | //} |
| | | // |
| | | //.time-filters button.active { |
| | | // background-color: #ff4c16; |
| | | // color: #fff; |
| | | //} |
| | | |
| | | .chart-container { |
| | | width: 100%; |
| | | height: 400px; |
| | | } |
| | | |
| | | .update-time { |
| | | color: #86909c; |
| | | font-size: 12px; |
| | | text-align: right; |
| | | } |
| | | |
| | | @media (max-width: 768px) { |
| | | .chart-header { |
| | | flex-direction: column; |
| | | align-items: flex-start; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .chart-container { |
| | | height: 300px; |
| | | } |
| | | } |
| | | </style> |