import type { InternalAxiosRequestConfig } from '@vben/request';
|
|
import { RequestClient } from '@vben/request';
|
import { useAccessStore } from '@vben/stores';
|
|
import { requestClient } from '#/api/request';
|
|
/**
|
* Python 智能体服务不在 /admin-api 下,开发期由 Vite 代理 /agent-api 转发到 127.0.0.1:8091。
|
* 该服务直接返回业务 JSON,不使用 CommonResult 包装,因此单独建客户端。
|
*/
|
const agentRequestClient = new RequestClient({
|
baseURL: '/agent-api',
|
responseReturn: 'body',
|
timeout: 120_000,
|
});
|
|
agentRequestClient.addRequestInterceptor({
|
fulfilled: (config: InternalAxiosRequestConfig) => {
|
const token = useAccessStore().accessToken;
|
if (token) {
|
config.headers.Authorization = `Bearer ${token}`;
|
}
|
return config;
|
},
|
});
|
|
export namespace MdmAgentImportApi {
|
export type RowAction = 'CREATE' | 'SKIP' | 'BLOCKED';
|
export type RowStatus = 'SUCCESS' | 'FAILED' | 'SKIPPED' | 'UNKNOWN';
|
|
export interface Evidence {
|
sheet: string;
|
row: number;
|
column: string;
|
raw: string;
|
}
|
|
export interface Candidate {
|
candidate_id: string;
|
source_sha256: string;
|
values: Record<string, string>;
|
evidence: Record<string, Evidence>;
|
issues: string[];
|
}
|
|
export interface Issue {
|
code?: string;
|
field?: string;
|
message: string;
|
retryable?: boolean;
|
}
|
|
export interface Resolved {
|
category_id?: number;
|
category_name?: string;
|
unit_measure_id?: number;
|
unit_measure_name?: string;
|
}
|
|
export interface PreflightRow {
|
candidate_id: string;
|
row_no?: number;
|
code?: string;
|
name?: string;
|
action: RowAction;
|
resolved?: Resolved;
|
blockers?: Issue[];
|
warnings?: Issue[];
|
target_item_id?: number;
|
}
|
|
export interface Preflight {
|
preflight_hash: string;
|
source: {
|
attachment_id: number;
|
session_id?: number;
|
source_sha256: string;
|
proposal_revision?: string;
|
};
|
policy: {
|
update_allowed: boolean;
|
mes_sync_allowed: boolean;
|
max_rows: number;
|
};
|
summary: {
|
total: number;
|
create: number;
|
skip: number;
|
blocked: number;
|
};
|
can_commit: boolean;
|
side_effects: string[];
|
rows: PreflightRow[];
|
blocking_items: Issue[];
|
}
|
|
export interface Correction {
|
candidate_id: string;
|
field: 'categoryCode' | 'code' | 'name' | 'specification' | 'unitMeasureCode';
|
value: string;
|
reason: string;
|
}
|
|
export interface ReceiptRow {
|
candidate_id: string;
|
row_no?: number;
|
code?: string;
|
name?: string;
|
action: 'CREATE' | 'SKIP';
|
status: RowStatus;
|
target_item_id?: number;
|
target_version?: string;
|
error_code?: string;
|
error_message?: string;
|
retryable?: boolean;
|
}
|
|
export interface Receipt {
|
command_id: string;
|
idempotency_key: string;
|
status: 'FAILED' | 'PARTIAL_FAILED' | 'RUNNING' | 'SUCCEEDED' | 'UNKNOWN';
|
attachment_id: number;
|
session_id?: number;
|
source_sha256: string;
|
preflight_hash: string;
|
proposal_hash?: string;
|
summary: {
|
total: number;
|
success: number;
|
failed: number;
|
skipped: number;
|
unknown: number;
|
};
|
error_code?: string;
|
error_message?: string;
|
rows: ReceiptRow[];
|
create_time?: string;
|
completed_time?: string;
|
}
|
|
export interface ImportState {
|
task_id: string;
|
attachment_id: string;
|
filename: string;
|
source_sha256: string;
|
candidates: Candidate[];
|
issues: Array<Issue & { candidate_id?: string; candidate_ids?: string[] }>;
|
revision: number;
|
status: string;
|
preflight?: Preflight;
|
preflight_hash?: string;
|
proposal?: Record<string, unknown>;
|
proposal_hash?: string;
|
command_id?: string;
|
receipt?: Receipt;
|
last_error?: string;
|
}
|
|
export interface ReviewInterrupt {
|
type: string;
|
revision: number;
|
issues: Array<Issue & { candidate_id?: string; candidate_ids?: string[] }>;
|
candidates: Candidate[];
|
preflight: {
|
hash?: string;
|
can_commit: boolean;
|
summary?: Preflight['summary'];
|
blocking_items: Issue[];
|
needs_attention: PreflightRow[];
|
};
|
last_error?: string;
|
notice?: string;
|
}
|
|
export interface PublicState {
|
state: ImportState;
|
interrupts: ReviewInterrupt[];
|
}
|
|
export interface ReviewReq {
|
expected_revision: number;
|
action: 'cancel' | 'confirm' | 'revise';
|
corrections?: Correction[];
|
expected_preflight_hash?: string;
|
expected_proposal_hash?: string;
|
}
|
}
|
|
/** 创建补录会话(Java) */
|
export function createImportSession() {
|
return requestClient.post<number>('/agent/bridge/import-sessions');
|
}
|
|
/** 绑定附件到补录会话,返回 attachmentId(Java) */
|
export function bindImportAttachment(sessionId: number, blobId: number) {
|
return requestClient.post<number>(
|
`/agent/bridge/import-sessions/${sessionId}/attachments`,
|
{ blobId },
|
);
|
}
|
|
/** 创建智能体导入任务并触发解析与预检(Python) */
|
export function startMaterialImport(attachmentId: number) {
|
return agentRequestClient.post<MdmAgentImportApi.PublicState>(
|
'/v1/material-imports',
|
{ attachment_id: String(attachmentId) },
|
);
|
}
|
|
/** 读取任务当前状态(Python) */
|
export function getMaterialImportTask(taskId: string) {
|
return agentRequestClient.get<MdmAgentImportApi.PublicState>(
|
`/v1/material-imports/${taskId}`,
|
);
|
}
|
|
/** 修订或确认(Python) */
|
export function reviewMaterialImport(
|
taskId: string,
|
data: MdmAgentImportApi.ReviewReq,
|
) {
|
return agentRequestClient.post<MdmAgentImportApi.PublicState>(
|
`/v1/material-imports/${taskId}/review`,
|
data,
|
);
|
}
|
|
/** 查询提交回执(Python) */
|
export function getMaterialImportReceipt(taskId: string) {
|
return agentRequestClient.get<MdmAgentImportApi.Receipt>(
|
`/v1/material-imports/${taskId}/receipt`,
|
);
|
}
|
|
interface AgentErrorDetail {
|
error_code?: string;
|
message?: string;
|
}
|
|
/** 从 Python 错误响应中提取可读文案 */
|
export function agentImportErrorMessage(error: unknown): string {
|
const err = error as
|
| { data?: unknown; message?: string; response?: { data?: unknown } }
|
| undefined;
|
const body = (err?.response?.data ?? err?.data) as
|
| AgentErrorDetail
|
| string
|
| undefined;
|
const detail =
|
typeof body === 'string'
|
? body
|
: ((body as { detail?: unknown } | undefined)?.detail ?? body);
|
if (typeof detail === 'string') {
|
return detail;
|
}
|
const info = detail as AgentErrorDetail | undefined;
|
if (info?.message) {
|
return info.error_code
|
? `${info.message}(${info.error_code})`
|
: info.message;
|
}
|
return err?.message || '智能体服务请求失败';
|
}
|