Files
gongxue-base/apps/admin/src/api/imports.ts
wangziqi 8dc72d6e1b fix(admin): 编辑消息/切换会话保护、行内编辑撤销与上传进度反馈
- 编辑旧消息会删除其后全部消息时,先弹确认告知影响范围
- 有待发送附件时切换会话,先确认再丢弃(避免静默删除已上传文件)
- EditableCell 保存成功后提供 6 秒内"撤销"入口(把旧值重新保存),
  重新编辑时自动清除
- 导入向导/重新上传显示上传进度条与百分比,不再"假死"
- AI 附件上传透传进度给附件列表
- 租赁合同上传显示按钮 loading 与上传百分比
2026-08-07 17:38:21 +08:00

85 lines
2.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import api from './index';
import { validateResponse } from '../utils/validate';
import { importRunEnvelopeSchema } from './schemas';
import type {
ImportPreviewResult,
ImportReceipt,
ImportRunDetail,
ImportStageRequest,
} from '../components/ImportWizard/types';
interface ApiEnvelope<T> {
success: boolean;
data: T;
message?: string;
}
export async function createImportRun(
file: File,
options: {
source: 'ai' | 'manual';
conversationId?: number;
stages?: ImportStageRequest[];
mapping?: Record<string, Record<string, string>>;
/** 上传进度回调0-100 */
onProgress?: (percent: number) => void;
},
): Promise<ImportRunDetail> {
const form = new FormData();
form.append('file', file);
form.append('source', options.source);
if (options.conversationId) form.append('conversationId', String(options.conversationId));
if (options.stages?.length) form.append('stages', JSON.stringify(options.stages));
if (options.mapping && Object.keys(options.mapping).length > 0) {
form.append('mapping', JSON.stringify(options.mapping));
}
const res = await api.post<ApiEnvelope<ImportRunDetail>>('/imports/runs', form, {
onUploadProgress: (event) => {
if (!options.onProgress || !event.total) return;
options.onProgress(Math.min(Math.round((event.loaded / event.total) * 100), 100));
},
});
return res.data;
}
export async function getImportRun(runId: string): Promise<ImportRunDetail> {
const res = await api.get<ApiEnvelope<ImportRunDetail>>(
`/imports/runs/${encodeURIComponent(runId)}`,
);
return validateResponse<ApiEnvelope<ImportRunDetail>>(importRunEnvelopeSchema, res).data;
}
export async function previewImportStep(
runId: string,
stepKey: string,
body: { sheets?: string[]; mapping?: Record<string, string> },
): Promise<ImportPreviewResult> {
const res = await api.post<ApiEnvelope<ImportPreviewResult>>(
`/imports/runs/${encodeURIComponent(runId)}/steps/${encodeURIComponent(stepKey)}/preview`,
body,
);
return res.data;
}
export async function commitImportStep(
runId: string,
stepKey: string,
decisions: Array<{ rowId: number; action: 'create' | 'update' | 'skip' }>,
): Promise<ImportReceipt> {
const res = await api.post<ApiEnvelope<ImportReceipt>>(
`/imports/runs/${encodeURIComponent(runId)}/steps/${encodeURIComponent(stepKey)}/commit`,
{ decisions },
);
return res.data;
}
export function importErrorReportUrl(runId: string, stepKey?: string): string {
const base = import.meta.env.PROD
? '/api'
: `http://localhost:${import.meta.env.VITE_API_PORT || 3002}/api`;
const params = new URLSearchParams();
if (stepKey) params.set('stepKey', stepKey);
const query = params.toString();
return `${base}/imports/runs/${encodeURIComponent(runId)}/report${query ? `?${query}` : ''}`;
}