Files
Cloud-Tour-to-Libo/admin-web/src/api.ts
T

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 } : {} });