refactor: align electric overview drilldown
This commit is contained in:
@@ -5,6 +5,7 @@ import hydrogenPool from '../../hydrogen-db.js';
|
||||
import { cached } from './cache.js';
|
||||
import {
|
||||
parseHydrogenCustomerKind,
|
||||
parseElectricVehicleScope,
|
||||
parseHydrogenCustomerName,
|
||||
parseHydrogenStationId,
|
||||
parseEnergyDate,
|
||||
@@ -602,14 +603,13 @@ app.get('/electric/orders', async (c) => {
|
||||
if (date === null) return c.json({ error: 'date 必须是有效的 YYYY-MM-DD 日期' }, 400);
|
||||
|
||||
const customerParam = c.req.query('customer');
|
||||
if (customerParam !== undefined && customerParam !== 'lingniu' && customerParam !== 'external') {
|
||||
return c.json({ error: 'customer 必须是 lingniu 或 external' }, 400);
|
||||
}
|
||||
const customer = customerParam === 'external' ? 'external' : 'lingniu';
|
||||
const vehicleKind = customer === 'lingniu' ? 'internal' : 'external';
|
||||
const customer = parseElectricVehicleScope(customerParam);
|
||||
if (customer === null) return c.json({ error: 'customer 必须是 all、lingniu 或 external' }, 400);
|
||||
const vehicleKind = customer === 'all' ? null : customer === 'lingniu' ? 'internal' : 'external';
|
||||
const kindClause = vehicleKind === null ? '' : 'AND vehicle_kind = ?';
|
||||
|
||||
const data = await cached(`electric/orders?date=${date}&customer=${customer}`, async () => {
|
||||
const params = [date, date, vehicleKind];
|
||||
const params = vehicleKind === null ? [date, date] : [date, date, vehicleKind];
|
||||
const [[summaryRows], [detailRows]] = await Promise.all([
|
||||
pool.query<RowDataPacket[]>(
|
||||
`SELECT COUNT(*) AS recordCount,
|
||||
@@ -617,7 +617,7 @@ app.get('/electric/orders', async (c) => {
|
||||
SUM(fee) AS totalFee
|
||||
FROM bi_ele_charge_record
|
||||
WHERE start_time >= ? AND start_time < DATE_ADD(?, INTERVAL 1 DAY)
|
||||
AND vehicle_kind = ?`,
|
||||
${kindClause}`,
|
||||
params,
|
||||
),
|
||||
pool.query<RowDataPacket[]>(
|
||||
@@ -634,7 +634,7 @@ app.get('/electric/orders', async (c) => {
|
||||
fee AS totalFee
|
||||
FROM bi_ele_charge_record
|
||||
WHERE start_time >= ? AND start_time < DATE_ADD(?, INTERVAL 1 DAY)
|
||||
AND vehicle_kind = ?
|
||||
${kindClause}
|
||||
ORDER BY start_time DESC, id DESC
|
||||
LIMIT 501`,
|
||||
params,
|
||||
@@ -674,7 +674,8 @@ app.get('/electric/orders', async (c) => {
|
||||
// 缺失日期补零
|
||||
// =========================================================
|
||||
app.get('/electric/monthly', async (c) => {
|
||||
const customer = parseHydrogenCustomerKind(c.req.query('customer'));
|
||||
const customer = parseElectricVehicleScope(c.req.query('customer'));
|
||||
if (customer === null) return c.json({ error: 'customer 必须是 all、lingniu 或 external' }, 400);
|
||||
const range = (c.req.query('range') || 'last15') as Range;
|
||||
const dateRange = resolveDateRange(range, c.req.query('startDate'), c.req.query('endDate'));
|
||||
const force = c.req.query('force') === '1';
|
||||
|
||||
@@ -3,6 +3,7 @@ import test from 'node:test';
|
||||
import app from './index.js';
|
||||
import {
|
||||
parseHydrogenCustomerKind,
|
||||
parseElectricVehicleScope,
|
||||
parseHydrogenCustomerName,
|
||||
parseHydrogenStationId,
|
||||
parseEnergyDate,
|
||||
@@ -23,6 +24,14 @@ test('defaults unknown customer scopes to lingniu', () => {
|
||||
assert.equal(parseHydrogenCustomerKind(undefined), 'lingniu');
|
||||
});
|
||||
|
||||
test('parses explicit electric vehicle scopes', () => {
|
||||
assert.equal(parseElectricVehicleScope('all'), 'all');
|
||||
assert.equal(parseElectricVehicleScope('lingniu'), 'lingniu');
|
||||
assert.equal(parseElectricVehicleScope('external'), 'external');
|
||||
assert.equal(parseElectricVehicleScope(undefined), 'lingniu');
|
||||
assert.equal(parseElectricVehicleScope('unknown'), null);
|
||||
});
|
||||
|
||||
test('normalizes bounded customer names for exact matching', () => {
|
||||
assert.equal(parseHydrogenCustomerName(' 武汉客户 '), '武汉客户');
|
||||
assert.equal(parseHydrogenCustomerName('未指定客户'), '未指定客户');
|
||||
@@ -48,15 +57,15 @@ test('parses only valid energy calendar dates', () => {
|
||||
assert.equal(parseEnergyDate(undefined), null);
|
||||
});
|
||||
|
||||
test('rejects invalid electric order drill filters before querying data', async () => {
|
||||
test('rejects invalid electric drill filters before querying data', async () => {
|
||||
const invalidDate = await app.request('/electric/orders?date=2026-02-31&customer=lingniu');
|
||||
assert.equal(invalidDate.status, 400);
|
||||
assert.deepEqual(await invalidDate.json(), { error: 'date 必须是有效的 YYYY-MM-DD 日期' });
|
||||
|
||||
const invalidScope = await app.request('/electric/orders?date=2026-07-28&customer=all');
|
||||
const invalidScope = await app.request('/electric/orders?date=2026-07-28&customer=unknown');
|
||||
assert.equal(invalidScope.status, 400);
|
||||
assert.deepEqual(await invalidScope.json(), { error: 'customer 必须是 lingniu 或 external' });
|
||||
assert.deepEqual(await invalidScope.json(), { error: 'customer 必须是 all、lingniu 或 external' });
|
||||
|
||||
const unknownScope = await app.request('/electric/orders?date=2026-07-28&customer=unknown');
|
||||
assert.equal(unknownScope.status, 400);
|
||||
const invalidMonthlyScope = await app.request('/electric/monthly?customer=unknown');
|
||||
assert.equal(invalidMonthlyScope.status, 400);
|
||||
});
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
export type HydrogenCustomerKind = 'external' | 'lingniu' | 'all';
|
||||
export type ElectricVehicleScope = 'external' | 'lingniu' | 'all';
|
||||
|
||||
export function parseHydrogenCustomerKind(value: string | undefined): HydrogenCustomerKind {
|
||||
if (value === 'external' || value === 'all') return value;
|
||||
return 'lingniu';
|
||||
}
|
||||
|
||||
export function parseElectricVehicleScope(value: string | undefined): ElectricVehicleScope | null {
|
||||
if (value === undefined) return 'lingniu';
|
||||
if (value === 'external' || value === 'lingniu' || value === 'all') return value;
|
||||
return null;
|
||||
}
|
||||
|
||||
export function parseHydrogenStationId(value: string | undefined): number | null {
|
||||
if (value == null || !/^\d+$/.test(value)) return null;
|
||||
const parsed = Number(value);
|
||||
|
||||
Reference in New Issue
Block a user