This commit is contained in:
@@ -37,6 +37,53 @@ function customerClause(customer: CustomerKind): string {
|
||||
}
|
||||
|
||||
type Range = 'thisWeek' | 'thisMonth' | 'last15';
|
||||
interface DateRange {
|
||||
start: string;
|
||||
end: string;
|
||||
}
|
||||
|
||||
const YMD_RE = /^\d{4}-\d{2}-\d{2}$/;
|
||||
|
||||
function fmtYmd(d: Date): string {
|
||||
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
function addDays(d: Date, days: number): Date {
|
||||
const next = new Date(d);
|
||||
next.setDate(next.getDate() + days);
|
||||
return next;
|
||||
}
|
||||
|
||||
function parseYmd(value: string | undefined): string | null {
|
||||
if (!value || !YMD_RE.test(value)) return null;
|
||||
const d = new Date(`${value}T00:00:00`);
|
||||
return Number.isNaN(d.getTime()) ? null : value;
|
||||
}
|
||||
|
||||
function resolveDateRange(range: Range, startParam?: string, endParam?: string): DateRange {
|
||||
const customStart = parseYmd(startParam);
|
||||
const customEnd = parseYmd(endParam);
|
||||
if (customStart && customEnd) {
|
||||
return customStart <= customEnd
|
||||
? { start: customStart, end: customEnd }
|
||||
: { start: customEnd, end: customStart };
|
||||
}
|
||||
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
if (range === 'thisWeek') {
|
||||
const day = today.getDay() || 7;
|
||||
return { start: fmtYmd(addDays(today, -(day - 1))), end: fmtYmd(today) };
|
||||
}
|
||||
if (range === 'thisMonth') {
|
||||
return { start: fmtYmd(new Date(today.getFullYear(), today.getMonth(), 1)), end: fmtYmd(today) };
|
||||
}
|
||||
return { start: fmtYmd(addDays(today, -14)), end: fmtYmd(today) };
|
||||
}
|
||||
|
||||
function dateRangeClause(localExpr: string): string {
|
||||
return `${localExpr} >= ? AND ${localExpr} < DATE_ADD(?, INTERVAL 1 DAY)`;
|
||||
}
|
||||
|
||||
function rangeClause(localExpr: string, range: Range): string {
|
||||
switch (range) {
|
||||
@@ -48,25 +95,16 @@ function rangeClause(localExpr: string, range: Range): string {
|
||||
|
||||
/** 列出某 range 在当前时点下的全部日期(YYYY-MM-DD),用于补零 */
|
||||
function enumerateDates(range: Range): string[] {
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
const fmt = (d: Date) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
|
||||
let start: Date;
|
||||
if (range === 'thisWeek') {
|
||||
// 周一为一周开始(与 YEARWEEK(?, 1) 一致)
|
||||
const day = today.getDay() || 7; // 周日 7
|
||||
start = new Date(today);
|
||||
start.setDate(today.getDate() - (day - 1));
|
||||
} else if (range === 'thisMonth') {
|
||||
start = new Date(today.getFullYear(), today.getMonth(), 1);
|
||||
} else {
|
||||
start = new Date(today);
|
||||
start.setDate(today.getDate() - 14);
|
||||
}
|
||||
const { start, end } = resolveDateRange(range);
|
||||
return enumerateDateRange(start, end);
|
||||
}
|
||||
|
||||
function enumerateDateRange(startYmd: string, endYmd: string): string[] {
|
||||
const result: string[] = [];
|
||||
const cur = new Date(start);
|
||||
while (cur <= today) {
|
||||
result.push(fmt(cur));
|
||||
const cur = new Date(`${startYmd}T00:00:00`);
|
||||
const end = new Date(`${endYmd}T00:00:00`);
|
||||
while (cur <= end) {
|
||||
result.push(fmtYmd(cur));
|
||||
cur.setDate(cur.getDate() + 1);
|
||||
}
|
||||
return result;
|
||||
@@ -331,15 +369,16 @@ 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 force = c.req.query('force') === '1';
|
||||
|
||||
const data = await cached(`hydrogen/daily?range=${range}&customer=${customer}`, async () => {
|
||||
const data = await cached(`hydrogen/daily?start=${dateRange.start}&end=${dateRange.end}&customer=${customer}`, async () => {
|
||||
|
||||
const where = [
|
||||
HYDROGEN_BASE_WHERE_B,
|
||||
`b.${HYDROGEN_LOCAL} >= '${HYDROGEN_MIN_DATE}'`,
|
||||
rangeClause(`b.${HYDROGEN_LOCAL}`, range),
|
||||
dateRangeClause(`b.${HYDROGEN_LOCAL}`),
|
||||
customerClause(customer).replaceAll('customer_price', 'b.customer_price').replaceAll('fee_total', 'b.fee_total'),
|
||||
].join(' AND ');
|
||||
|
||||
@@ -360,6 +399,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],
|
||||
);
|
||||
|
||||
// 站点环比:同站点上一条记录的 kg
|
||||
@@ -409,7 +449,7 @@ app.get('/hydrogen/daily', async (c) => {
|
||||
}
|
||||
|
||||
// 补零:列出 range 内全部日期,缺失日期返回 totalKg=0、stations=[]
|
||||
const allDates = enumerateDates(range);
|
||||
const allDates = enumerateDateRange(dateRange.start, dateRange.end);
|
||||
const fullDays = allDates.map(date => {
|
||||
const info = dayMap.get(date);
|
||||
return {
|
||||
@@ -533,9 +573,10 @@ app.get('/electric/overview', async (c) => {
|
||||
app.get('/electric/monthly', async (c) => {
|
||||
const customer = (c.req.query('customer') || 'lingniu') as CustomerKind;
|
||||
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';
|
||||
|
||||
const data = await cached(`electric/monthly?customer=${customer}&range=${range}`, async () => {
|
||||
const data = await cached(`electric/monthly?customer=${customer}&start=${dateRange.start}&end=${dateRange.end}`, async () => {
|
||||
|
||||
// bi_ele_charge_record 用 vehicle_kind 区分:internal=我司,external=外部
|
||||
let kindClause = '1=1';
|
||||
@@ -548,8 +589,9 @@ app.get('/electric/monthly', async (c) => {
|
||||
SUM(fee) AS fee
|
||||
FROM bi_ele_charge_record
|
||||
WHERE ${kindClause}
|
||||
AND ${rangeClause('start_time', range)}
|
||||
AND ${dateRangeClause('start_time')}
|
||||
GROUP BY date`,
|
||||
[dateRange.start, dateRange.end],
|
||||
);
|
||||
|
||||
// 实际数据 map
|
||||
@@ -562,7 +604,7 @@ app.get('/electric/monthly', async (c) => {
|
||||
}
|
||||
|
||||
// 补零:枚举 range 全部日期
|
||||
const allDates = enumerateDates(range);
|
||||
const allDates = enumerateDateRange(dateRange.start, dateRange.end);
|
||||
const fullDays = allDates.map(date => {
|
||||
const d = dataMap.get(date);
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user