fix: refactor time range to single source of truth with correct dates

- Default range changed from 30d to 7d
- Presets (today/7d/30d) now directly set customStart/customEnd dates,
  eliminating duplicate getTimeRange() calculation
- "All" preset fetches actual data boundaries from /api/date-range
  and backfills the custom date picker
- Clicking "custom" opens popover without triggering data refresh;
  only confirm applies changes
- SQL trend dates cast to ::text to avoid pg driver Date timezone offset
- Fix created_at filter from < to <= for end timestamp
This commit is contained in:
2026-04-07 16:22:18 +08:00
parent 35b8fec96c
commit 13805a47be
5 changed files with 108 additions and 62 deletions

View File

@@ -6,6 +6,18 @@ const REAL_MODEL = `COALESCE(
THEN other::jsonb->>'upstream_model_name' END,
model_name)`;
// ── 数据时间边界 ────────────────────────────────────────────────
export async function getDateRange(): Promise<{ minDate: string; maxDate: string }> {
const rows = await query(
`SELECT
((MIN(to_timestamp(created_at)) AT TIME ZONE 'Asia/Shanghai')::date)::text as min_date,
((MAX(to_timestamp(created_at)) AT TIME ZONE 'Asia/Shanghai')::date)::text as max_date
FROM logs WHERE type = 2`
);
return { minDate: rows[0]?.min_date ?? "", maxDate: rows[0]?.max_date ?? "" };
}
// 时间条件构建
function timeWhere(
params: (string | number | boolean | null)[],
@@ -19,7 +31,7 @@ function timeWhere(
}
if (endTs) {
params.push(endTs);
where += ` AND created_at < $${params.length}`;
where += ` AND created_at <= $${params.length}`;
}
return where;
}
@@ -91,8 +103,8 @@ export async function getTrends(
const truncExpr =
granularity === "day"
? `(to_timestamp(created_at) AT TIME ZONE 'Asia/Shanghai')::date`
: `date_trunc('${granularity}', to_timestamp(created_at) AT TIME ZONE 'Asia/Shanghai')::date`;
? `((to_timestamp(created_at) AT TIME ZONE 'Asia/Shanghai')::date)::text`
: `(date_trunc('${granularity}', to_timestamp(created_at) AT TIME ZONE 'Asia/Shanghai')::date)::text`;
const rows = await query(
`SELECT
@@ -107,7 +119,7 @@ export async function getTrends(
);
return rows.map((r) => ({
date: r.date instanceof Date ? r.date.toISOString().slice(0, 10) : String(r.date).slice(0, 10),
date: String(r.date).slice(0, 10),
calls: Number(r.calls),
prompt_tokens: Number(r.prompt_tokens),
completion_tokens: Number(r.completion_tokens),