zmdms-utils 0.0.8 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -30,10 +30,32 @@ declare function parseQueryParams(url: string): {
30
30
  * @returns 转换过后的结果
31
31
  */
32
32
  declare function unescapeString(input: string): string;
33
+ /**
34
+ * 将一些危险字符替换成后台能识别的字符
35
+ * @param input 需要转换的内容
36
+ * @returns 转换过后的结果
37
+ */
38
+ declare function dangerouslyXss(input: string): string;
39
+ /**
40
+ * 去除特殊字符。这个方法在附件预览的场景中有用到
41
+ */
42
+ declare function specialString(input: string): string;
33
43
  /**
34
44
  * 将内容复制到粘贴板中
35
45
  * @param text 需要复制的内容
36
46
  */
37
47
  declare function copyToClipboard(text: string, callback?: any): void;
48
+ /**
49
+ * 获取文件名中的后缀 返回文件名 + 后缀
50
+ * @param fileName 文件名
51
+ * @returns
52
+ */
53
+ declare function getFileExtension(fileName: string): [string, string];
54
+ /**
55
+ * 判断后缀是否符合图片格式
56
+ * @param extension 后缀
57
+ * @returns
58
+ */
59
+ declare function isImageExtension(extension: string): boolean;
38
60
 
39
- export { addThousedSeparator, copyToClipboard, delay, emitter, parseQueryParams, unescapeString };
61
+ export { addThousedSeparator, copyToClipboard, dangerouslyXss, delay, emitter, getFileExtension, isImageExtension, parseQueryParams, specialString, unescapeString };
package/dist/es/common.js CHANGED
@@ -108,6 +108,35 @@ function unescapeString(input) {
108
108
  return escapedChars[match] || match;
109
109
  });
110
110
  }
