feat(energy): rebuild hydrogen BI board and drill-through
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
kkfluous
2026-08-20 13:59:03 +08:00
parent 37a9f303ec
commit 62efef0ab9
72 changed files with 36773 additions and 965 deletions
@@ -2,12 +2,37 @@ import assert from 'node:assert/strict';
import test from 'node:test';
import type { HydrogenOverviewResponse } from '../api.js';
import {
buildCustomerDrillPayload,
buildMetricDrillPayload,
buildMonthDrillPayload,
buildRegionDrillPayload,
buildStationDrillPayload,
deriveOverviewMetrics,
formatKg,
formatRelative,
formatYuan,
} from './model.js';
const drillKpi = {
yearKg: 10_000,
yearFee: 80_000,
yearRevenue: 75_000,
yearProfit: 15_000,
ourYearKg: 4_000,
ourYearFee: 20_000,
customerYearKg: 6_000,
monthKg: 1_000,
monthFee: 8_000,
monthRevenue: 7_500,
monthProfit: 1_500,
todayKg: 100,
todayFee: 800,
todayRevenue: 750,
todayProfit: 150,
lingniuBornKg: 0,
lingniuBornFee: 0,
};
test('重量和金额单位保持现有阈值及负数格式', () => {
assert.deepEqual(formatKg(999.5), { value: '999.50', unit: 'Kg' });
assert.deepEqual(formatKg(1000), { value: '1.00', unit: 'T' });
@@ -45,7 +70,7 @@ test('总览派生指标保持月份顺序、动能、集中度和收益率口
lingniuBornKg: 0,
lingniuBornFee: 0,
},
top5: [{ rank: 1, name: 'A', kg: 600, fee: 100, share: 0.6 }],
top5: [{ id: 1, rank: 1, name: 'A', kg: 600, fee: 100, share: 0.6 }],
regions: [],
monthly: [
{ month: '2026-01', kg: 100, fee: 20, revenue: 30, profit: 10 },
@@ -53,11 +78,13 @@ test('总览派生指标保持月份顺序、动能、集中度和收益率口
],
customers: [],
stations: [
{ name: 'A', kg: 600, share: 0.6, revenue: 300, revenueShare: 0.6 },
{ name: 'B', kg: 400, share: 0.4, revenue: 200, revenueShare: 0.4 },
{ id: 1, name: 'A', kg: 600, share: 0.6, revenue: 300, revenueShare: 0.6 },
{ id: 2, name: 'B', kg: 400, share: 0.4, revenue: 200, revenueShare: 0.4 },
],
availableYears: [2026],
year: 2026,
latestLedgerTime: '2026-08-17 21:50:09',
filter: { stationId: null, vehicleScope: 'all', verifyScope: 'all' },
} satisfies HydrogenOverviewResponse;
const metrics = deriveOverviewMetrics(data);
@@ -66,7 +93,56 @@ test('总览派生指标保持月份顺序、动能、集中度和收益率口
assert.equal(metrics.latestMonth?.month, '2026-02');
assert.equal(metrics.monthMomentum, 50);
assert.equal(metrics.top5Share, 60);
assert.equal(metrics.profitYield, -10);
assert.equal(metrics.customerGrossMarginPct, -10);
assert.equal(metrics.stationAvgKg, 500);
assert.deepEqual(metrics.monthlyDual.map(item => item.monthLabel), ['1月', '2月']);
});
test('KPI 下钻只使用真实汇总口径且保留客户单毛利语义', () => {
const payload = buildMetricDrillPayload(drillKpi, 'yearProfit');
assert.equal(payload.title, '客户单毛利');
assert.equal(payload.metrics[0]?.label, '客户单毛利');
assert.equal(payload.metrics[0]?.value, '¥1.5 万元');
assert.equal(payload.rows.length, 0);
assert.match(payload.emptyMessage ?? '', /未返回站点、客户、车牌及单笔订单层级/);
});
test('月度下钻按接口返回的羚牛与外部车辆加氢量拆分', () => {
const payload = buildMonthDrillPayload({
month: '2026-08',
kg: 1_000,
lingniuKg: 700,
externalKg: 300,
fee: 4_500,
revenue: 5_000,
profit: 500,
});
assert.equal(payload.rows[0]?.category, '羚牛车辆');
assert.equal(payload.rows[0]?.share, '70.0%');
assert.equal(payload.rows[1]?.share, '30.0%');
assert.equal(payload.metrics[3]?.label, '客户单毛利');
});
test('省级区域下钻仅关联同省真实站点,市级缺少映射时明确空态', () => {
const stations = [
{ id: 1, name: '嘉兴站', province: '浙江', kg: 600, revenue: 1_000, share: 0.6, revenueShare: 0.5 },
{ id: 2, name: '广州站', province: '广东', kg: 400, revenue: 1_000, share: 0.4, revenueShare: 0.5 },
];
const provincePayload = buildRegionDrillPayload({ region: '浙江', kg: 600, share: 0.6 }, stations, 'province');
assert.equal(provincePayload.rows.length, 1);
assert.equal(provincePayload.rows[0]?.station, '嘉兴站');
const cityPayload = buildRegionDrillPayload({ region: '嘉兴', kg: 600, share: 0.6 }, stations, 'city');
assert.equal(cityPayload.rows.length, 0);
assert.match(cityPayload.emptyMessage ?? '', /未返回城市字段/);
});
test('站点与客户弹层提供汇总指标及真实事件入口', () => {
const stationPayload = buildStationDrillPayload({ id: 9, name: '测试站', province: '广东', kg: 900, revenue: 3_000, share: 0.3, revenueShare: 0.4 });
assert.equal(stationPayload.primaryActionLabel, '进入单站视图');
assert.equal(stationPayload.metrics[0]?.value, '900.00 Kg');
const customerPayload = buildCustomerDrillPayload({ name: '测试客户', payer: 'customer', kg: 500, cost: 2_000, revenue: 2_500 });
assert.equal(customerPayload.metrics[3]?.label, '价差');
assert.equal(customerPayload.metrics[3]?.value, '¥500 元');
});