@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.
@@ -0,0 +1,259 @@
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
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
6
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
7
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
8
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
9
+ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
10
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
11
+ import { saveAs } from "../utils/download";
12
+ import { DownOutlined, DownloadOutlined } from '@ant-design/icons';
13
+ import { useRequest } from 'ahooks';
14
+ import { Button, Dropdown, message, Tooltip } from 'antd';
15
+ import React, { useMemo, useState } from 'react';
16
+ import { buildExportUrl, DEFAULT_EXPORT_TEMPLATE_API, resolveExportAction, resolveExportError, resolveFileName } from "./exportAction";
17
+
18
+ /**
19
+ * 列表页统一导出按钮。
20
+ *
21
+ * <p>导出格式由运维在「导出模板」里配,页面这边只提供 gridKey 和当前筛选条件。
22
+ * 一个页面配了几份模板(各客户各一份),这里就出下拉让人挑。</p>
23
+ *
24
+ * <p><b>没有模板时走 `legacy`</b>——即页面原来那个硬编码的导出接口。
25
+ * 老导出接口保留并存,模板配好之前现场照常能导;模板接口挂了也走这条路。
26
+ * 三种形态(老接口 / 单模板 / 多模板)长得一样,只有多模板时右边多一个下拉箭头,
27
+ * 所以运维配不配模板,操作员那边看到的都是同一个按钮。</p>
28
+ *
29
+ * @author nokecy
30
+ */
31
+
32
+ var ExportButton = function ExportButton(_ref) {
33
+ var request = _ref.request,
34
+ _ref$templateApi = _ref.templateApi,
35
+ templateApi = _ref$templateApi === void 0 ? DEFAULT_EXPORT_TEMPLATE_API : _ref$templateApi,
36
+ gridKey = _ref.gridKey,
37
+ filter = _ref.filter,
38
+ legacy = _ref.legacy,
39
+ _ref$children = _ref.children,
40
+ children = _ref$children === void 0 ? '导出' : _ref$children;
41
+ var _useRequest = useRequest(function () {
42
+ return request(templateApi.options, {
43
+ method: 'GET',
44
+ params: {
45
+ gridKey: gridKey
46
+ },
47
+ // 模板服务不可用不该在列表页弹一堆报错——拿不到就当没配模板,走 legacy
48
+ skipErrorHandler: true
49
+ }).catch(function () {
50
+ return null;
51
+ });
52
+ }, {
53
+ refreshDeps: [gridKey]
54
+ }),
55
+ data = _useRequest.data;
56
+ var action = useMemo(function () {
57
+ return resolveExportAction(data);
58
+ }, [data]);
59
+ var _useState = useState(false),
60
+ _useState2 = _slicedToArray(_useState, 2),
61
+ exporting = _useState2[0],
62
+ setExporting = _useState2[1];
63
+
64
+ /**
65
+ * 跑一次导出,全程给反馈。
66
+ *
67
+ * 十万行的导出服务端要跑几十秒,原先从点下去到文件落地界面上没有任何变化,
68
+ * 现场的反应就是「点了没反应」,然后连点——每点一次服务端多跑一遍全量查询。
69
+ * 这里同时做三件事:按钮转圈(antd 的 loading 态本身就吞掉后续点击,顺带防重)、
70
+ * 挂一条不自动消失的提示(等了几十秒的人多半已经在看别处,按钮上那圈他看不见)、
71
+ * 结束时明确说成了还是败了。
72
+ */
73
+ var runExport = /*#__PURE__*/function () {
74
+ var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(task) {
75
+ var hideTip;
76
+ return _regeneratorRuntime().wrap(function _callee$(_context) {
77
+ while (1) switch (_context.prev = _context.next) {
78
+ case 0:
79
+ if (!exporting) {
80
+ _context.next = 2;
81
+ break;
82
+ }
83
+ return _context.abrupt("return");
84
+ case 2:
85
+ setExporting(true);
86
+ hideTip = message.loading('正在生成导出文件,请稍候…', 0);
87
+ _context.prev = 4;
88
+ _context.next = 7;
89
+ return task();
90
+ case 7:
91
+ message.success('导出完成');
92
+ _context.next = 17;
93
+ break;
94
+ case 10:
95
+ _context.prev = 10;
96
+ _context.t0 = _context["catch"](4);
97
+ _context.t1 = message;
98
+ _context.next = 15;
99
+ return resolveExportError(_context.t0);
100
+ case 15:
101
+ _context.t2 = _context.sent;
102
+ _context.t1.error.call(_context.t1, _context.t2);
103
+ case 17:
104
+ _context.prev = 17;
105
+ hideTip();
106
+ setExporting(false);
107
+ return _context.finish(17);
108
+ case 21:
109
+ case "end":
110
+ return _context.stop();
111
+ }
112
+ }, _callee, null, [[4, 10, 17, 21]]);
113
+ }));
114
+ return function runExport(_x) {
115
+ return _ref2.apply(this, arguments);
116
+ };
117
+ }();
118
+
119
+ /**
120
+ * 按模板导出。
121
+ *
122
+ * 没用公共的 `downloadBlob`,两个原因:
123
+ * ① 它会对已经编码好的 URL 再 `encodeURI` 一次,筛选串里的 `%` 被二次转义,导出就丢筛选;
124
+ * ② 它要求调用方自己起文件名,而文件名是运维在模板上配的(支持 {date} 之类),
125
+ * 只能从响应头里取,写死模板名会让那项配置永远不生效。
126
+ */
127
+ var download = function download(templateId, fallbackName) {
128
+ return runExport( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2() {
129
+ var _headers, _data;
130
+ var response, headers;
131
+ return _regeneratorRuntime().wrap(function _callee2$(_context2) {
132
+ while (1) switch (_context2.prev = _context2.next) {
133
+ case 0:
134
+ _context2.next = 2;
135
+ return request(buildExportUrl(templateId, filter, templateApi.render), {
136
+ method: 'GET',
137
+ responseType: 'blob',
138
+ getResponse: true,
139
+ skipErrorHandler: true
140
+ });
141
+ case 2:
142
+ response = _context2.sent;
143
+ headers = (_headers = response === null || response === void 0 ? void 0 : response.headers) !== null && _headers !== void 0 ? _headers : {};
144
+ saveAs((_data = response === null || response === void 0 ? void 0 : response.data) !== null && _data !== void 0 ? _data : response, resolveFileName(headers['content-disposition'], fallbackName));
145
+ case 5:
146
+ case "end":
147
+ return _context2.stop();
148
+ }
149
+ }, _callee2);
150
+ })));
151
+ };
152
+
153
+ /**
154
+ * 走页面原有的老导出接口。
155
+ *
156
+ * 等价于 `downloadBlob`(老接口的 url 里筛选串没编码,同样靠 `encodeURI` 补),
157
+ * 只是加了 `skipErrorHandler`:错误统一由 `runExport` 报一次,
158
+ * 否则 umi 的全局处理器先弹一次、这里再弹一次。
159
+ */
160
+ var downloadLegacy = function downloadLegacy(target) {
161
+ return runExport( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3() {
162
+ var blob;
163
+ return _regeneratorRuntime().wrap(function _callee3$(_context3) {
164
+ while (1) switch (_context3.prev = _context3.next) {
165
+ case 0:
166
+ _context3.next = 2;
167
+ return request(encodeURI(target.url), {
168
+ method: 'GET',
169
+ responseType: 'blob',
170
+ skipErrorHandler: true
171
+ });
172
+ case 2:
173
+ blob = _context3.sent;
174
+ saveAs(blob, target.fileName);
175
+ case 4:
176
+ case "end":
177
+ return _context3.stop();
178
+ }
179
+ }, _callee3);
180
+ })));
181
+ };
182
+ if (action.kind === 'legacy') {
183
+ if (!legacy) return null;
184
+ return /*#__PURE__*/React.createElement(Tooltip, {
185
+ title: "\u6309\u7CFB\u7EDF\u9ED8\u8BA4\u683C\u5F0F\u5BFC\u51FA\u5F53\u524D\u7B5B\u9009\u7ED3\u679C"
186
+ }, /*#__PURE__*/React.createElement(Button, {
187
+ type: "primary",
188
+ icon: /*#__PURE__*/React.createElement(DownloadOutlined, null),
189
+ loading: exporting,
190
+ onClick: function onClick() {
191
+ return void downloadLegacy(legacy);
192
+ }
193
+ }, children));
194
+ }
195
+ if (action.kind === 'single') {
196
+ var template = action.template;
197
+ return /*#__PURE__*/React.createElement(Tooltip, {
198
+ title: "\u6309\u6A21\u677F\u300C".concat(template.name, "\u300D\u5BFC\u51FA\u5F53\u524D\u7B5B\u9009\u7ED3\u679C")
199
+ }, /*#__PURE__*/React.createElement(Button, {
200
+ type: "primary",
201
+ icon: /*#__PURE__*/React.createElement(DownloadOutlined, null),
202
+ loading: exporting,
203
+ onClick: function onClick() {
204
+ return void download(template.id, template.name);
205
+ }
206
+ }, children));
207
+ }
208
+ var templates = action.templates,
209
+ defaultTemplate = action.defaultTemplate;
210
+ return /*#__PURE__*/React.createElement(Dropdown.Button, {
211
+ type: "primary",
212
+ loading: exporting
213
+ // 导出期间把下拉的 trigger 置空:光有 loading 只拦得住主按钮,下拉照样能展开,
214
+ // 点进去的模板会被上面那道并发守卫静默吃掉——又成了「点了没反应」。
215
+ // 这里不用 disabled,那会把主按钮一起变灰,跟另外两种形态导出中的样子对不上。
216
+ ,
217
+ trigger: exporting ? [] : undefined
218
+ // Dropdown.Button 的 icon 给的是右边那半,正好用来做「这里能展开」的指示;
219
+ // 左边主按钮不吃 icon,只能在 buttonsRender 里补。
220
+ ,
221
+ icon: /*#__PURE__*/React.createElement(DownOutlined, null),
222
+ onClick: function onClick() {
223
+ return void download(defaultTemplate.id, defaultTemplate.name);
224
+ },
225
+ menu: {
226
+ items: templates.map(function (item) {
227
+ return {
228
+ key: item.id,
229
+ // 标出默认项,让人对得上主按钮直接导的是哪一份
230
+ label: item.id === defaultTemplate.id ? "".concat(item.name, "\uFF08\u9ED8\u8BA4\uFF09") : item.name,
231
+ onClick: function onClick() {
232
+ return void download(item.id, item.name);
233
+ }
234
+ };
235
+ })
236
+ }
237
+ // Tooltip 包在主按钮上而不是整个 Dropdown.Button 外面:DropdownButton 是普通函数组件、
238
+ // 没有 forwardRef,Tooltip 拿不到它的 DOM(React 会报 refs 警告,气泡定位也不准)。
239
+ ,
240
+ buttonsRender: function buttonsRender(_ref5) {
241
+ var _ref6 = _slicedToArray(_ref5, 2),
242
+ mainButton = _ref6[0],
243
+ arrowButton = _ref6[1];
244
+ return [/*#__PURE__*/React.createElement(Tooltip, {
245
+ key: "main",
246
+ title: "\u6309\u6A21\u677F\u300C".concat(defaultTemplate.name, "\u300D\u5BFC\u51FA\uFF1B\u70B9\u53F3\u4FA7\u7BAD\u5934\u53EF\u6362\u5176\u5B83\u683C\u5F0F")
247
+ }, /*#__PURE__*/React.cloneElement(mainButton, {
248
+ icon: /*#__PURE__*/React.createElement(DownloadOutlined, null)
249
+ })),
250
+ /*#__PURE__*/
251
+ // 右半边 antd 不给传 disabled,导出期间它看着能点其实点不开,得自己补上
252
+ React.cloneElement(arrowButton, {
253
+ disabled: exporting
254
+ })];
255
+ }
256
+ }, children);
257
+ };
258
+ export default ExportButton;
259
+ export { buildExportUrl, DEFAULT_EXPORT_TEMPLATE_API, resolveExportAction, resolveExportError, resolveFileName };
@@ -18,6 +18,15 @@ export interface ImportModalProps {
18
18
  serverUrl?: () => string;
19
19
  /** 按钮属性 */
20
20
  buttonProps?: any;
21
+ /**
22
+ * 发上传请求的函数,约定与 umi 的 `request` 一致:`request(url, { method, data, headers, skipErrorHandler, onUploadProgress })`。
23
+ * 传入后上传改走它(宿主在这里带上自己的鉴权与网关前缀);不传则由 antd Upload 直接请求 `action`。
24
+ */
25
+ request?: (url: string, options?: Record<string, any>) => Promise<any>;
26
+ /** 上传请求的方法,仅配合 `request` 使用,默认 POST */
27
+ method?: string;
28
+ /** 上传请求成功后的回调,参数是接口响应(早于「导入成功」提示);仅配合 `request` 使用 */
29
+ onRealSuccess?: (response: any) => void;
21
30
  }
