统计模块的订单分析

This commit is contained in:
yis 2025-08-04 11:31:52 +08:00
parent 2f163bafd9
commit 499d80ab0e

View File

@ -12,7 +12,7 @@
<div class="card-header"> <div class="card-header">
<span class="card-label">总订单量</span> <span class="card-label">总订单量</span>
<div class="card-icon"> <div class="card-icon">
<svg-icon icon-class="shopping" class="text-blue-600" /> <svg-icon icon-class="shopping" />
</div> </div>
</div> </div>
<div class="card-value">{{ summaryData.totalOrderCount }}</div> <div class="card-value">{{ summaryData.totalOrderCount }}</div>
@ -23,7 +23,7 @@
<div class="card-header"> <div class="card-header">
<span class="card-label">订单总金额</span> <span class="card-label">订单总金额</span>
<div class="card-icon"> <div class="card-icon">
<svg-icon icon-class="money" class="text-green-600" /> <svg-icon icon-class="money" />
</div> </div>
</div> </div>
<div class="card-value">¥{{ summaryData.totalOrderAmount }}</div> <div class="card-value">¥{{ summaryData.totalOrderAmount }}</div>
@ -125,7 +125,7 @@
<div class="double-chart-section"> <div class="double-chart-section">
<!-- 无人机型号分布图 --> <!-- 无人机型号分布图 -->
<div class="chart-box"> <div class="chart-box">
<h3 class="chart-title">无人机型号分布</h3> <h3 class="chart-title">无人机型号订单占比</h3>
<div class="chart-wrapper" ref="modelChartContainer"></div> <div class="chart-wrapper" ref="modelChartContainer"></div>
</div> </div>
@ -493,9 +493,9 @@ export default {
} }
console.log('接口响应数据:', response); console.log('接口响应数据:', response);
this.summaryData.totalOrderAmount = response.totalOrderAmount;
this.summaryData.totalOrderCount = response.totalOrderCount; this.processResponseData(response);
this.processResponseData(response.data);
} catch (error) { } catch (error) {
console.error('获取订单分析数据失败:', error); console.error('获取订单分析数据失败:', error);
this.$message.error('获取数据失败,请重试'); this.$message.error('获取数据失败,请重试');
@ -599,15 +599,17 @@ export default {
break; break;
} }
} }
//
const maxValue = Math.max(...seriesData);
const maxIndex = seriesData.indexOf(maxValue);
const option = { const option = {
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
axisPointer: { type: 'shadow' },
formatter: params => { formatter: params => {
const value = params[0].value; const value = params[0].value;
const axisValue = params[0].axisValue; const axisValue = params[0].axisValue;
return `${axisValue}<br/>订单量: ${value}`; return `${axisValue}<br/>当前订单量: ${value}`;
} }
}, },
grid: { grid: {
@ -618,20 +620,25 @@ export default {
}, },
xAxis: { xAxis: {
type: 'category', type: 'category',
name:'时间',
data: xAxisData, data: xAxisData,
axisTick: {
show: true,
inside: true, //
},
axisLabel: { axisLabel: {
rotate: xAxisData.length > 10 ? 45 : 0, rotate: xAxisData.length > 10 ? 45 : 0,
formatter: value => { formatter: value => {
switch (this.filter.timeRange) { switch (this.filter.timeRange) {
case 'day': return value.split('-').slice(1).join('-'); case 'day': return value.split('-').slice(1).join('-');
case 'month': return value.split('-')[1]; case 'month': return value.split('-')[1]+ '月';
case 'year': return value; case 'year': return value+ '年';
default: return value; default: return value;
} }
} }
} }
}, },
yAxis: { type: 'value', minInterval: 1 }, yAxis: { type: 'value', minInterval: 1,name: '订单数量'},
series: [{ series: [{
name: '订单数量', name: '订单数量',
data: seriesData, data: seriesData,
@ -639,11 +646,23 @@ export default {
smooth: true, smooth: true,
areaStyle: { areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(58, 77, 233, 0.8)' }, { offset: 0, color: 'rgb(121, 165, 247,0.5)' },
{ offset: 1, color: 'rgba(58, 77, 233, 0.1)' } { offset: 1, color: 'rgb(234, 241, 253, 0.1)' }
]) ])
}, },
itemStyle: { color: '#3a4de9' } axisTick: {
show: true,
inside: true, //
},
itemStyle: { color: '#4E80EE' },
markPoint: {
data: [{
type: 'max',
label: {
formatter: '{c}'
}
}]
}
}] }]
}; };
@ -673,13 +692,14 @@ export default {
legend: { legend: {
orient: 'vertical', orient: 'vertical',
right: 10, right: 10,
top: 'center' top: 'center',
itemGap: 10
}, },
series: [{ series: [{
name: '无人机型号分布', name: '无人机型号分布',
type: 'pie', type: 'pie',
radius: ['40%', '70%'], radius: ['40%', '70%'],
avoidLabelOverlap: false, center: ['40%', '50%'],
itemStyle: { itemStyle: {
borderRadius: 10, borderRadius: 10,
borderColor: '#fff', borderColor: '#fff',
@ -707,7 +727,7 @@ export default {
updateRouteChart(routeDistribution) { updateRouteChart(routeDistribution) {
if (!this.routeChart) return; if (!this.routeChart) return;
// 0线 // 1.
const topRoutes = (routeDistribution || []) const topRoutes = (routeDistribution || [])
.filter(item => item.count > 0) .filter(item => item.count > 0)
.sort((a, b) => b.count - a.count) .sort((a, b) => b.count - a.count)
@ -724,49 +744,79 @@ export default {
return; return;
} }
// 2.
const maxValue = Math.max(...topRoutes.map(item => item.count));
const colorGradient = (value) => {
const ratio = value / maxValue;
return new echarts.graphic.LinearGradient(0, 0, 0,1, [
{ offset: 0, color: `rgba(9, 71, 179, ${0.3 + ratio * 0.7})` }, //
{ offset: 1, color: `rgba(58, 119, 233, ${0.3 + ratio * 0.7})` } //
]);
};
// 3.
this.routeChart.setOption({ this.routeChart.setOption({
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
axisPointer: { type: 'shadow' }, axisPointer: { type: 'shadow' },
formatter: params => { formatter: (params) => {
const route = topRoutes[params[0].dataIndex]; const data = params[0];
return `路线: ${route.routeName || '未知路线'}<br>景区: ${route.scenicName || '未知景区'}<br>订单量: ${params[0].data}`; return `
<div style="font-weight:bold">${data.name}</div>
<div>订单量: ${data.value}</div>
${data.data.percentage ? `<div>完成率: ${data.data.percentage}</div>` : ''}
`;
} }
}, },
grid: { grid: {
left: '3%', left: '3%',
right: '4%', right: '12%', //
bottom: '3%', bottom: '3%',
containLabel: true containLabel: true
}, },
xAxis: { xAxis: {
type: 'value', type: 'value',
boundaryGap: [0, 0.01], name: '订单数量(件)',
minInterval: 1 // splitLine: {
show: false // 线
},
axisTick: {
show: false //
},
max: Math.max(50, maxValue) //
}, },
yAxis: { yAxis: {
type: 'category', type: 'category',
data: topRoutes.map(item => item.routeName || `路线 ${item.routeId}`), name: '景区路线',
nameLocation: 'start',
data: topRoutes.map(item => item.routeName),
axisLabel: { axisLabel: {
formatter: value => value.length > 6 ? value.substring(0, 6) + '...' : value formatter: (name) => name.length > 8 ? `${name.substring(0, 8)}...` : name
} },
axisTick: {
show: false //
},
splitLine: {
show: false // 线
},
inverse: true // Y使
}, },
series: [{ series: [{
name: '订单量', name: '订单量',
type: 'bar', type: 'bar',
data: topRoutes.map(item => item.count), data: topRoutes.map(item => ({
value: item.count,
name: item.routeName,
percentage: item.count.toString().includes('%') ? item.count : null,
itemStyle: { itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [ color: colorGradient(item.count)
{ offset: 0, color: '#83bff6' }, }
{ offset: 0.5, color: '#188df0' }, })),
{ offset: 1, color: '#0052d9' } barWidth: '40%',
]),
borderRadius: [0, 5, 5, 0]
},
label: { label: {
show: true, show: true,
position: 'right', position: 'right', //
formatter: '{c}' formatter: ({ data }) => data.displayValue || `${data.value}`,
} }
}] }]
}, true); }, true);
@ -837,11 +887,9 @@ export default {
</script> </script>
<style scoped> <style scoped>
/* 保持原有的样式不变 */
.order-analysis-container { .order-analysis-container {
min-height: 100vh; min-height: 100vh;
background-color: #f5f7fa; background-color: #f5f7fa;
font-family: 'Arial', sans-serif;
} }
.main-content { .main-content {
@ -858,61 +906,48 @@ export default {
} }
.page-title { .page-title {
font-size: 24px; font-size: 20px;
font-weight: 600; font-weight: 600;
color: #333; margin-bottom: 16px;
margin-bottom: 24px;
display: flex; display: flex;
align-items: center; align-items: center;
} }
/* 卡片布局 */
.card-grid { .card-grid {
display: grid; display: grid;
grid-template-columns: repeat(4, 1fr); grid-template-columns: repeat(4, 1fr);
gap: 10px; gap: 8px;
margin-bottom: 16px; margin-bottom: 12px;
} }
.stat-card { .stat-card {
padding: 16px; padding: 12px;
min-height: 70px; min-height: 60px;
border-radius: 8px; border-radius: 6px;
transition: transform 0.2s; transition: transform 0.2s;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
} }
.stat-card:hover { .stat-card:hover {
transform: translateY(-5px); transform: translateY(-5px);
} }
.blue-card { /* 卡片颜色变体 */
background: linear-gradient(to bottom right, #ebf4ff, white); .blue-card { background: linear-gradient(to bottom right, #ebf4ff, white) }
} .green-card { background: linear-gradient(to bottom right, #ecfdf5, white) }
.purple-card { background: linear-gradient(to bottom right, #e5e2f4, white) }
.green-card { .orange-card { background: linear-gradient(to bottom right, #f7f5e7, white) }
background: linear-gradient(to bottom right, #ecfdf5, white);
}
.purple-card {
background: linear-gradient(to bottom right, #e5e2f4, white);
}
.orange-card {
background: linear-gradient(to bottom right, #f7f5e7, white);
}
.card-header { .card-header {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
margin-bottom: 14px; margin-bottom: 8px;
} }
.card-label { .card-label {
font-size: 18px; font-size: 14px;
font-weight: 700; font-weight: 700;
} }
.card-icon { .card-icon {
width: 40px; width: 40px;
height: 40px; height: 40px;
@ -920,63 +955,53 @@ export default {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
background-color: inherit;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
} }
.card-value { .card-value {
font-size: 28px; font-size: 22px;
font-weight: 700; font-weight: 700;
margin-bottom: 12px; margin-bottom: 8px;
} }
/* 筛选区域 */
.filter-section { .filter-section {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; margin-bottom: 16px;
margin-bottom: 24px; padding: 12px;
padding: 16px;
background-color: #f9fafb; background-color: #f9fafb;
border-radius: 8px; border-radius: 8px;
flex-wrap: wrap; flex-wrap: wrap;
gap: 16px;
} }
.filter-group { .filter-group {
display: flex; display: flex;
gap: 24px; gap: 24px;
flex-wrap: wrap; flex-wrap: wrap;
} }
.filter-item { .filter-item {
display: flex; display: flex;
align-items: center; align-items: center;
flex-wrap: wrap; flex-wrap: wrap;
} }
.filter-label { .filter-label {
font-size: 14px; font-size: 14px;
color: #666; color: #666;
margin-right: 12px; margin-right: 12px;
white-space: nowrap;
} }
.time-range-buttons { .time-range-buttons {
display: flex; display: flex;
gap: 8px; gap: 8px;
flex-wrap: wrap;
} }
.time-button { .time-button {
padding: 8px 16px; padding: 8px 16px;
border-radius: 4px; border-radius: 4px;
border: 1px solid #dcdfe6; border: 1px solid #dcdfe6;
background: #f5f7fa; background: #f5f7fa;
cursor: pointer; cursor: pointer;
transition: all 0.3s;
font-size: 14px; font-size: 14px;
white-space: nowrap;
} }
.time-button.active { .time-button.active {
background: #409eff; background: #409eff;
color: white; color: white;
@ -989,45 +1014,34 @@ export default {
gap: 10px; gap: 10px;
} }
.separator { /* 图表区域 */
color: #606266; .chart-section, .data-table-section {
padding: 0 5px; margin-bottom: 24px;
} }
.action-buttons {
display: flex;
align-items: center;
gap: 10px;
}
.chart-section {
margin-bottom: 32px;
}
.double-chart-section { .double-chart-section {
display: grid; display: grid;
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, 1fr);
gap: 20px; gap: 20px;
margin-bottom: 32px; margin-bottom: 24px;
} }
.chart-box { .chart-box, .data-table-section {
background-color: white; background-color: white;
border-radius: 8px; border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05); box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
padding: 20px; padding: 16px;
} }
.chart-title { .chart-title, .table-title {
font-size: 18px;
font-weight: 500; font-weight: 500;
color: #333; margin-bottom: 12px;
margin-bottom: 16px;
display: flex; display: flex;
align-items: center; align-items: center;
} }
.chart-title { font-size: 16px }
.table-title { font-size: 18px }
.chart-title::before { .chart-title::before, .table-title::before {
content: ''; content: '';
display: inline-block; display: inline-block;
width: 4px; width: 4px;
@ -1039,39 +1053,13 @@ export default {
.chart-wrapper { .chart-wrapper {
width: 100%; width: 100%;
height: 400px; height: 320px;
}
.data-table-section {
background-color: white;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
padding: 20px;
}
.table-title {
font-size: 18px;
font-weight: 500;
color: #333;
margin-bottom: 16px;
display: flex;
align-items: center;
}
.table-title::before {
content: '';
display: inline-block;
width: 4px;
height: 16px;
background-color: #3a4de9;
margin-right: 8px;
border-radius: 2px;
} }
/* 表格区域 */
.table-wrapper { .table-wrapper {
overflow-x: auto; overflow-x: auto;
} }
.pagination-wrapper { .pagination-wrapper {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@ -1080,113 +1068,39 @@ export default {
padding: 10px 0; padding: 10px 0;
border-top: 1px solid #ebeef5; border-top: 1px solid #ebeef5;
} }
.pagination-info { .pagination-info {
font-size: 12px; font-size: 12px;
color: #606266;
} }
.pagination-jump { .pagination-jump {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; gap: 8px;
} }
.jump-text { .jump-text {
font-size: 14px; font-size: 14px;
color: #606266;
} }
.jump-input { .jump-input {
width: 60px; width: 60px;
} }
.jump-input .el-input__inner { .jump-input .el-input__inner {
text-align: center; text-align: center;
padding: 0 5px; padding: 0 5px;
} }
.jump-button { /* 响应式布局 */
padding: 8px 15px;
}
@media (max-width: 1200px) { @media (max-width: 1200px) {
.card-grid { .card-grid { grid-template-columns: repeat(2, 1fr) }
grid-template-columns: repeat(2, 1fr); .double-chart-section { grid-template-columns: 1fr }
} }
.double-chart-section {
grid-template-columns: 1fr;
}
.date-range-picker {
width: 280px;
}
}
@media (max-width: 768px) { @media (max-width: 768px) {
.card-grid { .card-grid { grid-template-columns: 1fr }
grid-template-columns: 1fr; .filter-section { flex-direction: column }
.filter-group, .time-range-buttons, .date-range-picker { width: 100% }
.filter-item { flex-direction: column; align-items: flex-start }
} }
.filter-section {
flex-direction: column;
gap: 16px;
}
.filter-group {
flex-direction: column;
width: 100%;
gap: 12px;
}
.filter-item {
flex-direction: column;
align-items: flex-start;
width: 100%;
gap: 8px;
}
.date-range-picker {
width: 100%;
}
.time-range-buttons {
width: 100%;
}
.action-buttons {
width: 100%;
justify-content: flex-end;
}
}
@media (max-width: 480px) { @media (max-width: 480px) {
.main-content { .main-content { padding: 10px }
padding: 10px; .content-box { padding: 16px }
} .chart-wrapper { height: 280px }
.content-box {
padding: 16px;
}
.card-grid {
gap: 12px;
}
.chart-wrapper {
height: 300px;
}
} }
</style> </style>