Refactor financial chart implementation

This commit is contained in:
R524809
2026-08-28 16:32:10 +08:00
parent 5ecc554aaa
commit 7aab3d7134
73 changed files with 2340 additions and 594 deletions
+52 -4
View File
@@ -27,6 +27,27 @@ export const PALETTE = {
axisLine: '#d0d0d0',
};
/**
* 试行语义色:柱线组合图中,柱采用低饱和辅助色,折线保留单一强调色。
* 待页面视觉确认后再固化为新增图表的正式规范。
*/
export const FINANCIAL_COLORS = {
operatingCashFlow: '#6E9A83',
investingCashFlow: '#7897B2',
financingCashFlow: '#B18A66',
netCashIncrease: '#A8465C',
netProfit: '#C9885C',
cashConversion: '#6B4A6C',
};
export const CHANNEL_COLORS = {
retail: '#597A9B',
online: '#C87368',
robotStore: '#98A77A',
wholesale: '#BB9A5C',
revenueGrowth: '#775D8B',
};
/** 坐标轴通用样式:只留浅色横向网格,去掉轴线的存在感 */
export const axisCommon = {
axisLine: { show: false },
@@ -104,13 +125,14 @@ export const LAYOUT = {
gridTop: 145, // 绘图区顶部边距(图例到绘图区约 60px)
};
// 统一图例图标宽度,同时保留 ECharts 按系列类型生成的形状。
export const LEGEND_ITEM_WIDTH = 20;
export const legendStyle = {
top: 62, // ⚠️ 已废弃:请改用 LAYOUT.legendTop 或 standardLegend()
itemGap: 26,
itemWidth: 18,
// ❌ 删除 icon: 'roundRect'
// 原因:它会覆盖 ECharts 按系列类型自动生成的图例样式(折线图的"短线+空心圆")
// 现在让每个图表按需设置,或使用 standardLegend() 获得正确默认值
itemWidth: LEGEND_ITEM_WIDTH,
// 不设置 icon:柱状图自动使用矩形,折线图自动使用“短线 + 空心圆”。
textStyle: {
color: PALETTE.ink,
fontSize: 14,
@@ -139,6 +161,7 @@ export function labelStyle(color, position = 'top') {
export function standardLegend(data, options = {}) {
return {
top: LAYOUT.legendTop,
itemWidth: LEGEND_ITEM_WIDTH,
itemGap: options.itemGap ?? 28,
textStyle: {
color: PALETTE.ink,
@@ -176,6 +199,31 @@ export function lineSeries({ name, data, color, labelPosition = 'top', formatter
};
}
/**
* 柱线组合图的折线标签:正值放在点上方、负值放在点下方;
* 若与同期间柱值接近,则加大距离,避免文字压在柱体端点附近。
*/
export function lineDataWithSafeLabels(rows, { lineKey, barKeys, distance = 8, closeDistance = 14 }) {
const values = rows.map((row) => row[lineKey]).filter(Number.isFinite);
const range = Math.max(...values) - Math.min(...values) || 1;
const threshold = range * 0.06;
return rows.map((row) => {
const value = row[lineKey];
const nearestBarGap = Math.min(...barKeys
.map((key) => row[key])
.filter(Number.isFinite)
.map((barValue) => Math.abs(value - barValue)));
return {
value,
label: {
position: value < 0 ? 'bottom' : 'top',
distance: nearestBarGap <= threshold ? closeDistance : distance,
},
};
});
}
/**
* 柱状图系列标准配置
* 强制显示所有标签(overflow: 'none'),避免小柱子标签被 ECharts 自动隐藏