200 lines
5.6 KiB
TypeScript
200 lines
5.6 KiB
TypeScript
import { apiFetch, apiFetchBlob, downloadBlob } from "@/lib/api";
|
||||
|
|
|
|||
|
|
/**
|
|||
|
|
* NL2SQL 查询(/nl2sql/*)与管理(/nl2sql/admin/*)适配层。
|
|||
|
|
* 按本次约定:页面以只读展示为主,运维类接口(jobs / refresh / kill / cache-invalidate)
|
|||
|
|
* 提供触发按钮,权限类接口只做列表展示,不建增删改表单。
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
export interface Nl2SqlQueryResult {
|
|||
|
|
query_id?: string;
|
|||
|
|
question?: string;
|
|||
|
|
generated_sql?: string | null;
|
|||
|
|
columns?: string[];
|
|||
|
|
rows?: Record<string, unknown>[];
|
|||
|
|
row_count?: number;
|
|||
|
|
truncated?: boolean;
|
|||
|
|
summary?: string;
|
|||
|
|
answer?: string;
|
|||
|
|
elapsed_ms?: number | null;
|
|||
|
|
trace_id?: string;
|
|||
|
|
[key: string]: unknown;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export interface QueryHistoryItem {
|
|||
|
|
query_id: string;
|
|||
|
|
user_id?: number;
|
|||
|
|
session_id?: string | null;
|
|||
|
|
caller_agent?: string | null;
|
|||
|
|
question?: string;
|
|||
|
|
generated_sql?: string | null;
|
|||
|
|
access_tables?: string[];
|
|||
|
|
status?: string;
|
|||
|
|
error_code?: string | null;
|
|||
|
|
error_message?: string | null;
|
|||
|
|
row_count?: number;
|
|||
|
|
truncated?: boolean;
|
|||
|
|
elapsed_ms?: number | null;
|
|||
|
|
trace_id?: string | null;
|
|||
|
|
create_time?: string | null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export interface Nl2SqlHealth {
|
|||
|
|
[component: string]: unknown;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export interface QueryRole {
|
|||
|
|
id?: number;
|
|||
|
|
employee_role?: string;
|
|||
|
|
max_rows?: number;
|
|||
|
|
active?: boolean;
|
|||
|
|
[key: string]: unknown;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export interface TablePermission {
|
|||
|
|
id?: number;
|
|||
|
|
table_name?: string;
|
|||
|
|
active?: boolean;
|
|||
|
|
[key: string]: unknown;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export interface ColumnPermission {
|
|||
|
|
id?: number;
|
|||
|
|
table_name?: string;
|
|||
|
|
column_name?: string;
|
|||
|
|
active?: boolean;
|
|||
|
|
[key: string]: unknown;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export interface SensitiveField {
|
|||
|
|
id?: number;
|
|||
|
|
table_name?: string;
|
|||
|
|
column_name?: string;
|
|||
|
|
mask_type?: string;
|
|||
|
|
active?: boolean;
|
|||
|
|
[key: string]: unknown;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export interface MaintenanceJobResult {
|
|||
|
|
name?: string;
|
|||
|
|
status?: string;
|
|||
|
|
attempts?: number;
|
|||
|
|
detail?: unknown;
|
|||
|
|
error_type?: string | null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export type MaintenanceTask =
|
|||
|
|
| "metadata_sync"
|
|||
|
|
| "vector_cleanup"
|
|||
|
|
| "consistency_check"
|
|||
|
|
| "history_cleanup";
|
|||
|
|
|
|||
|
|
function qs(params: Record<string, string | number | undefined | null>) {
|
|||
|
|
const search = new URLSearchParams();
|
|||
|
|
for (const [key, value] of Object.entries(params)) {
|
|||
|
|
if (value !== undefined && value !== null && value !== "") search.set(key, String(value));
|
|||
|
|
}
|
|||
|
|
const text = search.toString();
|
|||
|
|
return text ? `?${text}` : "";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export const nl2sqlApi = {
|
|||
|
|
/* ---------------------------------------------------------- 查询域(11) */
|
|||
|
|
|
|||
|
|
query: (body: {
|
|||
|
|
question: string;
|
|||
|
|
session_id?: string;
|
|||
|
|
caller_agent?: string;
|
|||
|
|
max_rows?: number;
|
|||
|
|
include_sql?: boolean;
|
|||
|
|
page?: number;
|
|||
|
|
page_size?: number;
|
|||
|
|
sort_by?: string;
|
|||
|
|
sort_order?: "asc" | "desc";
|
|||
|
|
}) => apiFetch<Nl2SqlQueryResult>("/nl2sql/query", { method: "POST", body: JSON.stringify(body) }),
|
|||
|
|
|
|||
|
|
health: () => apiFetch<Nl2SqlHealth>("/nl2sql/health"),
|
|||
|
|
|
|||
|
|
explain: (sql: string) =>
|
|||
|
|
apiFetch<Record<string, unknown>[]>("/nl2sql/query/explain", {
|
|||
|
|
method: "POST",
|
|||
|
|
body: JSON.stringify({ sql }),
|
|||
|
|
}),
|
|||
|
|
|
|||
|
|
history: (params: {
|
|||
|
|
page?: number;
|
|||
|
|
page_size?: number;
|
|||
|
|
status?: string;
|
|||
|
|
start_time?: string;
|
|||
|
|
end_time?: string;
|
|||
|
|
} = {}) =>
|
|||
|
|
apiFetch<{ page?: number; page_size?: number; items?: QueryHistoryItem[] }>(
|
|||
|
|
`/nl2sql/query-history${qs(params)}`
|
|||
|
|
),
|
|||
|
|
|
|||
|
|
historyDetail: (queryId: string) =>
|
|||
|
|
apiFetch<QueryHistoryItem>(`/nl2sql/query-history/${encodeURIComponent(queryId)}`),
|
|||
|
|
|
|||
|
|
exportHistory: async (queryId: string) => {
|
|||
|
|
const blob = await apiFetchBlob(`/nl2sql/query-history/${encodeURIComponent(queryId)}/export`);
|
|||
|
|
downloadBlob(blob, `nl2sql-${queryId}.csv`);
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
running: () => apiFetch<Record<string, unknown>[]>("/nl2sql/query/running"),
|
|||
|
|
|
|||
|
|
kill: (queryId: string) =>
|
|||
|
|
apiFetch<{ query_id?: string; verified?: boolean }>("/nl2sql/query/kill", {
|
|||
|
|
method: "POST",
|
|||
|
|
body: JSON.stringify({ query_id: queryId }),
|
|||
|
|
}),
|
|||
|
|
|
|||
|
|
diagnostics: () =>
|
|||
|
|
apiFetch<{
|
|||
|
|
health?: Nl2SqlHealth;
|
|||
|
|
running?: Record<string, unknown>[];
|
|||
|
|
metrics?: Record<string, unknown>;
|
|||
|
|
recent?: unknown[];
|
|||
|
|
}>("/nl2sql/query/diagnostics"),
|
|||
|
|
|
|||
|
|
invalidateCache: (tableNames: string[]) =>
|
|||
|
|
apiFetch<Record<string, unknown>>("/nl2sql/cache/invalidate", {
|
|||
|
|
method: "POST",
|
|||
|
|
body: JSON.stringify({ table_names: tableNames }),
|
|||
|
|
}),
|
|||
|
|
|
|||
|
|
/* ------------------------------------------------------ 管理域(20) */
|
|||
|
|
|
|||
|
|
roles: () => apiFetch<QueryRole[]>("/nl2sql/admin/roles"),
|
|||
|
|
|
|||
|
|
roleTables: (roleId: number) =>
|
|||
|
|
apiFetch<TablePermission[]>(`/nl2sql/admin/roles/${roleId}/tables`),
|
|||
|
|
|
|||
|
|
roleColumns: (roleId: number) =>
|
|||
|
|
apiFetch<ColumnPermission[]>(`/nl2sql/admin/roles/${roleId}/columns`),
|
|||
|
|
|
|||
|
|
sensitiveFields: () => apiFetch<SensitiveField[]>("/nl2sql/admin/sensitive-fields"),
|
|||
|
|
|
|||
|
|
metrics: () => apiFetch<Record<string, unknown>>("/nl2sql/admin/metrics"),
|
|||
|
|
|
|||
|
|
metricsPrometheus: () =>
|
|||
|
|
apiFetch<unknown>("/nl2sql/admin/metrics/prometheus"),
|
|||
|
|
|
|||
|
|
runtimeConfig: () => apiFetch<Record<string, unknown>>("/nl2sql/admin/runtime-config"),
|
|||
|
|
|
|||
|
|
runJob: (task: MaintenanceTask, beforeDays = 180) =>
|
|||
|
|
apiFetch<MaintenanceJobResult>("/nl2sql/admin/jobs", {
|
|||
|
|
method: "POST",
|
|||
|
|
body: JSON.stringify({ task, before_days: beforeDays }),
|
|||
|
|
}),
|
|||
|
|
|
|||
|
|
jobHistory: (params: { page?: number; page_size?: number; status?: string } = {}) =>
|
|||
|
|
apiFetch<{ items?: Record<string, unknown>[]; page?: number; page_size?: number }>(
|
|||
|
|
`/nl2sql/admin/jobs/history${qs(params)}`
|
|||
|
|
),
|
|||
|
|
|
|||
|
|
semantics: () => apiFetch<Record<string, unknown>>("/nl2sql/admin/semantics"),
|
|||
|
|
|
|||
|
|
refreshSemantics: () =>
|
|||
|
|
apiFetch<Record<string, unknown>>("/nl2sql/admin/semantics/refresh", { method: "POST" }),
|
|||
|
|
};
|