All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m50s
71 lines
2.1 KiB
TypeScript
71 lines
2.1 KiB
TypeScript
// utils/export.ts
|
|
export type ExportParams = {
|
|
baseUrl?: string; // e.g. process.env.NEXT_PUBLIC_API_URL
|
|
site: string; // PROJ-0028
|
|
suffix?: "grid" | "solar"; // default "grid"
|
|
serial?: string | null; // device id like "01"
|
|
day?: string; // "YYYY-MM-DD" (preferred)
|
|
start?: string; // ISO string (if not using day)
|
|
end?: string; // ISO string (if not using day)
|
|
columns?: string[]; // optional list of columns
|
|
localTz?: string; // default "Asia/Kuala_Lumpur"
|
|
};
|
|
|
|
export function buildExportUrl(p: ExportParams): string {
|
|
const {
|
|
baseUrl = "",
|
|
site,
|
|
suffix = "grid",
|
|
serial,
|
|
day,
|
|
start,
|
|
end,
|
|
columns,
|
|
localTz = "Asia/Kuala_Lumpur",
|
|
} = p;
|
|
|
|
const params = new URLSearchParams();
|
|
params.set("site", site);
|
|
params.set("suffix", suffix);
|
|
params.set("local_tz", localTz);
|
|
|
|
const s = serial?.trim();
|
|
if (s) params.set("serial", s);
|
|
|
|
if (day) {
|
|
params.set("day", day); // simple whole-day export
|
|
} else {
|
|
if (!start || !end) throw new Error("Provide either day=YYYY-MM-DD or both start and end.");
|
|
params.set("start", start); // URLSearchParams will encode '+' correctly
|
|
params.set("end", end);
|
|
}
|
|
|
|
if (columns?.length) {
|
|
// backend expects ?columns=... repeated; append each
|
|
columns.forEach(c => params.append("columns", c));
|
|
}
|
|
|
|
// ensure there's a single slash join for /export/xlsx
|
|
const root = baseUrl.replace(/\/+$/, "");
|
|
return `${root}/export/xlsx?${params.toString()}`;
|
|
}
|
|
|
|
/** Parse filename from Content-Disposition (handles RFC5987 filename*) */
|
|
export function getFilenameFromCD(cd: string | null): string | null {
|
|
if (!cd) return null;
|
|
|
|
// filename*=UTF-8''encoded-name.xlsx
|
|
const star = /filename\*\s*=\s*([^']*)''([^;]+)/i.exec(cd);
|
|
if (star && star[2]) {
|
|
try {
|
|
return decodeURIComponent(star[2]);
|
|
} catch {
|
|
return star[2];
|
|
}
|
|
}
|
|
|
|
// filename="name.xlsx" OR filename=name.xlsx
|
|
const plain = /filename\s*=\s*("?)([^";]+)\1/i.exec(cd);
|
|
return plain ? plain[2] : null;
|
|
}
|