/**
|
* 附件字段兼容工具
|
*
|
* 后端各模块的附件字段名与形态不统一:
|
* 对象数组:storageBlobVOs(回显) / attachmentList / fileList,项含 url||previewURL||fileUrl||path
|
* 逗号字符串:attachmentUrls / attachmentIds
|
* 页面统一转成 [{url}] 交给 CommonUpload,提交时再按各模块约定转回。
|
*/
|
import config from "@/config";
|
import { getToken } from "@/utils/auth";
|
|
/**
|
* 任意形态的附件数据 → 对象数组(每项保证有可渲染的 url)
|
*/
|
export function toFileList(source) {
|
if (!source) return [];
|
if (Array.isArray(source)) {
|
return source
|
.map(item => {
|
if (typeof item === "string") return item ? { url: item } : null;
|
const url = item?.url || item?.previewURL || item?.fileUrl || item?.path;
|
return url ? { ...item, url } : null;
|
})
|
.filter(Boolean);
|
}
|
if (typeof source === "string") {
|
return source
|
.split(",")
|
.map(part => part.trim())
|
.filter(Boolean)
|
.map(url => ({ url }));
|
}
|
return [];
|
}
|
|
/**
|
* 对象数组 / 字符串数组 → 逗号分隔字符串(attachmentUrls 这类后端字段要的形态)
|
*/
|
export function toUrlString(fileList) {
|
return (fileList || [])
|
.map(item =>
|
typeof item === "string" ? item : item?.url || item?.previewURL || ""
|
)
|
.filter(Boolean)
|
.join(",");
|
}
|
|
/**
|
* 附件 url → 可下载的完整地址
|
* 附件接口回的常是 /profile/upload/... 这类后端相对路径,直接丢给 uni.downloadFile 会失败,
|
* 按管理端 getRealUrl 的做法补上 baseUrl。
|
*/
|
export function resolveFileUrl(url) {
|
const target = String(url ?? "").trim();
|
if (!target) return "";
|
if (/^https?:\/\//i.test(target)) return target;
|
return `${config.baseUrl}${target.startsWith("/") ? "" : "/"}${target}`;
|
}
|
|
/**
|
* 打开附件:request.ts 未透传 responseType,blob 下载不可用,
|
* 只能 downloadFile 到临时文件再 openDocument。
|
*/
|
export function openFile(url) {
|
const target = resolveFileUrl(url);
|
if (!target) {
|
uni.showToast({ title: "文件地址无效", icon: "none" });
|
return;
|
}
|
uni.showLoading({ title: "打开中...", mask: true });
|
uni.downloadFile({
|
url: target,
|
header: { Authorization: "Bearer " + getToken() },
|
success: res => {
|
if (res.statusCode !== 200) {
|
uni.showToast({ title: "文件下载失败", icon: "none" });
|
return;
|
}
|
uni.openDocument({
|
filePath: res.tempFilePath,
|
showMenu: true,
|
fail: () => uni.showToast({ title: "暂不支持预览该文件", icon: "none" }),
|
});
|
},
|
fail: () => uni.showToast({ title: "文件下载失败", icon: "none" }),
|
complete: () => uni.hideLoading(),
|
});
|
}
|
|
/**
|
* 后端生成文件(PDF/Word)并下载打开。
|
*
|
* 这类接口是 POST + body,而 uni.downloadFile 只支持 GET,所以只能先用
|
* uni.request 拿 arraybuffer,再落到 USER_DATA_PATH 后 openDocument。
|
* uni.getFileSystemManager 在 H5 不存在,H5 下会提示不支持。
|
*
|
* @param {string} path 接口路径,如 /quality/qualityInspect/downPdf
|
* @param {object} data 请求体
|
* @param {string} fileName 落盘文件名(含后缀)
|
*/
|
export function downloadFileByPost(path, data = {}, fileName = "download.pdf") {
|
uni.showLoading({ title: "生成中...", mask: true });
|
return new Promise((resolve, reject) => {
|
uni.request({
|
url: `${config.baseUrl}${path}`,
|
method: "POST",
|
data,
|
responseType: "arraybuffer",
|
header: {
|
Authorization: "Bearer " + getToken(),
|
"Content-Type": "application/json",
|
},
|
success: res => {
|
const contentType = String(
|
res.header?.["Content-Type"] || res.header?.["content-type"] || ""
|
);
|
// 后端出错时回的是 JSON(code/msg),照原样写成 pdf 会得到一个打不开的文件
|
if (res.statusCode !== 200 || contentType.includes("application/json")) {
|
uni.showToast({ title: "生成文件失败", icon: "none" });
|
reject(new Error("生成文件失败"));
|
return;
|
}
|
const fs = uni.getFileSystemManager && uni.getFileSystemManager();
|
if (!fs) {
|
uni.showToast({ title: "当前环境不支持下载文件", icon: "none" });
|
reject(new Error("unsupported"));
|
return;
|
}
|
const filePath = `${uni.env.USER_DATA_PATH}/${fileName}`;
|
fs.writeFile({
|
filePath,
|
data: res.data,
|
encoding: "binary",
|
success: () => {
|
uni.openDocument({
|
filePath,
|
showMenu: true,
|
fail: () =>
|
uni.showToast({ title: "暂不支持预览该文件", icon: "none" }),
|
});
|
resolve(filePath);
|
},
|
fail: () => {
|
uni.showToast({ title: "文件保存失败", icon: "none" });
|
reject(new Error("文件保存失败"));
|
},
|
});
|
},
|
fail: () => {
|
uni.showToast({ title: "生成文件失败", icon: "none" });
|
reject(new Error("生成文件失败"));
|
},
|
complete: () => uni.hideLoading(),
|
});
|
});
|
}
|