refactor(stage3): 下线 5 个无调用方的 legacy 氢能接口
先确认调用方再删:/hydrogen/station-board 被单站日报页面(StationDailyApp / StationDailyDetailView)实际使用,必须保留;其余 5 个确认零调用方。 - 删服务端路由 hydrogen-overview / -overview-detail / -daily / -daily-detail / -settlement(约 1,080 行),energy/index.ts 保留原有注册顺序语义。 - 删客户端对应请求函数与类型:api.ts 由 202 行精简为 74 行; types.ts 由 291 行精简为 112 行(只保留 StationBoard / Electric / ETC 闭包)。 - 顺带修正命名:HydrogenDailyQuery -> EnergyRangeQuery(它服务于电能按月接口)。 - routes.test.ts 同步收敛:删除 settlement / overview 两个已下线接口的测试, '四个处理器' 改为只覆盖电能;路由顺序断言更新为现存 9 条。 电能 SQL 指纹沿用原值,证明取数口径未变。 测试 131 -> 128(删掉的 3 个用例覆盖的是已下线接口)。lint / test / build 全绿。
This commit is contained in:
@@ -12,18 +12,6 @@ import {
|
||||
registerEtcOverviewRoute,
|
||||
type EtcOverviewDependencies,
|
||||
} from "./etc.js";
|
||||
import {
|
||||
registerHydrogenDailyRoute,
|
||||
type HydrogenDailyDependencies,
|
||||
} from "./hydrogen-daily.js";
|
||||
import {
|
||||
registerHydrogenOverviewRoute,
|
||||
type HydrogenOverviewDependencies,
|
||||
} from "./hydrogen-overview.js";
|
||||
import {
|
||||
registerHydrogenSettlementRoute,
|
||||
type HydrogenSettlementDependencies,
|
||||
} from "./hydrogen-settlement.js";
|
||||
import {
|
||||
registerHydrogenStationBoardRoute,
|
||||
type HydrogenStationBoardDependencies,
|
||||
@@ -90,11 +78,6 @@ test("能源路由按既有顺序注册并增加只读单站看板接口", () =>
|
||||
.filter((route) => route.method === "GET")
|
||||
.map((route) => route.path),
|
||||
[
|
||||
"/hydrogen/overview",
|
||||
"/hydrogen/overview-detail",
|
||||
"/hydrogen/daily",
|
||||
"/hydrogen/daily-detail",
|
||||
"/hydrogen/settlement",
|
||||
"/hydrogen/station-board",
|
||||
"/h2/v2/meta",
|
||||
"/h2/v2/overview",
|
||||
@@ -704,117 +687,10 @@ test("单站外部客户按唯一标准化车牌聚合,进账保持租户客
|
||||
assert.match(calls[9].sql, /refuel_time < DATE_ADD\(\?, INTERVAL 1 DAY\)/);
|
||||
});
|
||||
|
||||
test("站日现结台账仅读取付款流水,并按最近有数据的 15 天聚合", async () => {
|
||||
const calls: QueryCall[] = [];
|
||||
const cacheCalls: CacheCall[] = [];
|
||||
const app = new Hono();
|
||||
registerHydrogenSettlementRoute(app, {
|
||||
hydrogenPool: {
|
||||
query: createQueryMock(
|
||||
[
|
||||
[{ latestPaymentDate: "2026-05-26" }],
|
||||
[
|
||||
{
|
||||
date: "2026-05-26",
|
||||
stationId: 44,
|
||||
stationName: "联新加氢站",
|
||||
amount: 30000,
|
||||
paymentCount: 1,
|
||||
matchMode: "exact",
|
||||
},
|
||||
{
|
||||
date: "2026-05-25",
|
||||
stationId: null,
|
||||
stationName: "佛山中石化",
|
||||
amount: 20000,
|
||||
paymentCount: 2,
|
||||
matchMode: "group",
|
||||
},
|
||||
],
|
||||
],
|
||||
calls,
|
||||
),
|
||||
},
|
||||
cached: createCachedMock(cacheCalls),
|
||||
} as unknown as HydrogenSettlementDependencies);
|
||||
|
||||
const response = await app.request(
|
||||
"/hydrogen/settlement?range=latest&force=1",
|
||||
);
|
||||
assert.equal(response.status, 200);
|
||||
assert.deepEqual(await response.json(), {
|
||||
range: { start: "2026-05-12", end: "2026-05-26", mode: "latest" },
|
||||
summary: {
|
||||
amount: 50000,
|
||||
paymentCount: 3,
|
||||
stationDayCount: 2,
|
||||
stationCount: 2,
|
||||
latestPaymentDate: "2026-05-26",
|
||||
},
|
||||
rows: [
|
||||
{
|
||||
date: "2026-05-26",
|
||||
stationId: 44,
|
||||
stationName: "联新加氢站",
|
||||
amount: 30000,
|
||||
paymentCount: 1,
|
||||
matchMode: "exact",
|
||||
},
|
||||
{
|
||||
date: "2026-05-25",
|
||||
stationId: null,
|
||||
stationName: "佛山中石化",
|
||||
amount: 20000,
|
||||
paymentCount: 2,
|
||||
matchMode: "group",
|
||||
},
|
||||
],
|
||||
});
|
||||
assert.deepEqual(cacheCalls, [
|
||||
{ key: "hydrogen/settlement?start=2026-05-12&end=2026-05-26", force: true },
|
||||
]);
|
||||
assert.equal(calls.length, 2);
|
||||
assert.match(calls[0].sql, /MAX\(payment_date\)/);
|
||||
assert.match(calls[1].sql, /FROM hydrogen_station_payment p/);
|
||||
assert.match(calls[1].sql, /LIMIT 500/);
|
||||
assert.deepEqual(calls[1].params, ["2026-05-12", "2026-05-26"]);
|
||||
});
|
||||
|
||||
test("四个处理器继续使用原缓存语义、数据库、SQL 与参数", async () => {
|
||||
const hydrogenCalls: QueryCall[] = [];
|
||||
test("电能处理器继续使用原缓存语义、数据库、SQL 与参数", async () => {
|
||||
const electricCalls: QueryCall[] = [];
|
||||
const cacheCalls: CacheCall[] = [];
|
||||
const cached = createCachedMock(cacheCalls);
|
||||
const hydrogenQuery = createQueryMock(
|
||||
[
|
||||
[{ y: 2025, latestLedgerTime: "2025-01-02 10:30:00" }],
|
||||
[{}],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
{
|
||||
name: "混合承担客户",
|
||||
payer: "mixed",
|
||||
kg: 10,
|
||||
cost: 350,
|
||||
revenue: 360,
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
d: "2025-01-02",
|
||||
stationId: 7,
|
||||
stationName: "测试站",
|
||||
kg: 10,
|
||||
fee: 350,
|
||||
pricePerKg: 35,
|
||||
},
|
||||
],
|
||||
],
|
||||
hydrogenCalls,
|
||||
);
|
||||
const electricQuery = createQueryMock(
|
||||
[
|
||||
[
|
||||
@@ -835,65 +711,6 @@ test("四个处理器继续使用原缓存语义、数据库、SQL 与参数", a
|
||||
electricCalls,
|
||||
);
|
||||
|
||||
const hydrogenOverviewApp = new Hono();
|
||||
registerHydrogenOverviewRoute(hydrogenOverviewApp, {
|
||||
hydrogenPool: { query: hydrogenQuery },
|
||||
cached,
|
||||
} as unknown as HydrogenOverviewDependencies);
|
||||
const overviewResponse = await hydrogenOverviewApp.request(
|
||||
"/hydrogen/overview?year=2025&force=1",
|
||||
);
|
||||
assert.equal(overviewResponse.status, 200);
|
||||
const overviewPayload = (await overviewResponse.json()) as {
|
||||
customers: { payer: string; name: string }[];
|
||||
};
|
||||
assert.deepEqual(overviewPayload.customers, [
|
||||
{
|
||||
name: "混合承担客户",
|
||||
payer: "mixed",
|
||||
kg: 10,
|
||||
cost: 350,
|
||||
revenue: 360,
|
||||
},
|
||||
]);
|
||||
|
||||
const hydrogenDailyApp = new Hono();
|
||||
registerHydrogenDailyRoute(hydrogenDailyApp, {
|
||||
hydrogenPool: { query: hydrogenQuery },
|
||||
cached,
|
||||
} as unknown as HydrogenDailyDependencies);
|
||||
const dailyResponse = await hydrogenDailyApp.request(
|
||||
"/hydrogen/daily?startDate=2025-01-01&endDate=2025-01-02&customer=external&force=1",
|
||||
);
|
||||
assert.equal(dailyResponse.status, 200);
|
||||
assert.deepEqual(await dailyResponse.json(), [
|
||||
{
|
||||
date: "2025-01-02",
|
||||
totalKg: 10,
|
||||
totalFee: 350,
|
||||
chainPct: 0,
|
||||
customerType: "external",
|
||||
stations: [
|
||||
{
|
||||
id: 7,
|
||||
name: "测试站",
|
||||
pricePerKg: 35,
|
||||
kg: 10,
|
||||
fee: 350,
|
||||
chainPct: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
date: "2025-01-01",
|
||||
totalKg: 0,
|
||||
totalFee: 0,
|
||||
chainPct: 0,
|
||||
customerType: "external",
|
||||
stations: [],
|
||||
},
|
||||
]);
|
||||
|
||||
const electricApp = new Hono();
|
||||
const electricDependencies = {
|
||||
pool: { query: electricQuery },
|
||||
@@ -911,11 +728,6 @@ test("四个处理器继续使用原缓存语义、数据库、SQL 与参数", a
|
||||
assert.equal(electricMonthlyResponse.status, 200);
|
||||
|
||||
assert.deepEqual(cacheCalls, [
|
||||
{ key: "hydrogen/overview?year=2025", force: true },
|
||||
{
|
||||
key: "hydrogen/daily?start=2025-01-01&end=2025-01-02&customer=external",
|
||||
force: true,
|
||||
},
|
||||
{ key: "electric/overview", force: true },
|
||||
{
|
||||
key: "electric/monthly?customer=external&start=2025-01-01&end=2025-01-02",
|
||||
@@ -923,18 +735,10 @@ test("四个处理器继续使用原缓存语义、数据库、SQL 与参数", a
|
||||
},
|
||||
]);
|
||||
|
||||
// 指纹覆盖加氢事实专用过滤与既有查询结构,避免手工充值重新混入统计。
|
||||
// 指纹锁定既有查询结构,避免取数口径被无意改动。
|
||||
assert.deepEqual(
|
||||
[...hydrogenCalls, ...electricCalls].map((call) => sqlHash(call.sql)),
|
||||
electricCalls.map((call) => sqlHash(call.sql)),
|
||||
[
|
||||
"4fa77c56a990",
|
||||
"ac6329507bc2",
|
||||
"e46a92ba851e",
|
||||
"0295b2deee31",
|
||||
"852b5b0b9fe1",
|
||||
"abad6dcf0b2f",
|
||||
"41cc73632c26",
|
||||
"1224ee38f710",
|
||||
"03fd669f8077",
|
||||
"6e4031b10926",
|
||||
"4fc77463294c",
|
||||
@@ -943,103 +747,12 @@ test("四个处理器继续使用原缓存语义、数据库、SQL 与参数", a
|
||||
],
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
hydrogenCalls.map((call) => call.params),
|
||||
[
|
||||
["2024-01-01"],
|
||||
[
|
||||
2025,
|
||||
2025,
|
||||
2025,
|
||||
2025,
|
||||
2025,
|
||||
2025,
|
||||
2025,
|
||||
2025,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
"2024-01-01",
|
||||
],
|
||||
["2024-01-01", 2025],
|
||||
["2024-01-01", 2025],
|
||||
["2024-01-01", 2025],
|
||||
["2024-01-01", 2025],
|
||||
["2024-01-01", 2025],
|
||||
["2025-01-01", "2025-01-02"],
|
||||
],
|
||||
);
|
||||
assert.match(hydrogenCalls[7].sql, /b\.vehicle_id IS NULL/);
|
||||
assert.ok(hydrogenCalls.every((call) =>
|
||||
call.sql.includes("external_recharge_manual"),
|
||||
));
|
||||
assert.deepEqual(
|
||||
electricCalls.map((call) => call.params),
|
||||
[undefined, undefined, undefined, undefined, ["2025-01-01", "2025-01-02"]],
|
||||
);
|
||||
});
|
||||
|
||||
test("氢能总览按车辆归属和单站筛选,并隔离缓存结果", async () => {
|
||||
const calls: QueryCall[] = [];
|
||||
const cacheCalls: CacheCall[] = [];
|
||||
const app = new Hono();
|
||||
registerHydrogenOverviewRoute(app, {
|
||||
hydrogenPool: {
|
||||
query: createQueryMock(
|
||||
[
|
||||
[{ y: 2026, latestLedgerTime: "2026-08-17 21:50:09" }],
|
||||
[{ yearKg: 12, latestLedgerTime: "2026-08-17 21:50:09" }],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
],
|
||||
calls,
|
||||
),
|
||||
},
|
||||
cached: createCachedMock(cacheCalls),
|
||||
} as unknown as HydrogenOverviewDependencies);
|
||||
|
||||
const response = await app.request(
|
||||
"/hydrogen/overview?year=2026&stationId=7&vehicleScope=lingniu",
|
||||
);
|
||||
const payload = await response.json();
|
||||
|
||||
assert.equal(response.status, 200);
|
||||
assert.equal(payload.latestLedgerTime, "2026-08-17 21:50:09");
|
||||
assert.deepEqual(cacheCalls, [
|
||||
{
|
||||
key: "hydrogen/overview?year=2026&station=7&vehicle=lingniu",
|
||||
force: false,
|
||||
},
|
||||
]);
|
||||
assert.deepEqual(payload.filter, {
|
||||
stationId: 7,
|
||||
vehicleScope: "lingniu",
|
||||
verifyScope: "all",
|
||||
});
|
||||
// 年份候选项是全局元数据;其余查询都必须带上单站筛选参数。
|
||||
assert.ok(
|
||||
calls
|
||||
.slice(1)
|
||||
.every(
|
||||
(call) =>
|
||||
Array.isArray(call.params) && (call.params as unknown[]).includes(7),
|
||||
),
|
||||
);
|
||||
assert.match(calls[1].sql, /station_id = \? AND vehicle_id IS NOT NULL/);
|
||||
assert.match(
|
||||
calls[2].sql,
|
||||
/b\.station_id = \? AND b\.vehicle_id IS NOT NULL/,
|
||||
);
|
||||
});
|
||||
|
||||
test("ETC 总览对空台账返回明确空状态", async () => {
|
||||
const calls: QueryCall[] = [];
|
||||
const cacheCalls: CacheCall[] = [];
|
||||
|
||||
Reference in New Issue
Block a user