@nokecy/qc-ui 1.1.75 → 1.1.76
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/dist/cjs/exportButton/exportAction.d.ts +74 -0
- package/dist/cjs/exportButton/exportAction.js +199 -0
- package/dist/cjs/exportButton/index.d.ts +39 -0
- package/dist/cjs/exportButton/index.js +295 -0
- package/dist/cjs/importModal/index.d.ts +9 -0
- package/dist/cjs/importModal/index.js +46 -8
- package/dist/cjs/index.d.ts +3 -0
- package/dist/cjs/index.js +54 -0
- package/dist/cjs/utils/download.d.ts +6 -0
- package/dist/cjs/utils/download.js +23 -0
- package/dist/esm/exportButton/exportAction.d.ts +74 -0
- package/dist/esm/exportButton/exportAction.js +193 -0
- package/dist/esm/exportButton/index.d.ts +39 -0
- package/dist/esm/exportButton/index.js +259 -0
- package/dist/esm/importModal/index.d.ts +9 -0
- package/dist/esm/importModal/index.js +46 -8
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/utils/download.d.ts +6 -0
- package/dist/esm/utils/download.js +17 -0
- package/dist/umd/qc-ui.min.js +1 -1
- package/package.json +1 -1
|
@@ -40,7 +40,10 @@ var ImportModal = function ImportModal(props) {
|
|
|
40
40
|
_props$downloadBlob = props.downloadBlob,
|
|
41
41
|
downloadBlob = _props$downloadBlob === void 0 ? defaultDownloadBlob : _props$downloadBlob,
|
|
42
42
|
serverUrl = props.serverUrl,
|
|
43
|
-
buttonProps = props.buttonProps
|
|
43
|
+
buttonProps = props.buttonProps,
|
|
44
|
+
request = props.request,
|
|
45
|
+
method = props.method,
|
|
46
|
+
onRealSuccess = props.onRealSuccess;
|
|
44
47
|
var _useBoolean = (0, _ahooks.useBoolean)(false),
|
|
45
48
|
_useBoolean2 = _slicedToArray(_useBoolean, 2),
|
|
46
49
|
visible = _useBoolean2[0],
|
|
@@ -70,12 +73,46 @@ var ImportModal = function ImportModal(props) {
|
|
|
70
73
|
}
|
|
71
74
|
}, "\u6A21\u7248")),
|
|
72
75
|
type: "info"
|
|
73
|
-
}), /*#__PURE__*/_react.default.createElement(_antd.Upload.Dragger, {
|
|
76
|
+
}), /*#__PURE__*/_react.default.createElement(_antd.Upload.Dragger, _extends({
|
|
74
77
|
style: {
|
|
75
78
|
marginTop: 10
|
|
76
79
|
},
|
|
77
80
|
multiple: false,
|
|
78
|
-
action: getUploadUrl()
|
|
81
|
+
action: getUploadUrl()
|
|
82
|
+
}, request ? {
|
|
83
|
+
customRequest: function customRequest(_ref) {
|
|
84
|
+
var action = _ref.action,
|
|
85
|
+
file = _ref.file,
|
|
86
|
+
headers = _ref.headers,
|
|
87
|
+
onError = _ref.onError,
|
|
88
|
+
onProgress = _ref.onProgress,
|
|
89
|
+
onSuccess = _ref.onSuccess;
|
|
90
|
+
var formData = new FormData();
|
|
91
|
+
formData.append('file', file);
|
|
92
|
+
request(action, {
|
|
93
|
+
method: method || 'POST',
|
|
94
|
+
data: formData,
|
|
95
|
+
headers: headers,
|
|
96
|
+
// 导入失败要展示行级原因,交给下面的弹窗统一报,不再走全局吐司。
|
|
97
|
+
skipErrorHandler: true,
|
|
98
|
+
onUploadProgress: function onUploadProgress(_ref2) {
|
|
99
|
+
var total = _ref2.total,
|
|
100
|
+
loaded = _ref2.loaded;
|
|
101
|
+
onProgress === null || onProgress === void 0 || onProgress({
|
|
102
|
+
percent: Number((loaded / total * 100).toFixed(2))
|
|
103
|
+
}, file);
|
|
104
|
+
}
|
|
105
|
+
}).then(function (response) {
|
|
106
|
+
onSuccess === null || onSuccess === void 0 || onSuccess(response, file);
|
|
107
|
+
onRealSuccess === null || onRealSuccess === void 0 || onRealSuccess(response);
|
|
108
|
+
})
|
|
109
|
+
// 第二个参数成为 info.file.response,onChange 靠它拿到后端的失败原因,而不是 axios 的英文文案。
|
|
110
|
+
.catch(function (err) {
|
|
111
|
+
var _err$response;
|
|
112
|
+
return onError === null || onError === void 0 ? void 0 : onError(err, err === null || err === void 0 || (_err$response = err.response) === null || _err$response === void 0 ? void 0 : _err$response.data);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
} : {}, {
|
|
79
116
|
onChange: function onChange(info) {
|
|
80
117
|
if (info.file.status === 'done') {
|
|
81
118
|
_antd.message.success('导入成功');
|
|
@@ -84,15 +121,16 @@ var ImportModal = function ImportModal(props) {
|
|
|
84
121
|
}
|
|
85
122
|
if (info.file.status === 'error') {
|
|
86
123
|
var _info$file;
|
|
87
|
-
|
|
88
|
-
|
|
124
|
+
// 没有后端给的原因时也要有提示,不能让失败无声无息。
|
|
125
|
+
_antd.Modal.error({
|
|
126
|
+
title: '导入失败',
|
|
89
127
|
closable: true,
|
|
90
|
-
width:
|
|
91
|
-
content: info === null || info === void 0 || (_info$file = info.file) === null || _info$file === void 0 || (_info$file = _info$file.response) === null || _info$file === void 0 || (_info$file = _info$file.error) === null || _info$file === void 0 ? void 0 : _info$file.message
|
|
128
|
+
width: 800,
|
|
129
|
+
content: (info === null || info === void 0 || (_info$file = info.file) === null || _info$file === void 0 || (_info$file = _info$file.response) === null || _info$file === void 0 || (_info$file = _info$file.error) === null || _info$file === void 0 ? void 0 : _info$file.message) || '文件未能导入。请核对模板格式与必填列后重试;若持续失败请联系技术支持。'
|
|
92
130
|
});
|
|
93
131
|
}
|
|
94
132
|
}
|
|
95
|
-
}, /*#__PURE__*/_react.default.createElement("p", {
|
|
133
|
+
}), /*#__PURE__*/_react.default.createElement("p", {
|
|
96
134
|
className: "ant-upload-drag-icon"
|
|
97
135
|
}, /*#__PURE__*/_react.default.createElement(_icons.InboxOutlined, null)), /*#__PURE__*/_react.default.createElement("p", {
|
|
98
136
|
className: "ant-upload-text"
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -33,6 +33,9 @@ export type { CentralizedColumnScheme, QueryScheme, SchemeStorageAdapter, Scheme
|
|
|
33
33
|
export * from './adapters';
|
|
34
34
|
export * from "./readPretty";
|
|
35
35
|
export { createEntitySelect } from "./entitySelect";
|
|
36
|
+
export { default as ExportButton, buildExportUrl, DEFAULT_EXPORT_TEMPLATE_API, resolveExportAction, resolveExportError, resolveFileName } from "./exportButton";
|
|
37
|
+
export type { ExportButtonProps, ExportTemplateApi, ExportTemplateOption } from "./exportButton";
|
|
38
|
+
export { saveAs } from "./utils/download";
|
|
36
39
|
export type { EntitySelectConfig, EntitySelectProps, EntitySelectQuery } from "./entitySelect";
|
|
37
40
|
export { semanticTextColors, toGridTextColor, gridValueEnum } from "./ag-grid-plus/utils/valueEnumColor";
|
|
38
41
|
export type { SemanticPreset } from "./ag-grid-plus/utils/valueEnumColor";
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
3
4
|
Object.defineProperty(exports, "__esModule", {
|
|
4
5
|
value: true
|
|
5
6
|
});
|
|
@@ -48,6 +49,13 @@ var _exportNames = {
|
|
|
48
49
|
MatchItem: true,
|
|
49
50
|
RegexRailroadDiagram: true,
|
|
50
51
|
createEntitySelect: true,
|
|
52
|
+
ExportButton: true,
|
|
53
|
+
buildExportUrl: true,
|
|
54
|
+
DEFAULT_EXPORT_TEMPLATE_API: true,
|
|
55
|
+
resolveExportAction: true,
|
|
56
|
+
resolveExportError: true,
|
|
57
|
+
resolveFileName: true,
|
|
58
|
+
saveAs: true,
|
|
51
59
|
semanticTextColors: true,
|
|
52
60
|
toGridTextColor: true,
|
|
53
61
|
gridValueEnum: true,
|
|
@@ -120,6 +128,12 @@ Object.defineProperty(exports, "ConfirmPro", {
|
|
|
120
128
|
return _ConfirmPro.default;
|
|
121
129
|
}
|
|
122
130
|
});
|
|
131
|
+
Object.defineProperty(exports, "DEFAULT_EXPORT_TEMPLATE_API", {
|
|
132
|
+
enumerable: true,
|
|
133
|
+
get: function get() {
|
|
134
|
+
return _exportButton.DEFAULT_EXPORT_TEMPLATE_API;
|
|
135
|
+
}
|
|
136
|
+
});
|
|
123
137
|
Object.defineProperty(exports, "Dashboard", {
|
|
124
138
|
enumerable: true,
|
|
125
139
|
get: function get() {
|
|
@@ -150,6 +164,12 @@ Object.defineProperty(exports, "Editable", {
|
|
|
150
164
|
return _editable.default;
|
|
151
165
|
}
|
|
152
166
|
});
|
|
167
|
+
Object.defineProperty(exports, "ExportButton", {
|
|
168
|
+
enumerable: true,
|
|
169
|
+
get: function get() {
|
|
170
|
+
return _exportButton.default;
|
|
171
|
+
}
|
|
172
|
+
});
|
|
153
173
|
Object.defineProperty(exports, "ExtensibleGrid", {
|
|
154
174
|
enumerable: true,
|
|
155
175
|
get: function get() {
|
|
@@ -276,6 +296,12 @@ Object.defineProperty(exports, "ToolBar", {
|
|
|
276
296
|
return _toolBar.default;
|
|
277
297
|
}
|
|
278
298
|
});
|
|
299
|
+
Object.defineProperty(exports, "buildExportUrl", {
|
|
300
|
+
enumerable: true,
|
|
301
|
+
get: function get() {
|
|
302
|
+
return _exportButton.buildExportUrl;
|
|
303
|
+
}
|
|
304
|
+
});
|
|
279
305
|
Object.defineProperty(exports, "contrastRatio", {
|
|
280
306
|
enumerable: true,
|
|
281
307
|
get: function get() {
|
|
@@ -360,12 +386,36 @@ Object.defineProperty(exports, "relativeLuminance", {
|
|
|
360
386
|
return _contrast.relativeLuminance;
|
|
361
387
|
}
|
|
362
388
|
});
|
|
389
|
+
Object.defineProperty(exports, "resolveExportAction", {
|
|
390
|
+
enumerable: true,
|
|
391
|
+
get: function get() {
|
|
392
|
+
return _exportButton.resolveExportAction;
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
Object.defineProperty(exports, "resolveExportError", {
|
|
396
|
+
enumerable: true,
|
|
397
|
+
get: function get() {
|
|
398
|
+
return _exportButton.resolveExportError;
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
Object.defineProperty(exports, "resolveFileName", {
|
|
402
|
+
enumerable: true,
|
|
403
|
+
get: function get() {
|
|
404
|
+
return _exportButton.resolveFileName;
|
|
405
|
+
}
|
|
406
|
+
});
|
|
363
407
|
Object.defineProperty(exports, "roundDecimal", {
|
|
364
408
|
enumerable: true,
|
|
365
409
|
get: function get() {
|
|
366
410
|
return _businessDecimal.roundDecimal;
|
|
367
411
|
}
|
|
368
412
|
});
|
|
413
|
+
Object.defineProperty(exports, "saveAs", {
|
|
414
|
+
enumerable: true,
|
|
415
|
+
get: function get() {
|
|
416
|
+
return _download.saveAs;
|
|
417
|
+
}
|
|
418
|
+
});
|
|
369
419
|
Object.defineProperty(exports, "semanticTextColors", {
|
|
370
420
|
enumerable: true,
|
|
371
421
|
get: function get() {
|
|
@@ -480,7 +530,11 @@ Object.keys(_readPretty).forEach(function (key) {
|
|
|
480
530
|
});
|
|
481
531
|
});
|
|
482
532
|
var _entitySelect = require("./entitySelect");
|
|
533
|
+
var _exportButton = _interopRequireWildcard(require("./exportButton"));
|
|
534
|
+
var _download = require("./utils/download");
|
|
483
535
|
var _valueEnumColor = require("./ag-grid-plus/utils/valueEnumColor");
|
|
484
536
|
var _contrast = require("./utils/contrast");
|
|
485
537
|
var _businessDecimal = require("./utils/businessDecimal");
|
|
538
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
|
|
539
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
486
540
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.saveAs = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* 把 Blob 存成本地文件。
|
|
9
|
+
*
|
|
10
|
+
* @author nokecy
|
|
11
|
+
*/
|
|
12
|
+
var saveAs = exports.saveAs = function saveAs(blob, filename) {
|
|
13
|
+
var nav = window.navigator;
|
|
14
|
+
if (typeof nav.msSaveBlob === 'function') {
|
|
15
|
+
nav.msSaveBlob(blob, filename);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
var link = document.createElement('a');
|
|
19
|
+
link.href = window.URL.createObjectURL(blob);
|
|
20
|
+
link.download = filename;
|
|
21
|
+
link.click();
|
|
22
|
+
window.URL.revokeObjectURL(link.href);
|
|
23
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 导出按钮的行为决策与地址构造。
|
|
3
|
+
*
|
|
4
|
+
* 抽成纯函数是为了能直接测:这里的分支决定了「现场点导出会发生什么」,
|
|
5
|
+
* 而它最容易出问题的两个场景——模板没配、模板接口挂了——在页面里很难复现。
|
|
6
|
+
*
|
|
7
|
+
* @author nokecy
|
|
8
|
+
*/
|
|
9
|
+
/** 导出模板服务的接口地址:可用模板列表与按模板渲染文件。默认指向 MES 后端的 export-template 服务,其他后端可在 ExportButton 上覆盖。 */
|
|
10
|
+
export interface ExportTemplateApi {
|
|
11
|
+
/** 按页面标识取可用模板(GET,参数 gridKey) */
|
|
12
|
+
options: string;
|
|
13
|
+
/** 按模板渲染并下载(GET,参数 TemplateId、Filter) */
|
|
14
|
+
render: string;
|
|
15
|
+
}
|
|
16
|
+
/** 默认的导出模板服务地址。 */
|
|
17
|
+
export declare const DEFAULT_EXPORT_TEMPLATE_API: ExportTemplateApi;
|
|
18
|
+
/** 后端 `export-template/options` 返回的模板项 */
|
|
19
|
+
export interface ExportTemplateOption {
|
|
20
|
+
id: string;
|
|
21
|
+
name: string;
|
|
22
|
+
isDefault: boolean;
|
|
23
|
+
}
|
|
24
|
+
/** 导出按钮该以什么形态出现 */
|
|
25
|
+
export type ExportAction =
|
|
26
|
+
/** 没有可用模板:走页面自带的旧导出入口 */
|
|
27
|
+
{
|
|
28
|
+
kind: 'legacy';
|
|
29
|
+
}
|
|
30
|
+
/** 只有一个模板:按钮直接导 */
|
|
31
|
+
| {
|
|
32
|
+
kind: 'single';
|
|
33
|
+
template: ExportTemplateOption;
|
|
34
|
+
}
|
|
35
|
+
/** 多个模板:下拉选择 */
|
|
36
|
+
| {
|
|
37
|
+
kind: 'menu';
|
|
38
|
+
templates: ExportTemplateOption[];
|
|
39
|
+
defaultTemplate: ExportTemplateOption;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* 根据可用模板决定导出按钮的行为。
|
|
43
|
+
*
|
|
44
|
+
* 传 null / undefined 表示「没拿到模板列表」(接口失败或还没加载),
|
|
45
|
+
* 与「确实一个模板都没配」一样回落到旧导出——模板服务出问题不该让现场导不出数据。
|
|
46
|
+
*/
|
|
47
|
+
export declare const resolveExportAction: (templates: ExportTemplateOption[] | null | undefined) => ExportAction;
|
|
48
|
+
/**
|
|
49
|
+
* 导出接口地址。这里已经把参数百分号编码好了(Gridify 的值里可能有 `&` `#` `+`,不编会截断 query string)。
|
|
50
|
+
*
|
|
51
|
+
* <b>因此下载不能走 `downloadBlob`</b>:它内部还会 `encodeURI(url)` 再编一次,
|
|
52
|
+
* `%` 被转义成 `%25`(`boxCode%3D*BOX001` → `boxCode%253D*BOX001`),
|
|
53
|
+
* 后端解析不出筛选串——现场表现是「在列表上筛完点导出,导出的是全量」。
|
|
54
|
+
* 见本目录 index.tsx 里的 `download`。
|
|
55
|
+
*/
|
|
56
|
+
export declare const buildExportUrl: (templateId: string, filter?: string | null, renderUrl?: string) => string;
|
|
57
|
+
/**
|
|
58
|
+
* 从响应头取导出文件名。
|
|
59
|
+
*
|
|
60
|
+
* 文件名是运维在模板上配的(可带 {date} 之类的占位),只有服务端知道最终值;
|
|
61
|
+
* 客户端自己起名会让那项配置永远不生效。头里取不到就用兜底名。
|
|
62
|
+
*
|
|
63
|
+
* 后端用 `filename*=UTF-8''xxx`(RFC 5987)传中文名,老式 `filename="xxx"` 也认。
|
|
64
|
+
*/
|
|
65
|
+
export declare const resolveFileName: (contentDisposition: string | undefined | null, fallback: string) => string;
|
|
66
|
+
/**
|
|
67
|
+
* 从导出失败的异常里取出给人看的错误信息。
|
|
68
|
+
*
|
|
69
|
+
* 导出请求是 `responseType: 'blob'`,后端返回的 JSON 错误体也会被 axios 当成 blob 收下,
|
|
70
|
+
* `e.response.data.error.message` 这条路永远取不到东西——现场看到的是 axios 自己的
|
|
71
|
+
* "Request failed with status code 500",既不知道是数据太多超时还是模板配错。
|
|
72
|
+
* 所以先把 blob 读回来解析一次。
|
|
73
|
+
*/
|
|
74
|
+
export declare const resolveExportError: (error: any) => Promise<string>;
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
2
|
+
function _regeneratorRuntime() { "use strict"; /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */ _regeneratorRuntime = function _regeneratorRuntime() { return e; }; var t, e = {}, r = Object.prototype, n = r.hasOwnProperty, o = Object.defineProperty || function (t, e, r) { t[e] = r.value; }, i = "function" == typeof Symbol ? Symbol : {}, a = i.iterator || "@@iterator", c = i.asyncIterator || "@@asyncIterator", u = i.toStringTag || "@@toStringTag"; function define(t, e, r) { return Object.defineProperty(t, e, { value: r, enumerable: !0, configurable: !0, writable: !0 }), t[e]; } try { define({}, ""); } catch (t) { define = function define(t, e, r) { return t[e] = r; }; } function wrap(t, e, r, n) { var i = e && e.prototype instanceof Generator ? e : Generator, a = Object.create(i.prototype), c = new Context(n || []); return o(a, "_invoke", { value: makeInvokeMethod(t, r, c) }), a; } function tryCatch(t, e, r) { try { return { type: "normal", arg: t.call(e, r) }; } catch (t) { return { type: "throw", arg: t }; } } e.wrap = wrap; var h = "suspendedStart", l = "suspendedYield", f = "executing", s = "completed", y = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} var p = {}; define(p, a, function () { return this; }); var d = Object.getPrototypeOf, v = d && d(d(values([]))); v && v !== r && n.call(v, a) && (p = v); var g = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(p); function defineIteratorMethods(t) { ["next", "throw", "return"].forEach(function (e) { define(t, e, function (t) { return this._invoke(e, t); }); }); } function AsyncIterator(t, e) { function invoke(r, o, i, a) { var c = tryCatch(t[r], t, o); if ("throw" !== c.type) { var u = c.arg, h = u.value; return h && "object" == _typeof(h) && n.call(h, "__await") ? e.resolve(h.__await).then(function (t) { invoke("next", t, i, a); }, function (t) { invoke("throw", t, i, a); }) : e.resolve(h).then(function (t) { u.value = t, i(u); }, function (t) { return invoke("throw", t, i, a); }); } a(c.arg); } var r; o(this, "_invoke", { value: function value(t, n) { function callInvokeWithMethodAndArg() { return new e(function (e, r) { invoke(t, n, e, r); }); } return r = r ? r.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg(); } }); } function makeInvokeMethod(e, r, n) { var o = h; return function (i, a) { if (o === f) throw new Error("Generator is already running"); if (o === s) { if ("throw" === i) throw a; return { value: t, done: !0 }; } for (n.method = i, n.arg = a;;) { var c = n.delegate; if (c) { var u = maybeInvokeDelegate(c, n); if (u) { if (u === y) continue; return u; } } if ("next" === n.method) n.sent = n._sent = n.arg;else if ("throw" === n.method) { if (o === h) throw o = s, n.arg; n.dispatchException(n.arg); } else "return" === n.method && n.abrupt("return", n.arg); o = f; var p = tryCatch(e, r, n); if ("normal" === p.type) { if (o = n.done ? s : l, p.arg === y) continue; return { value: p.arg, done: n.done }; } "throw" === p.type && (o = s, n.method = "throw", n.arg = p.arg); } }; } function maybeInvokeDelegate(e, r) { var n = r.method, o = e.iterator[n]; if (o === t) return r.delegate = null, "throw" === n && e.iterator.return && (r.method = "return", r.arg = t, maybeInvokeDelegate(e, r), "throw" === r.method) || "return" !== n && (r.method = "throw", r.arg = new TypeError("The iterator does not provide a '" + n + "' method")), y; var i = tryCatch(o, e.iterator, r.arg); if ("throw" === i.type) return r.method = "throw", r.arg = i.arg, r.delegate = null, y; var a = i.arg; return a ? a.done ? (r[e.resultName] = a.value, r.next = e.nextLoc, "return" !== r.method && (r.method = "next", r.arg = t), r.delegate = null, y) : a : (r.method = "throw", r.arg = new TypeError("iterator result is not an object"), r.delegate = null, y); } function pushTryEntry(t) { var e = { tryLoc: t[0] }; 1 in t && (e.catchLoc = t[1]), 2 in t && (e.finallyLoc = t[2], e.afterLoc = t[3]), this.tryEntries.push(e); } function resetTryEntry(t) { var e = t.completion || {}; e.type = "normal", delete e.arg, t.completion = e; } function Context(t) { this.tryEntries = [{ tryLoc: "root" }], t.forEach(pushTryEntry, this), this.reset(!0); } function values(e) { if (e || "" === e) { var r = e[a]; if (r) return r.call(e); if ("function" == typeof e.next) return e; if (!isNaN(e.length)) { var o = -1, i = function next() { for (; ++o < e.length;) if (n.call(e, o)) return next.value = e[o], next.done = !1, next; return next.value = t, next.done = !0, next; }; return i.next = i; } } throw new TypeError(_typeof(e) + " is not iterable"); } return GeneratorFunction.prototype = GeneratorFunctionPrototype, o(g, "constructor", { value: GeneratorFunctionPrototype, configurable: !0 }), o(GeneratorFunctionPrototype, "constructor", { value: GeneratorFunction, configurable: !0 }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, u, "GeneratorFunction"), e.isGeneratorFunction = function (t) { var e = "function" == typeof t && t.constructor; return !!e && (e === GeneratorFunction || "GeneratorFunction" === (e.displayName || e.name)); }, e.mark = function (t) { return Object.setPrototypeOf ? Object.setPrototypeOf(t, GeneratorFunctionPrototype) : (t.__proto__ = GeneratorFunctionPrototype, define(t, u, "GeneratorFunction")), t.prototype = Object.create(g), t; }, e.awrap = function (t) { return { __await: t }; }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, c, function () { return this; }), e.AsyncIterator = AsyncIterator, e.async = function (t, r, n, o, i) { void 0 === i && (i = Promise); var a = new AsyncIterator(wrap(t, r, n, o), i); return e.isGeneratorFunction(r) ? a : a.next().then(function (t) { return t.done ? t.value : a.next(); }); }, defineIteratorMethods(g), define(g, u, "Generator"), define(g, a, function () { return this; }), define(g, "toString", function () { return "[object Generator]"; }), e.keys = function (t) { var e = Object(t), r = []; for (var n in e) r.push(n); return r.reverse(), function next() { for (; r.length;) { var t = r.pop(); if (t in e) return next.value = t, next.done = !1, next; } return next.done = !0, next; }; }, e.values = values, Context.prototype = { constructor: Context, reset: function reset(e) { if (this.prev = 0, this.next = 0, this.sent = this._sent = t, this.done = !1, this.delegate = null, this.method = "next", this.arg = t, this.tryEntries.forEach(resetTryEntry), !e) for (var r in this) "t" === r.charAt(0) && n.call(this, r) && !isNaN(+r.slice(1)) && (this[r] = t); }, stop: function stop() { this.done = !0; var t = this.tryEntries[0].completion; if ("throw" === t.type) throw t.arg; return this.rval; }, dispatchException: function dispatchException(e) { if (this.done) throw e; var r = this; function handle(n, o) { return a.type = "throw", a.arg = e, r.next = n, o && (r.method = "next", r.arg = t), !!o; } for (var o = this.tryEntries.length - 1; o >= 0; --o) { var i = this.tryEntries[o], a = i.completion; if ("root" === i.tryLoc) return handle("end"); if (i.tryLoc <= this.prev) { var c = n.call(i, "catchLoc"), u = n.call(i, "finallyLoc"); if (c && u) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } else if (c) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); } else { if (!u) throw new Error("try statement without catch or finally"); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } } } }, abrupt: function abrupt(t, e) { for (var r = this.tryEntries.length - 1; r >= 0; --r) { var o = this.tryEntries[r]; if (o.tryLoc <= this.prev && n.call(o, "finallyLoc") && this.prev < o.finallyLoc) { var i = o; break; } } i && ("break" === t || "continue" === t) && i.tryLoc <= e && e <= i.finallyLoc && (i = null); var a = i ? i.completion : {}; return a.type = t, a.arg = e, i ? (this.method = "next", this.next = i.finallyLoc, y) : this.complete(a); }, complete: function complete(t, e) { if ("throw" === t.type) throw t.arg; return "break" === t.type || "continue" === t.type ? this.next = t.arg : "return" === t.type ? (this.rval = this.arg = t.arg, this.method = "return", this.next = "end") : "normal" === t.type && e && (this.next = e), y; }, finish: function finish(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.finallyLoc === t) return this.complete(r.completion, r.afterLoc), resetTryEntry(r), y; } }, catch: function _catch(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.tryLoc === t) { var n = r.completion; if ("throw" === n.type) { var o = n.arg; resetTryEntry(r); } return o; } } throw new Error("illegal catch attempt"); }, delegateYield: function delegateYield(e, r, n) { return this.delegate = { iterator: values(e), resultName: r, nextLoc: n }, "next" === this.method && (this.arg = t), y; } }, e; }
|
|
3
|
+
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
|
4
|
+
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
|
5
|
+
/**
|
|
6
|
+
* 导出按钮的行为决策与地址构造。
|
|
7
|
+
*
|
|
8
|
+
* 抽成纯函数是为了能直接测:这里的分支决定了「现场点导出会发生什么」,
|
|
9
|
+
* 而它最容易出问题的两个场景——模板没配、模板接口挂了——在页面里很难复现。
|
|
10
|
+
*
|
|
11
|
+
* @author nokecy
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/** 导出模板服务的接口地址:可用模板列表与按模板渲染文件。默认指向 MES 后端的 export-template 服务,其他后端可在 ExportButton 上覆盖。 */
|
|
15
|
+
|
|
16
|
+
/** 默认的导出模板服务地址。 */
|
|
17
|
+
export var DEFAULT_EXPORT_TEMPLATE_API = {
|
|
18
|
+
options: '/api/mes/export-template/options',
|
|
19
|
+
render: '/api/mes/export-template/render'
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/** 后端 `export-template/options` 返回的模板项 */
|
|
23
|
+
|
|
24
|
+
/** 导出按钮该以什么形态出现 */
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 根据可用模板决定导出按钮的行为。
|
|
28
|
+
*
|
|
29
|
+
* 传 null / undefined 表示「没拿到模板列表」(接口失败或还没加载),
|
|
30
|
+
* 与「确实一个模板都没配」一样回落到旧导出——模板服务出问题不该让现场导不出数据。
|
|
31
|
+
*/
|
|
32
|
+
export var resolveExportAction = function resolveExportAction(templates) {
|
|
33
|
+
var _templates$find;
|
|
34
|
+
if (!templates || templates.length === 0) {
|
|
35
|
+
return {
|
|
36
|
+
kind: 'legacy'
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
if (templates.length === 1) {
|
|
40
|
+
return {
|
|
41
|
+
kind: 'single',
|
|
42
|
+
template: templates[0]
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 后端已按「默认优先、其次按名称」排序,所以取不到 isDefault 时用首个兜底,
|
|
47
|
+
// 不让默认项落空导致下拉没有选中态。
|
|
48
|
+
var defaultTemplate = (_templates$find = templates.find(function (item) {
|
|
49
|
+
return item.isDefault;
|
|
50
|
+
})) !== null && _templates$find !== void 0 ? _templates$find : templates[0];
|
|
51
|
+
return {
|
|
52
|
+
kind: 'menu',
|
|
53
|
+
templates: templates,
|
|
54
|
+
defaultTemplate: defaultTemplate
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 导出接口地址。这里已经把参数百分号编码好了(Gridify 的值里可能有 `&` `#` `+`,不编会截断 query string)。
|
|
60
|
+
*
|
|
61
|
+
* <b>因此下载不能走 `downloadBlob`</b>:它内部还会 `encodeURI(url)` 再编一次,
|
|
62
|
+
* `%` 被转义成 `%25`(`boxCode%3D*BOX001` → `boxCode%253D*BOX001`),
|
|
63
|
+
* 后端解析不出筛选串——现场表现是「在列表上筛完点导出,导出的是全量」。
|
|
64
|
+
* 见本目录 index.tsx 里的 `download`。
|
|
65
|
+
*/
|
|
66
|
+
export var buildExportUrl = function buildExportUrl(templateId, filter) {
|
|
67
|
+
var renderUrl = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : DEFAULT_EXPORT_TEMPLATE_API.render;
|
|
68
|
+
var params = new URLSearchParams();
|
|
69
|
+
params.set('TemplateId', templateId);
|
|
70
|
+
|
|
71
|
+
// 空筛选串不拼参数:拼上 Filter= 会让后端把空串当成一个筛选串去解析
|
|
72
|
+
if (filter) {
|
|
73
|
+
params.set('Filter', filter);
|
|
74
|
+
}
|
|
75
|
+
return "".concat(renderUrl, "?").concat(params.toString());
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 从响应头取导出文件名。
|
|
80
|
+
*
|
|
81
|
+
* 文件名是运维在模板上配的(可带 {date} 之类的占位),只有服务端知道最终值;
|
|
82
|
+
* 客户端自己起名会让那项配置永远不生效。头里取不到就用兜底名。
|
|
83
|
+
*
|
|
84
|
+
* 后端用 `filename*=UTF-8''xxx`(RFC 5987)传中文名,老式 `filename="xxx"` 也认。
|
|
85
|
+
*/
|
|
86
|
+
export var resolveFileName = function resolveFileName(contentDisposition, fallback) {
|
|
87
|
+
var withExtension = function withExtension(name) {
|
|
88
|
+
return /\.xlsx$/i.test(name) ? name : "".concat(name, ".xlsx");
|
|
89
|
+
};
|
|
90
|
+
if (!contentDisposition) return withExtension(fallback);
|
|
91
|
+
var star = /filename\*=(?:UTF-8'')?([^;]+)/i.exec(contentDisposition);
|
|
92
|
+
if (star !== null && star !== void 0 && star[1]) {
|
|
93
|
+
try {
|
|
94
|
+
return withExtension(decodeURIComponent(star[1].trim().replace(/^"|"$/g, '')));
|
|
95
|
+
} catch (_unused) {
|
|
96
|
+
// 头里的编码坏了不该让整个下载失败,退回兜底名
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
var plain = /filename="?([^";]+)"?/i.exec(contentDisposition);
|
|
100
|
+
if (plain !== null && plain !== void 0 && plain[1]) return withExtension(plain[1].trim());
|
|
101
|
+
return withExtension(fallback);
|
|
102
|
+
};
|
|
103
|
+
var readBlobText = function readBlobText(blob) {
|
|
104
|
+
if (typeof blob.text === 'function') return blob.text();
|
|
105
|
+
// 个别环境(旧浏览器、jsdom)的 Blob 没有 text(),用 FileReader 兜底
|
|
106
|
+
return new Promise(function (resolve, reject) {
|
|
107
|
+
var reader = new FileReader();
|
|
108
|
+
reader.onload = function () {
|
|
109
|
+
var _reader$result;
|
|
110
|
+
return resolve(String((_reader$result = reader.result) !== null && _reader$result !== void 0 ? _reader$result : ''));
|
|
111
|
+
};
|
|
112
|
+
reader.onerror = function () {
|
|
113
|
+
return reject(reader.error);
|
|
114
|
+
};
|
|
115
|
+
reader.readAsText(blob);
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* 从导出失败的异常里取出给人看的错误信息。
|
|
121
|
+
*
|
|
122
|
+
* 导出请求是 `responseType: 'blob'`,后端返回的 JSON 错误体也会被 axios 当成 blob 收下,
|
|
123
|
+
* `e.response.data.error.message` 这条路永远取不到东西——现场看到的是 axios 自己的
|
|
124
|
+
* "Request failed with status code 500",既不知道是数据太多超时还是模板配错。
|
|
125
|
+
* 所以先把 blob 读回来解析一次。
|
|
126
|
+
*/
|
|
127
|
+
export var resolveExportError = /*#__PURE__*/function () {
|
|
128
|
+
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(error) {
|
|
129
|
+
var _error$response, _data$error;
|
|
130
|
+
var data, _JSON$parse, message;
|
|
131
|
+
return _regeneratorRuntime().wrap(function _callee$(_context) {
|
|
132
|
+
while (1) switch (_context.prev = _context.next) {
|
|
133
|
+
case 0:
|
|
134
|
+
data = error === null || error === void 0 || (_error$response = error.response) === null || _error$response === void 0 ? void 0 : _error$response.data;
|
|
135
|
+
if (!(typeof Blob !== 'undefined' && data instanceof Blob)) {
|
|
136
|
+
_context.next = 26;
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
_context.prev = 2;
|
|
140
|
+
_context.t2 = JSON;
|
|
141
|
+
_context.next = 6;
|
|
142
|
+
return readBlobText(data);
|
|
143
|
+
case 6:
|
|
144
|
+
_context.t3 = _context.sent;
|
|
145
|
+
_context.t4 = _JSON$parse = _context.t2.parse.call(_context.t2, _context.t3);
|
|
146
|
+
_context.t1 = _context.t4 === null;
|
|
147
|
+
if (_context.t1) {
|
|
148
|
+
_context.next = 11;
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
_context.t1 = _JSON$parse === void 0;
|
|
152
|
+
case 11:
|
|
153
|
+
_context.t0 = _context.t1;
|
|
154
|
+
if (_context.t0) {
|
|
155
|
+
_context.next = 14;
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
_context.t0 = (_JSON$parse = _JSON$parse.error) === null || _JSON$parse === void 0;
|
|
159
|
+
case 14:
|
|
160
|
+
if (!_context.t0) {
|
|
161
|
+
_context.next = 18;
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
_context.t5 = void 0;
|
|
165
|
+
_context.next = 19;
|
|
166
|
+
break;
|
|
167
|
+
case 18:
|
|
168
|
+
_context.t5 = _JSON$parse.message;
|
|
169
|
+
case 19:
|
|
170
|
+
message = _context.t5;
|
|
171
|
+
if (!message) {
|
|
172
|
+
_context.next = 22;
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
return _context.abrupt("return", message);
|
|
176
|
+
case 22:
|
|
177
|
+
_context.next = 26;
|
|
178
|
+
break;
|
|
179
|
+
case 24:
|
|
180
|
+
_context.prev = 24;
|
|
181
|
+
_context.t6 = _context["catch"](2);
|
|
182
|
+
case 26:
|
|
183
|
+
return _context.abrupt("return", (data === null || data === void 0 || (_data$error = data.error) === null || _data$error === void 0 ? void 0 : _data$error.message) || (error === null || error === void 0 ? void 0 : error.message) || '导出失败');
|
|
184
|
+
case 27:
|
|
185
|
+
case "end":
|
|
186
|
+
return _context.stop();
|
|
187
|
+
}
|
|
188
|
+
}, _callee, null, [[2, 24]]);
|
|
189
|
+
}));
|
|
190
|
+
return function resolveExportError(_x) {
|
|
191
|
+
return _ref.apply(this, arguments);
|
|
192
|
+
};
|
|
193
|
+
}();
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { buildExportUrl, DEFAULT_EXPORT_TEMPLATE_API, resolveExportAction, resolveExportError, resolveFileName, type ExportTemplateApi, type ExportTemplateOption } from './exportAction';
|
|
3
|
+
/**
|
|
4
|
+
* 列表页统一导出按钮。
|
|
5
|
+
*
|
|
6
|
+
* <p>导出格式由运维在「导出模板」里配,页面这边只提供 gridKey 和当前筛选条件。
|
|
7
|
+
* 一个页面配了几份模板(各客户各一份),这里就出下拉让人挑。</p>
|
|
8
|
+
*
|
|
9
|
+
* <p><b>没有模板时走 `legacy`</b>——即页面原来那个硬编码的导出接口。
|
|
10
|
+
* 老导出接口保留并存,模板配好之前现场照常能导;模板接口挂了也走这条路。
|
|
11
|
+
* 三种形态(老接口 / 单模板 / 多模板)长得一样,只有多模板时右边多一个下拉箭头,
|
|
12
|
+
* 所以运维配不配模板,操作员那边看到的都是同一个按钮。</p>
|
|
13
|
+
*
|
|
14
|
+
* @author nokecy
|
|
15
|
+
*/
|
|
16
|
+
export interface ExportButtonProps {
|
|
17
|
+
/**
|
|
18
|
+
* 发请求的函数,约定与 umi 的 `request` 一致:`request(url, { method, params, responseType, getResponse, skipErrorHandler })`,
|
|
19
|
+
* 传 `getResponse: true` 时返回 `{ data, headers }`。宿主在这里带上自己的鉴权、网关前缀与错误处理。
|
|
20
|
+
*/
|
|
21
|
+
request: (url: string, options?: Record<string, any>) => Promise<any>;
|
|
22
|
+
/** 导出模板服务的接口地址,默认 MES 后端的 `/api/mes/export-template/{options,render}` */
|
|
23
|
+
templateApi?: ExportTemplateApi;
|
|
24
|
+
/** 页面标识,取自 `getGridKey(...)`,与导出模板上配的「适用页面」对应 */
|
|
25
|
+
gridKey: string;
|
|
26
|
+
/** 列表当前的 Gridify 筛选串,原样透传给后端 */
|
|
27
|
+
filter?: string;
|
|
28
|
+
/** 没有可用模板时导什么:页面原有导出接口的地址,以及响应头没给文件名时的兜底名 */
|
|
29
|
+
legacy?: {
|
|
30
|
+
url: string;
|
|
31
|
+
fileName: string;
|
|
32
|
+
};
|
|
33
|
+
/** 按钮文字,默认「导出」 */
|
|
34
|
+
children?: React.ReactNode;
|
|
35
|
+
}
|
|
36
|
+
declare const ExportButton: React.FC<ExportButtonProps>;
|
|
37
|
+
export default ExportButton;
|
|
38
|
+
export { buildExportUrl, DEFAULT_EXPORT_TEMPLATE_API, resolveExportAction, resolveExportError, resolveFileName };
|
|
39
|
+
export type { ExportTemplateApi, ExportTemplateOption };
|