From 7dd7e676022e613aedfe1d619578ac7aae8ba271 Mon Sep 17 00:00:00 2001 From: shishengliang Date: Tue, 29 Sep 2026 10:03:45 +0800 Subject: [PATCH] fix(energy): connect Foshan external vehicle hydrogen orders --- src/modules/energy/HydrogenDaily.tsx | 36 ++++---------------- src/server/routes/energy/hydrogen-daily.ts | 2 +- src/server/routes/energy/query-model.test.ts | 30 +++++++++++++--- src/server/routes/energy/query-model.ts | 10 ++++-- src/server/routes/energy/routes.test.ts | 9 +++-- 5 files changed, 48 insertions(+), 39 deletions(-) diff --git a/src/modules/energy/HydrogenDaily.tsx b/src/modules/energy/HydrogenDaily.tsx index 3f6b4b1..ec0fe46 100644 --- a/src/modules/energy/HydrogenDaily.tsx +++ b/src/modules/energy/HydrogenDaily.tsx @@ -28,6 +28,7 @@ export default function HydrogenDaily() { useEffect(() => { let cancelled = false; setError(null); + setRows(null); const query = pick === 'custom' ? { startDate: effectiveRange.start, endDate: effectiveRange.end } : { range: pick }; @@ -81,34 +82,13 @@ export default function HydrogenDaily() {
- +
- {/* 外部车辆:新系统数据还没准备好 */} - {customer === 'external' && rows !== null && totalKg === 0 && ( - -
- - - -
-
外部车辆 · 数据未就绪
-
- 新系统的外部车辆加氢数据还在准备中 -
- 上线后此处将展示完整明细 -
-
- )} - - {/* 时段加氢量柱图(外部车辆无数据时不渲染) */} - {!(customer === 'external' && totalKg === 0) && trendData.length > 0 && ( + {/* 时段加氢量柱图 */} + {!error && trendData.length > 0 && totalKg > 0 && (
每日加氢量 @@ -184,8 +164,7 @@ export default function HydrogenDaily() { )} - {/* 表格(外部车辆 + 全 0 时不渲染,由上方友好空状态替代) */} - {!(customer === 'external' && rows !== null && totalKg === 0) && ( + {/* 日明细:加载失败、无订单与正常数据分别展示。 */}
{/* 表头 */}
@@ -206,8 +185,8 @@ export default function HydrogenDaily() {
) : rows === null ? (
- ) : rows.length === 0 ? ( -
+ ) : rows.length === 0 || totalKg === 0 ? ( +
) : rows.map(r => { const open = expanded.has(r.date); const isAbnormal = Math.abs(r.chainPct) >= 0.3; @@ -270,7 +249,6 @@ export default function HydrogenDaily() { ); })}
- )}
); diff --git a/src/server/routes/energy/hydrogen-daily.ts b/src/server/routes/energy/hydrogen-daily.ts index 57a7a65..0ee5210 100644 --- a/src/server/routes/energy/hydrogen-daily.ts +++ b/src/server/routes/energy/hydrogen-daily.ts @@ -39,7 +39,7 @@ export function registerHydrogenDailyRoute( HYDROGEN_BASE_WHERE_B, `b.${HYDROGEN_LOCAL} >= '${HYDROGEN_MIN_DATE}'`, dateRangeClause(`b.${HYDROGEN_LOCAL}`), - customerClause(customer).replaceAll('customer_price', 'b.customer_price').replaceAll('fee_total', 'b.fee_total'), + customerClause(customer), ].join(' AND '); // 站点级聚合(每日 × 每站)。前端组装成 day → stations diff --git a/src/server/routes/energy/query-model.test.ts b/src/server/routes/energy/query-model.test.ts index 02aa74e..a046814 100644 --- a/src/server/routes/energy/query-model.test.ts +++ b/src/server/routes/energy/query-model.test.ts @@ -1,5 +1,6 @@ import assert from 'node:assert/strict'; import test from 'node:test'; +import { DatabaseSync } from 'node:sqlite'; import { customerClause, dateRangeClause, @@ -7,10 +8,31 @@ import { resolveDateRange, } from './query-model.js'; -test('客户范围继续让外部车辆返回空数据', () => { - assert.equal(customerClause('external'), '1=0'); - assert.equal(customerClause('lingniu'), '1=1'); - assert.equal(customerClause('all'), '1=1'); +test('外部车辆只取佛山羚牛站未关联车辆的订单,车牌文字和收费不影响分类', () => { + const db = new DatabaseSync(':memory:'); + try { + db.exec(`CREATE TABLE orders ( + id INTEGER, station_id INTEGER, vehicle_id INTEGER, + license_plate TEXT, customer_price REAL, del_flag TEXT + ); + INSERT INTO orders VALUES + (1, 341, NULL, '粤A外部', 38, '0'), + (2, 341, NULL, '', 0, '0'), + (3, 341, 123, '粤A羚牛', 38, '0'), + (4, 52, NULL, '粤A其他站', 38, '0'), + (5, NULL, NULL, '', 0, '0'), + (6, NULL, 456, '粤A未关联站点', 0, '0'), + (7, 341, NULL, '粤A已删除', 38, '1');`); + const ids = (kind: 'external' | 'lingniu' | 'all') => db + .prepare(`SELECT b.id FROM orders b WHERE b.del_flag = '0' AND ${customerClause(kind)} ORDER BY b.id`) + .all().map(row => row.id); + assert.deepEqual(ids('external'), [1, 2]); + assert.deepEqual(ids('lingniu'), [3, 4, 5, 6]); + assert.deepEqual(ids('all'), [1, 2, 3, 4, 5, 6]); + assert.deepEqual([...ids('external'), ...ids('lingniu')].sort(), ids('all')); + } finally { + db.close(); + } }); test('能源日期快捷区间继续按本地自然日计算', () => { diff --git a/src/server/routes/energy/query-model.ts b/src/server/routes/energy/query-model.ts index eb2b07a..71fb540 100644 --- a/src/server/routes/energy/query-model.ts +++ b/src/server/routes/energy/query-model.ts @@ -8,10 +8,14 @@ export interface EnergyDateRange { const YMD_RE = /^\d{4}-\d{2}-\d{2}$/; -// 新账本目前只承载羚牛车辆订单;外部车辆仍需返回空集合而不是混用羚牛数据。 +// 主数据 ID 341:佛山南海羚牛加氢站。车牌文字存在不代表已关联车辆。 +const FOSHAN_LINGNIU_STATION_ID = 341; + +// 日明细账本使用别名 b;两类互斥,其他订单继续保留在原羚牛范围内。 export function customerClause(customer: CustomerKind): string { - if (customer === 'external') return '1=0'; - if (customer === 'lingniu') return '1=1'; + const external = `(COALESCE(b.station_id, 0) = ${FOSHAN_LINGNIU_STATION_ID} AND b.vehicle_id IS NULL)`; + if (customer === 'external') return external; + if (customer === 'lingniu') return `NOT ${external}`; return '1=1'; } diff --git a/src/server/routes/energy/routes.test.ts b/src/server/routes/energy/routes.test.ts index 8e3fdf8..86fddf3 100644 --- a/src/server/routes/energy/routes.test.ts +++ b/src/server/routes/energy/routes.test.ts @@ -105,6 +105,11 @@ test('四个处理器保持缓存和参数契约,加氢站点使用新主数 '/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, chainPct: 0, customerType: 'external', + stations: [{ name: '测试站', pricePerKg: 35, kg: 10, chainPct: 0 }] }, + { date: '2025-01-01', totalKg: 0, chainPct: 0, customerType: 'external', stations: [] }, + ]); const electricApp = new Hono(); const electricDependencies = { @@ -127,7 +132,7 @@ test('四个处理器保持缓存和参数契约,加氢站点使用新主数 { key: 'electric/monthly?customer=external&start=2025-01-01&end=2025-01-02', force: true }, ]); - // 指纹来自拆分前的 13 条 SQL,连空白符变化也会使测试失败。 + // 保留查询契约指纹;日明细已更新为佛山羚牛站未关联车辆的外部订单筛选。 assert.deepEqual( [...hydrogenCalls, ...electricCalls].map(call => sqlHash(call.sql)), [ @@ -138,7 +143,7 @@ test('四个处理器保持缓存和参数契约,加氢站点使用新主数 '256ac8309d5a', 'dac9e86fc527', 'a71da8f05765', - '24b23780a259', + 'd1620280f520', '226fd8f950a1', '6e4031b10926', '4fc77463294c',