22
31
  /**
23
32
  * 通用导入弹出框
@@ -33,7 +33,10 @@ var ImportModal = function ImportModal(props) {
33
33
  _props$downloadBlob = props.downloadBlob,
34
34
  downloadBlob = _props$downloadBlob === void 0 ? defaultDownloadBlob : _props$downloadBlob,
35
35
  serverUrl = props.serverUrl,
36
- buttonProps = props.buttonProps;
36
+ buttonProps = props.buttonProps,
37
+ request = props.request,
38
+ method = props.method,
39
+ onRealSuccess = props.onRealSuccess;
37
40
  var _useBoolean = useBoolean(false),
38
41
  _useBoolean2 = _slicedToArray(_useBoolean, 2),
39
42
  visible = _useBoolean2[0],
@@ -63,12 +66,46 @@ var ImportModal = function ImportModal(props) {
63
66
  }
64
67
  }, "\u6A21\u7248")),
65
68
  type: "info"
66
- }), /*#__PURE__*/React.createElement(Upload.Dragger, {
69
+ }), /*#__PURE__*/React.createElement(Upload.Dragger, _extends({
67
70
  style: {
68
71
  marginTop: 10
69
72
  },
70
73
  multiple: false,
71
- action: getUploadUrl(),
74
+ action: getUploadUrl()
75
+ }, request ? {
76
+ customRequest: function customRequest(_ref) {
77
+ var action = _ref.action,
78
+ file = _ref.file,
79
+ headers = _ref.headers,
80
+ onError = _ref.onError,
81
+ onProgress = _ref.onProgress,
82
+ onSuccess = _ref.onSuccess;
83
+ var formData = new FormData();
84
+ formData.append('file', file);
85
+ request(action, {
86
+ method: method || 'POST',
87
+ data: formData,
88
+ headers: headers,
89
+ // 导入失败要展示行级原因,交给下面的弹窗统一报,不再走全局吐司。
90
+ skipErrorHandler: true,
91
+ onUploadProgress: function onUploadProgress(_ref2) {
92
+ var total = _ref2.total,
93
+ loaded = _ref2.loaded;
94
+ onProgress === null || onProgress === void 0 || onProgress({
95
+ percent: Number((loaded / total * 100).toFixed(2))
96
+ }, file);
97
+ }
98
+ }).then(function (response) {
99
+ onSuccess === null || onSuccess === void 0 || onSuccess(response, file);
100
+ onRealSuccess === null || onRealSuccess === void 0 || onRealSuccess(response);
101
+ })
102
+ // 第二个参数成为 info.file.response,onChange 靠它拿到后端的失败原因,而不是 axios 的英文文案。
103
+ .catch(function (err) {
104
+ var _err$response;
105
+ 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);
106
+ });
107
+ }
108
+ } : {}, {
72
109
  onChange: function onChange(info) {
73
110
  if (info.file.status === 'done') {
74
111
  message.success('导入成功');
@@ -77,15 +114,16 @@ var ImportModal = function ImportModal(props) {
77
114
  }
78
115
  if (info.file.status === 'error') {
79
116
  var _info$file;
80
- Modal.info({
81
- title: '导入失败,原因如下:',
117
+ // 没有后端给的原因时也要有提示,不能让失败无声无息。
118
+ Modal.error({
119
+ title: '导入失败',
82
120
  closable: true,
83
- width: 1000,
84
- 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
121
+ width: 800,
122
+ 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) || '文件未能导入。请核对模板格式与必填列后重试;若持续失败请联系技术支持。'
85
123
  });
86
124
  }
87
125
  }
88
- }, /*#__PURE__*/React.createElement("p", {
126
+ }), /*#__PURE__*/React.createElement("p", {
89
127
  className: "ant-upload-drag-icon"
90
128
  }, /*#__PURE__*/React.createElement(InboxOutlined, null)), /*#__PURE__*/React.createElement("p", {
91
129
  className: "ant-upload-text"
@@ -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/esm/index.js CHANGED
@@ -44,6 +44,8 @@ useSchemeManager, useGridSchemes, LocalStorageSchemeAdapter, BackendApiSchemeAda
44
44
  export * from "./adapters";
45
45
  export * from "./readPretty";
46
46
  export { createEntitySelect } from "./entitySelect";
47
+ export { default as ExportButton, buildExportUrl, DEFAULT_EXPORT_TEMPLATE_API, resolveExportAction, resolveExportError, resolveFileName } from "./exportButton";
48
+ export { saveAs } from "./utils/download";
47
49
  export { semanticTextColors, toGridTextColor, gridValueEnum } from "./ag-grid-plus/utils/valueEnumColor";
48
50
  export { contrastRatio, relativeLuminance, darkenUntilContrast, lightenUntilContrast, toRgb, toHsl, fromHsl } from "./utils/contrast";
49
51
  export { BusinessDecimal, decimal, decimalText, nonNegativeDecimal, roundDecimal, sumDecimals, formatDecimal } from "./utils/businessDecimal";
@@ -0,0 +1,6 @@
1
+ /**
2
+ * 把 Blob 存成本地文件。
3
+ *
4
+ * @author nokecy
5
+ */
6
+ export declare const saveAs: (blob: Blob, filename: string) => void;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * 把 Blob 存成本地文件。
3
+ *
4
+ * @author nokecy
5
+ */
6
+ export var saveAs = function saveAs(blob, filename) {
7
+ var nav = window.navigator;
8
+ if (typeof nav.msSaveBlob === 'function') {
9
+ nav.msSaveBlob(blob, filename);
10
+ return;
11
+ }
12
+ var link = document.createElement('a');
13
+ link.href = window.URL.createObjectURL(blob);
14
+ link.download = filename;
15
+ link.click();
16
+ window.URL.revokeObjectURL(link.href);
17
+ };