refactor: modularize application domains
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import type { HydrogenOverviewResponse } from '../api.js';
|
||||
import {
|
||||
deriveOverviewMetrics,
|
||||
formatKg,
|
||||
formatRelative,
|
||||
formatYuan,
|
||||
} from './model.js';
|
||||
|
||||
test('重量和金额单位保持现有阈值及负数格式', () => {
|
||||
assert.deepEqual(formatKg(999.5), { value: '999.50', unit: 'Kg' });
|
||||
assert.deepEqual(formatKg(1000), { value: '1.00', unit: 'T' });
|
||||
assert.deepEqual(formatYuan(9999), { value: '9,999', unit: '元' });
|
||||
assert.deepEqual(formatYuan(12345), { value: '1.23', unit: '万元' });
|
||||
assert.deepEqual(formatYuan(-100_000_000), { value: '-1.00', unit: '亿元' });
|
||||
});
|
||||
|
||||
test('相对更新时间保持秒、分钟、小时和未来时间边界', () => {
|
||||
const now = new Date(2026, 7, 13, 12, 0, 0).getTime();
|
||||
assert.equal(formatRelative(now + 60_000, now), '刚刚');
|
||||
assert.equal(formatRelative(now - 30_000, now), '30 秒前');
|
||||
assert.equal(formatRelative(now - 5 * 60_000, now), '5 分钟前');
|
||||
assert.equal(formatRelative(now - 3 * 60 * 60_000, now), '3 小时前');
|
||||
});
|
||||
|
||||
test('总览派生指标保持月份顺序、动能、集中度和收益率口径', () => {
|
||||
const data = {
|
||||
kpi: {
|
||||
yearKg: 1000,
|
||||
yearFee: 0,
|
||||
yearProfit: -50,
|
||||
ourYearKg: 0,
|
||||
customerYearKg: 0,
|
||||
ourYearFee: 0,
|
||||
yearRevenue: 500,
|
||||
monthKg: 0,
|
||||
monthFee: 0,
|
||||
monthRevenue: 0,
|
||||
monthProfit: 0,
|
||||
todayKg: 0,
|
||||
todayFee: 0,
|
||||
todayRevenue: 0,
|
||||
todayProfit: 0,
|
||||
lingniuBornKg: 0,
|
||||
lingniuBornFee: 0,
|
||||
},
|
||||
top5: [{ rank: 1, name: 'A', kg: 600, fee: 100, share: 0.6 }],
|
||||
regions: [],
|
||||
monthly: [
|
||||
{ month: '2026-01', kg: 100, fee: 20, revenue: 30, profit: 10 },
|
||||
{ month: '2026-02', kg: 150, fee: 30, revenue: 40, profit: 10 },
|
||||
],
|
||||
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 },
|
||||
],
|
||||
availableYears: [2026],
|
||||
year: 2026,
|
||||
} satisfies HydrogenOverviewResponse;
|
||||
|
||||
const metrics = deriveOverviewMetrics(data);
|
||||
assert.equal(metrics.monthAvgKg, 125);
|
||||
assert.equal(metrics.bestMonth?.month, '2026-02');
|
||||
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.stationAvgKg, 500);
|
||||
assert.deepEqual(metrics.monthlyDual.map(item => item.monthLabel), ['1月', '2月']);
|
||||
});
|
||||
Reference in New Issue
Block a user