refactor: add hydrogen customer drilldown
This commit is contained in:
@@ -5,6 +5,7 @@ import hydrogenPool from '../../hydrogen-db.js';
|
||||
import { cached } from './cache.js';
|
||||
import {
|
||||
parseHydrogenCustomerKind,
|
||||
parseHydrogenCustomerName,
|
||||
parseHydrogenStationId,
|
||||
type HydrogenCustomerKind,
|
||||
} from './query.js';
|
||||
@@ -370,16 +371,25 @@ app.get('/hydrogen/overview', async (c) => {
|
||||
});
|
||||
|
||||
// =========================================================
|
||||
// 氢能 每日:日期范围 + 客户类型 + 站点级下钻
|
||||
// 氢能 每日:日期范围 + 车辆归属 + 站点/客户下钻
|
||||
// =========================================================
|
||||
app.get('/hydrogen/daily', async (c) => {
|
||||
const range = (c.req.query('range') || 'last15') as Range;
|
||||
const dateRange = resolveDateRange(range, c.req.query('startDate'), c.req.query('endDate'));
|
||||
const customer = parseHydrogenCustomerKind(c.req.query('customer'));
|
||||
const stationId = parseHydrogenStationId(c.req.query('stationId'));
|
||||
const stationIdParam = c.req.query('stationId');
|
||||
const customerNameParam = c.req.query('customerName');
|
||||
const stationId = parseHydrogenStationId(stationIdParam);
|
||||
const customerName = parseHydrogenCustomerName(customerNameParam);
|
||||
if (stationIdParam !== undefined && stationId === null) {
|
||||
return c.json({ error: 'stationId 必须是非负整数' }, 400);
|
||||
}
|
||||
if (customerNameParam !== undefined && customerName === null) {
|
||||
return c.json({ error: 'customerName 必须是 1-128 个字符' }, 400);
|
||||
}
|
||||
const force = c.req.query('force') === '1';
|
||||
|
||||
const data = await cached(`hydrogen/daily?start=${dateRange.start}&end=${dateRange.end}&customer=${customer}&station=${stationId ?? 'all'}`, async () => {
|
||||
const data = await cached(`hydrogen/daily?start=${dateRange.start}&end=${dateRange.end}&customer=${customer}&station=${stationId ?? 'all'}&customerName=${encodeURIComponent(customerName ?? 'all')}`, async () => {
|
||||
|
||||
const whereParts = [
|
||||
HYDROGEN_BASE_WHERE_B,
|
||||
@@ -392,6 +402,10 @@ app.get('/hydrogen/daily', async (c) => {
|
||||
whereParts.push('COALESCE(b.station_id, 0) = ?');
|
||||
whereParams.push(stationId);
|
||||
}
|
||||
if (customerName !== null) {
|
||||
whereParts.push("COALESCE(NULLIF(TRIM(b.customer_name), ''), '未指定客户') = ?");
|
||||
whereParams.push(customerName);
|
||||
}
|
||||
const where = whereParts.join(' AND ');
|
||||
|
||||
// 站点级聚合(每日 × 每站)。前端组装成 day → stations
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import app from './index.js';
|
||||
import {
|
||||
parseHydrogenCustomerKind,
|
||||
parseHydrogenCustomerName,
|
||||
parseHydrogenStationId,
|
||||
} from './query.js';
|
||||
|
||||
@@ -19,3 +21,21 @@ test('defaults unknown customer scopes to lingniu', () => {
|
||||
assert.equal(parseHydrogenCustomerKind('invalid'), 'lingniu');
|
||||
assert.equal(parseHydrogenCustomerKind(undefined), 'lingniu');
|
||||
});
|
||||
|
||||
test('normalizes bounded customer names for exact matching', () => {
|
||||
assert.equal(parseHydrogenCustomerName(' 武汉客户 '), '武汉客户');
|
||||
assert.equal(parseHydrogenCustomerName('未指定客户'), '未指定客户');
|
||||
assert.equal(parseHydrogenCustomerName(' '), null);
|
||||
assert.equal(parseHydrogenCustomerName('x'.repeat(129)), null);
|
||||
assert.equal(parseHydrogenCustomerName(undefined), null);
|
||||
});
|
||||
|
||||
test('rejects invalid entity filters before querying hydrogen data', async () => {
|
||||
const invalidStation = await app.request('/hydrogen/daily?stationId=-1');
|
||||
assert.equal(invalidStation.status, 400);
|
||||
assert.deepEqual(await invalidStation.json(), { error: 'stationId 必须是非负整数' });
|
||||
|
||||
const invalidCustomer = await app.request(`/hydrogen/daily?customerName=${'x'.repeat(129)}`);
|
||||
assert.equal(invalidCustomer.status, 400);
|
||||
assert.deepEqual(await invalidCustomer.json(), { error: 'customerName 必须是 1-128 个字符' });
|
||||
});
|
||||
|
||||
@@ -10,3 +10,9 @@ export function parseHydrogenStationId(value: string | undefined): number | null
|
||||
const parsed = Number(value);
|
||||
return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : null;
|
||||
}
|
||||
|
||||
export function parseHydrogenCustomerName(value: string | undefined): string | null {
|
||||
if (value == null) return null;
|
||||
const normalized = value.trim();
|
||||
return normalized.length > 0 && normalized.length <= 128 ? normalized : null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user