@nokecy/qc-ui 1.1.76 → 1.1.79

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.
Files changed (85) hide show
  1. package/dist/cjs/attachment/AttachmentFileButton.d.ts +4 -0
  2. package/dist/cjs/attachment/AttachmentFileButton.js +86 -0
  3. package/dist/cjs/attachment/AttachmentImageUpload.d.ts +16 -0
  4. package/dist/cjs/attachment/AttachmentImageUpload.js +206 -0
  5. package/dist/cjs/attachment/AttachmentPanel.d.ts +8 -0
  6. package/dist/cjs/attachment/AttachmentPanel.js +63 -0
  7. package/dist/cjs/attachment/AttachmentVideoUpload.d.ts +13 -0
  8. package/dist/cjs/attachment/AttachmentVideoUpload.js +88 -0
  9. package/dist/cjs/attachment/ChunkedDragger.d.ts +14 -0
  10. package/dist/cjs/attachment/ChunkedDragger.js +160 -0
  11. package/dist/cjs/attachment/attachmentList.d.ts +91 -0
  12. package/dist/cjs/attachment/attachmentList.js +214 -0
  13. package/dist/cjs/attachment/chunkUpload.d.ts +26 -0
  14. package/dist/cjs/attachment/chunkUpload.js +276 -0
  15. package/dist/cjs/attachment/env.d.ts +41 -0
  16. package/dist/cjs/attachment/env.js +41 -0
  17. package/dist/cjs/attachment/index.d.ts +20 -0
  18. package/dist/cjs/attachment/index.js +92 -0
  19. package/dist/cjs/index.d.ts +2 -0
  20. package/dist/cjs/index.js +24 -0
  21. package/dist/cjs/standardList/StandardAgGridPlus.d.ts +58 -0
  22. package/dist/cjs/standardList/StandardAgGridPlus.js +698 -0
  23. package/dist/cjs/standardList/dateFormat.d.ts +16 -0
  24. package/dist/cjs/standardList/dateFormat.js +56 -0
  25. package/dist/cjs/standardList/emptyState.d.ts +36 -0
  26. package/dist/cjs/standardList/emptyState.js +89 -0
  27. package/dist/cjs/standardList/enumColumns.d.ts +31 -0
  28. package/dist/cjs/standardList/enumColumns.js +87 -0
  29. package/dist/cjs/standardList/gridColumnDefs.d.ts +33 -0
  30. package/dist/cjs/standardList/gridColumnDefs.js +61 -0
  31. package/dist/cjs/standardList/groupedHeaders.d.ts +28 -0
  32. package/dist/cjs/standardList/groupedHeaders.js +84 -0
  33. package/dist/cjs/standardList/groupedHeaders.less +29 -0
  34. package/dist/cjs/standardList/index.d.ts +20 -0
  35. package/dist/cjs/standardList/index.js +176 -0
  36. package/dist/cjs/standardList/listDateDisplay.d.ts +9 -0
  37. package/dist/cjs/standardList/listDateDisplay.js +64 -0
  38. package/dist/cjs/standardList/listDefaultSort.d.ts +38 -0
  39. package/dist/cjs/standardList/listDefaultSort.js +139 -0
  40. package/dist/cjs/standardList/listRefresh.d.ts +25 -0
  41. package/dist/cjs/standardList/listRefresh.js +53 -0
  42. package/dist/esm/attachment/AttachmentFileButton.d.ts +4 -0
  43. package/dist/esm/attachment/AttachmentFileButton.js +77 -0
  44. package/dist/esm/attachment/AttachmentImageUpload.d.ts +16 -0
  45. package/dist/esm/attachment/AttachmentImageUpload.js +199 -0
  46. package/dist/esm/attachment/AttachmentPanel.d.ts +8 -0
  47. package/dist/esm/attachment/AttachmentPanel.js +52 -0
  48. package/dist/esm/attachment/AttachmentVideoUpload.d.ts +13 -0
  49. package/dist/esm/attachment/AttachmentVideoUpload.js +82 -0
  50. package/dist/esm/attachment/ChunkedDragger.d.ts +14 -0
  51. package/dist/esm/attachment/ChunkedDragger.js +153 -0
  52. package/dist/esm/attachment/attachmentList.d.ts +91 -0
  53. package/dist/esm/attachment/attachmentList.js +207 -0
  54. package/dist/esm/attachment/chunkUpload.d.ts +26 -0
  55. package/dist/esm/attachment/chunkUpload.js +272 -0
  56. package/dist/esm/attachment/env.d.ts +41 -0
  57. package/dist/esm/attachment/env.js +35 -0
  58. package/dist/esm/attachment/index.d.ts +20 -0
  59. package/dist/esm/attachment/index.js +14 -0
  60. package/dist/esm/index.d.ts +2 -0
  61. package/dist/esm/index.js +2 -0
  62. package/dist/esm/standardList/StandardAgGridPlus.d.ts +58 -0
  63. package/dist/esm/standardList/StandardAgGridPlus.js +691 -0
  64. package/dist/esm/standardList/dateFormat.d.ts +16 -0
  65. package/dist/esm/standardList/dateFormat.js +50 -0
  66. package/dist/esm/standardList/emptyState.d.ts +36 -0
  67. package/dist/esm/standardList/emptyState.js +83 -0
  68. package/dist/esm/standardList/enumColumns.d.ts +31 -0
  69. package/dist/esm/standardList/enumColumns.js +82 -0
  70. package/dist/esm/standardList/gridColumnDefs.d.ts +33 -0
  71. package/dist/esm/standardList/gridColumnDefs.js +55 -0
  72. package/dist/esm/standardList/groupedHeaders.d.ts +28 -0
  73. package/dist/esm/standardList/groupedHeaders.js +78 -0
  74. package/dist/esm/standardList/groupedHeaders.less +29 -0
  75. package/dist/esm/standardList/index.d.ts +20 -0
  76. package/dist/esm/standardList/index.js +15 -0
  77. package/dist/esm/standardList/listDateDisplay.d.ts +9 -0
  78. package/dist/esm/standardList/listDateDisplay.js +58 -0
  79. package/dist/esm/standardList/listDefaultSort.d.ts +38 -0
  80. package/dist/esm/standardList/listDefaultSort.js +133 -0
  81. package/dist/esm/standardList/listRefresh.d.ts +25 -0
  82. package/dist/esm/standardList/listRefresh.js +47 -0
  83. package/dist/umd/qc-ui.min.css +1 -1
  84. package/dist/umd/qc-ui.min.js +1 -1
  85. package/package.json +1 -1
