refactor: add hydrogen station drilldown
This commit is contained in:
@@ -3,6 +3,11 @@ import type { RowDataPacket } from 'mysql2';
|
||||
import pool from '../../db.js';
|
||||
import hydrogenPool from '../../hydrogen-db.js';
|
||||
import { cached } from './cache.js';
|
||||
import {
|
||||
parseHydrogenCustomerKind,
|
||||
parseHydrogenStationId,
|
||||
type HydrogenCustomerKind,
|
||||
} from './query.js';
|
||||
import type { AuthUser } from '../../auth/types.js';
|
||||
import { canAccessEnergy } from '../../auth/types.js';
|
||||
|
||||
@@ -27,10 +32,8 @@ const HYDROGEN_BASE_WHERE = `del_flag = '0'`;
|
||||
const HYDROGEN_BASE_WHERE_B = `b.del_flag = '0'`;
|
||||
const ELECTRIC_LOCAL = `charging_start_time`;
|
||||
|
||||
type CustomerKind = 'external' | 'lingniu' | 'all';
|
||||
|
||||
// 新账本 hydrogen_fuel_ledger 当前只承载羚牛车辆订单;外部车辆数据源待接入。
|
||||
function customerClause(customer: CustomerKind): string {
|
||||
function customerClause(customer: HydrogenCustomerKind): string {
|
||||
if (customer === 'external') return '1=0';
|
||||
if (customer === 'lingniu') return '1=1';
|
||||
return '1=1';
|
||||
@@ -229,6 +232,7 @@ app.get('/hydrogen/overview', async (c) => {
|
||||
);
|
||||
const top5KgSum = kpi.yearKg || 1;
|
||||
const top5 = top5Rows.map((r, i) => ({
|
||||
id: Number(r.id) || 0,
|
||||
rank: i + 1,
|
||||
name: r.name as string,
|
||||
kg: Number(r.kg) || 0,
|
||||
@@ -256,6 +260,7 @@ app.get('/hydrogen/overview', async (c) => {
|
||||
const stationKgSum = stationFullRows.reduce((s, r) => s + (Number(r.kg) || 0), 0) || 1;
|
||||
const stationRevSum = stationFullRows.reduce((s, r) => s + (Number(r.revenue) || 0), 0) || 1;
|
||||
const stations = stationFullRows.map(r => ({
|
||||
id: Number(r.id) || 0,
|
||||
name: r.name as string,
|
||||
kg: Number(r.kg) || 0,
|
||||
revenue: Number(r.revenue) || 0,
|
||||
@@ -370,17 +375,24 @@ 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 = (c.req.query('customer') || 'external') as CustomerKind;
|
||||
const customer = parseHydrogenCustomerKind(c.req.query('customer'));
|
||||
const stationId = parseHydrogenStationId(c.req.query('stationId'));
|
||||
const force = c.req.query('force') === '1';
|
||||
|
||||
const data = await cached(`hydrogen/daily?start=${dateRange.start}&end=${dateRange.end}&customer=${customer}`, async () => {
|
||||
const data = await cached(`hydrogen/daily?start=${dateRange.start}&end=${dateRange.end}&customer=${customer}&station=${stationId ?? 'all'}`, async () => {
|
||||
|
||||
const where = [
|
||||
const whereParts = [
|
||||
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'),
|
||||
].join(' AND ');
|
||||
];
|
||||
const whereParams: Array<string | number> = [dateRange.start, dateRange.end];
|
||||
if (stationId !== null) {
|
||||
whereParts.push('COALESCE(b.station_id, 0) = ?');
|
||||
whereParams.push(stationId);
|
||||
}
|
||||
const where = whereParts.join(' AND ');
|
||||
|
||||
// 站点级聚合(每日 × 每站)。前端组装成 day → stations
|
||||
// 站点名 fallback:站点主数据 → 账本冗余站点名 → 未关联站点
|
||||
@@ -399,7 +411,7 @@ app.get('/hydrogen/daily', async (c) => {
|
||||
WHERE ${where}
|
||||
GROUP BY d, COALESCE(b.station_id, 0)
|
||||
ORDER BY d DESC, kg DESC`,
|
||||
[dateRange.start, dateRange.end],
|
||||
whereParams,
|
||||
);
|
||||
|
||||
// 站点环比:同站点上一条记录的 kg
|
||||
@@ -459,6 +471,7 @@ app.get('/hydrogen/daily', async (c) => {
|
||||
customerType: customer,
|
||||
stations: info
|
||||
? info.stations.slice().sort((a, b) => b.kg - a.kg).map(s => ({
|
||||
stationId: s.stationId,
|
||||
name: s.name,
|
||||
pricePerKg: Math.round(s.pricePerKg * 100) / 100,
|
||||
kg: Math.round(s.kg * 100) / 100,
|
||||
@@ -571,7 +584,7 @@ app.get('/electric/overview', async (c) => {
|
||||
// 缺失日期补零
|
||||
// =========================================================
|
||||
app.get('/electric/monthly', async (c) => {
|
||||
const customer = (c.req.query('customer') || 'lingniu') as CustomerKind;
|
||||
const customer = parseHydrogenCustomerKind(c.req.query('customer'));
|
||||
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';
|
||||
|
||||
Reference in New Issue
Block a user