落地报价模板主账与后台:合同映射、灌种 SQL/脚本、智能体填表,并补测服运维探针与合同文档对齐。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
linmianxun
2026-09-14 14:09:45 +08:00
co-authored by Cursor
parent 8bdf4990a2
commit a70bce3c8f
138 changed files with 7239 additions and 1085 deletions
@@ -0,0 +1,103 @@
/**
* 报价模板 API(主账 /inquiry/quoteTemplate)。
* 列表/上传/映射/启停/样例预览;禁止浏览器直连对象存储填表以外的 TMS/LLM。
*/
import { defHttp } from '/@/utils/http/axios';
import { useGlobSetting } from '/@/hooks/setting';
import { getToken } from '/@/utils/auth';
enum Api {
list = '/inquiry/quoteTemplate/list',
upload = '/inquiry/quoteTemplate/upload',
version = '/inquiry/quoteTemplate/version',
versions = '/inquiry/quoteTemplate/versions',
mapping = '/inquiry/quoteTemplate/mapping',
enable = '/inquiry/quoteTemplate/enable',
disable = '/inquiry/quoteTemplate/disable',
setDefault = '/inquiry/quoteTemplate/setDefault',
editMeta = '/inquiry/quoteTemplate/editMeta',
previewSample = '/inquiry/quoteTemplate/previewSample',
download = '/inquiry/quoteTemplate/download',
}
export const getTemplateList = (params) => defHttp.get({ url: Api.list, params });
export const uploadTemplate = (data: FormData) =>
defHttp.post({
url: Api.upload,
data,
headers: { 'Content-Type': 'multipart/form-data' },
});
export const getTemplateVersion = (versionId: string) =>
defHttp.get({ url: Api.version, params: { versionId } });
export const listTemplateVersions = (templateId: string) =>
defHttp.get({ url: Api.versions, params: { templateId } });
export const saveTemplateMapping = (versionId: string, mappingJson: string) =>
defHttp.put({ url: Api.mapping, data: { versionId, mappingJson } });
export const enableTemplate = (templateId: string, versionId: string) =>
defHttp.post({ url: Api.enable, params: { templateId, versionId } });
export const disableTemplate = (templateId: string) =>
defHttp.post({ url: Api.disable, params: { templateId } });
export const setTemplateDefault = (templateId: string, isDefault = true) =>
defHttp.post({ url: Api.setDefault, params: { templateId, isDefault } });
export const editTemplateMeta = (params) => defHttp.put({ url: Api.editMeta, params });
/**
* 带鉴权下载样例预览 / 原文件。
* window.open+query token 遇 500 JSON 时浏览器只显示失败;改为 blob 下载并提示 message。
*/
export async function downloadTemplateFile(kind: 'previewSample' | 'download', versionId: string, fileNameHint?: string) {
const glob = useGlobSetting();
const base = (glob.apiUrl || '').replace(/\/$/, '');
const path = kind === 'previewSample' ? Api.previewSample : Api.download;
const url = `${base}${path}?versionId=${encodeURIComponent(versionId)}`;
const token = getToken() || '';
const res = await fetch(url, {
method: 'GET',
headers: {
'X-Access-Token': String(token),
},
});
const ctype = (res.headers.get('content-type') || '').toLowerCase();
if (!res.ok || ctype.includes('application/json')) {
let msg = `下载失败 HTTP ${res.status}`;
try {
const j = await res.json();
if (j?.message) msg = String(j.message);
} catch {
/* ignore */
}
throw new Error(msg);
}
const blob = await res.blob();
let name = fileNameHint || (kind === 'previewSample' ? 'preview.xlsx' : 'template.bin');
const cd = res.headers.get('content-disposition') || '';
const m = /filename\*=UTF-8''([^;]+)|filename=\"?([^\";]+)\"?/i.exec(cd);
if (m) {
name = decodeURIComponent((m[1] || m[2] || name).trim());
}
const href = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = href;
a.download = name;
document.body.appendChild(a);
a.click();
a.remove();
URL.revokeObjectURL(href);
}
/** 带 token 下载样例预览 / 原文件(新窗口,兼容旧调用) */
export function buildTemplateFileUrl(kind: 'previewSample' | 'download', versionId: string) {
const glob = useGlobSetting();
const base = (glob.apiUrl || '').replace(/\/$/, '');
const path = kind === 'previewSample' ? Api.previewSample : Api.download;
const token = getToken() || '';
return `${base}${path}?versionId=${encodeURIComponent(versionId)}&token=${encodeURIComponent(String(token))}`;
}