@@ -0,0 +1,91 @@
1
+ import type { UploadChangeParam } from 'antd/lib/upload/interface';
2
+ import React from 'react';
3
+ import { type AttachmentEnv } from './env';
4
+ /** 附件组件的公共属性。 */
5
+ export interface AttachmentListProps {
6
+ /** 宿主环境(传输层、地址前缀、接口路径) */
7
+ env: AttachmentEnv;
8
+ /** 当前用户名,写入每个文件的上传者列 */
9
+ currentUserName?: string;
10
+ /** 列表使用的表格组件,默认 `AgGridPlus`;宿主可注入自己封装过的表格基座 */
11
+ gridComponent?: React.ComponentType<any>;
12
+ value?: any[];
13
+ defaultValue?: any[];
14
+ onChange?: (value: any[]) => void;
15
+ disabled?: boolean;
16
+ /** 移除一项后的回调,参数是移除后的列表 */
17
+ removeCallBack?: (list: any[]) => void;
18
+ /** 上传或移除后的回调,参数是最新列表 */
19
+ changeCallBack?: (list: any[]) => void;
20
+ /** 不允许删除(只能下载) */
21
+ notDelete?: boolean;
22
+ /** 隐藏上传进度列 */
23
+ hidePercent?: boolean;
24
+ /** 隐藏操作列 */
25
+ hideDownBtn?: boolean;
26
+ [key: string]: any;
27
+ }
28
+ /** 取 `YYYY-MM-DD`:无时区的字符串按本地日期取,带时区或时间戳按本地时间换算。 */
29
+ export declare const formatAttachmentDate: (value: unknown) => string;
30
+ /** 当前时间 `YYYY-MM-DD HH:mm`。 */
31
+ export declare const nowText: () => string;
32
+ export declare const useAttachmentFiles: (props: AttachmentListProps) => {
33
+ state: any;
34
+ onFileChange: (info: UploadChangeParam) => void;
35
+ chongfuVerify: (file: any) => string | true;
36
+ columnDefs: ({
37
+ field: string;
38
+ headerName: string;
39
+ flex: number;
40
+ cellRenderer: ({ value, data }: any) => React.JSX.Element;
41
+ width?: undefined;
42
+ hideInSearch?: undefined;
43
+ hide?: undefined;
44
+ hideInTable?: undefined;
45
+ } | {
46
+ field: string;
47
+ headerName: string;
48
+ width: number;
49
+ hideInSearch: boolean;
50
+ flex?: undefined;
51
+ cellRenderer?: undefined;
52
+ hide?: undefined;
53
+ hideInTable?: undefined;
54
+ } | {
55
+ field: string;
56
+ headerName: string;
57
+ width: number;
58
+ hideInSearch: boolean;
59
+ cellRenderer: (params: any) => React.JSX.Element;
60
+ flex?: undefined;
61
+ hide?: undefined;
62
+ hideInTable?: undefined;
63
+ } | {
64
+ field: string;
65
+ headerName: string;
66
+ width: number;
67
+ hideInSearch: boolean;
68
+ hide: boolean;
69
+ flex?: undefined;
70
+ cellRenderer?: undefined;
71
+ hideInTable?: undefined;
72
+ } | {
73
+ field: string;
74
+ headerName: string;
75
+ width: number;
76
+ hideInTable: boolean | undefined;
77
+ hideInSearch: boolean;
78
+ cellRenderer: ({ value, data }: any) => React.JSX.Element;
79
+ flex?: undefined;
80
+ hide?: undefined;
81
+ } | {
82
+ field: string;
83
+ headerName: string;
84
+ width: number;
85
+ hideInTable: boolean | undefined;
86
+ cellRenderer: (row: any) => React.JSX.Element;
87
+ flex?: undefined;
88
+ hideInSearch?: undefined;
89
+ hide?: undefined;
90
+ })[];
91
+ };
@@ -0,0 +1,207 @@
1
+ function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
2
+ function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
3
+ function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
4
+ function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
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
+ /**
12
+ * 附件列表的共用逻辑:值的受控、重复文件拦截、上传回调字段补全、列定义。
13
+ * `AttachmentPanel`(直接铺开)与 `AttachmentFileButton`(按钮 + 弹窗)共用。
14
+ *
15
+ * @author nokecy
16
+ */
17
+ import { useControllableValue } from 'ahooks';
18
+ import { message, Progress, Space, Upload } from 'antd';
19
+ import React, { useEffect, useState } from 'react';
20
+ import { getBlobDownloadUrl } from "./env";
21
+
22
+ /** 附件组件的公共属性。 */
23
+
24
+ var pad = function pad(n) {
25
+ return String(n).padStart(2, '0');
26
+ };
27
+
28
+ /** 取 `YYYY-MM-DD`:无时区的字符串按本地日期取,带时区或时间戳按本地时间换算。 */
29
+ export var formatAttachmentDate = function formatAttachmentDate(value) {
30
+ // 与 dayjs 一致:未传值取今天,null 与空串是无效日期。
31
+ if (value === undefined) value = new Date();
32
+ if (value === null || value === '') return 'Invalid Date';
33
+ if (typeof value === 'string' && !/(?:Z|[+-]\d{2}:?\d{2})$/i.test(value)) {
34
+ var m = /^(\d{4})-(\d{2})-(\d{2})/.exec(value);
35
+ if (m) return "".concat(m[1], "-").concat(m[2], "-").concat(m[3]);
36
+ }
37
+ var d = new Date(value);
38
+ if (Number.isNaN(d.getTime())) return 'Invalid Date';
39
+ return "".concat(d.getFullYear(), "-").concat(pad(d.getMonth() + 1), "-").concat(pad(d.getDate()));
40
+ };
41
+
42
+ /** 当前时间 `YYYY-MM-DD HH:mm`。 */
43
+ export var nowText = function nowText() {
44
+ var d = new Date();
45
+ return "".concat(d.getFullYear(), "-").concat(pad(d.getMonth() + 1), "-").concat(pad(d.getDate()), " ").concat(pad(d.getHours()), ":").concat(pad(d.getMinutes()));
46
+ };
47
+ export var useAttachmentFiles = function useAttachmentFiles(props) {
48
+ var env = props.env,
49
+ currentUserName = props.currentUserName,
50
+ disabled = props.disabled,
51
+ removeCallBack = props.removeCallBack,
52
+ changeCallBack = props.changeCallBack,
53
+ notDelete = props.notDelete,
54
+ hidePercent = props.hidePercent,
55
+ hideDownBtn = props.hideDownBtn;
56
+ var _useControllableValue = useControllableValue(props),
57
+ _useControllableValue2 = _slicedToArray(_useControllableValue, 2),
58
+ state = _useControllableValue2[0],
59
+ setState = _useControllableValue2[1];
60
+ var _useState = useState([]),
61
+ _useState2 = _slicedToArray(_useState, 2),
62
+ uploadedFiles = _useState2[0],
63
+ setUploadedFiles = _useState2[1];
64
+ useEffect(function () {
65
+ setUploadedFiles(Array.isArray(state) ? state.map(function (i) {
66
+ return i.fileName || i.name;
67
+ }) : []);
68
+ }, [state]);
69
+ var onFileChange = function onFileChange(info) {
70
+ var file = info.file;
71
+ if (file && file.error) {
72
+ var _file$error;
73
+ message.error((file === null || file === void 0 || (_file$error = file.error) === null || _file$error === void 0 ? void 0 : _file$error.message) || '上传失败请稍后重试');
74
+ return;
75
+ }
76
+ var list = info.fileList.map(function (a) {
77
+ var _a$response, _a$response2;
78
+ a.blobName = (_a$response = a.response) !== null && _a$response !== void 0 && _a$response.filename ? (_a$response2 = a.response) === null || _a$response2 === void 0 ? void 0 : _a$response2.filename : a.blobName;
79
+ a.contentType = a.contentType ? a.contentType : a.type;
80
+ a.fileName = a.fileName ? a.fileName : a.name;
81
+ a.creator = currentUserName;
82
+ // 属性名沿用历史数据里的拼写
83
+ a.ceaterTime = nowText();
84
+ return a;
85
+ });
86
+ setState(list);
87
+ changeCallBack === null || changeCallBack === void 0 || changeCallBack(list);
88
+ };
89
+ var removeFile = function removeFile(row) {
90
+ var data = row.data;
91
+ var next = function next(fileList) {
92
+ removeCallBack === null || removeCallBack === void 0 || removeCallBack(fileList.filter(function (a) {
93
+ return a.uid != data.uid;
94
+ }));
95
+ var files = _toConsumableArray(fileList);
96
+ var index = files.findIndex(function (a) {
97
+ return a.uid === data.uid;
98
+ });
99
+ files.splice(index, 1);
100
+ return files;
101
+ };
102
+ if (data.name) {
103
+ // 同时移除已上传文件名记录
104
+ setUploadedFiles(uploadedFiles.filter(function (a) {
105
+ return a !== data.name;
106
+ }));
107
+ }
108
+ setState(next);
109
+ };
110
+ var chongfuVerify = function chongfuVerify(file) {
111
+ if (uploadedFiles.includes(file.name)) {
112
+ message.error('上传文件重复');
113
+ return Upload.LIST_IGNORE;
114
+ }
115
+ uploadedFiles.push(file.name);
116
+ setUploadedFiles(uploadedFiles);
117
+ return true;
118
+ };
119
+ var download = function download(blobName) {
120
+ if (blobName) window.open(getBlobDownloadUrl(env, blobName));else message.error('下载失败请稍后重试');
121
+ };
122
+ var columnDefs = [{
123
+ field: 'fileName',
124
+ headerName: '文档名称',
125
+ flex: 1,
126
+ cellRenderer: function cellRenderer(_ref) {
127
+ var value = _ref.value,
128
+ data = _ref.data;
129
+ return /*#__PURE__*/React.createElement("a", {
130
+ target: "_blank",
131
+ onClick: function onClick(event) {
132
+ event.stopPropagation();
133
+ download(data.blobName);
134
+ },
135
+ rel: "noreferrer"
136
+ }, data.name || value || data.fileName);
137
+ }
138
+ }, {
139
+ field: 'creator',
140
+ headerName: '上传者',
141
+ width: 100,
142
+ hideInSearch: true
143
+ }, {
144
+ field: 'creationTime',
145
+ headerName: '时间',
146
+ width: 130,
147
+ hideInSearch: true,
148
+ cellRenderer: function cellRenderer(params) {
149
+ var _params$data, _params$data2;
150
+ return /*#__PURE__*/React.createElement("div", null, formatAttachmentDate(((_params$data = params.data) === null || _params$data === void 0 ? void 0 : _params$data.creationTime) || ((_params$data2 = params.data) === null || _params$data2 === void 0 ? void 0 : _params$data2.ceaterTime)));
151
+ }
152
+ }, {
153
+ field: 'type',
154
+ headerName: '类型',
155
+ width: 150,
156
+ hideInSearch: true,
157
+ hide: true
158
+ }, {
159
+ field: 'percent',
160
+ headerName: '上传进度',
161
+ width: 100,
162
+ hideInTable: hidePercent,
163
+ hideInSearch: true,
164
+ cellRenderer: function cellRenderer(_ref2) {
165
+ var value = _ref2.value,
166
+ data = _ref2.data;
167
+ return /*#__PURE__*/React.createElement(Progress, {
168
+ percent: (data === null || data === void 0 ? void 0 : data.id) !== null ? 100 : value
169
+ });
170
+ }
171
+ }, {
172
+ field: 'options',
173
+ headerName: '操作',
174
+ width: 150,
175
+ hideInTable: hideDownBtn,
176
+ cellRenderer: function cellRenderer(row) {
177
+ return /*#__PURE__*/React.createElement(Space, {
178
+ onClick: function onClick(event) {
179
+ event.stopPropagation();
180
+ event.preventDefault();
181
+ }
182
+ }, /*#__PURE__*/React.createElement("a", {
183
+ target: "_blank",
184
+ onClick: function onClick(event) {
185
+ event.stopPropagation();
186
+ download(row === null || row === void 0 ? void 0 : row.data.blobName);
187
+ },
188
+ rel: "noreferrer"
189
+ }, "\u4E0B\u8F7D"), disabled || notDelete ? null : /*#__PURE__*/React.createElement("a", {
190
+ style: {
191
+ color: 'red'
192
+ },
193
+ onClick: function onClick(event) {
194
+ event.stopPropagation();
195
+ event.preventDefault();
196
+ removeFile(row);
197
+ }
198
+ }, "\u79FB\u9664"));
199
+ }
200
+ }];
201
+ return {
202
+ state: state,
203
+ onFileChange: onFileChange,
204
+ chongfuVerify: chongfuVerify,
205
+ columnDefs: columnDefs
206
+ };
207
+ };
@@ -0,0 +1,26 @@
1
+ /**
2
+ * 附件上传协议:普通文件(带断点续传与合并校验)与视频(分块后确认)。
3
+ * 两套协议的端点、参数大小写、进度算法与收尾都不同,各自照原样实现,不合并成带开关的一套。
4
+ *
5
+ * @author nokecy
6
+ */
7
+ import { type AttachmentEnv } from './env';
8
+ /** 分块大小,同时也是切块上传的阈值。 */
9
+ export declare const CHUNK_SIZE: number;
10
+ type Progress = (event: any) => void;
11
+ /** 把文件切成 `chunks` 块。 */
12
+ export declare const splitFile: (file: Blob, eachSize: number, chunks: number) => Promise<Blob[]>;
13
+ /** 普通文件协议。 */
14
+ export declare const createFileProtocol: (env: AttachmentEnv) => {
15
+ uploadSingle: (file: any, onProgress: Progress) => Promise<{
16
+ nextchunk: any;
17
+ filename: any;
18
+ }>;
19
+ uploadChunked: (file: any, onProgress: Progress) => Promise<any>;
20
+ };
21
+ /** 视频协议。 */
22
+ export declare const createVideoProtocol: (env: AttachmentEnv) => {
23
+ uploadSingle: (file: any, onProgress: Progress) => Promise<any>;
24
+ uploadChunked: (file: any, onProgress: Progress) => Promise<any>;
25
+ };
26
+ export {};
@@ -0,0 +1,272 @@
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
+ * @author nokecy
10
+ */
11
+ import { resolveEndpoints } from "./env";
12
+
13
+ /** 分块大小,同时也是切块上传的阈值。 */
14
+ export var CHUNK_SIZE = 5 * 1024 * 1024;
15
+ /** 把文件切成 `chunks` 块。 */
16
+ export var splitFile = function splitFile(file, eachSize, chunks) {
17
+ return new Promise(function (resolve, reject) {
18
+ try {
19
+ setTimeout(function () {
20
+ var fileChunk = [];
21
+ for (var chunk = 0; chunks > 0; chunks--) {
22
+ fileChunk.push(file.slice(chunk, chunk + eachSize));
23
+ chunk += eachSize;
24
+ }
25
+ resolve(fileChunk);
26
+ }, 0);
27
+ } catch (e) {
28
+ console.error(e);
29
+ reject(new Error('文件切块发生错误'));
30
+ }
31
+ });
32
+ };
33
+ var toFormData = function toFormData(param) {
34
+ var formData = new FormData();
35
+ for (var p in param) formData.append(p, param[p]);
36
+ return formData;
37
+ };
38
+ var headersOf = function headersOf(env) {
39
+ var _env$getHeaders, _env$getHeaders2;
40
+ return (_env$getHeaders = (_env$getHeaders2 = env.getHeaders) === null || _env$getHeaders2 === void 0 ? void 0 : _env$getHeaders2.call(env)) !== null && _env$getHeaders !== void 0 ? _env$getHeaders : {};
41
+ };
42
+
43
+ /** 普通文件协议。 */
44
+ export var createFileProtocol = function createFileProtocol(env) {
45
+ var endpoints = resolveEndpoints(env);
46
+ var postFile = function postFile(param, onProgress) {
47
+ return env.post("".concat(env.serverUrl()).concat(endpoints.upload), toFormData(param), {
48
+ headers: headersOf(env),
49
+ onUploadProgress: function onUploadProgress(e) {
50
+ if (param.chunked) {
51
+ e.percent = Number(((param.chunk * (param.eachSize - 1) + e.loaded) / param.fullSize * 100).toFixed(2));
52
+ } else {
53
+ e.percent = Number((e.loaded / e.total * 100).toFixed(2));
54
+ }
55
+ onProgress(e);
56
+ }
57
+ }).then(function (rs) {
58
+ return {
59
+ nextchunk: rs.data.nextchunk,
60
+ filename: rs.data.filename
61
+ };
62
+ });
63
+ };
64
+ var validateFile = function validateFile(body) {
65
+ return env.post("".concat(env.serverUrl()).concat(endpoints.validate), body, {
66
+ headers: headersOf(env)
67
+ }).then(function (rs) {
68
+ return rs.data;
69
+ });
70
+ };
71
+
72
+ /** 单文件上传,返回 `{ nextchunk, filename }`。 */
73
+ var uploadSingle = function uploadSingle(file, onProgress) {
74
+ return postFile({
75
+ file: file,
76
+ uid: file.uid,
77
+ fileName: file.fileName
78
+ }, onProgress);
79
+ };
80
+
81
+ /** 分块上传:服务端返回的 `nextchunk` 决定下一块(断点续传),最后合并校验,校验不通过则抛错。 */
82
+ var uploadChunked = /*#__PURE__*/function () {
83
+ var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(file, onProgress) {
84
+ var chunks, fileChunks, currentChunk, i, _yield$postFile, nextchunk, data;
85
+ return _regeneratorRuntime().wrap(function _callee$(_context) {
86
+ while (1) switch (_context.prev = _context.next) {
87
+ case 0:
88
+ chunks = Math.ceil(file.size / CHUNK_SIZE);
89
+ _context.next = 3;
90
+ return splitFile(file, CHUNK_SIZE, chunks);
91
+ case 3:
92
+ fileChunks = _context.sent;
93
+ currentChunk = 0;
94
+ i = 0;
95
+ case 6:
96
+ if (!(i < fileChunks.length)) {
97
+ _context.next = 16;
98
+ break;
99
+ }
100
+ if (!(Number(currentChunk) === i)) {
101
+ _context.next = 13;
102
+ break;
103
+ }
104
+ _context.next = 10;
105
+ return postFile({
106
+ chunked: true,
107
+ chunk: i,
108
+ chunks: chunks,
109
+ eachSize: CHUNK_SIZE,
110
+ fileName: file.name,
111
+ fullSize: file.size,
112
+ uid: file.uid,
113
+ file: fileChunks[i]
114
+ }, onProgress);
115
+ case 10:
116
+ _yield$postFile = _context.sent;
117
+ nextchunk = _yield$postFile.nextchunk;
118
+ currentChunk = nextchunk;
119
+ case 13:
120
+ i++;
121
+ _context.next = 6;
122
+ break;
123
+ case 16:
124
+ _context.next = 18;
125
+ return validateFile({
126
+ chunks: fileChunks.length,
127
+ fileName: file.name,
128
+ fullSize: file.size,
129
+ uid: file.uid
130
+ });
131
+ case 18:
132
+ data = _context.sent;
133
+ if (data.isValid) {
134
+ _context.next = 21;
135
+ break;
136
+ }
137
+ throw new Error('文件校验异常');
138
+ case 21:
139
+ return _context.abrupt("return", data);
140
+ case 22:
141
+ case "end":
142
+ return _context.stop();
143
+ }
144
+ }, _callee);
145
+ }));
146
+ return function uploadChunked(_x, _x2) {
147
+ return _ref.apply(this, arguments);
148
+ };
149
+ }();
150
+ return {
151
+ uploadSingle: uploadSingle,
152
+ uploadChunked: uploadChunked
153
+ };
154
+ };
155
+
156
+ /** 视频协议。 */
157
+ export var createVideoProtocol = function createVideoProtocol(env) {
158
+ var endpoints = resolveEndpoints(env);
159
+ var postFile = function postFile(param, onProgress) {
160
+ return env.post("".concat(env.serverUrl()).concat(endpoints.uploadVideoChunk), toFormData(param), {
161
+ headers: headersOf(env),
162
+ // 视频接口的参数是大写开头,下面的 `chunked` 恒为 undefined,进度始终按单次请求计算——沿用原行为。
163
+ onUploadProgress: function onUploadProgress(e) {
164
+ if (param.chunked) {
165
+ e.percent = Number(((param.chunk * (param.eachSize - 1) + e.loaded) / param.fullSize * 100).toFixed(2));
166
+ } else {
167
+ e.percent = Number((e.loaded / e.total * 100).toFixed(2));
168
+ }
169
+ onProgress(e);
170
+ }
171
+ }).then(function (rs) {
172
+ return {
173
+ nextchunk: rs.data.nextchunk,
174
+ filename: rs.data.filename
175
+ };
176
+ });
177
+ };
178
+ var confirm = function confirm(body) {
179
+ return env.post("".concat(env.serverUrl()).concat(endpoints.confirmVideo), body, {
180
+ headers: headersOf(env)
181
+ }).then(function (rs) {
182
+ return rs.data;
183
+ });
184
+ };
185
+
186
+ /** 单文件上传后确认;确认失败时返回 undefined 而不抛错——沿用原行为。 */
187
+ var uploadSingle = function uploadSingle(file, onProgress) {
188
+ return postFile({
189
+ File: file,
190
+ Uid: file.uid,
191
+ FileName: file.fileName
192
+ }, onProgress).then( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2() {
193
+ return _regeneratorRuntime().wrap(function _callee2$(_context2) {
194
+ while (1) switch (_context2.prev = _context2.next) {
195
+ case 0:
196
+ _context2.prev = 0;
197
+ _context2.next = 3;
198
+ return confirm({
199
+ Chunks: 1,
200
+ FileName: file.name,
201
+ FullSize: file.size,
202
+ Uid: file.uid
203
+ });
204
+ case 3:
205
+ return _context2.abrupt("return", _context2.sent);
206
+ case 6:
207
+ _context2.prev = 6;
208
+ _context2.t0 = _context2["catch"](0);
209
+ return _context2.abrupt("return", undefined);
210
+ case 9:
211
+ case "end":
212
+ return _context2.stop();
213
+ }
214
+ }, _callee2, null, [[0, 6]]);
215
+ })));
216
+ };
217
+
218
+ /** 分块上传:每一块都按顺序上传(不按 nextchunk 跳块、不检查 isValid),最后确认。 */
219
+ var uploadChunked = /*#__PURE__*/function () {
220
+ var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3(file, onProgress) {
221
+ var Chunks, fileChunks, i;
222
+ return _regeneratorRuntime().wrap(function _callee3$(_context3) {
223
+ while (1) switch (_context3.prev = _context3.next) {
224
+ case 0:
225
+ Chunks = Math.ceil(file.size / CHUNK_SIZE);
226
+ _context3.next = 3;
227
+ return splitFile(file, CHUNK_SIZE, Chunks);
228
+ case 3:
229
+ fileChunks = _context3.sent;
230
+ i = 0;
231
+ case 5:
232
+ if (!(i < fileChunks.length)) {
233
+ _context3.next = 11;
234
+ break;
235
+ }
236
+ _context3.next = 8;
237
+ return postFile({
238
+ Chunked: true,
239
+ Chunk: i,
240
+ Chunks: Chunks,
241
+ EachSize: CHUNK_SIZE,
242
+ FileName: file.name,
243
+ FullSize: file.size,
244
+ Uid: file.uid,
245
+ File: fileChunks[i]
246
+ }, onProgress);
247
+ case 8:
248
+ i++;
249
+ _context3.next = 5;
250
+ break;
251
+ case 11:
252
+ return _context3.abrupt("return", confirm({
253
+ Chunks: fileChunks.length,
254
+ FileName: file.name,
255
+ FullSize: file.size,
256
+ Uid: file.uid
257
+ }));
258
+ case 12:
259
+ case "end":
260
+ return _context3.stop();
261
+ }
262
+ }, _callee3);
263
+ }));
264
+ return function uploadChunked(_x3, _x4) {
265
+ return _ref3.apply(this, arguments);
266
+ };
267
+ }();
268
+ return {
269
+ uploadSingle: uploadSingle,
270
+ uploadChunked: uploadChunked
271
+ };
272
+ };
@@ -0,0 +1,41 @@
1
+ /**
2
+ * 附件上传的宿主环境:后端地址、传输层与接口路径。
3
+ * qc-ui 不依赖具体的 HTTP 库,宿主把自己的 POST 实现与地址前缀注入进来。
4
+ *
5
+ * @author nokecy
6
+ */
7
+ /** 附件服务的接口路径(相对于 `serverUrl()`)。`validate` 沿用后端的拼写 `valiate`。 */
8
+ export interface AttachmentEndpoints {
9
+ /** 普通文件上传(单文件与分块共用) */
10
+ upload: string;
11
+ /** 普通文件分块合并后的校验 */
12
+ validate: string;
13
+ /** 视频分块上传 */
14
+ uploadVideoChunk: string;
15
+ /** 视频上传完成后的确认 */
16
+ confirmVideo: string;
17
+ /** 按 blobName 下载,blobName 直接拼在末尾 */
18
+ downloadByBlobName: string;
19
+ }
20
+ export declare const defaultAttachmentEndpoints: AttachmentEndpoints;
21
+ /** `post` 的第三个参数,约定与 axios 一致。 */
22
+ export interface AttachmentPostConfig {
23
+ headers?: Record<string, string | undefined>;
24
+ onUploadProgress?: (event: any) => void;
25
+ }
26
+ /** 宿主注入的环境。 */
27
+ export interface AttachmentEnv {
28
+ /** 后端地址前缀,如 `() => window.serverUrl.apiServerUrl`;与路径直接拼接,不加斜杠 */
29
+ serverUrl: () => string;
30
+ /** 发 POST 请求(multipart 或 JSON),约定与 `axios.post` 一致,返回含 `data` 的响应 */
31
+ post: (url: string, data: any, config?: AttachmentPostConfig) => Promise<{
32
+ data: any;
33
+ }>;
34
+ /** 每次请求附带的请求头(例如防伪令牌),请求时才读取 */
35
+ getHeaders?: () => Record<string, string | undefined>;
36
+ /** 覆盖默认的接口路径 */
37
+ endpoints?: Partial<AttachmentEndpoints>;
38
+ }
39
+ export declare const resolveEndpoints: (env: AttachmentEnv) => AttachmentEndpoints;
40
+ /** 按 blobName 拼出下载地址。 */
41
+ export declare const getBlobDownloadUrl: (env: AttachmentEnv, blobName: string) => string;