|
@@ -61,6 +61,8 @@ const trendChartRef = ref<HTMLDivElement>()
|
|
|
let distributionChart: echarts.ECharts | null = null
|
|
let distributionChart: echarts.ECharts | null = null
|
|
|
let trendChart: echarts.ECharts | null = null
|
|
let trendChart: echarts.ECharts | null = null
|
|
|
let distributionResizeObserver: ResizeObserver | null = null
|
|
let distributionResizeObserver: ResizeObserver | null = null
|
|
|
|
|
+let trendResizeObserver: ResizeObserver | null = null
|
|
|
|
|
+let trendResizeFrame: number | null = null
|
|
|
|
|
|
|
|
const panelOptions: Array<{ label: string; value: ActivePanel }> = [
|
|
const panelOptions: Array<{ label: string; value: ActivePanel }> = [
|
|
|
{ label: '存货分布', value: 'distribution' },
|
|
{ label: '存货分布', value: 'distribution' },
|
|
@@ -140,8 +142,9 @@ function getChartLayout(chartRef: Ref<HTMLDivElement | undefined>) {
|
|
|
distributionLegendItemSize: compact ? 9 : 13,
|
|
distributionLegendItemSize: compact ? 9 : 13,
|
|
|
distributionLegendGap: compact ? 4 : 10,
|
|
distributionLegendGap: compact ? 4 : 10,
|
|
|
distributionLegendFontSize: compact ? 10 : 14,
|
|
distributionLegendFontSize: compact ? 10 : 14,
|
|
|
- trendGridTop: compact ? 10 : 32,
|
|
|
|
|
- trendGridRight: compact ? 12 : THEME.grid.right,
|
|
|
|
|
|
|
+ trendGridTop: compact ? 24 : 48,
|
|
|
|
|
+ trendGridLeft: compact ? 34 : 48,
|
|
|
|
|
+ trendGridRight: compact ? 34 : 48,
|
|
|
trendGridBottom: compact ? 2 : THEME.grid.bottom,
|
|
trendGridBottom: compact ? 2 : THEME.grid.bottom,
|
|
|
legendTop: compact ? 0 : 4,
|
|
legendTop: compact ? 0 : 4,
|
|
|
legendRight: compact ? 2 : 6,
|
|
legendRight: compact ? 2 : 6,
|
|
@@ -155,7 +158,9 @@ function getChartLayout(chartRef: Ref<HTMLDivElement | undefined>) {
|
|
|
barGap: compact ? '12%' : '5%',
|
|
barGap: compact ? '12%' : '5%',
|
|
|
barCategoryGap: compact ? '46%' : '36%',
|
|
barCategoryGap: compact ? '46%' : '36%',
|
|
|
labelDistance: compact ? 4 : 7,
|
|
labelDistance: compact ? 4 : 7,
|
|
|
- labelFontSize: compact ? 10 : 12
|
|
|
|
|
|
|
+ distributionLabelFontSize: compact ? 6 : 8,
|
|
|
|
|
+ trendLabelFontSize: compact ? 10 : 12,
|
|
|
|
|
+ trendLabelDistance: compact ? 4 : 8
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -238,37 +243,8 @@ function getDistributionOption(
|
|
|
fontFamily: FONT_FAMILY
|
|
fontFamily: FONT_FAMILY
|
|
|
}
|
|
}
|
|
|
}),
|
|
}),
|
|
|
- graphic: [
|
|
|
|
|
- {
|
|
|
|
|
- type: 'text',
|
|
|
|
|
- left: '19.5%',
|
|
|
|
|
- top: '45%',
|
|
|
|
|
- style: {
|
|
|
|
|
- text: `总库存\n${formatAmount(inventoryTotal)}万元`,
|
|
|
|
|
- textAlign: 'center',
|
|
|
|
|
- fill: THEME.text.strong,
|
|
|
|
|
- fontSize: layout.compact ? 8 : 10,
|
|
|
|
|
- fontWeight: 700,
|
|
|
|
|
- lineHeight: layout.distributionTitleLineHeight + 6,
|
|
|
|
|
- fontFamily: FONT_FAMILY
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- type: 'text',
|
|
|
|
|
- left: '67%',
|
|
|
|
|
- top: '45%',
|
|
|
|
|
- style: {
|
|
|
|
|
- text: `总积压\n${formatAmount(backlogTotal)}万元`,
|
|
|
|
|
- textAlign: 'center',
|
|
|
|
|
- fill: THEME.text.strong,
|
|
|
|
|
- fontSize: layout.compact ? 8 : 10,
|
|
|
|
|
- fontWeight: 700,
|
|
|
|
|
- lineHeight: layout.distributionTitleLineHeight + 6,
|
|
|
|
|
- fontFamily: FONT_FAMILY
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- ],
|
|
|
|
|
series: [
|
|
series: [
|
|
|
|
|
+ // ===== 第一个饼图:库存数据(带外标签) =====
|
|
|
{
|
|
{
|
|
|
name: '库存',
|
|
name: '库存',
|
|
|
type: 'pie',
|
|
type: 'pie',
|
|
@@ -283,17 +259,14 @@ function getDistributionOption(
|
|
|
bleedMargin: 0,
|
|
bleedMargin: 0,
|
|
|
formatter: '{b}\n{d}%',
|
|
formatter: '{b}\n{d}%',
|
|
|
color: 'inherit',
|
|
color: 'inherit',
|
|
|
- fontSize: layout.labelFontSize,
|
|
|
|
|
|
|
+ fontSize: layout.distributionLabelFontSize,
|
|
|
fontWeight: 500,
|
|
fontWeight: 500,
|
|
|
fontFamily: FONT_FAMILY
|
|
fontFamily: FONT_FAMILY
|
|
|
},
|
|
},
|
|
|
labelLine: {
|
|
labelLine: {
|
|
|
show: true,
|
|
show: true,
|
|
|
- // length: layout.compact ? 6 : 10,
|
|
|
|
|
- // length2: layout.compact ? 8 : 14,
|
|
|
|
|
minTurnAngle: 90,
|
|
minTurnAngle: 90,
|
|
|
lineStyle: {
|
|
lineStyle: {
|
|
|
- color: distributionColors[0],
|
|
|
|
|
width: 1.5,
|
|
width: 1.5,
|
|
|
opacity: 1
|
|
opacity: 1
|
|
|
}
|
|
}
|
|
@@ -320,6 +293,34 @@ function getDistributionOption(
|
|
|
}
|
|
}
|
|
|
}))
|
|
}))
|
|
|
},
|
|
},
|
|
|
|
|
+ // ===== 第二个饼图:库存中心文字(不显示饼图) =====
|
|
|
|
|
+ {
|
|
|
|
|
+ name: '库存中心文字',
|
|
|
|
|
+ type: 'pie',
|
|
|
|
|
+ radius: ['0%', '0%'],
|
|
|
|
|
+ center: ['25%', layout.distributionPieCenterY],
|
|
|
|
|
+ label: {
|
|
|
|
|
+ show: true,
|
|
|
|
|
+ position: 'center',
|
|
|
|
|
+ formatter: `总库存\n${formatAmount(inventoryTotal)}万元`,
|
|
|
|
|
+ color: THEME.text.strong,
|
|
|
|
|
+ fontSize: layout.compact ? 8 : 10,
|
|
|
|
|
+ fontWeight: 700,
|
|
|
|
|
+ lineHeight: layout.distributionTitleLineHeight + 6,
|
|
|
|
|
+ fontFamily: FONT_FAMILY
|
|
|
|
|
+ },
|
|
|
|
|
+ data: [{ name: '中心文字', value: 1 }],
|
|
|
|
|
+ animation: false,
|
|
|
|
|
+ tooltip: { show: false },
|
|
|
|
|
+ legend: { show: false },
|
|
|
|
|
+ // ✅ 关键:禁用所有交互
|
|
|
|
|
+ silent: true,
|
|
|
|
|
+ emphasis: {
|
|
|
|
|
+ scale: false,
|
|
|
|
|
+ label: { show: false }
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ // ===== 第三个饼图:积压数据(带外标签) =====
|
|
|
{
|
|
{
|
|
|
name: '积压库存',
|
|
name: '积压库存',
|
|
|
type: 'pie',
|
|
type: 'pie',
|
|
@@ -334,17 +335,14 @@ function getDistributionOption(
|
|
|
bleedMargin: 0,
|
|
bleedMargin: 0,
|
|
|
formatter: '{b}\n{d}%',
|
|
formatter: '{b}\n{d}%',
|
|
|
color: 'inherit',
|
|
color: 'inherit',
|
|
|
- fontSize: layout.labelFontSize,
|
|
|
|
|
|
|
+ fontSize: layout.distributionLabelFontSize,
|
|
|
fontWeight: 500,
|
|
fontWeight: 500,
|
|
|
fontFamily: FONT_FAMILY
|
|
fontFamily: FONT_FAMILY
|
|
|
},
|
|
},
|
|
|
labelLine: {
|
|
labelLine: {
|
|
|
show: true,
|
|
show: true,
|
|
|
- // length: layout.compact ? 6 : 10,
|
|
|
|
|
- // length2: layout.compact ? 8 : 14,
|
|
|
|
|
minTurnAngle: 90,
|
|
minTurnAngle: 90,
|
|
|
lineStyle: {
|
|
lineStyle: {
|
|
|
- color: distributionColors[0],
|
|
|
|
|
width: 1.5,
|
|
width: 1.5,
|
|
|
opacity: 1
|
|
opacity: 1
|
|
|
}
|
|
}
|
|
@@ -372,6 +370,33 @@ function getDistributionOption(
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}))
|
|
}))
|
|
|
|
|
+ },
|
|
|
|
|
+ // ===== 第四个饼图:积压中心文字(不显示饼图) =====
|
|
|
|
|
+ {
|
|
|
|
|
+ name: '积压中心文字',
|
|
|
|
|
+ type: 'pie',
|
|
|
|
|
+ radius: ['0%', '0%'],
|
|
|
|
|
+ center: ['73%', layout.distributionPieCenterY],
|
|
|
|
|
+ label: {
|
|
|
|
|
+ show: true,
|
|
|
|
|
+ position: 'center',
|
|
|
|
|
+ formatter: `总积压\n${formatAmount(backlogTotal)}万元`,
|
|
|
|
|
+ color: THEME.text.strong,
|
|
|
|
|
+ fontSize: layout.compact ? 8 : 10,
|
|
|
|
|
+ fontWeight: 700,
|
|
|
|
|
+ lineHeight: layout.distributionTitleLineHeight + 6,
|
|
|
|
|
+ fontFamily: FONT_FAMILY
|
|
|
|
|
+ },
|
|
|
|
|
+ data: [{ name: '中心文字', value: 1 }],
|
|
|
|
|
+ animation: false,
|
|
|
|
|
+ tooltip: { show: false },
|
|
|
|
|
+ legend: { show: false },
|
|
|
|
|
+ // ✅ 关键:禁用所有交互
|
|
|
|
|
+ silent: true,
|
|
|
|
|
+ emphasis: {
|
|
|
|
|
+ scale: false,
|
|
|
|
|
+ label: { show: false }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
]
|
|
]
|
|
|
}
|
|
}
|
|
@@ -422,6 +447,7 @@ function getInventoryAgingOption(data: unknown): echarts.EChartsOption {
|
|
|
animation: false,
|
|
animation: false,
|
|
|
grid: {
|
|
grid: {
|
|
|
...THEME.grid,
|
|
...THEME.grid,
|
|
|
|
|
+ left: layout.trendGridLeft,
|
|
|
top: layout.trendGridTop,
|
|
top: layout.trendGridTop,
|
|
|
right: layout.trendGridRight,
|
|
right: layout.trendGridRight,
|
|
|
bottom: layout.trendGridBottom
|
|
bottom: layout.trendGridBottom
|
|
@@ -434,7 +460,7 @@ function getInventoryAgingOption(data: unknown): echarts.EChartsOption {
|
|
|
}),
|
|
}),
|
|
|
xAxis: {
|
|
xAxis: {
|
|
|
type: 'category',
|
|
type: 'category',
|
|
|
- boundaryGap: false,
|
|
|
|
|
|
|
+ boundaryGap: true,
|
|
|
data: months,
|
|
data: months,
|
|
|
axisTick: { show: false },
|
|
axisTick: { show: false },
|
|
|
axisLabel: {
|
|
axisLabel: {
|
|
@@ -445,7 +471,7 @@ function getInventoryAgingOption(data: unknown): echarts.EChartsOption {
|
|
|
},
|
|
},
|
|
|
yAxis: {
|
|
yAxis: {
|
|
|
type: 'value',
|
|
type: 'value',
|
|
|
- name: '万元',
|
|
|
|
|
|
|
+ // name: '万元',
|
|
|
min: 0,
|
|
min: 0,
|
|
|
axisTick: { show: false },
|
|
axisTick: { show: false },
|
|
|
axisLabel: {
|
|
axisLabel: {
|
|
@@ -486,12 +512,18 @@ function getInventoryAgingOption(data: unknown): echarts.EChartsOption {
|
|
|
},
|
|
},
|
|
|
label: {
|
|
label: {
|
|
|
show: true,
|
|
show: true,
|
|
|
|
|
+ position: 'top',
|
|
|
|
|
+ distance: layout.trendLabelDistance,
|
|
|
color: THEME.color.orange.line,
|
|
color: THEME.color.orange.line,
|
|
|
- fontSize: layout.labelFontSize,
|
|
|
|
|
|
|
+ fontSize: layout.trendLabelFontSize,
|
|
|
fontFamily: FONT_FAMILY,
|
|
fontFamily: FONT_FAMILY,
|
|
|
formatter(params: any) {
|
|
formatter(params: any) {
|
|
|
return `${formatAmount(Number(params.value))}万`
|
|
return `${formatAmount(Number(params.value))}万`
|
|
|
}
|
|
}
|
|
|
|
|
+ },
|
|
|
|
|
+ labelLayout: {
|
|
|
|
|
+ hideOverlap: false,
|
|
|
|
|
+ moveOverlap: 'shiftY'
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
]
|
|
]
|
|
@@ -529,7 +561,7 @@ function initTrendChart() {
|
|
|
|
|
|
|
|
function resizeCharts() {
|
|
function resizeCharts() {
|
|
|
distributionChart?.resize()
|
|
distributionChart?.resize()
|
|
|
- trendChart?.resize()
|
|
|
|
|
|
|
+ scheduleTrendResize()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function handleDistributionResize() {
|
|
function handleDistributionResize() {
|
|
@@ -539,6 +571,19 @@ function handleDistributionResize() {
|
|
|
renderDistributionChart()
|
|
renderDistributionChart()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+function scheduleTrendResize() {
|
|
|
|
|
+ if (trendResizeFrame !== null) return
|
|
|
|
|
+
|
|
|
|
|
+ trendResizeFrame = requestAnimationFrame(() => {
|
|
|
|
|
+ trendResizeFrame = null
|
|
|
|
|
+ if (activePanel.value !== 'trend' || !trendChartRef.value) return
|
|
|
|
|
+
|
|
|
|
|
+ if (!trendChart) initTrendChart()
|
|
|
|
|
+ trendChart?.resize()
|
|
|
|
|
+ renderTrendChart()
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
function destroyCharts() {
|
|
function destroyCharts() {
|
|
|
distributionChart?.dispose()
|
|
distributionChart?.dispose()
|
|
|
trendChart?.dispose()
|
|
trendChart?.dispose()
|
|
@@ -632,6 +677,8 @@ onMounted(() => {
|
|
|
initDistributionChart()
|
|
initDistributionChart()
|
|
|
distributionResizeObserver = new ResizeObserver(handleDistributionResize)
|
|
distributionResizeObserver = new ResizeObserver(handleDistributionResize)
|
|
|
distributionResizeObserver.observe(distributionChartRef.value!)
|
|
distributionResizeObserver.observe(distributionChartRef.value!)
|
|
|
|
|
+ trendResizeObserver = new ResizeObserver(scheduleTrendResize)
|
|
|
|
|
+ trendResizeObserver.observe(trendChartRef.value!)
|
|
|
})
|
|
})
|
|
|
})
|
|
})
|
|
|
window.addEventListener('resize', resizeCharts)
|
|
window.addEventListener('resize', resizeCharts)
|
|
@@ -659,6 +706,12 @@ onUnmounted(() => {
|
|
|
window.removeEventListener('rhkb:resize', resizeCharts)
|
|
window.removeEventListener('rhkb:resize', resizeCharts)
|
|
|
distributionResizeObserver?.disconnect()
|
|
distributionResizeObserver?.disconnect()
|
|
|
distributionResizeObserver = null
|
|
distributionResizeObserver = null
|
|
|
|
|
+ trendResizeObserver?.disconnect()
|
|
|
|
|
+ trendResizeObserver = null
|
|
|
|
|
+ if (trendResizeFrame !== null) {
|
|
|
|
|
+ cancelAnimationFrame(trendResizeFrame)
|
|
|
|
|
+ trendResizeFrame = null
|
|
|
|
|
+ }
|
|
|
destroyCharts()
|
|
destroyCharts()
|
|
|
})
|
|
})
|
|
|
</script>
|
|
</script>
|