117 lines
4 KiB
TypeScript
117 lines
4 KiB
TypeScript
// app/api/options/lens/route.ts
|
||
import { NextResponse } from "next/server";
|
||
import { directusFetch } from "@/lib/directus";
|
||
|
||
type Target =
|
||
| "settings_fiber"
|
||
| "settings_uv"
|
||
| "settings_co2gal"
|
||
| "settings_co2gan";
|
||
|
||
/** Map target -> Directus collection */
|
||
function collectionForTarget(t?: string) {
|
||
switch ((t ?? "") as Target) {
|
||
case "settings_fiber":
|
||
case "settings_uv":
|
||
case "settings_co2gal":
|
||
return "laser_scan_lens" as const; // has field_size + focal_length
|
||
case "settings_co2gan":
|
||
return "laser_focus_lens" as const; // has name (no focal_length)
|
||
default:
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/** Parse "110x110", "110×110", "110 x 110", or single "110" => {w,h} */
|
||
function parseFieldSize(raw: unknown): { w: number; h: number } | null {
|
||
if (raw == null) return null;
|
||
const s = String(raw).trim();
|
||
const m = s.match(/(\d+(?:\.\d+)?)(?:\s*[x×]\s*(\d+(?:\.\d+)?))?/i);
|
||
if (!m) return null;
|
||
const w = Number(m[1]);
|
||
const h = m[2] ? Number(m[2]) : w;
|
||
if (!Number.isFinite(w) || !Number.isFinite(h)) return null;
|
||
return { w, h };
|
||
}
|
||
|
||
const fmtNum = (n: number) =>
|
||
Number.isInteger(n) ? String(n) : String(n).replace(/\.0+$/, "");
|
||
const dimsText = (d: { w: number; h: number }) => `${fmtNum(d.w)}x${fmtNum(d.h)}`;
|
||
|
||
export async function GET(req: Request) {
|
||
try {
|
||
const { searchParams } = new URL(req.url);
|
||
const target = searchParams.get("target") || undefined;
|
||
const q = (searchParams.get("q") || "").toLowerCase().trim();
|
||
const limit = Number(searchParams.get("limit") || "500");
|
||
|
||
const coll = collectionForTarget(target);
|
||
if (!coll) return NextResponse.json({ data: [] });
|
||
|
||
if (coll === "laser_scan_lens") {
|
||
// fiber / uv / co2gal → scan lenses have field_size + focal_length
|
||
const { data } = await directusFetch<{ data: any[] }>(
|
||
`/items/${coll}?fields=id,field_size,focal_length&limit=${encodeURIComponent(
|
||
String(limit)
|
||
)}`
|
||
);
|
||
|
||
const rows = (data ?? []).map((r) => {
|
||
const dim = parseFieldSize(r.field_size);
|
||
const fnumRaw = r.focal_length;
|
||
const label =
|
||
dim && fnumRaw != null && fnumRaw !== ""
|
||
? `${dimsText(dim)} (F${fmtNum(Number(fnumRaw))})`
|
||
: dim
|
||
? dimsText(dim)
|
||
: String(r.field_size ?? r.id);
|
||
|
||
const area =
|
||
dim && Number.isFinite(dim.w) && Number.isFinite(dim.h)
|
||
? dim.w * dim.h
|
||
: Number.POSITIVE_INFINITY;
|
||
|
||
return {
|
||
id: String(r.id),
|
||
label,
|
||
_sort: { area, w: dim?.w ?? Number.POSITIVE_INFINITY, h: dim?.h ?? Number.POSITIVE_INFINITY },
|
||
_search: `${r.field_size ?? ""} ${r.focal_length ?? ""} ${label}`.toLowerCase(),
|
||
};
|
||
});
|
||
|
||
const filtered = q ? rows.filter((r) => r._search.includes(q)) : rows;
|
||
|
||
filtered.sort((a, b) => {
|
||
if (a._sort.area !== b._sort.area) return a._sort.area - b._sort.area;
|
||
if (a._sort.w !== b._sort.w) return a._sort.w - b._sort.w;
|
||
if (a._sort.h !== b._sort.h) return a._sort.h - b._sort.h;
|
||
return a.label.localeCompare(b.label);
|
||
});
|
||
|
||
return NextResponse.json({
|
||
data: filtered.map(({ id, label }) => ({ id, label })),
|
||
});
|
||
}
|
||
|
||
// CO2 Gantry → focus lenses only have "name"
|
||
const { data } = await directusFetch<{ data: any[] }>(
|
||
`/items/${coll}?fields=id,name&limit=${encodeURIComponent(String(limit))}`
|
||
);
|
||
|
||
const rows = (data ?? []).map((r) => ({
|
||
id: String(r.id),
|
||
label: String(r.name ?? r.id),
|
||
_search: String(r.name ?? r.id).toLowerCase(),
|
||
}));
|
||
|
||
const filtered = q ? rows.filter((r) => r._search.includes(q)) : rows;
|
||
filtered.sort((a, b) => a.label.localeCompare(b.label));
|
||
|
||
return NextResponse.json({
|
||
data: filtered.map(({ id, label }) => ({ id, label })),
|
||
});
|
||
} catch (err: any) {
|
||
console.error("[options/lens] error:", err?.message || err);
|
||
return NextResponse.json({ data: [] }, { status: 200 });
|
||
}
|
||
}
|