This commit is contained in:
2026-10-20 23:34:11 +08:00
parent f155976f52
commit 13e4aa56ec
321 changed files with 6756 additions and 2110 deletions
@@ -1,4 +1,6 @@
<script setup lang="ts">
import '@/styles/adminWorkbench.css'
import { adminWorkbenchChartTheme as chartTheme } from '@/styles/adminWorkbenchChartTheme'
import { computed, ref } from 'vue'
import VChart from 'vue-echarts'
import { use } from 'echarts/core'
@@ -12,7 +14,7 @@ use([PieChart, LegendComponent, TooltipComponent, GraphicComponent, AriaComponen
const props = withDefaults(defineProps<{ charts: TripOperationsCharts; summary: TripOperationsSummary; detailsVisible?: boolean }>(), { detailsVisible: false })
const emit = defineEmits<{ 'show-details': [] }>()
const selectedSeries = ref<Record<string, string>>({})
const palette = ['#3b82f6', '#14b8a6', '#f59e0b', '#8b5cf6', '#f46565', '#06b6d4', '#ec4899', '#84cc16', '#6366f1', '#f97316']
const palette = [chartTheme.colors.primary, chartTheme.colors.teal, chartTheme.colors.amber, chartTheme.colors.purple, chartTheme.colors.rose, chartTheme.colors.tealLight, chartTheme.colors.green, chartTheme.colors.primaryLight, chartTheme.colors.unknown, chartTheme.colors.text]
const sections = computed(() => [
{ key: 'pallets', title: '实运托盘', note: '按实际发车日(UTC)分布,物理托盘去重', series: props.charts.physicalPallets, money: false },
{ key: 'destinations', title: '派送目的地', note: '按目的地涉及车次分布,同车多站可分别计入', series: props.charts.destinationTrips, money: false },
@@ -37,8 +39,10 @@ function pieOption(series: TripOperationsSeries, money: boolean): EChartsOption
const hasPositive = series.points.some(point => point.value > 0)
return {
animation: false,
textStyle: { fontFamily: chartTheme.fontFamily },
aria: { enabled: true, description: `${seriesTitle(series)},完整日期、图例和数值可在统计详情读取` },
tooltip: {
...chartTheme.tooltip,
trigger: 'item', confine: true, renderMode: 'richText',
formatter: params => {
if (Array.isArray(params)) return ''
@@ -48,20 +52,20 @@ function pieOption(series: TripOperationsSeries, money: boolean): EChartsOption
legend: {
type: 'plain', left: 'center', bottom: 4, width: series.points.length > 5 ? '82%' : '96%',
icon: 'circle', itemWidth: 9, itemHeight: 9, itemGap: 10, selectedMode: false,
textStyle: { color: '#8492a6', fontSize: 12 },
textStyle: { color: chartTheme.colors.muted, fontSize: 12 },
data: series.points.slice(0, 5).map(point => point.label), formatter: legendLabel,
tooltip: { show: true, confine: true },
},
series: [{
name: seriesTitle(series), type: 'pie', radius: 64, center: ['50%', 72],
label: { show: false }, labelLine: { show: false },
itemStyle: { borderColor: '#fff', borderWidth: 2 },
itemStyle: { borderColor: chartTheme.colors.surface, borderWidth: 2 },
emphasis: { scale: false, focus: 'self' },
stillShowZeroSum: false, showEmptyCircle: true,
emptyCircleStyle: { color: '#f3f4f6', borderWidth: 0 },
emptyCircleStyle: { color: chartTheme.colors.primarySoft, borderWidth: 0 },
data: series.points.map((point, index) => ({ name: point.label, value: point.value, itemStyle: { color: color(index) } })),
}],
graphic: hasPositive ? [] : [{ type: 'text', left: 'center', top: 66, style: { text: '暂无正值数据', fill: '#8492a6', fontSize: 12 } }],
graphic: hasPositive ? [] : [{ type: 'text', left: 'center', top: 66, style: { text: '暂无正值数据', fill: chartTheme.colors.muted, fontSize: 12 } }],
}
}
</script>
@@ -95,7 +99,7 @@ function pieOption(series: TripOperationsSeries, money: boolean): EChartsOption
<p v-else class="chart-empty">暂无对应统计</p>
</article>
</section>
<section v-if="detailsVisible && hasPoints" class="chart-details" aria-label="完整统计明细">
<section v-if="detailsVisible && hasPoints" class="chart-details workbench-evidence" aria-label="完整统计明细">
<div class="chart-details-grid">
<section v-for="section in sections" :key="section.key" :aria-label="`${section.title}明细`">
<h3>{{ section.title }}</h3>
@@ -116,13 +120,13 @@ function pieOption(series: TripOperationsSeries, money: boolean): EChartsOption
<style scoped>
.operations-visualizations { display: grid; gap: var(--admin-space-3); min-width: 0; }
.operations-charts, .chart-details-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--admin-space-6); }
.chart { min-width: 0; padding-right: var(--admin-space-6); border-right: 1px solid var(--cc-border); color: var(--cc-text); text-align: center; }
.chart { min-width: 0; padding-right: var(--admin-space-6); border-right: 1px solid var(--workbench-border); color: var(--workbench-text); text-align: center; }
.chart:last-child { padding-right: 0; border-right: 0; }
.chart h3, .chart-details h3 { margin: 0 0 var(--admin-space-2); font-size: var(--admin-font-section); }
.chart-metric { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: center; gap: var(--admin-space-1) var(--admin-space-5); margin-bottom: var(--admin-space-1); font-variant-numeric: tabular-nums; }
.chart-metric > strong { font-size: calc(var(--admin-font-title) * 1.25); overflow-wrap: anywhere; }
.chart-metric small { font-size: var(--admin-font-caption); font-weight: normal; color: var(--cc-muted); }
.chart-note, .chart-empty { margin: 0; font-size: var(--admin-font-caption); color: var(--cc-muted); line-height: 1.6; }
.chart-metric small { font-size: var(--admin-font-caption); font-weight: normal; color: var(--workbench-muted); }
.chart-note, .chart-empty { margin: 0; font-size: var(--admin-font-caption); color: var(--workbench-muted); line-height: 1.6; }
.chart-empty { display: grid; min-height: 136px; place-content: center; }
.series-selector { display: flex; justify-content: center; flex-wrap: wrap; gap: var(--admin-space-2); margin-top: var(--admin-space-2); }
.series-selector :deep(.el-button + .el-button) { margin-left: 0; }
@@ -133,8 +137,8 @@ function pieOption(series: TripOperationsSeries, money: boolean): EChartsOption
.chart-details-grid { margin-top: var(--admin-space-5); }
.chart-details-grid > section { min-width: 0; }
.chart-details table { width: 100%; table-layout: fixed; }
.chart-details caption { text-align: left; padding: var(--admin-space-2) 0; color: var(--cc-muted); font-size: var(--admin-font-caption); }
.chart-details caption { text-align: left; padding: var(--admin-space-2) 0; color: var(--workbench-muted); font-size: var(--admin-font-caption); }
.chart-details td { overflow-wrap: anywhere; }
@media (max-width: 1100px) { .operations-charts, .chart-details-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } .chart:nth-child(2n) { padding-right: 0; border-right: 0; } }
@media (max-width: 720px) { .operations-charts, .chart-details-grid { grid-template-columns: minmax(0, 1fr); } .chart { padding-right: 0; padding-bottom: var(--admin-space-5); border-right: 0; border-bottom: 1px solid var(--cc-border); } .chart:last-child { padding-bottom: 0; border-bottom: 0; } }
@media (max-width: 720px) { .operations-charts, .chart-details-grid { grid-template-columns: minmax(0, 1fr); } .chart { padding-right: 0; padding-bottom: var(--admin-space-5); border-right: 0; border-bottom: 1px solid var(--workbench-border); } .chart:last-child { padding-bottom: 0; border-bottom: 0; } }
</style>