tools-min-ns 1.18.15 → 1.18.17

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.
package/README.md CHANGED
@@ -5,6 +5,10 @@ pnpm i tools-min-ns --save
5
5
  ```
6
6
 
7
7
  # updates
8
+ ## v1.18.17
9
+ fix: FileUtil
10
+ ## v1.18.16
11
+ fix: SystemUtil 流式下载
8
12
  ## v1.18.15
9
13
  fix: SystemUtil 优化下载功能
10
14
  ## v1.18.14
@@ -74,6 +74,13 @@ declare namespace DateUtil {
74
74
  * formatDateToFriendly2() => 2017年11月11日
75
75
  */
76
76
  function formatDateToFriendly3(date?: Date | number | string): string;
77
+ /**
78
+ * 格式化时间为友好格式
79
+ * @param seconds
80
+ * @example
81
+ * formatBySeconds(10) => 10秒
82
+ */
83
+ function formatBySeconds(seconds: number): string;
77
84
  /**
78
85
  * 判断是否为本周
79
86
  * @param date
@@ -233,6 +233,29 @@ var DateUtil;
233
233
  return "".concat(years, "\u5E74\u524D");
234
234
  }
235
235
  DateUtil.formatDateToFriendly3 = formatDateToFriendly3;
236
+ /**
237
+ * 格式化时间为友好格式
238
+ * @param seconds
239
+ * @example
240
+ * formatBySeconds(10) => 10秒
241
+ */
242
+ function formatBySeconds(seconds) {
243
+ if (!isFinite(seconds) || seconds < 0) return '计算中...';
244
+ var day = Math.floor(seconds / 3600 * 24);
245
+ var hours = Math.floor(seconds / 3600);
246
+ var minutes = Math.floor(seconds % 3600 / 60);
247
+ var secs = Math.floor(seconds % 60);
248
+ if (day > 0) {
249
+ return "".concat(day, "\u5929").concat(hours, "\u5C0F\u65F6").concat(minutes, "\u5206\u949F").concat(secs, "\u79D2");
250
+ } else if (hours > 0) {
251
+ return "".concat(hours, "\u5C0F\u65F6").concat(minutes, "\u5206\u949F").concat(secs, "\u79D2");
252
+ } else if (minutes > 0) {
253
+ return "".concat(minutes, "\u5206\u949F").concat(secs, "\u79D2");
254
+ } else {
255
+ return "".concat(secs, "\u79D2");
256
+ }
257
+ }
258
+ DateUtil.formatBySeconds = formatBySeconds;
236
259
  /**
237
260
  * 判断是否为本周
238
261
  * @param date
@@ -1,10 +1,16 @@
1
1
  declare namespace FileUtil {
2
2
  /**
3
- * 多个文件压缩成zip
4
- * @param fileList
5
- * @param onProgress
6
- * @returns
3
+ * 提取文件名的辅助函数
4
+ * @param url
5
+ * @param response
7
6
  */
8
- function getZipByFiles(fileList: File[], onProgress?: (file: string, percent: number) => void): Promise<File>;
7
+ function extractFilename(url: string, response: Response): string;
8
+ /**
9
+ * 简单提取文件扩展名的辅助函数
10
+ * @param url
11
+ */
12
+ function getExt(url: string): string;
13
+ const ellisipsFileName: (fileName: string | undefined, maxLength?: number) => string;
14
+ const getFileName: (url: string, maxLength?: number) => string | undefined;
9
15
  }
10
16
  export default FileUtil;
@@ -1,182 +1,55 @@
1
- var __awaiter = this && this.__awaiter || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) {
3
- return value instanceof P ? value : new P(function (resolve) {
4
- resolve(value);
5
- });
6
- }
7
- return new (P || (P = Promise))(function (resolve, reject) {
8
- function fulfilled(value) {
9
- try {
10
- step(generator.next(value));
11
- } catch (e) {
12
- reject(e);
13
- }
14
- }
15
- function rejected(value) {
16
- try {
17
- step(generator["throw"](value));
18
- } catch (e) {
19
- reject(e);
20
- }
21
- }
22
- function step(result) {
23
- result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
24
- }
25
- step((generator = generator.apply(thisArg, _arguments || [])).next());
26
- });
27
- };
28
- var __generator = this && this.__generator || function (thisArg, body) {
29
- var _ = {
30
- label: 0,
31
- sent: function sent() {
32
- if (t[0] & 1) throw t[1];
33
- return t[1];
34
- },
35
- trys: [],
36
- ops: []
37
- },
38
- f,
39
- y,
40
- t,
41
- g;
42
- return g = {
43
- next: verb(0),
44
- "throw": verb(1),
45
- "return": verb(2)
46
- }, typeof Symbol === "function" && (g[Symbol.iterator] = function () {
47
- return this;
48
- }), g;
49
- function verb(n) {
50
- return function (v) {
51
- return step([n, v]);
52
- };
53
- }
54
- function step(op) {
55
- if (f) throw new TypeError("Generator is already executing.");
56
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
57
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
58
- if (y = 0, t) op = [op[0] & 2, t.value];
59
- switch (op[0]) {
60
- case 0:
61
- case 1:
62
- t = op;
63
- break;
64
- case 4:
65
- _.label++;
66
- return {
67
- value: op[1],
68
- done: false
69
- };
70
- case 5:
71
- _.label++;
72
- y = op[1];
73
- op = [0];
74
- continue;
75
- case 7:
76
- op = _.ops.pop();
77
- _.trys.pop();
78
- continue;
79
- default:
80
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
81
- _ = 0;
82
- continue;
83
- }
84
- if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
85
- _.label = op[1];
86
- break;
87
- }
88
- if (op[0] === 6 && _.label < t[1]) {
89
- _.label = t[1];
90
- t = op;
91
- break;
92
- }
93
- if (t && _.label < t[2]) {
94
- _.label = t[2];
95
- _.ops.push(op);
96
- break;
97
- }
98
- if (t[2]) _.ops.pop();
99
- _.trys.pop();
100
- continue;
1
+ var FileUtil;
2
+ (function (FileUtil) {
3
+ /**
4
+ * 提取文件名的辅助函数
5
+ * @param url
6
+ * @param response
7
+ */
8
+ function extractFilename(url, response) {
9
+ // 尝试从 Content-Disposition 头获取文件名
10
+ var contentDisposition = response.headers.get('content-disposition');
11
+ if (contentDisposition) {
12
+ var filenameMatch = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/);
13
+ if (filenameMatch && filenameMatch[1]) {
14
+ return filenameMatch[1].replace(/['"]/g, '');
101
15
  }
102
- op = body.call(thisArg, _);
103
- } catch (e) {
104
- op = [6, e];
105
- y = 0;
106
- } finally {
107
- f = t = 0;
108
16
  }
109
- if (op[0] & 5) throw op[1];
110
- return {
111
- value: op[0] ? op[1] : void 0,
112
- done: true
113
- };
17
+ // URL 提取文件名
18
+ var urlFilename = url.split('/').pop();
19
+ return urlFilename || 'download';
114
20
  }
115
- };
116
- var __values = this && this.__values || function (o) {
117
- var s = typeof Symbol === "function" && Symbol.iterator,
118
- m = s && o[s],
119
- i = 0;
120
- if (m) return m.call(o);
121
- if (o && typeof o.length === "number") return {
122
- next: function next() {
123
- if (o && i >= o.length) o = void 0;
124
- return {
125
- value: o && o[i++],
126
- done: !o
127
- };
128
- }
129
- };
130
- throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
131
- };
132
- import JSZip from 'jszip';
133
- var FileUtil;
134
- (function (FileUtil) {
21
+ FileUtil.extractFilename = extractFilename;
135
22
  /**
136
- * 多个文件压缩成zip
137
- * @param fileList
138
- * @param onProgress
139
- * @returns
23
+ * 简单提取文件扩展名的辅助函数
24
+ * @param url
140
25
  */
141
- function getZipByFiles(fileList, onProgress) {
142
- return __awaiter(this, void 0, void 0, function () {
143
- var zip, fileList_1, fileList_1_1, file_1, blob, file;
144
- var e_1, _a;
145
- return __generator(this, function (_b) {
146
- switch (_b.label) {
147
- case 0:
148
- zip = new JSZip();
149
- try {
150
- for (fileList_1 = __values(fileList), fileList_1_1 = fileList_1.next(); !fileList_1_1.done; fileList_1_1 = fileList_1.next()) {
151
- file_1 = fileList_1_1.value;
152
- zip.file(file_1.name, file_1);
153
- }
154
- } catch (e_1_1) {
155
- e_1 = {
156
- error: e_1_1
157
- };
158
- } finally {
159
- try {
160
- if (fileList_1_1 && !fileList_1_1.done && (_a = fileList_1.return)) _a.call(fileList_1);
161
- } finally {
162
- if (e_1) throw e_1.error;
163
- }
164
- }
165
- return [4 /*yield*/, zip.generateAsync({
166
- type: 'blob'
167
- }, function (item) {
168
- onProgress === null || onProgress === void 0 ? void 0 : onProgress(item.currentFile, item.percent);
169
- })];
170
- case 1:
171
- blob = _b.sent();
172
- file = new File([blob], "\u201C".concat(fileList[0].name, "\u201D\u7B49").concat(fileList.length, "\u4E2A\u6587\u4EF6.zip"), {
173
- type: blob.type
174
- });
175
- return [2 /*return*/, file];
176
- }
177
- });
178
- });
26
+ function getExt(url) {
27
+ var _a;
28
+ var ext = (_a = url.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLocaleLowerCase();
29
+ return ext || url;
179
30
  }
180
- FileUtil.getZipByFiles = getZipByFiles;
31
+ FileUtil.getExt = getExt;
32
+ FileUtil.ellisipsFileName = function (fileName, maxLength) {
33
+ if (maxLength === void 0) {
34
+ maxLength = 30;
35
+ }
36
+ if (!fileName) return '';
37
+ if (fileName.length > maxLength) {
38
+ var len = Math.floor((maxLength - 3) / 2);
39
+ return fileName.slice(0, len) + '...' + fileName.slice(-len);
40
+ }
41
+ return fileName;
42
+ };
43
+ var _getFileName = function _getFileName(url) {
44
+ if (!url) return;
45
+ if (url.includes('*')) return url.split('*')[1];
46
+ return url.split('/').slice(-1).toString();
47
+ };
48
+ FileUtil.getFileName = function (url, maxLength) {
49
+ if (maxLength) {
50
+ return FileUtil.ellisipsFileName(_getFileName(url), maxLength);
51
+ }
52
+ return _getFileName(url);
53
+ };
181
54
  })(FileUtil || (FileUtil = {}));
182
55
  export default FileUtil;
@@ -119,7 +119,11 @@ var __generator = this && this.__generator || function (thisArg, body) {
119
119
  * @author nanshen
120
120
  * @creat 2021-09-15 14:24:57
121
121
  */
122
+ import FileUtil from '../file/FileUtil';
122
123
  import TransferUtil from '../transfer/TransferUtil';
124
+ import streamSaver from 'streamsaver';
125
+ var MITM = 'https://ns.nihaonanshen.com/assets/stream/mitm.html';
126
+ streamSaver.mitm = MITM;
123
127
  var SystemUtil;
124
128
  (function (SystemUtil) {
125
129
  /**
@@ -147,12 +151,13 @@ var SystemUtil;
147
151
  * downloadFile('http://XXX.txt','text.txt')
148
152
  */
149
153
  function downloadFile(url, name) {
154
+ var _a;
150
155
  return __awaiter(this, void 0, void 0, function () {
151
- var response, blob, error_1, a, clickEvent;
152
- return __generator(this, function (_a) {
153
- switch (_a.label) {
156
+ var response, contentLength, total, finalFilename, fileStream, error_1;
157
+ return __generator(this, function (_b) {
158
+ switch (_b.label) {
154
159
  case 0:
155
- _a.trys.push([0, 3,, 4]);
160
+ _b.trys.push([0, 2,, 3]);
156
161
  return [4 /*yield*/, fetch(url, {
157
162
  method: 'GET',
158
163
  headers: {
@@ -160,33 +165,90 @@ var SystemUtil;
160
165
  }
161
166
  })];
162
167
  case 1:
163
- response = _a.sent();
164
- if (!response.ok) {
165
- throw new Error("HTTP error! status: ".concat(response.status));
168
+ response = _b.sent();
169
+ if (!response.ok) throw new Error("HTTP error! status: ".concat(response.status));
170
+ contentLength = response.headers.get('content-length');
171
+ total = contentLength ? parseInt(contentLength, 10) : undefined;
172
+ finalFilename = name || FileUtil.extractFilename(url, response);
173
+ fileStream = streamSaver.createWriteStream(finalFilename, {
174
+ size: total
175
+ });
176
+ // 检查浏览器是否支持流式传输
177
+ if (window.WritableStream && ((_a = response.body) === null || _a === void 0 ? void 0 : _a.pipeTo)) {
178
+ // 直接管道传输(最高效)
179
+ return [2 /*return*/, response.body.pipeTo(fileStream).then(function () {
180
+ return console.log('下载完成');
181
+ }).catch(function (error) {
182
+ console.error('下载失败:', error);
183
+ throw error;
184
+ })];
185
+ } else {
186
+ // 降级方案:手动读取和写入
187
+ return [2 /*return*/, manualStreamDownload(response, fileStream)];
166
188
  }
167
- return [4 /*yield*/, response.blob()];
189
+ return [3 /*break*/, 3];
168
190
  case 2:
169
- blob = _a.sent();
170
- SystemUtil.downloadFileByBlob(blob, name || url.split('/').pop());
171
- return [3 /*break*/, 4];
172
- case 3:
173
- error_1 = _a.sent();
191
+ error_1 = _b.sent();
174
192
  console.error('下载失败:', error_1);
175
- a = document.createElement('a');
176
- a.setAttribute('href', url);
177
- if (name) a.setAttribute('download', name);
178
- a.setAttribute('target', '_blank');
179
- clickEvent = document.createEvent('MouseEvents');
180
- clickEvent.initEvent('click', true, true);
181
- a.dispatchEvent(clickEvent);
182
- return [3 /*break*/, 4];
183
- case 4:
193
+ // 降级方案
194
+ fallbackDownload(url, name);
195
+ return [3 /*break*/, 3];
196
+ case 3:
184
197
  return [2 /*return*/];
185
198
  }
186
199
  });
187
200
  });
188
201
  }
189
202
  SystemUtil.downloadFile = downloadFile;
203
+ // 最终降级方案
204
+ function fallbackDownload(url, filename) {
205
+ var a = document.createElement('a');
206
+ a.href = url;
207
+ if (filename) a.download = filename;
208
+ a.target = '_blank';
209
+ a.style.display = 'none';
210
+ document.body.appendChild(a);
211
+ a.click();
212
+ document.body.removeChild(a);
213
+ }
214
+ // 手动流式下载(兼容性降级)
215
+ function manualStreamDownload(response, fileStream) {
216
+ var _a;
217
+ return __awaiter(this, void 0, void 0, function () {
218
+ var reader, writer, _b, done, value;
219
+ return __generator(this, function (_c) {
220
+ switch (_c.label) {
221
+ case 0:
222
+ reader = (_a = response.body) === null || _a === void 0 ? void 0 : _a.getReader();
223
+ writer = fileStream.getWriter();
224
+ if (!reader) throw new Error('无法获取响应流');
225
+ _c.label = 1;
226
+ case 1:
227
+ _c.trys.push([1,, 6, 8]);
228
+ _c.label = 2;
229
+ case 2:
230
+ if (!true) return [3 /*break*/, 5];
231
+ return [4 /*yield*/, reader.read()];
232
+ case 3:
233
+ _b = _c.sent(), done = _b.done, value = _b.value;
234
+ if (done) return [3 /*break*/, 5];
235
+ return [4 /*yield*/, writer.write(value)];
236
+ case 4:
237
+ _c.sent();
238
+ return [3 /*break*/, 2];
239
+ case 5:
240
+ return [3 /*break*/, 8];
241
+ case 6:
242
+ return [4 /*yield*/, writer.close()];
243
+ case 7:
244
+ _c.sent();
245
+ return [7 /*endfinally*/];
246
+ case 8:
247
+ return [2 /*return*/];
248
+ }
249
+ });
250
+ });
251
+ }
190
252
  /**
191
253
  * 通过base64下载文件
192
254
  * @param base64 base64字符串
@@ -74,6 +74,13 @@ declare namespace DateUtil {
74
74
  * formatDateToFriendly2() => 2017年11月11日
75
75
  */
76
76
  function formatDateToFriendly3(date?: Date | number | string): string;
77
+ /**
78
+ * 格式化时间为友好格式
79
+ * @param seconds
80
+ * @example
81
+ * formatBySeconds(10) => 10秒
82
+ */
83
+ function formatBySeconds(seconds: number): string;
77
84
  /**
78
85
  * 判断是否为本周
79
86
  * @param date
@@ -243,6 +243,29 @@ var DateUtil;
243
243
  return "".concat(years, "\u5E74\u524D");
244
244
  }
245
245
  DateUtil.formatDateToFriendly3 = formatDateToFriendly3;
246
+ /**
247
+ * 格式化时间为友好格式
248
+ * @param seconds
249
+ * @example
250
+ * formatBySeconds(10) => 10秒
251
+ */
252
+ function formatBySeconds(seconds) {
253
+ if (!isFinite(seconds) || seconds < 0) return '计算中...';
254
+ var day = Math.floor(seconds / 3600 * 24);
255
+ var hours = Math.floor(seconds / 3600);
256
+ var minutes = Math.floor(seconds % 3600 / 60);
257
+ var secs = Math.floor(seconds % 60);
258
+ if (day > 0) {
259
+ return "".concat(day, "\u5929").concat(hours, "\u5C0F\u65F6").concat(minutes, "\u5206\u949F").concat(secs, "\u79D2");
260
+ } else if (hours > 0) {
261
+ return "".concat(hours, "\u5C0F\u65F6").concat(minutes, "\u5206\u949F").concat(secs, "\u79D2");
262
+ } else if (minutes > 0) {
263
+ return "".concat(minutes, "\u5206\u949F").concat(secs, "\u79D2");
264
+ } else {
265
+ return "".concat(secs, "\u79D2");
266
+ }
267
+ }
268
+ DateUtil.formatBySeconds = formatBySeconds;
246
269
  /**
247
270
  * 判断是否为本周
248
271
  * @param date
@@ -1,10 +1,16 @@
1
1
  declare namespace FileUtil {
2
2
  /**
3
- * 多个文件压缩成zip
4
- * @param fileList
5
- * @param onProgress
6
- * @returns
3
+ * 提取文件名的辅助函数
4
+ * @param url
5
+ * @param response
7
6
  */
8
- function getZipByFiles(fileList: File[], onProgress?: (file: string, percent: number) => void): Promise<File>;
7
+ function extractFilename(url: string, response: Response): string;
8
+ /**
9
+ * 简单提取文件扩展名的辅助函数
10
+ * @param url
11
+ */
12
+ function getExt(url: string): string;
13
+ const ellisipsFileName: (fileName: string | undefined, maxLength?: number) => string;
14
+ const getFileName: (url: string, maxLength?: number) => string | undefined;
9
15
  }
10
16
  export default FileUtil;
@@ -1,192 +1,60 @@
1
1
  "use strict";
2
2
 
3
- var __awaiter = this && this.__awaiter || function (thisArg, _arguments, P, generator) {
4
- function adopt(value) {
5
- return value instanceof P ? value : new P(function (resolve) {
6
- resolve(value);
7
- });
8
- }
9
- return new (P || (P = Promise))(function (resolve, reject) {
10
- function fulfilled(value) {
11
- try {
12
- step(generator.next(value));
13
- } catch (e) {
14
- reject(e);
15
- }
16
- }
17
- function rejected(value) {
18
- try {
19
- step(generator["throw"](value));
20
- } catch (e) {
21
- reject(e);
22
- }
23
- }
24
- function step(result) {
25
- result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
26
- }
27
- step((generator = generator.apply(thisArg, _arguments || [])).next());
28
- });
29
- };
30
- var __generator = this && this.__generator || function (thisArg, body) {
31
- var _ = {
32
- label: 0,
33
- sent: function sent() {
34
- if (t[0] & 1) throw t[1];
35
- return t[1];
36
- },
37
- trys: [],
38
- ops: []
39
- },
40
- f,
41
- y,
42
- t,
43
- g;
44
- return g = {
45
- next: verb(0),
46
- "throw": verb(1),
47
- "return": verb(2)
48
- }, typeof Symbol === "function" && (g[Symbol.iterator] = function () {
49
- return this;
50
- }), g;
51
- function verb(n) {
52
- return function (v) {
53
- return step([n, v]);
54
- };
55
- }
56
- function step(op) {
57
- if (f) throw new TypeError("Generator is already executing.");
58
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
59
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
60
- if (y = 0, t) op = [op[0] & 2, t.value];
61
- switch (op[0]) {
62
- case 0:
63
- case 1:
64
- t = op;
65
- break;
66
- case 4:
67
- _.label++;
68
- return {
69
- value: op[1],
70
- done: false
71
- };
72
- case 5:
73
- _.label++;
74
- y = op[1];
75
- op = [0];
76
- continue;
77
- case 7:
78
- op = _.ops.pop();
79
- _.trys.pop();
80
- continue;
81
- default:
82
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
83
- _ = 0;
84
- continue;
85
- }
86
- if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
87
- _.label = op[1];
88
- break;
89
- }
90
- if (op[0] === 6 && _.label < t[1]) {
91
- _.label = t[1];
92
- t = op;
93
- break;
94
- }
95
- if (t && _.label < t[2]) {
96
- _.label = t[2];
97
- _.ops.push(op);
98
- break;
99
- }
100
- if (t[2]) _.ops.pop();
101
- _.trys.pop();
102
- continue;
103
- }
104
- op = body.call(thisArg, _);
105
- } catch (e) {
106
- op = [6, e];
107
- y = 0;
108
- } finally {
109
- f = t = 0;
110
- }
111
- if (op[0] & 5) throw op[1];
112
- return {
113
- value: op[0] ? op[1] : void 0,
114
- done: true
115
- };
116
- }
117
- };
118
- var __values = this && this.__values || function (o) {
119
- var s = typeof Symbol === "function" && Symbol.iterator,
120
- m = s && o[s],
121
- i = 0;
122
- if (m) return m.call(o);
123
- if (o && typeof o.length === "number") return {
124
- next: function next() {
125
- if (o && i >= o.length) o = void 0;
126
- return {
127
- value: o && o[i++],
128
- done: !o
129
- };
130
- }
131
- };
132
- throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
133
- };
134
- var __importDefault = this && this.__importDefault || function (mod) {
135
- return mod && mod.__esModule ? mod : {
136
- "default": mod
137
- };
138
- };
139
3
  Object.defineProperty(exports, "__esModule", {
140
4
  value: true
141
5
  });
142
- var jszip_1 = __importDefault(require("jszip"));
143
6
  var FileUtil;
144
7
  (function (FileUtil) {
145
8
  /**
146
- * 多个文件压缩成zip
147
- * @param fileList
148
- * @param onProgress
149
- * @returns
9
+ * 提取文件名的辅助函数
10
+ * @param url
11
+ * @param response
12
+ */
13
+ function extractFilename(url, response) {
14
+ // 尝试从 Content-Disposition 头获取文件名
15
+ var contentDisposition = response.headers.get('content-disposition');
16
+ if (contentDisposition) {
17
+ var filenameMatch = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/);
18
+ if (filenameMatch && filenameMatch[1]) {
19
+ return filenameMatch[1].replace(/['"]/g, '');
20
+ }
21
+ }
22
+ // 从 URL 提取文件名
23
+ var urlFilename = url.split('/').pop();
24
+ return urlFilename || 'download';
25
+ }
26
+ FileUtil.extractFilename = extractFilename;
27
+ /**
28
+ * 简单提取文件扩展名的辅助函数
29
+ * @param url
150
30
  */
151
- function getZipByFiles(fileList, onProgress) {
152
- return __awaiter(this, void 0, void 0, function () {
153
- var zip, fileList_1, fileList_1_1, file_1, blob, file;
154
- var e_1, _a;
155
- return __generator(this, function (_b) {
156
- switch (_b.label) {
157
- case 0:
158
- zip = new jszip_1.default();
159
- try {
160
- for (fileList_1 = __values(fileList), fileList_1_1 = fileList_1.next(); !fileList_1_1.done; fileList_1_1 = fileList_1.next()) {
161
- file_1 = fileList_1_1.value;
162
- zip.file(file_1.name, file_1);
163
- }
164
- } catch (e_1_1) {
165
- e_1 = {
166
- error: e_1_1
167
- };
168
- } finally {
169
- try {
170
- if (fileList_1_1 && !fileList_1_1.done && (_a = fileList_1.return)) _a.call(fileList_1);
171
- } finally {
172
- if (e_1) throw e_1.error;
173
- }
174
- }
175
- return [4 /*yield*/, zip.generateAsync({
176
- type: 'blob'
177
- }, function (item) {
178
- onProgress === null || onProgress === void 0 ? void 0 : onProgress(item.currentFile, item.percent);
179
- })];
180
- case 1:
181
- blob = _b.sent();
182
- file = new File([blob], "\u201C".concat(fileList[0].name, "\u201D\u7B49").concat(fileList.length, "\u4E2A\u6587\u4EF6.zip"), {
183
- type: blob.type
184
- });
185
- return [2 /*return*/, file];
186
- }
187
- });
188
- });
31
+ function getExt(url) {
32
+ var _a;
33
+ var ext = (_a = url.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLocaleLowerCase();
34
+ return ext || url;
189
35
  }
190
- FileUtil.getZipByFiles = getZipByFiles;
36
+ FileUtil.getExt = getExt;
37
+ FileUtil.ellisipsFileName = function (fileName, maxLength) {
38
+ if (maxLength === void 0) {
39
+ maxLength = 30;
40
+ }
41
+ if (!fileName) return '';
42
+ if (fileName.length > maxLength) {
43
+ var len = Math.floor((maxLength - 3) / 2);
44
+ return fileName.slice(0, len) + '...' + fileName.slice(-len);
45
+ }
46
+ return fileName;
47
+ };
48
+ var _getFileName = function _getFileName(url) {
49
+ if (!url) return;
50
+ if (url.includes('*')) return url.split('*')[1];
51
+ return url.split('/').slice(-1).toString();
52
+ };
53
+ FileUtil.getFileName = function (url, maxLength) {
54
+ if (maxLength) {
55
+ return FileUtil.ellisipsFileName(_getFileName(url), maxLength);
56
+ }
57
+ return _getFileName(url);
58
+ };
191
59
  })(FileUtil || (FileUtil = {}));
192
60
  exports.default = FileUtil;
@@ -129,7 +129,11 @@ Object.defineProperty(exports, "__esModule", {
129
129
  * @author nanshen
130
130
  * @creat 2021-09-15 14:24:57
131
131
  */
132
+ var FileUtil_1 = __importDefault(require("../file/FileUtil"));
132
133
  var TransferUtil_1 = __importDefault(require("../transfer/TransferUtil"));
134
+ var streamsaver_1 = __importDefault(require("streamsaver"));
135
+ var MITM = 'https://ns.nihaonanshen.com/assets/stream/mitm.html';
136
+ streamsaver_1.default.mitm = MITM;
133
137
  var SystemUtil;
134
138
  (function (SystemUtil) {
135
139
  /**
@@ -157,12 +161,13 @@ var SystemUtil;
157
161
  * downloadFile('http://XXX.txt','text.txt')
158
162
  */
159
163
  function downloadFile(url, name) {
164
+ var _a;
160
165
  return __awaiter(this, void 0, void 0, function () {
161
- var response, blob, error_1, a, clickEvent;
162
- return __generator(this, function (_a) {
163
- switch (_a.label) {
166
+ var response, contentLength, total, finalFilename, fileStream, error_1;
167
+ return __generator(this, function (_b) {
168
+ switch (_b.label) {
164
169
  case 0:
165
- _a.trys.push([0, 3,, 4]);
170
+ _b.trys.push([0, 2,, 3]);
166
171
  return [4 /*yield*/, fetch(url, {
167
172
  method: 'GET',
168
173
  headers: {
@@ -170,33 +175,90 @@ var SystemUtil;
170
175
  }
171
176
  })];
172
177
  case 1:
173
- response = _a.sent();
174
- if (!response.ok) {
175
- throw new Error("HTTP error! status: ".concat(response.status));
178
+ response = _b.sent();
179
+ if (!response.ok) throw new Error("HTTP error! status: ".concat(response.status));
180
+ contentLength = response.headers.get('content-length');
181
+ total = contentLength ? parseInt(contentLength, 10) : undefined;
182
+ finalFilename = name || FileUtil_1.default.extractFilename(url, response);
183
+ fileStream = streamsaver_1.default.createWriteStream(finalFilename, {
184
+ size: total
185
+ });
186
+ // 检查浏览器是否支持流式传输
187
+ if (window.WritableStream && ((_a = response.body) === null || _a === void 0 ? void 0 : _a.pipeTo)) {
188
+ // 直接管道传输(最高效)
189
+ return [2 /*return*/, response.body.pipeTo(fileStream).then(function () {
190
+ return console.log('下载完成');
191
+ }).catch(function (error) {
192
+ console.error('下载失败:', error);
193
+ throw error;
194
+ })];
195
+ } else {
196
+ // 降级方案:手动读取和写入
197
+ return [2 /*return*/, manualStreamDownload(response, fileStream)];
176
198
  }
177
- return [4 /*yield*/, response.blob()];
199
+ return [3 /*break*/, 3];
178
200
  case 2:
179
- blob = _a.sent();
180
- SystemUtil.downloadFileByBlob(blob, name || url.split('/').pop());
181
- return [3 /*break*/, 4];
182
- case 3:
183
- error_1 = _a.sent();
201
+ error_1 = _b.sent();
184
202
  console.error('下载失败:', error_1);
185
- a = document.createElement('a');
186
- a.setAttribute('href', url);
187
- if (name) a.setAttribute('download', name);
188
- a.setAttribute('target', '_blank');
189
- clickEvent = document.createEvent('MouseEvents');
190
- clickEvent.initEvent('click', true, true);
191
- a.dispatchEvent(clickEvent);
192
- return [3 /*break*/, 4];
193
- case 4:
203
+ // 降级方案
204
+ fallbackDownload(url, name);
205
+ return [3 /*break*/, 3];
206
+ case 3:
194
207
  return [2 /*return*/];
195
208
  }
196
209
  });
197
210
  });
198
211
  }
199
212
  SystemUtil.downloadFile = downloadFile;
213
+ // 最终降级方案
214
+ function fallbackDownload(url, filename) {
215
+ var a = document.createElement('a');
216
+ a.href = url;
217
+ if (filename) a.download = filename;
218
+ a.target = '_blank';
219
+ a.style.display = 'none';
220
+ document.body.appendChild(a);
221
+ a.click();
222
+ document.body.removeChild(a);
223
+ }
224
+ // 手动流式下载(兼容性降级)
225
+ function manualStreamDownload(response, fileStream) {
226
+ var _a;
227
+ return __awaiter(this, void 0, void 0, function () {
228
+ var reader, writer, _b, done, value;
229
+ return __generator(this, function (_c) {
230
+ switch (_c.label) {
231
+ case 0:
232
+ reader = (_a = response.body) === null || _a === void 0 ? void 0 : _a.getReader();
233
+ writer = fileStream.getWriter();
234
+ if (!reader) throw new Error('无法获取响应流');
235
+ _c.label = 1;
236
+ case 1:
237
+ _c.trys.push([1,, 6, 8]);
238
+ _c.label = 2;
239
+ case 2:
240
+ if (!true) return [3 /*break*/, 5];
241
+ return [4 /*yield*/, reader.read()];
242
+ case 3:
243
+ _b = _c.sent(), done = _b.done, value = _b.value;
244
+ if (done) return [3 /*break*/, 5];
245
+ return [4 /*yield*/, writer.write(value)];
246
+ case 4:
247
+ _c.sent();
248
+ return [3 /*break*/, 2];
249
+ case 5:
250
+ return [3 /*break*/, 8];
251
+ case 6:
252
+ return [4 /*yield*/, writer.close()];
253
+ case 7:
254
+ _c.sent();
255
+ return [7 /*endfinally*/];
256
+ case 8:
257
+ return [2 /*return*/];
258
+ }
259
+ });
260
+ });
261
+ }
200
262
  /**
201
263
  * 通过base64下载文件
202
264
  * @param base64 base64字符串
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tools-min-ns",
3
3
  "description": "工具包适用于前端以及node",
4
- "version": "1.18.15",
4
+ "version": "1.18.17",
5
5
  "main": "lib/index.js",
6
6
  "license": "MIT",
7
7
  "author": "nanshen",
@@ -41,6 +41,7 @@
41
41
  "@babel/preset-typescript": "^7.10.4",
42
42
  "@types/node": "^20.5.0",
43
43
  "@types/react": "^17.0.21",
44
+ "@types/streamsaver": "^2.0.5",
44
45
  "core-js": "3",
45
46
  "del": "^5.1.0",
46
47
  "gulp": "^4.0.2",
@@ -52,6 +53,6 @@
52
53
  "typescript": "^4.9.5"
53
54
  },
54
55
  "dependencies": {
55
- "jszip": "^3.10.1"
56
+ "streamsaver": "^2.0.6"
56
57
  }
57
58
  }