| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990 |
- /**
- * 附件上传到 DMS 的文件服务(`POST {DMS}/file/uploadFile`)。
- *
- * **实测契约(2026-09-23,打真实服务)**:
- * - `multipart/form-data`,**五个字段都必填**:
- * `file` / `type` / `columnId` / `contentId` / `paraName` ——
- * 少任何一个都返回 `{"code":-1,"message":"缺少必传字段"}`
- * - `type` 决定**存储目录**:`0` 图 → `/static/photo/…`;`1` 音 / `2` 视 / `3` 文件 → `/static/file/…`
- * - 成功返回 `{"code":200,"message":"上传成功!","content":"/static/photo/1889-c_question-<uuid>.png"}`
- * —— **`content` 就是那个相对路径**
- * - ⚠️ 返回的相对路径**当前直接取不到**(10081 / 10011 都 404)——
- * 所以聊天里的缩略图**不能拿它当 `<img>` 的 src**,预览要用本地 blob(见上传模块)
- * - ⚠️ 走 `/dms-api` 代理:页面是 HTTPS、接口是 HTTP,直连会被混合内容拦掉
- * (代理已注入 DMS token,实测这个端点不校验 token 也无妨)
- *
- * 这个相对路径要放进聊天请求体的 `pictures` / `files` 里(用户 2026-09-23 指定)。
- */
- import { getDmsApiBaseUrl } from "@/utils/runtime-config";
- /**
- * 上传时随文件一起提交的三个 DMS 定位字段(**会进文件名**)。
- *
- * 取值由用户 2026-09-23 指定:附件按「属于 1889 助手问答记录的问题内容」落库 ——
- * 会话/问答记录都在 1889,附件跟着问题走。
- */
- export const DMS_ATTACHMENT_COLUMN_ID = 1889;
- export const DMS_ATTACHMENT_CONTENT_ID = 0;
- export const DMS_ATTACHMENT_PARA_NAME = "c_question";
- /** `type`:0 图 · 1 音 · 2 视 · 3 文件(实测 0 与 3 的差别就是落在 photo/ 还是 file/ 目录) */
- export const DMS_ATTACHMENT_TYPE_IMAGE = "0";
- export const DMS_ATTACHMENT_TYPE_FILE = "3";
- /**
- * 把上传返回的**相对路径**变成一个**可显示**的地址(用于聊天里的缩略图预览)。
- *
- * 实测(2026-09-23):相对路径本身取不到(10081 / 10011 的根路径都 404),
- * 但**在 DMS 主机前加上 `/dms` 就能取到** ——
- * `http://121.43.55.7:10081/dms/static/photo/….png` → **200**。
- * 而 `/dms-api` 代理补的正好就是 `/dms`,所以这里直接拼代理前缀即可。
- *
- * ⚠️ 存进消息里的就是这个地址:它依赖代理前缀保持不变;
- * 发给**后端**的仍是相对路径(见 `toChatAttachmentUrls` 用的 `fileUrl` 字段),两者不要混。
- */
- export const buildDmsFileDisplayUrl = (relativePath: string): string => {
- const path = String(relativePath || "").trim();
- if (!path) return "";
- if (/^https?:\/\//i.test(path)) return path; // 已经是绝对地址就原样返回
- const base = getDmsApiBaseUrl();
- return base ? `${base}${path.startsWith("/") ? "" : "/"}${path}` : "";
- };
- /**
- * 上传一个附件,返回**相对路径**(如 `/static/photo/1889-c_question-<uuid>.png`)。
- * 任何失败都抛 `Error`(消息可直接给用户看),由调用方更新上传项状态。
- */
- export const uploadDmsAttachment = async (
- file: File,
- options: { isImage: boolean; signal?: AbortSignal }
- ): Promise<string> => {
- const base = getDmsApiBaseUrl();
- if (!base) {
- throw new Error("未配置 DMS 接口地址,无法上传附件");
- }
- const form = new FormData();
- form.append("file", file);
- form.append("type", options.isImage ? DMS_ATTACHMENT_TYPE_IMAGE : DMS_ATTACHMENT_TYPE_FILE);
- form.append("columnId", String(DMS_ATTACHMENT_COLUMN_ID));
- form.append("contentId", String(DMS_ATTACHMENT_CONTENT_ID));
- form.append("paraName", DMS_ATTACHMENT_PARA_NAME);
- const response = await fetch(`${base}/file/uploadFile`, {
- method: "POST",
- body: form,
- signal: options.signal,
- });
- if (!response.ok) {
- throw new Error(`上传失败(HTTP ${response.status})`);
- }
- const payload = await response.json().catch(() => null);
- const path = String(payload?.content ?? "").trim();
- if (payload?.code !== 200 || !path) {
- throw new Error(String(payload?.message || "上传失败"));
- }
- return path;
- };
|