gaoluyang
2 小时以前 e449a5408265e4bd1f6c66f5be28a42efac444ee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/**
 * 附件字段兼容工具
 *
 * 后端各模块的附件字段名与形态不统一:
 *   对象数组: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(),
    });
  });
}