111
+ /**
112
+ * 将一些危险字符替换成后台能识别的字符
113
+ * @param input 需要转换的内容
114
+ * @returns 转换过后的结果
115
+ */
116
+ function dangerouslyXss(input) {
117
+ if (!input) {
118
+ return "";
119
+ }
120
+ var escapedChars = {
121
+ lt: "",
122
+ gt: "",
123
+ nbsp: " ",
124
+ amp: "&",
125
+ quot: '"',
126
+ };
127
+ return input.replace(/&(amp|lt|gt|quot|nbsp);/g, function (match) {
128
+ return escapedChars[match] || match;
129
+ });
130
+ }
131
+ /**
132
+ * 去除特殊字符。这个方法在附件预览的场景中有用到
133
+ */
134
+ function specialString(input) {
135
+ if (!input) {
136
+ return "";
137
+ }
138
+ return input.replace(/[~!@#$%^&*{}|]/g, "");
139
+ }
111
140
  /**
112
141
  * 将内容复制到粘贴板中
113
142
  * @param text 需要复制的内容
@@ -139,5 +168,39 @@ function copyToClipboard(text, callback) {
139
168
  callback && callback(0);
140
169
  }
141
170
  }
171
+ /**
172
+ * 获取文件名中的后缀 返回文件名 + 后缀
173
+ * @param fileName 文件名
174
+ * @returns
175
+ */
176
+ function getFileExtension(fileName) {
177
+ if (!fileName) {
178
+ return ["", ""];
179
+ }
180
+ var lastPointIndex = fileName.lastIndexOf("."); // 从最后取点
181
+ var filePreName = fileName.substring(0, lastPointIndex); // 前面的名字
182
+ var fileExtension = fileName.substring(lastPointIndex + 1); // 后面的文件后缀
183
+ return [filePreName, fileExtension];
184
+ }
185
+ /**
186
+ * 判断后缀是否符合图片格式
187
+ * @param extension 后缀
188
+ * @returns
189
+ */
190
+ function isImageExtension(extension) {
191
+ var imageExtensions = [
192
+ "jpg",
193
+ "png",
194
+ "jpeg",
195
+ "gif",
196
+ "tif",
197
+ "tga",
198
+ "bmp",
199
+ "dds",
200
+ "svg",
201
+ "webp",
202
+ ];
203
+ return imageExtensions.includes(extension.toLowerCase());
204
+ }
142
205
 
143
- export { addThousedSeparator, copyToClipboard, delay, emitter, parseQueryParams, unescapeString };
206
+ export { addThousedSeparator, copyToClipboard, dangerouslyXss, delay, emitter, getFileExtension, isImageExtension, parseQueryParams, specialString, unescapeString };
@@ -0,0 +1,90 @@
1
+ /**
2
+ * 附件下载方法
3
+ * @param fileId 附件id
4
+ * @param fileName 附件名称
5
+ * @param options
6
+ * @param options.API_BASEURL {string} 接口请求的前缀地址 必传
7
+ * @param options.authToken {string} token 非必传
8
+ * @param options.waterMark {boolean | string} 是否添加水印 是否指定水印名称 非必传
9
+ * @param options.open boolean 是否不需要登录信息
10
+ */
11
+ declare function downloadFile(fileId: string, fileName: string, options: IDownloadOptions): Promise<unknown>;
12
+ /**
13
+ * 附件批量下载方法
14
+ * @param fileList 附件列表
15
+ * @param options.API_BASEURL {string} 接口请求的前缀地址 必传
16
+ * @param options.authToken {string} token 非必传
17
+ * @param options.waterMark {boolean | string} 是否添加水印 是否指定水印名称 非必传
18
+ * @param options.zipName string zip名字
19
+ * @returns
20
+ */
21
+ declare function batchDownloadFiles(fileList: {
22
+ attachId: string;
23
+ attachName: string;
24
+ [props: string]: string;
25
+ }[], options: IBatchDownloadOptions): Promise<unknown>;
26
+ /**
27
+ * 附件预览。如果传入的附件是图片,那么实现批量预览
28
+ * @param fileId 附件id
29
+ * @param fileName 附件名称
30
+ * @param options
31
+ * @param options.API_BASEURL {string} 接口请求的前缀地址 必传
32
+ * @param options.authToken {string} token 非必传
33
+ * @param options.fileList { attachId: string, attachName: string ... }[] 附件列表。批量预览时有用
34
+ */
35
+ declare function previewFile(fileId: string, fileName: string, options: IPreviewOptions): void;
36
+ /**
37
+ * 生成附件下载链接
38
+ * @param fileId 附件id
39
+ * @param options
40
+ * @param options.API_BASEURL {string} 接口请求的前缀地址 非必传
41
+ * @param options.authToken {string} token 非必传
42
+ * @returns
43
+ */
44
+ declare function createDownloadLink(fileId: string, options?: IDownloadLinkOptions): string;
45
+ /**
46
+ * 生成原始图片路径
47
+ * @param fileId 附件id
48
+ * @param fileName 附件名称
49
+ * @param options
50
+ * @param options.API_BASEURL {string} 接口请求的前缀地址 非必传
51
+ * @param options.authToken {string} token 非必传
52
+ * @returns
53
+ */
54
+ declare function createOriginalLink(fileId: string, fileName: string, options?: IOriginLinkOptions): string;
55
+ declare function createThumbnailLink(fileId: string, fileName: string, options: IThumbnailLinkOptions): string;
56
+ interface IOptions {
57
+ API_BASEURL: string;
58
+ authToken?: string;
59
+ }
60
+ interface IDownloadOptions extends IOptions {
61
+ /** 是否添加水印 */
62
+ waterMark?: boolean | string;
63
+ /** 是否开发不需要登录信息 */
64
+ open?: boolean;
65
+ }
66
+ interface IBatchDownloadOptions extends IOptions {
67
+ zipName: string;
68
+ /** 是否添加水印 */
69
+ waterMark?: boolean | string;
70
+ }
71
+ interface IDownloadLinkOptions extends Partial<IOptions> {
72
+ /** 不需要登录信息的附件下载链接 */
73
+ open?: boolean;
74
+ }
75
+ interface IPreviewOptions extends IOptions {
76
+ /** 附件列表 */
77
+ fileList?: {
78
+ attachId: string;
79
+ attachName: string;
80
+ [props: string]: string;
81
+ }[];
82
+ }
83
+ interface IOriginLinkOptions extends Partial<IOptions> {
84
+ }
85
+ interface IThumbnailLinkOptions extends Partial<IOptions> {
86
+ /** 缩放比例 */
87
+ scale?: number;
88
+ }
89
+
90
+ export { batchDownloadFiles, createDownloadLink, createOriginalLink, createThumbnailLink, downloadFile, previewFile };
@@ -0,0 +1,222 @@
1
+ import { getToken } from './auth.js';
2
+ import { dangerouslyXss, specialString, getFileExtension, isImageExtension } from './common.js';
3
+
4
+ /**
5
+ * 附件相关接口
6
+ */
7
+ /**
8
+ * 附件下载方法
9
+ * @param fileId 附件id
10
+ * @param fileName 附件名称
11
+ * @param options
12
+ * @param options.API_BASEURL {string} 接口请求的前缀地址 必传
13
+ * @param options.authToken {string} token 非必传
14
+ * @param options.waterMark {boolean | string} 是否添加水印 是否指定水印名称 非必传
15
+ * @param options.open boolean 是否不需要登录信息
16
+ */
17
+ function downloadFile(fileId, fileName, options) {
18
+ var API_BASEURL = options.API_BASEURL, authToken = options.authToken, _a = options.waterMark, waterMark = _a === void 0 ? true : _a, open = options.open;
19
+ return new Promise(function (resolve, reject) {
20
+ var xhr = new XMLHttpRequest();
21
+ // 获取请求基础数据
22
+ var _a = getBasicInfo(API_BASEURL, authToken), token = _a.token, apiBaseURL = _a.apiBaseURL;
23
+ if (open) {
24
+ xhr.open("GET", "".concat(apiBaseURL, "/api/zmdms-resource/oss/endpoint/public/download-file/").concat(fileId), true);
25
+ }
26
+ else {
27
+ xhr.open("GET", "".concat(apiBaseURL, "/api/zmdms-resource/oss/endpoint/download-file/").concat(fileId, "?Zmdms-Auth=bearer ").concat(token, "&addWaterMark=").concat(waterMark), true);
28
+ }
29
+ xhr.responseType = "blob";
30
+ xhr.onload = function () {
31
+ if (xhr.status === 200 || xhr.status === 201) {
32
+ var link = document.createElement("a");
33
+ var body = document.querySelector("body");
34
+ link.href = window.URL.createObjectURL(xhr.response);
35
+ link.download = dangerouslyXss(fileName);
36
+ // fix Firefox
37
+ link.style.display = "none";
38
+ body.appendChild(link);
39
+ link.click();
40
+ body.removeChild(link);
41
+ window.URL.revokeObjectURL(link.href);
42
+ resolve({ msg: "文件下载成功!" });
43
+ }
44
+ else {
45
+ reject();
46
+ }
47
+ };
48
+ xhr.onerror = function (err) {
49
+ reject(err);
50
+ };
51
+ xhr.send();
52
+ });
53
+ }
54
+ /**
55
+ * 附件批量下载方法
56
+ * @param fileList 附件列表
57
+ * @param options.API_BASEURL {string} 接口请求的前缀地址 必传
58
+ * @param options.authToken {string} token 非必传
59
+ * @param options.waterMark {boolean | string} 是否添加水印 是否指定水印名称 非必传
60
+ * @param options.zipName string zip名字
61
+ * @returns
62
+ */
63
+ function batchDownloadFiles(fileList, options) {
64
+ var API_BASEURL = options.API_BASEURL, authToken = options.authToken, zipName = options.zipName, _a = options.waterMark, waterMark = _a === void 0 ? true : _a;
65
+ return new Promise(function (resolve, reject) {
66
+ var _a, _b, _c, _d, _e, _f;
67
+ var xhr = new XMLHttpRequest();
68
+ // 获取请求基础数据
69
+ var _g = getBasicInfo(API_BASEURL, authToken), token = _g.token, apiBaseURL = _g.apiBaseURL;
70
+ xhr.open("POST", "".concat(apiBaseURL, "/api/zmdms-resource/oss/endpoint/batch-download-file"), true);
71
+ xhr.responseType = "blob";
72
+ xhr.onload = function () {
73
+ if (xhr.status === 200 || xhr.status === 201) {
74
+ var link = document.createElement("a");
75
+ var body = document.querySelector("body");
76
+ link.href = window.URL.createObjectURL(xhr.response);
77
+ link.download = zipName;
78
+ // fix Firefox
79
+ link.style.display = "none";
80
+ body.appendChild(link);
81
+ link.click();
82
+ body.removeChild(link);
83
+ window.URL.revokeObjectURL(link.href);
84
+ resolve({ msg: "文件下载成功!" });
85
+ }
86
+ else {
87
+ reject();
88
+ }
89
+ };
90
+ xhr.onerror = function (err) {
91
+ reject(err);
92
+ };
93
+ xhr.setRequestHeader("Zmdms-Auth", token || "");
94
+ xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
95
+ var fileIds = (_c = (_b = (_a = fileList === null || fileList === void 0 ? void 0 : fileList.map) === null || _a === void 0 ? void 0 : _a.call(fileList, function (item) { return item.attachId; })) === null || _b === void 0 ? void 0 : _b.join) === null || _c === void 0 ? void 0 : _c.call(_b, ",");
96
+ var fileNames = (_f = (_e = (_d = fileList === null || fileList === void 0 ? void 0 : fileList.map) === null || _d === void 0 ? void 0 : _d.call(fileList, function (item) { return item.attachName; })) === null || _e === void 0 ? void 0 : _e.join) === null || _f === void 0 ? void 0 : _f.call(_e, ",");
97
+ xhr.send("attachIds=".concat(fileIds, "&fileNames=").concat(fileNames, "&zipName=").concat(zipName, "&addWaterMark=").concat(waterMark));
98
+ });
99
+ }
100
+ /**
101
+ * 附件预览。如果传入的附件是图片,那么实现批量预览
102
+ * @param fileId 附件id
103
+ * @param fileName 附件名称
104
+ * @param options
105
+ * @param options.API_BASEURL {string} 接口请求的前缀地址 必传
106
+ * @param options.authToken {string} token 非必传
107
+ * @param options.fileList { attachId: string, attachName: string ... }[] 附件列表。批量预览时有用
108
+ */
109
+ function previewFile(fileId, fileName, options) {
110
+ var API_BASEURL = options.API_BASEURL, authToken = options.authToken, _a = options.fileList, fileList = _a === void 0 ? [] : _a;
111
+ // 获取请求基础数据
112
+ var _b = getBasicInfo(API_BASEURL, authToken), token = _b.token, apiBaseURL = _b.apiBaseURL;
113
+ // 处理附件名中的一些特殊字符
114
+ var previewFileName = dangerouslyXss(fileName);
115
+ try {
116
+ previewFileName = specialString(previewFileName);
117
+ }
118
+ catch (err) {
119
+ console.log(err);
120
+ }
121
+ // 获取文件后缀
122
+ var _c = getFileExtension(previewFileName), filePreName = _c[0], fileExtension = _c[1];
123
+ // 由于预览使用了文件名地址作为iframe的路径
124
+ // 如果文件名没变,文件内容改变。这样就会导致再次预览时 内容不会更新
125
+ // 所以将文件名 与 文件id组合来生成不同的文件名
126
+ previewFileName = "".concat(filePreName, "-").concat(fileId, ".").concat(fileExtension);
127
+ // 如果是图片 走批量预览接口
128
+ var isImage = isImageExtension(fileExtension);
129
+ if (isImage) {
130
+ var imgFiles = fileList.filter(function (item) {
131
+ var attachName = item.attachName, attachId = item.attachId;
132
+ var _a = getFileExtension(attachName), fileExtension = _a[1];
133
+ if (isImageExtension(fileExtension) && attachId !== fileId) {
134
+ return true;
135
+ }
136
+ return false;
137
+ });
138
+ var attachIds = imgFiles.map(function (item) { return item.attachId; }).join(",");
139
+ // 批量图片预览
140
+ window.open("".concat(apiBaseURL, "/picturesAttchPreview?attachIds=").concat(attachIds ? "".concat(fileId, ",").concat(attachIds) : fileId, "&Zmdms-Auth=bearer ").concat(token) + fileName
141
+ ? "&titleName=".concat(encodeURIComponent(previewFileName))
142
+ : "");
143
+ }
144
+ else {
145
+ // 普通预览
146
+ window.open("".concat(apiBaseURL, "/attchPreview?attachId=").concat(fileId, "&Zmdms-Auth=bearer ").concat(token, "&officePreviewType=pdf") +
147
+ fileName
148
+ ? "&titleName=".concat(encodeURIComponent(previewFileName))
149
+ : "");
150
+ }
151
+ }
152
+ /**
153
+ * 生成附件下载链接
154
+ * @param fileId 附件id
155
+ * @param options
156
+ * @param options.API_BASEURL {string} 接口请求的前缀地址 非必传
157
+ * @param options.authToken {string} token 非必传
158
+ * @returns
159
+ */
160
+ function createDownloadLink(fileId, options) {
161
+ if (options === void 0) { options = {}; }
162
+ var API_BASEURL = options.API_BASEURL, authToken = options.authToken, open = options.open;
163
+ var _a = getBasicInfo(API_BASEURL || "", authToken), token = _a.token, apiBaseURL = _a.apiBaseURL;
164
+ if (open) {
165
+ return "".concat(apiBaseURL, "/api/zmdms-resource/oss/endpoint/public/download-file/").concat(fileId);
166
+ }
167
+ return "".concat(apiBaseURL, "/api/zmdms-resource/oss/endpoint/download-file/").concat(fileId, "?Zmdms-Auth=bearer ").concat(token);
168
+ }
169
+ /**
170
+ * 生成原始图片路径
171
+ * @param fileId 附件id
172
+ * @param fileName 附件名称
173
+ * @param options
174
+ * @param options.API_BASEURL {string} 接口请求的前缀地址 非必传
175
+ * @param options.authToken {string} token 非必传
176
+ * @returns
177
+ */
178
+ function createOriginalLink(fileId, fileName, options) {
179
+ if (options === void 0) { options = {}; }
180
+ var API_BASEURL = options.API_BASEURL, authToken = options.authToken;
181
+ var _a = getBasicInfo(API_BASEURL || "", authToken), token = _a.token, apiBaseURL = _a.apiBaseURL;
182
+ // 处理附件名中的一些特殊字符
183
+ var previewFileName = dangerouslyXss(fileName);
184
+ try {
185
+ previewFileName = specialString(previewFileName);
186
+ }
187
+ catch (err) {
188
+ console.log(err);
189
+ }
190
+ // 获取文件后缀
191
+ var _b = getFileExtension(previewFileName), filePreName = _b[0], fileExtension = _b[1];
192
+ // 由于预览使用了文件名地址作为iframe的路径
193
+ // 如果文件名没变,文件内容改变。这样就会导致再次预览时 内容不会更新
194
+ // 所以将文件名 与 文件id组合来生成不同的文件名
195
+ previewFileName = "".concat(filePreName, "-").concat(fileId, ".").concat(fileExtension);
196
+ return "".concat(apiBaseURL, "/attchPreview?attachId=").concat(fileId, "&Zmdms-Auth=bearer ").concat(token, "&officePreviewType=pdf") +
197
+ fileName
198
+ ? "&titleName=".concat(encodeURIComponent(previewFileName))
199
+ : "";
200
+ }
201
+ function createThumbnailLink(fileId, fileName, options) {
202
+ var API_BASEURL = options.API_BASEURL, authToken = options.authToken, _a = options.scale, scale = _a === void 0 ? 0.5 : _a;
203
+ var _b = getBasicInfo(API_BASEURL || "", authToken), token = _b.token, apiBaseURL = _b.apiBaseURL;
204
+ return "".concat(apiBaseURL, "/api/zmdms-resource/oss/endpoint/thumbnail/").concat(fileId, "?scale=").concat(scale, "&Zmdms-Auth=bearer ").concat(token);
205
+ }
206
+ /**
207
+ * 获取基础数据
208
+ * @param baseURL 基础URL
209
+ * @param token token
210
+ * @returns
211
+ */
212
+ function getBasicInfo(baseURL, token) {
213
+ var _a;
214
+ return {
215
+ token: token || getToken(),
216
+ apiBaseURL: ((_a = baseURL === null || baseURL === void 0 ? void 0 : baseURL.endsWith) === null || _a === void 0 ? void 0 : _a.call(baseURL, "/"))
217
+ ? baseURL.slice(0, baseURL.length - 1)
218
+ : baseURL,
219
+ };
220
+ }
221
+
222
+ export { batchDownloadFiles, createDownloadLink, createOriginalLink, createThumbnailLink, downloadFile, previewFile };
@@ -48,6 +48,8 @@ interface IOtherOptions {
48
48
  crypto?: Crypto;
49
49
  isTimeoutConfirm?: boolean;
50
50
  isTimeoutConfirmStr?: string;
51
+ interceptorsRequestHandle?: () => void;
52
+ interceptorsResponseHandle?: () => void;
51
53
  }
52
54
 
53
55
  export { AxiosRequest, IOptions, IOtherOptions };
@@ -41,6 +41,10 @@ var AxiosRequest = /** @class */ (function () {
41
41
  };
42
42
  // 拦截请求
43
43
  AxiosRequest.prototype.interceptorsRequest = function () {
44
+ if (this.otherOptions.interceptorsRequestHandle) {
45
+ this.otherOptions.interceptorsRequestHandle();
46
+ return;
47
+ }
44
48
  axios.interceptors.request.use(function (config) {
45
49
  return config;
46
50
  }, function (error) {
@@ -50,6 +54,10 @@ var AxiosRequest = /** @class */ (function () {
50
54
  // 拦截响应
51
55
  AxiosRequest.prototype.interceptorsResponse = function () {
52
56
  var _this = this;
57
+ if (this.otherOptions.interceptorsResponseHandle) {
58
+ this.otherOptions.interceptorsResponseHandle();
59
+ return;
60
+ }
53
61
  axios.interceptors.response.use(function (response) {
54
62
  var _a;
55
63
  // console.log(response);
@@ -0,0 +1,54 @@
1
+ function unescapeString(input) {
2
+ if (!input) {
3
+ return "";
4
+ }
5
+
6
+ const escapedChars = {
7
+ "&amp;": "&",
8
+ "&lt;": "<",
9
+ "&gt;": ">",
10
+ "&quot;": '"',
11
+ "&#039;": "'",
12
+ };
13
+
14
+ return input.replace(/&(amp|lt|gt|quot|#039);/g, (match) => {
15
+ return escapedChars[match] || match;
16
+ });
17
+ }
18
+
19
+ function dangerouslySetXss(input) {
20
+ if (!input) {
21
+ return "";
22
+ }
23
+ const escapedChars = {
24
+ "&lt;": "",
25
+ "&gt;": "",
26
+ "&nbsp;": " ",
27
+ "&amp;": "&",
28
+ "&quot;": '"',
29
+ };
30
+
31
+ return input.replace(/&(amp|lt|gt|quot|nbsp);/g, (match) => {
32
+ return escapedChars[match] || match;
33
+ });
34
+ }
35
+
36
+ function dangerouslySetXss1(str) {
37
+ if (!str) {
38
+ return str;
39
+ }
40
+ try {
41
+ const arrEntities = { lt: "", gt: "", nbsp: " ", amp: "&", quot: '"' };
42
+ return str?.replace?.(/&(lt|gt|nbsp|amp|quot);/gi, function (all, t) {
43
+ return arrEntities[t];
44
+ });
45
+ } catch (err) {
46
+ return str;
47
+ }
48
+ }
49
+
50
+ console.log(unescapeString("&amp;&amp;&amp;啊你"));
51
+
52
+ console.log(dangerouslySetXss("&amp;&amp;&amp;啊你"));
53
+
54
+ console.log(dangerouslySetXss1("&amp;&amp;&amp;啊你"));
package/dist/index.d.ts CHANGED
@@ -5,7 +5,8 @@ export { getToken, removeToken, setToken } from './es/auth.js';
5
5
  export { AxiosRequest, IOptions, IOtherOptions } from './es/request.js';
6
6
  export { getBaseUrl } from './es/baseUrl.js';
7
7
  export { Crypto, md5 } from './es/crypto.js';
8
- export { addThousedSeparator, copyToClipboard, delay, emitter, parseQueryParams, unescapeString } from './es/common.js';
8
+ export { addThousedSeparator, copyToClipboard, dangerouslyXss, delay, emitter, getFileExtension, isImageExtension, parseQueryParams, specialString, unescapeString } from './es/common.js';
9
9
  export { divide, exactRound, formatUnit, minus, plus, times } from './es/math.js';
10
10
  export { validatePassword } from './es/passwordValidate.js';
11
11
  export { emailValidate, idCardValidate, morePhoneValidate, phoneValidate, strLenValidate } from './es/validate.js';
12
+ export { batchDownloadFiles, createDownloadLink, createOriginalLink, createThumbnailLink, downloadFile, previewFile } from './es/file.js';
package/dist/index.js CHANGED
@@ -5,7 +5,8 @@ export { getToken, removeToken, setToken } from './es/auth.js';
5
5
  export { AxiosRequest } from './es/request.js';
6
6
  export { getBaseUrl } from './es/baseUrl.js';
7
7
  export { Crypto, md5 } from './es/crypto.js';
8
- export { addThousedSeparator, copyToClipboard, delay, emitter, parseQueryParams, unescapeString } from './es/common.js';
8
+ export { addThousedSeparator, copyToClipboard, dangerouslyXss, delay, emitter, getFileExtension, isImageExtension, parseQueryParams, specialString, unescapeString } from './es/common.js';
9
9
  export { divide, exactRound, formatUnit, minus, plus, times } from './es/math.js';
10
10
  export { validatePassword } from './es/passwordValidate.js';
11
11
  export { emailValidate, idCardValidate, morePhoneValidate, phoneValidate, strLenValidate } from './es/validate.js';
12
+ export { batchDownloadFiles, createDownloadLink, createOriginalLink, createThumbnailLink, downloadFile, previewFile } from './es/file.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zmdms-utils",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
package/src/common.ts CHANGED
@@ -115,6 +115,38 @@ export function unescapeString(input: string): string {
115
115
  });
116
116
  }
117
117
 
118
+ /**
119
+ * 将一些危险字符替换成后台能识别的字符
120
+ * @param input 需要转换的内容
121
+ * @returns 转换过后的结果
122
+ */
123
+ export function dangerouslyXss(input: string): string {
124
+ if (!input) {
125
+ return "";
126
+ }
127
+ const escapedChars: { [key: string]: string } = {
128
+ lt: "",
129
+ gt: "",
130
+ nbsp: " ",
131
+ amp: "&",
132
+ quot: '"',
133
+ };
134
+
135
+ return input.replace(/&(amp|lt|gt|quot|nbsp);/g, (match) => {
136
+ return escapedChars[match] || match;
137
+ });
138
+ }
139
+
140
+ /**
141
+ * 去除特殊字符。这个方法在附件预览的场景中有用到
142
+ */
143
+ export function specialString(input: string): string {
144
+ if (!input) {
145
+ return "";
146
+ }
147
+ return input.replace(/[~!@#$%^&*{}|]/g, "");
148
+ }
149
+
118
150
  /**
119
151
  * 将内容复制到粘贴板中
120
152
  * @param text 需要复制的内容
@@ -142,3 +174,40 @@ export function copyToClipboard(text: string, callback?: any) {
142
174
  callback && callback(0);
143
175
  }
144
176
  }
177
+
178
+ /**
179
+ * 获取文件名中的后缀 返回文件名 + 后缀
180
+ * @param fileName 文件名
181
+ * @returns
182
+ */
183
+ export function getFileExtension(fileName: string): [string, string] {
184
+ if (!fileName) {
185
+ return ["", ""];
186
+ }
187
+ const lastPointIndex = fileName.lastIndexOf("."); // 从最后取点
188
+ const filePreName = fileName.substring(0, lastPointIndex); // 前面的名字
189
+ const fileExtension = fileName.substring(lastPointIndex + 1); // 后面的文件后缀
190
+ return [filePreName, fileExtension];
191
+ }
192
+
193
+ /**
194
+ * 判断后缀是否符合图片格式
195
+ * @param extension 后缀
196
+ * @returns
197
+ */
198
+ export function isImageExtension(extension: string): boolean {
199
+ const imageExtensions = [
200
+ "jpg",
201
+ "png",
202
+ "jpeg",
203
+ "gif",
204
+ "tif",
205
+ "tga",
206
+ "bmp",
207
+ "dds",
208
+ "svg",
209
+ "webp",
210
+ ];
211
+
212
+ return imageExtensions.includes(extension.toLowerCase());
213
+ }
package/src/file.ts ADDED
@@ -0,0 +1,310 @@
1
+ /**
2
+ * 附件相关接口
3
+ */
4
+ import { getToken } from "./auth";
5
+ import {
6
+ dangerouslyXss,
7
+ specialString,
8
+ getFileExtension,
9
+ isImageExtension,
10
+ } from "./common";
11
+
12
+ /**
13
+ * 附件下载方法
14
+ * @param fileId 附件id
15
+ * @param fileName 附件名称
16
+ * @param options
17
+ * @param options.API_BASEURL {string} 接口请求的前缀地址 必传
18
+ * @param options.authToken {string} token 非必传
19
+ * @param options.waterMark {boolean | string} 是否添加水印 是否指定水印名称 非必传
20
+ * @param options.open boolean 是否不需要登录信息
21
+ */
22
+ export function downloadFile(
23
+ fileId: string,
24
+ fileName: string,
25
+ options: IDownloadOptions
26
+ ) {
27
+ const { API_BASEURL, authToken, waterMark = true, open } = options;
28
+ return new Promise((resolve, reject) => {
29
+ const xhr = new XMLHttpRequest();
30
+ // 获取请求基础数据
31
+ const { token, apiBaseURL } = getBasicInfo(API_BASEURL, authToken);
32
+ if (open) {
33
+ xhr.open(
34
+ "GET",
35
+ `${apiBaseURL}/api/zmdms-resource/oss/endpoint/public/download-file/${fileId}`,
36
+ true
37
+ );
38
+ } else {
39
+ xhr.open(
40
+ "GET",
41
+ `${apiBaseURL}/api/zmdms-resource/oss/endpoint/download-file/${fileId}?Zmdms-Auth=bearer ${token}&addWaterMark=${waterMark}`,
42
+ true
43
+ );
44
+ }
45
+ xhr.responseType = "blob";
46
+ xhr.onload = function () {
47
+ if (xhr.status === 200 || xhr.status === 201) {
48
+ const link = document.createElement("a");
49
+ const body: any = document.querySelector("body");
50
+
51
+ link.href = window.URL.createObjectURL(xhr.response);
52
+ link.download = dangerouslyXss(fileName);
53
+
54
+ // fix Firefox
55
+ link.style.display = "none";
56
+ body.appendChild(link);
57
+
58
+ link.click();
59
+ body.removeChild(link);
60
+
61
+ window.URL.revokeObjectURL(link.href);
62
+
63
+ resolve({ msg: "文件下载成功!" });
64
+ } else {
65
+ reject();
66
+ }
67
+ };
68
+ xhr.onerror = function (err) {
69
+ reject(err);
70
+ };
71
+ xhr.send();
72
+ });
73
+ }
74
+
75
+ /**
76
+ * 附件批量下载方法
77
+ * @param fileList 附件列表
78
+ * @param options.API_BASEURL {string} 接口请求的前缀地址 必传
79
+ * @param options.authToken {string} token 非必传
80
+ * @param options.waterMark {boolean | string} 是否添加水印 是否指定水印名称 非必传
81
+ * @param options.zipName string zip名字
82
+ * @returns
83
+ */
84
+ export function batchDownloadFiles(
85
+ fileList: {
86
+ attachId: string;
87
+ attachName: string;
88
+ [props: string]: string;
89
+ }[],
90
+ options: IBatchDownloadOptions
91
+ ) {
92
+ const { API_BASEURL, authToken, zipName, waterMark = true } = options;
93
+ return new Promise((resolve, reject) => {
94
+ const xhr = new XMLHttpRequest();
95
+ // 获取请求基础数据
96
+ const { token, apiBaseURL } = getBasicInfo(API_BASEURL, authToken);
97
+ xhr.open(
98
+ "POST",
99
+ `${apiBaseURL}/api/zmdms-resource/oss/endpoint/batch-download-file`,
100
+ true
101
+ );
102
+ xhr.responseType = "blob";
103
+ xhr.onload = function () {
104
+ if (xhr.status === 200 || xhr.status === 201) {
105
+ const link = document.createElement("a");
106
+ const body: any = document.querySelector("body");
107
+
108
+ link.href = window.URL.createObjectURL(xhr.response);
109
+ link.download = zipName;
110
+
111
+ // fix Firefox
112
+ link.style.display = "none";
113
+ body.appendChild(link);
114
+
115
+ link.click();
116
+ body.removeChild(link);
117
+
118
+ window.URL.revokeObjectURL(link.href);
119
+
120
+ resolve({ msg: "文件下载成功!" });
121
+ } else {
122
+ reject();
123
+ }
124
+ };
125
+ xhr.onerror = function (err) {
126
+ reject(err);
127
+ };
128
+ xhr.setRequestHeader("Zmdms-Auth", token || "");
129
+ xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
130
+ const fileIds = fileList?.map?.((item) => item.attachId)?.join?.(",");
131
+ const fileNames = fileList?.map?.((item) => item.attachName)?.join?.(",");
132
+ xhr.send(
133
+ `attachIds=${fileIds}&fileNames=${fileNames}&zipName=${zipName}&addWaterMark=${waterMark}`
134
+ );
135
+ });
136
+ }
137
+
138
+ /**
139
+ * 附件预览。如果传入的附件是图片,那么实现批量预览
140
+ * @param fileId 附件id
141
+ * @param fileName 附件名称
142
+ * @param options
143
+ * @param options.API_BASEURL {string} 接口请求的前缀地址 必传
144
+ * @param options.authToken {string} token 非必传
145
+ * @param options.fileList { attachId: string, attachName: string ... }[] 附件列表。批量预览时有用
146
+ */
147
+ export function previewFile(
148
+ fileId: string,
149
+ fileName: string,
150
+ options: IPreviewOptions
151
+ ) {
152
+ const { API_BASEURL, authToken, fileList = [] } = options;
153
+ // 获取请求基础数据
154
+ const { token, apiBaseURL } = getBasicInfo(API_BASEURL, authToken);
155
+ // 处理附件名中的一些特殊字符
156
+ let previewFileName = dangerouslyXss(fileName);
157
+ try {
158
+ previewFileName = specialString(previewFileName);
159
+ } catch (err) {
160
+ console.log(err);
161
+ }
162
+ // 获取文件后缀
163
+ const [filePreName, fileExtension] = getFileExtension(previewFileName);
164
+ // 由于预览使用了文件名地址作为iframe的路径
165
+ // 如果文件名没变,文件内容改变。这样就会导致再次预览时 内容不会更新
166
+ // 所以将文件名 与 文件id组合来生成不同的文件名
167
+ previewFileName = `${filePreName}-${fileId}.${fileExtension}`;
168
+ // 如果是图片 走批量预览接口
169
+ const isImage = isImageExtension(fileExtension);
170
+ if (isImage) {
171
+ const imgFiles = fileList.filter((item) => {
172
+ const { attachName, attachId } = item;
173
+ const [, fileExtension] = getFileExtension(attachName);
174
+ if (isImageExtension(fileExtension) && attachId !== fileId) {
175
+ return true;
176
+ }
177
+ return false;
178
+ });
179
+ let attachIds = imgFiles.map((item) => item.attachId).join(",");
180
+ // 批量图片预览
181
+ window.open(
182
+ `${apiBaseURL}/picturesAttchPreview?attachIds=${
183
+ attachIds ? `${fileId},${attachIds}` : fileId
184
+ }&Zmdms-Auth=bearer ${token}` + fileName
185
+ ? `&titleName=${encodeURIComponent(previewFileName)}`
186
+ : ""
187
+ );
188
+ } else {
189
+ // 普通预览
190
+ window.open(
191
+ `${apiBaseURL}/attchPreview?attachId=${fileId}&Zmdms-Auth=bearer ${token}&officePreviewType=pdf` +
192
+ fileName
193
+ ? `&titleName=${encodeURIComponent(previewFileName)}`
194
+ : ""
195
+ );
196
+ }
197
+ }
198
+
199
+ /**
200
+ * 生成附件下载链接
201
+ * @param fileId 附件id
202
+ * @param options
203
+ * @param options.API_BASEURL {string} 接口请求的前缀地址 非必传
204
+ * @param options.authToken {string} token 非必传
205
+ * @returns
206
+ */
207
+ export function createDownloadLink(
208
+ fileId: string,
209
+ options: IDownloadLinkOptions = {}
210
+ ) {
211
+ const { API_BASEURL, authToken, open } = options;
212
+ const { token, apiBaseURL } = getBasicInfo(API_BASEURL || "", authToken);
213
+ if (open) {
214
+ return `${apiBaseURL}/api/zmdms-resource/oss/endpoint/public/download-file/${fileId}`;
215
+ }
216
+ return `${apiBaseURL}/api/zmdms-resource/oss/endpoint/download-file/${fileId}?Zmdms-Auth=bearer ${token}`;
217
+ }
218
+
219
+ /**
220
+ * 生成原始图片路径
221
+ * @param fileId 附件id
222
+ * @param fileName 附件名称
223
+ * @param options
224
+ * @param options.API_BASEURL {string} 接口请求的前缀地址 非必传
225
+ * @param options.authToken {string} token 非必传
226
+ * @returns
227
+ */
228
+ export function createOriginalLink(
229
+ fileId: string,
230
+ fileName: string,
231
+ options: IOriginLinkOptions = {}
232
+ ) {
233
+ const { API_BASEURL, authToken } = options;
234
+ const { token, apiBaseURL } = getBasicInfo(API_BASEURL || "", authToken);
235
+ // 处理附件名中的一些特殊字符
236
+ let previewFileName = dangerouslyXss(fileName);
237
+ try {
238
+ previewFileName = specialString(previewFileName);
239
+ } catch (err) {
240
+ console.log(err);
241
+ }
242
+ // 获取文件后缀
243
+ const [filePreName, fileExtension] = getFileExtension(previewFileName);
244
+ // 由于预览使用了文件名地址作为iframe的路径
245
+ // 如果文件名没变,文件内容改变。这样就会导致再次预览时 内容不会更新
246
+ // 所以将文件名 与 文件id组合来生成不同的文件名
247
+ previewFileName = `${filePreName}-${fileId}.${fileExtension}`;
248
+ return `${apiBaseURL}/attchPreview?attachId=${fileId}&Zmdms-Auth=bearer ${token}&officePreviewType=pdf` +
249
+ fileName
250
+ ? `&titleName=${encodeURIComponent(previewFileName)}`
251
+ : "";
252
+ }
253
+
254
+ export function createThumbnailLink(
255
+ fileId: string,
256
+ fileName: string,
257
+ options: IThumbnailLinkOptions
258
+ ) {
259
+ const { API_BASEURL, authToken, scale = 0.5 } = options;
260
+ const { token, apiBaseURL } = getBasicInfo(API_BASEURL || "", authToken);
261
+ return `${apiBaseURL}/api/zmdms-resource/oss/endpoint/thumbnail/${fileId}?scale=${scale}&Zmdms-Auth=bearer ${token}`;
262
+ }
263
+
264
+ /**
265
+ * 获取基础数据
266
+ * @param baseURL 基础URL
267
+ * @param token token
268
+ * @returns
269
+ */
270
+ function getBasicInfo(baseURL: string, token?: string) {
271
+ return {
272
+ token: token || getToken(),
273
+ apiBaseURL: baseURL?.endsWith?.("/")
274
+ ? baseURL.slice(0, baseURL.length - 1)
275
+ : baseURL,
276
+ };
277
+ }
278
+
279
+ interface IOptions {
280
+ API_BASEURL: string;
281
+ authToken?: string;
282
+ }
283
+ interface IDownloadOptions extends IOptions {
284
+ /** 是否添加水印 */
285
+ waterMark?: boolean | string;
286
+ /** 是否开发不需要登录信息 */
287
+ open?: boolean;
288
+ }
289
+ interface IBatchDownloadOptions extends IOptions {
290
+ zipName: string;
291
+ /** 是否添加水印 */
292
+ waterMark?: boolean | string;
293
+ }
294
+ interface IDownloadLinkOptions extends Partial<IOptions> {
295
+ /** 不需要登录信息的附件下载链接 */
296
+ open?: boolean;
297
+ }
298
+ interface IPreviewOptions extends IOptions {
299
+ /** 附件列表 */
300
+ fileList?: {
301
+ attachId: string;
302
+ attachName: string;
303
+ [props: string]: string;
304
+ }[];
305
+ }
306
+ interface IOriginLinkOptions extends Partial<IOptions> {}
307
+ interface IThumbnailLinkOptions extends Partial<IOptions> {
308
+ /** 缩放比例 */
309
+ scale?: number;
310
+ }
package/src/index.ts CHANGED
@@ -12,6 +12,10 @@ export {
12
12
  parseQueryParams,
13
13
  unescapeString,
14
14
  copyToClipboard,
15
+ getFileExtension,
16
+ isImageExtension,
17
+ dangerouslyXss,
18
+ specialString,
15
19
  } from "./common";
16
20
  export { plus, minus, times, divide, exactRound, formatUnit } from "./math";
17
21
  export { validatePassword } from "./passwordValidate";
@@ -22,3 +26,12 @@ export {
22
26
  idCardValidate,
23
27
  emailValidate,
24
28
  } from "./validate";
29
+ /** 附件预览相关 */
30
+ export {
31
+ downloadFile,
32
+ batchDownloadFiles,
33
+ previewFile,
34
+ createDownloadLink,
35
+ createOriginalLink,
36
+ createThumbnailLink,
37
+ } from "./file";
package/src/request.ts CHANGED
@@ -65,6 +65,10 @@ export class AxiosRequest {
65
65
 
66
66
  // 拦截请求
67
67
  private interceptorsRequest() {
68
+ if (this.otherOptions.interceptorsRequestHandle) {
69
+ this.otherOptions.interceptorsRequestHandle();
70
+ return;
71
+ }
68
72
  axios.interceptors.request.use(
69
73
  (config) => {
70
74
  return config;
@@ -77,6 +81,10 @@ export class AxiosRequest {
77
81
 
78
82
  // 拦截响应
79
83
  private interceptorsResponse() {
84
+ if (this.otherOptions.interceptorsResponseHandle) {
85
+ this.otherOptions.interceptorsResponseHandle();
86
+ return;
87
+ }
80
88
  axios.interceptors.response.use(
81
89
  (response) => {
82
90
  // console.log(response);
@@ -326,4 +334,8 @@ export interface IOtherOptions {
326
334
  isTimeoutConfirm?: boolean;
327
335
  // 超时弹框提示内容
328
336
  isTimeoutConfirmStr?: string;
337
+ // 拦截器自定义
338
+ interceptorsRequestHandle?: () => void;
339
+ // 响应器自定义
340
+ interceptorsResponseHandle?: () => void;
329
341
  }
package/src/test.js ADDED
@@ -0,0 +1,54 @@
1
+ function unescapeString(input) {
2
+ if (!input) {
3
+ return "";
4
+ }
5
+
6
+ const escapedChars = {
7
+ "&amp;": "&",
8
+ "&lt;": "<",
9
+ "&gt;": ">",
10
+ "&quot;": '"',
11
+ "&#039;": "'",
12
+ };
13
+
14
+ return input.replace(/&(amp|lt|gt|quot|#039);/g, (match) => {
15
+ return escapedChars[match] || match;
16
+ });
17
+ }
18
+
19
+ function dangerouslySetXss(input) {
20
+ if (!input) {
21
+ return "";
22
+ }
23
+ const escapedChars = {
24
+ "&lt;": "",
25
+ "&gt;": "",
26
+ "&nbsp;": " ",
27
+ "&amp;": "&",
28
+ "&quot;": '"',
29
+ };
30
+
31
+ return input.replace(/&(amp|lt|gt|quot|nbsp);/g, (match) => {
32
+ return escapedChars[match] || match;
33
+ });
34
+ }
35
+
36
+ function dangerouslySetXss1(str) {
37
+ if (!str) {
38
+ return str;
39
+ }
40
+ try {
41
+ const arrEntities = { lt: "", gt: "", nbsp: " ", amp: "&", quot: '"' };
42
+ return str?.replace?.(/&(lt|gt|nbsp|amp|quot);/gi, function (all, t) {
43
+ return arrEntities[t];
44
+ });
45
+ } catch (err) {
46
+ return str;
47
+ }
48
+ }
49
+
50
+ console.log(unescapeString("&amp;&amp;&amp;啊你"));
51
+
52
+ console.log(dangerouslySetXss("&amp;&amp;&amp;啊你"));
53
+
54
+ console.log(dangerouslySetXss1("&amp;&amp;&amp;啊你"));