Files
next-tjwater-frontend/src/features/workbench/api/gis-properties-client.ts
T
jiang 2d8506fea0
Generic Container CI/CD / test-build-publish (push) Successful in 2m9s
Frontend CI/CD / build-test-publish-and-deploy (push) Successful in 2m39s
feat: add project-aware agent workspace
2026-10-22 18:52:18 +08:00

116 lines
3.9 KiB
TypeScript

import { getWorkbenchAccessToken } from "./request-context";
import { z } from "zod";
import type { WorkbenchAccess } from "./request-context";
import { env } from "@/shared/config/env";
import type { WaterNetworkSourceId } from "../map/sources";
import {
createWorkbenchHeaders,
findOwnedWorkbenchProject,
getServerError
} from "./project-client";
const gisAttributeGroupSchema = z.object({
dataset_key: z.string().min(1),
dataset_title: z.string().min(1),
source_date: z.string().date(),
layer_key: z.string().min(1),
layer_name: z.string().min(1),
source_fid: z.number().int(),
match_method: z.enum(["node_pair", "geometry", "source"]),
match_distance_m: z.number().finite().nonnegative().nullable(),
attributes: z.record(z.unknown())
});
const elementGisPropertiesSchema = z.object({
element_type: z.enum([
"pipes",
"junctions",
"valves",
"reservoirs",
"pumps",
"tanks",
"scada"
]),
element_id: z.string().min(1),
groups: z.array(gisAttributeGroupSchema)
});
const sourceGisFeaturePropertiesSchema = z.object({
layer_key: z.string().min(1),
source_fid: z.number().int().nonnegative(),
group: gisAttributeGroupSchema
});
export type GisAttributeGroup = z.infer<typeof gisAttributeGroupSchema>;
const SERVER_API_BASE_URL = env.TJWATER_SERVER_API_BASE_URL.replace(/\/$/, "");
export async function fetchElementGisProperties(
elementType: WaterNetworkSourceId,
elementId: string,
projectId: string | null,
getAccessToken?: WorkbenchAccess,
signal?: AbortSignal
): Promise<GisAttributeGroup[]> {
const ownedProject = projectId
? null
: await findOwnedWorkbenchProject(getAccessToken, signal);
const accessToken = ownedProject?.accessToken ?? await getWorkbenchAccessToken(getAccessToken);
const resolvedProjectId = projectId ?? ownedProject?.project.project_id;
if (!resolvedProjectId) throw new Error("未找到 GIS 台账所属项目");
const path = [
"/api/v1/elements",
encodeURIComponent(elementType),
encodeURIComponent(elementId),
"gis-properties"
].join("/");
const response = await fetch(`${SERVER_API_BASE_URL}${path}`, {
headers: createWorkbenchHeaders(accessToken, resolvedProjectId),
signal
});
const payload: unknown = await response.json().catch(() => null);
if (!response.ok) {
throw new Error(getServerError(payload, response.status, "GIS 台账属性查询"));
}
const result = elementGisPropertiesSchema.parse(payload);
if (result.element_type !== elementType || result.element_id !== elementId) {
throw new Error("GIS 台账属性与所选元素不一致");
}
return result.groups;
}
export async function fetchSourceGisFeatureProperties(
layerKey: string,
sourceFid: number,
projectId: string | null,
getAccessToken?: WorkbenchAccess,
signal?: AbortSignal
): Promise<GisAttributeGroup[]> {
const ownedProject = projectId
? null
: await findOwnedWorkbenchProject(getAccessToken, signal);
const accessToken = ownedProject?.accessToken ?? await getWorkbenchAccessToken(getAccessToken);
const resolvedProjectId = projectId ?? ownedProject?.project.project_id;
if (!resolvedProjectId) throw new Error("未找到 GIS 台账所属项目");
const path = [
"/api/v1/source-gis/layers",
encodeURIComponent(layerKey),
"features",
encodeURIComponent(String(sourceFid)),
"properties"
].join("/");
const response = await fetch(`${SERVER_API_BASE_URL}${path}`, {
headers: createWorkbenchHeaders(accessToken, resolvedProjectId),
signal
});
const payload: unknown = await response.json().catch(() => null);
if (!response.ok) {
throw new Error(getServerError(payload, response.status, "源 GIS 属性查询"));
}
const result = sourceGisFeaturePropertiesSchema.parse(payload);
if (result.layer_key !== layerKey || result.source_fid !== sourceFid) {
throw new Error("源 GIS 属性与所选要素不一致");
}
return [result.group];
}