feat: add report center

This commit is contained in:
2026-06-24 17:26:04 +08:00
parent f0ac47e040
commit 049d6a711e
7 changed files with 841 additions and 21 deletions

View File

@@ -468,6 +468,43 @@ export type ScenarioRunResponse = {
variants: ScenarioVariant[];
};
export type Report = {
report_id: number;
report_type: string;
title: string;
target_month: string | null;
area_id: string | null;
area_name: string | null;
neighborhood_id: string | null;
neighborhood_name: string | null;
summary: string;
content_markdown: string;
linked_metrics: Record<string, unknown>;
status: string;
created_at: string;
updated_at: string;
};
export type CreateReport = {
report_type: "monthly" | "area_special" | "neighborhood_memo";
title: string;
target_month?: string;
area_id?: string;
neighborhood_id?: string;
summary?: string;
content_markdown: string;
linked_metrics?: Record<string, unknown>;
status?: "draft" | "published" | "archived";
};
export type ReportFilters = {
report_type?: string;
target_month?: string;
area_id?: string;
neighborhood_id?: string;
status?: string;
};
export type ComparisonMetricValue = {
id: string;
value: number | null;
@@ -739,6 +776,28 @@ export async function createScenarioRun(
});
}
export async function fetchReports(filters: ReportFilters = {}): Promise<Report[]> {
const params = new URLSearchParams();
for (const [key, value] of Object.entries(filters)) {
if (value) {
params.set(key, value);
}
}
const query = params.toString();
return fetchJson(`/api/v1/reports${query ? `?${query}` : ""}`);
}
export async function fetchReport(id: number): Promise<Report> {
return fetchJson(`/api/v1/reports/${id}`);
}
export async function createReport(payload: CreateReport): Promise<Report> {
return fetchJson("/api/v1/reports", {
method: "POST",
body: JSON.stringify(payload),
});
}
async function fetchJson<T>(path: string, init?: RequestInit): Promise<T> {
const response = await fetch(`${API_BASE_URL}${path}`, {
...init,