352 lines
15 KiB
TypeScript
352 lines
15 KiB
TypeScript
import axios from "axios";
|
|
|
|
const api = axios.create({ baseURL: "/v1/admin" });
|
|
|
|
export type KgProjectContext = {
|
|
tenantId: string;
|
|
projectId: string;
|
|
graphName: string;
|
|
};
|
|
|
|
export const PROJECT_CONTEXT_KEY = "znkg.currentProjectContext";
|
|
|
|
export const DEFAULT_PROJECT_CONTEXT: KgProjectContext = {
|
|
tenantId: "CityGraph-new2",
|
|
projectId: "CityGraph-new2",
|
|
graphName: "guiyang_new2",
|
|
};
|
|
|
|
const PROJECT_DISPLAY_NAMES: Record<string, string> = {
|
|
"CityGraph-new2": "城市图谱",
|
|
guiyang_new2: "贵阳城市图谱",
|
|
city_graph: "城市图谱",
|
|
travel_agency: "旅行社",
|
|
travel_graph: "旅行社线路制定",
|
|
travel_fixed_route_item: "旅行社固定线路资源图谱",
|
|
travel_agency_2_0_test: "旅行社2.0测试",
|
|
baixinghui_travel_agency: "百姓惠旅行社",
|
|
};
|
|
|
|
const GRAPH_DISPLAY_NAMES: Record<string, string> = {
|
|
guiyang_new2: "贵阳城市图谱",
|
|
travel_agency: "旅行社资料库",
|
|
travel_graph: "旅行社线路制定",
|
|
travel_fixed_route_item: "旅行社固定线路资源图谱",
|
|
travel_agency_2_0_test: "旅行社2.0测试图谱",
|
|
baixinghui_travel_agency: "百姓惠旅行社图谱",
|
|
};
|
|
|
|
const STATUS_DISPLAY_NAMES: Record<string, string> = {
|
|
active: "启用中",
|
|
published: "已发布",
|
|
draft: "草稿",
|
|
archived: "已归档",
|
|
};
|
|
|
|
export function displayProjectName(value?: string | null): string {
|
|
const key = String(value || "").trim();
|
|
return PROJECT_DISPLAY_NAMES[key] || key || "-";
|
|
}
|
|
|
|
export function displayGraphName(value?: string | null): string {
|
|
const key = String(value || "").trim();
|
|
return GRAPH_DISPLAY_NAMES[key] || PROJECT_DISPLAY_NAMES[key] || key || "-";
|
|
}
|
|
|
|
export function displayTenantName(value?: string | null): string {
|
|
return displayProjectName(value);
|
|
}
|
|
|
|
export function displayStatusName(value?: string | null): string {
|
|
const key = String(value || "").trim();
|
|
return STATUS_DISPLAY_NAMES[key] || key || "-";
|
|
}
|
|
|
|
export function getProjectContext(): KgProjectContext {
|
|
try {
|
|
const parsed = JSON.parse(localStorage.getItem(PROJECT_CONTEXT_KEY) || "{}");
|
|
return {
|
|
tenantId: parsed.tenantId || DEFAULT_PROJECT_CONTEXT.tenantId,
|
|
projectId: parsed.projectId || DEFAULT_PROJECT_CONTEXT.projectId,
|
|
graphName: parsed.graphName || DEFAULT_PROJECT_CONTEXT.graphName,
|
|
};
|
|
} catch {
|
|
return DEFAULT_PROJECT_CONTEXT;
|
|
}
|
|
}
|
|
|
|
export function setProjectContext(context: KgProjectContext) {
|
|
localStorage.setItem(PROJECT_CONTEXT_KEY, JSON.stringify(context));
|
|
window.dispatchEvent(new CustomEvent("znkg-project-context", { detail: context }));
|
|
}
|
|
|
|
api.interceptors.request.use((config) => {
|
|
const token = localStorage.getItem("token");
|
|
if (token) config.headers.Authorization = `Bearer ${token}`;
|
|
const context = getProjectContext();
|
|
config.headers["X-KG-Tenant-Id"] = context.tenantId;
|
|
config.headers["X-KG-Project-Id"] = context.projectId;
|
|
config.headers["X-KG-Graph-Name"] = context.graphName;
|
|
return config;
|
|
});
|
|
|
|
api.interceptors.response.use(
|
|
(r) => r,
|
|
(err) => {
|
|
if (err.response?.status === 401) {
|
|
localStorage.removeItem("token");
|
|
window.location.href = "/admin/login";
|
|
}
|
|
return Promise.reject(err);
|
|
}
|
|
);
|
|
|
|
export default api;
|
|
|
|
// ── Auth ──
|
|
export const login = (username: string, password: string) =>
|
|
api.post("/auth/login", { username, password });
|
|
export const whoami = () => api.get("/auth/me");
|
|
|
|
// ── Projects / Graph releases ──
|
|
export const listProjects = () => api.get("/projects");
|
|
export const createProject = (data: unknown) => api.post("/projects", data);
|
|
export const listGraphReleases = (projectId: string) =>
|
|
api.get(`/projects/${encodeURIComponent(projectId)}/graph-releases`);
|
|
export const createGraphRelease = (projectId: string, data: unknown) =>
|
|
api.post(`/projects/${encodeURIComponent(projectId)}/graph-releases`, data);
|
|
export const listOntologySchemas = () => api.get("/ontology-schemas");
|
|
export const getCurrentOntologySchema = () => api.get("/ontology-schemas/current");
|
|
export const getOntologySchema = (schemaId: string | number) =>
|
|
api.get(`/ontology-schemas/${encodeURIComponent(String(schemaId))}`);
|
|
|
|
// ── Source Profiles (STEP 01) ──
|
|
export const listSourceProfiles = (params?: Record<string, string>) =>
|
|
api.get("/source-profiles", { params });
|
|
export const createSourceProfile = (data: unknown) =>
|
|
api.post("/source-profiles", data);
|
|
export const updateSourceProfile = (id: number, data: unknown) =>
|
|
api.patch(`/source-profiles/${id}`, data);
|
|
|
|
// ── Batches (STEP 01) ──
|
|
export const listBatches = (params?: Record<string, string>) =>
|
|
api.get("/batches", { params });
|
|
export const getBatch = (id: number) => api.get(`/batches/${id}`);
|
|
export const getBatchRawRecords = (id: number, params?: Record<string, unknown>) =>
|
|
api.get(`/batches/${id}/raw-records`, { params });
|
|
export const getBatchQuality = (id: number) =>
|
|
api.get(`/batches/${id}/quality-summary`);
|
|
|
|
// ── Question Traces (STEP 02) ──
|
|
export const createQuestionTrace = (data: unknown) =>
|
|
api.post("/question-traces", data);
|
|
export const listQuestionTraces = (params?: Record<string, string>) =>
|
|
api.get("/question-traces", { params });
|
|
export const getQuestionTrace = (id: number) =>
|
|
api.get(`/question-traces/${id}`);
|
|
export const simulateQuestions = () =>
|
|
api.post("/question-traces/simulate");
|
|
|
|
// ── Simulation Panel (STEP 02) ──
|
|
export const listSimQuestions = () => api.get("/simulation-panel");
|
|
export const createSimQuestion = (data: unknown) =>
|
|
api.post("/simulation-panel", data);
|
|
export const updateSimQuestion = (id: number, data: unknown) =>
|
|
api.patch(`/simulation-panel/${id}`, data);
|
|
export const deleteSimQuestion = (id: number) =>
|
|
api.delete(`/simulation-panel/${id}`);
|
|
export const importSimQuestions = (text: string) =>
|
|
api.post("/simulation-panel/import", { text });
|
|
export const adoptHitQuestions = () =>
|
|
api.post("/simulation-panel/adopt-hits");
|
|
export const aiGenerateSimQuestions = (count: number, topic?: string) =>
|
|
api.post("/simulation-panel/ai-generate", { count, topic });
|
|
|
|
// ── Audit (STEP 02) ──
|
|
export const runAudit = () => api.post("/audit/run");
|
|
export const listAuditReports = () => api.get("/audit/reports");
|
|
export const latestAuditReport = () => api.get("/audit/reports/latest");
|
|
export const listAuditGaps = () => api.get("/audit/gaps");
|
|
export const getAuditRun = (id: number) => api.get(`/audit-runs/${id}`);
|
|
export const latestAuditRun = () => api.get("/audit-runs/latest");
|
|
|
|
// ── Plaza (STEP 02) ──
|
|
export const plazaOverview = () => api.get("/plaza/overview");
|
|
export const plazaUsage = () => api.get("/plaza/usage");
|
|
export const plazaAlerts = () => api.get("/plaza/alerts");
|
|
export const plazaAmapConfig = () => api.get("/plaza/amap-config");
|
|
export const plazaMapPois = () => api.get("/plaza/map-pois");
|
|
export const plazaBusRoutes = () => api.get("/plaza/bus-routes");
|
|
export const plazaMapPoiDetail = (placeId: string) =>
|
|
api.get(`/plaza/map-pois/${encodeURIComponent(placeId)}`);
|
|
export const plazaUserQuery = (data: unknown) => api.post("/plaza/user-query", data);
|
|
export const travelAssistantQuery = (data: unknown) => api.post("/travel/assistant-query", data);
|
|
|
|
// ── OCR (旅行社名单录入) ──
|
|
export const ocrPassport = (file: File) => {
|
|
const form = new FormData();
|
|
form.append("file", file);
|
|
return api.post("/ocr/passport", form, {
|
|
headers: { "Content-Type": "multipart/form-data" },
|
|
});
|
|
};
|
|
export const ocrPassportByUrl = (url: string) => {
|
|
const form = new FormData();
|
|
form.append("url", url);
|
|
return api.post("/ocr/passport", form);
|
|
};
|
|
export const graphOverview = () => api.get("/graph/overview");
|
|
export const graphQuery = (cypher: string, limit = 200) =>
|
|
api.post("/graph/query", { cypher, limit });
|
|
|
|
// ── Entities (STEP 03) ──
|
|
export const listCandidates = (params?: Record<string, string>) =>
|
|
api.get("/entities", { params });
|
|
export const getEntity = (id: number) => api.get(`/entities/${id}`);
|
|
export const getEntityProvenance = (id: number) =>
|
|
api.get(`/entities/${id}/provenance`);
|
|
export const listPoiEvidenceQuality = (params?: Record<string, unknown>) =>
|
|
api.get("/evidence/poi-quality", { params });
|
|
export const getPoiEvidenceQuality = (placeKey: string, params?: Record<string, unknown>) =>
|
|
api.get(`/evidence/poi-quality/${encodeURIComponent(placeKey)}`, { params });
|
|
export const approveEntity = (id: number) =>
|
|
api.post(`/entities/${id}/approve`);
|
|
export const rejectEntity = (id: number, note?: string) =>
|
|
api.post(`/entities/${id}/reject`, null, { params: { note } });
|
|
export const fieldDecisions = (id: number, data: unknown) =>
|
|
api.patch(`/entities/${id}/field-decisions`, data);
|
|
export const mergeEntities = (id: number, targetId: number, note?: string) =>
|
|
api.post(`/entities/${id}/merge-with/${targetId}`, null, { params: { note } });
|
|
|
|
// ── Acquisition Tasks (STEP 04) ──
|
|
export const listAcquisitionTasks = (params?: Record<string, string>) =>
|
|
api.get("/acquisition-tasks", { params });
|
|
export const createAcquisitionTask = (data: unknown) =>
|
|
api.post("/acquisition-tasks", data);
|
|
export const createTaskFromGap = (data: unknown) =>
|
|
api.post("/acquisition-tasks/from-gap", data);
|
|
export const getAcquisitionTask = (id: number) =>
|
|
api.get(`/acquisition-tasks/${id}`);
|
|
export const assignTask = (id: number, assignee: string) =>
|
|
api.post(`/acquisition-tasks/${id}/assign`, { assignee });
|
|
export const startTask = (id: number) =>
|
|
api.post(`/acquisition-tasks/${id}/start`);
|
|
export const completeTask = (id: number, resultSummary?: string) =>
|
|
api.post(`/acquisition-tasks/${id}/complete`, { result_summary: resultSummary });
|
|
export const cancelTask = (id: number, note?: string) =>
|
|
api.post(`/acquisition-tasks/${id}/cancel`, { note });
|
|
// work-order review state machine + urge
|
|
export const reviewApproveTask = (id: number, note?: string) =>
|
|
api.post(`/acquisition-tasks/${id}/review-approve`, { note });
|
|
export const reviewRejectTask = (id: number, note?: string) =>
|
|
api.post(`/acquisition-tasks/${id}/review-reject`, { note });
|
|
export const urgeTask = (id: number, note?: string) =>
|
|
api.post(`/acquisition-tasks/${id}/urge`, { note });
|
|
|
|
// ── Inventory (STEP 04) ──
|
|
export const listInventoryIssues = (params?: Record<string, string>) =>
|
|
api.get("/inventory/issues", { params });
|
|
export const runInventoryScan = () => api.post("/inventory/scan");
|
|
export const resolveIssue = (id: number, note?: string) =>
|
|
api.post(`/inventory/issues/${id}/resolve`, { resolution_note: note });
|
|
|
|
// ── Treatment History (STEP 04) ──
|
|
export const listTreatmentHistory = (params?: Record<string, unknown>) =>
|
|
api.get("/treatment-history", { params });
|
|
|
|
// ── Vocabulary (STEP 05) ──
|
|
export const listVocabulary = (params?: Record<string, string>) =>
|
|
api.get("/vocabulary", { params });
|
|
export const createVocabularyTerm = (data: unknown) =>
|
|
api.post("/vocabulary", data);
|
|
export const updateVocabularyTerm = (id: number, data: unknown) =>
|
|
api.patch(`/vocabulary/${id}`, data);
|
|
export const lookupVocabulary = (name: string) =>
|
|
api.get("/vocabulary/lookup", { params: { name } });
|
|
export const mergeVocabulary = (id: number, targetId: number) =>
|
|
api.post(`/vocabulary/${id}/merge-into/${targetId}`);
|
|
|
|
// ── Conflicts (STEP 05) ──
|
|
export const listConflicts = () => api.get("/conflicts");
|
|
export const resolveConflict = (id: number, data: unknown) =>
|
|
api.post(`/conflicts/${id}/resolve`, data);
|
|
|
|
// ── Aligner (STEP 05) ──
|
|
export const alignSuggest = (candidateIds: number[]) =>
|
|
api.post("/aligner/suggest", { candidate_ids: candidateIds });
|
|
export const autoMerge = (candidateIds: number[]) =>
|
|
api.post("/aligner/auto-merge", { candidate_ids: candidateIds });
|
|
|
|
// ── Publish Jobs (STEP 05) ──
|
|
export const listPublishJobs = () => api.get("/publish-jobs");
|
|
export const getPublishJob = (id: number) => api.get(`/publish-jobs/${id}`);
|
|
export const createPublishJob = (candidateIds: number[]) =>
|
|
api.post("/publish-jobs", { candidate_ids: candidateIds });
|
|
export const getPublishDiff = (id: number) =>
|
|
api.get(`/publish-jobs/${id}/diff`);
|
|
export const rollbackPublish = (id: number, reason?: string) =>
|
|
api.post(`/publish-jobs/${id}/rollback`, { reason });
|
|
|
|
// ── RBAC & Accounts (P1) ──
|
|
export const listRoles = () => api.get("/roles");
|
|
export const createRole = (data: unknown) => api.post("/roles", data);
|
|
export const updateRole = (roleKey: string, data: unknown) =>
|
|
api.patch(`/roles/${roleKey}`, data);
|
|
export const deleteRole = (roleKey: string) => api.delete(`/roles/${roleKey}`);
|
|
|
|
export const listCapabilities = () => api.get("/capabilities");
|
|
export const createCapability = (data: unknown) => api.post("/capabilities", data);
|
|
export const deleteCapability = (capKey: string) =>
|
|
api.delete(`/capabilities/${capKey}`);
|
|
|
|
export const getPermissionMatrix = () => api.get("/permission-matrix");
|
|
export const setPermissionCell = (
|
|
roleKey: string,
|
|
capKey: string,
|
|
value: string
|
|
) => api.put("/permission-matrix", { role_key: roleKey, cap_key: capKey, value });
|
|
|
|
export const listUsers = () => api.get("/users");
|
|
export const createUser = (data: unknown) => api.post("/users", data);
|
|
export const updateUser = (id: number, data: unknown) =>
|
|
api.patch(`/users/${id}`, data);
|
|
export const deleteUser = (id: number) => api.delete(`/users/${id}`);
|
|
|
|
// ── City Areas & responsibility (P3) ──
|
|
export const listAreas = () => api.get("/areas");
|
|
export const syncAreasFromGraph = () => api.post("/areas/sync-from-graph");
|
|
export const updateArea = (areaId: string, data: unknown) =>
|
|
api.patch(`/areas/${areaId}`, data);
|
|
export const getAreaTree = () => api.get("/areas/tree");
|
|
export const getUserAreas = (userId: number) =>
|
|
api.get(`/users/${userId}/areas`);
|
|
export const setUserAreas = (
|
|
userId: number,
|
|
areaIds: string[],
|
|
customAreas: string[]
|
|
) => api.put(`/users/${userId}/areas`, { area_ids: areaIds, custom_areas: customAreas });
|
|
|
|
// ── Notifications / inbox (P4) ──
|
|
export const listNotifications = (onlyUnread = false) =>
|
|
api.get("/notifications", { params: { only_unread: onlyUnread } });
|
|
export const unreadCount = () => api.get("/notifications/unread-count");
|
|
export const markNotificationRead = (id: number) =>
|
|
api.post(`/notifications/${id}/read`);
|
|
export const markAllNotificationsRead = () =>
|
|
api.post("/notifications/read-all");
|
|
|
|
// ── Agent settings ──
|
|
export const getAgentSettings = () => api.get("/agent-settings");
|
|
export const saveAgentSettings = (config: unknown) =>
|
|
api.put("/agent-settings", config);
|
|
|
|
// ── Super Agent (autonomous KG curator) ──
|
|
export const superAgentRun = () => api.post("/super-agent/run", {});
|
|
export const superAgentLatest = () => api.get("/super-agent/runs/latest");
|
|
export const superAgentGet = (id: number) => api.get(`/super-agent/runs/${id}`);
|
|
export const superAgentStop = (id: number) =>
|
|
api.post(`/super-agent/runs/${id}/stop`);
|
|
export const superAgentCoverage = () => api.get("/super-agent/coverage");
|
|
export const superAgentTasks = (runId?: number) =>
|
|
api.get("/super-agent/tasks", { params: runId ? { run_id: runId } : {} });
|