@vunk/form 1.1.70 → 1.1.72

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,74 @@
1
+
2
+
3
+ .vkf-download-plus{
4
+ --vkf-download-plus-height: 34px;
5
+ }
6
+ .vkf-download-plus-label{
7
+ position: relative;
8
+ }
9
+ .vkf-download-plus-cube-x,
10
+ .vkf-download-plus-msg-x
11
+ {
12
+ position: absolute;
13
+ top: 0;
14
+ left: 0;
15
+ bottom: 0;
16
+ right: 0;
17
+ }
18
+ .vkf-download-plus-msg-x{
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: center;
22
+ color: var(--el-color-success);
23
+ background: var(--el-bg-color);
24
+ animation-name: hide; /* 指定使用hide关键帧动画 */
25
+ animation-duration: 1s; /* 动画持续时间为2秒 */
26
+ animation-delay: 1s; /* 延迟2秒后开始动画 */
27
+ animation-fill-mode: forwards; /* 动画结束后保持最后一帧的状态 */
28
+ }
29
+ .vkf-download-plus-msg{
30
+ margin-left: 2px;
31
+ }
32
+ .vkf-download-plus-cube {
33
+ float: left;
34
+ height: 100%;
35
+ }
36
+ .vkf-download-plus-cube.error {
37
+ background: var(--el-color-danger);
38
+ }
39
+ .vkf-download-plus-cube .success{
40
+ background: var(--el-color-success);
41
+ }
42
+ .vkf-download-plus-cube .uploading{
43
+ background: var(--el-color-primary);
44
+ }
45
+ .vkf-download-plus-cube .error{
46
+ background: var(--el-color-danger);
47
+ }
48
+
49
+ .vkf-download-plus-btng >.el-button:first-child{
50
+ border-radius: 0;
51
+ }
52
+ .vkf-download-plus-btng >.el-button{
53
+ height: var(--vkf-download-plus-height);
54
+ }
55
+ .vkf-download-plus-main{
56
+ display: flex;
57
+ align-items: center;
58
+ border: var(--el-border);
59
+ border-radius: var(--el-border-radius-base);
60
+ }
61
+
62
+ .vkf-download-plus-label .el-input{
63
+ --el-input-border-color: transparent;
64
+ --el-input-focus-border-color: transparent;
65
+ --el-input-hover-border-color: transparent;
66
+ }
67
+ .vkf-download-plus-label .el-input.is-success .el-icon{
68
+ color: var(--el-color-success);
69
+ }
70
+ .vkf-download-plus-label .el-input.is-error .el-icon{
71
+ color: var(--el-color-danger);
72
+ }
73
+
74
+
@@ -0,0 +1,4 @@
1
+ import VkfDownloadPlus from './src/index.vue';
2
+ export * as __VkfDownloadPlus from './src/types';
3
+ export { VkfDownloadPlus, };
4
+ export default VkfDownloadPlus;
@@ -0,0 +1,384 @@
1
+ import { _VkfFormItemCtx, VkfFormItem } from '@vunk/form/components/form-item';
2
+ import { restFetch as restFetch$1 } from '@skzz/platform/shared/fetch/platform';
3
+ import { defineComponent, ref, watch, onBeforeUnmount, resolveComponent, openBlock, createBlock, mergeProps, withCtx, createElementVNode, createVNode, createElementBlock, Fragment, renderList, normalizeClass, normalizeStyle, createCommentVNode, createTextVNode } from 'vue';
4
+ import { rFile } from '@skzz/platform/api/basic';
5
+ import { ElButtonGroup, ElButton, ElInput } from 'element-plus';
6
+ import { RestFetch } from '@vunk/core/shared/utils-fetch';
7
+ import { useModelComputed } from '@vunk/core/composables';
8
+
9
+ const props = {
10
+ ..._VkfFormItemCtx.props,
11
+ fileId: {
12
+ type: String,
13
+ default: ""
14
+ },
15
+ url: {
16
+ type: String,
17
+ default: restFetch$1.baseURL
18
+ },
19
+ /**
20
+ * @description 分片大小
21
+ */
22
+ chunkSize: {
23
+ type: Number,
24
+ default: 1024 * 1024 * 10
25
+ },
26
+ fileServiceType: {
27
+ type: String,
28
+ default: void 0
29
+ },
30
+ /**
31
+ * @description
32
+ * v-model:fileStatus 当前文件状态: wait, doPause, pause, doDownload, downloading, error, done
33
+ */
34
+ fileStatus: {
35
+ type: String,
36
+ default: void 0
37
+ }
38
+ };
39
+ const emits = {
40
+ "update:fileStatus": null
41
+ };
42
+
43
+ var Status = /* @__PURE__ */ ((Status2) => {
44
+ Status2["wait"] = "wait";
45
+ Status2["doPause"] = "doPause";
46
+ Status2["pause"] = "pause";
47
+ Status2["doDownload"] = "doDownload";
48
+ Status2["downloading"] = "downloading";
49
+ Status2["error"] = "error";
50
+ Status2["done"] = "done";
51
+ return Status2;
52
+ })(Status || {});
53
+
54
+ const KeyConfig = {
55
+ TokenKey: "VUNK_SKZZ_REST_TOKEN",
56
+ ApplicationKey: "VUNK_SKZZ_REST_APPLICATION",
57
+ TenantKey: "VUNK_SKZZ_REST_TENANT"
58
+ };
59
+ function getToken() {
60
+ return localStorage.getItem(KeyConfig.TokenKey) || "";
61
+ }
62
+
63
+ const restFetch = new RestFetch({
64
+ baseURL: restFetch$1.baseURL,
65
+ presetRequestInit: (config) => {
66
+ const header = config.headers;
67
+ const token = getToken();
68
+ if (token) {
69
+ header.set("Token", token);
70
+ }
71
+ return config;
72
+ }
73
+ });
74
+ const downChunk = (params, init) => {
75
+ return new Promise((resolve, reject) => {
76
+ const xhr = new XMLHttpRequest();
77
+ let url = `${restFetch.baseURL}/file/downloadByRange?fileId=${params.fileId}`;
78
+ if (params.fileServiceType) {
79
+ url += `&fileServiceType=${params.fileServiceType}`;
80
+ xhr.setRequestHeader("fileServiceType", params.fileServiceType);
81
+ }
82
+ if (init?.onprogress) {
83
+ xhr.onprogress = init?.onprogress;
84
+ }
85
+ xhr.open("GET", url, true);
86
+ xhr.responseType = "blob";
87
+ xhr.setRequestHeader("Token", getToken());
88
+ xhr.setRequestHeader("tenant", "default");
89
+ xhr.setRequestHeader("application", "platform");
90
+ xhr.setRequestHeader("Content-Range", `bytes=${params.start}-${params.end}`);
91
+ xhr.setRequestHeader("Accept-Ranges", "bytes");
92
+ xhr.onreadystatechange = (e) => {
93
+ const target = e.target;
94
+ if (xhr.readyState === 4) {
95
+ if (xhr.status === 200 || xhr.status === 206) {
96
+ if (init?.xhrs) {
97
+ const i = init.xhrs.findIndex((req) => req === xhr);
98
+ init.xhrs.splice(i, 1);
99
+ }
100
+ resolve({
101
+ data: target.response
102
+ });
103
+ } else if (xhr.status === 500) {
104
+ reject(target.response);
105
+ }
106
+ }
107
+ };
108
+ xhr.onerror = () => {
109
+ reject(xhr.response);
110
+ };
111
+ xhr.send();
112
+ init?.xhrs?.push(xhr);
113
+ });
114
+ };
115
+
116
+ var script = defineComponent({
117
+ name: "VkfDownloadPlus",
118
+ components: {
119
+ VkfFormItem,
120
+ ElButtonGroup,
121
+ ElButton,
122
+ ElInput
123
+ },
124
+ props,
125
+ emits,
126
+ setup(props2, {
127
+ emit
128
+ }) {
129
+ const formItemBindProps = _VkfFormItemCtx.createBindProps(props2);
130
+ const fileInfo = ref();
131
+ rFileInfo();
132
+ watch(() => props2.fileId, rFileInfo);
133
+ function rFileInfo() {
134
+ if (!props2.fileId) {
135
+ return;
136
+ }
137
+ rFile({
138
+ fileId: props2.fileId
139
+ }).then((res) => {
140
+ fileInfo.value = res;
141
+ });
142
+ }
143
+ const chunks = ref([]);
144
+ const downloadingXhrs = ref([]);
145
+ const fileStatus = useModelComputed({
146
+ default: Status.wait,
147
+ key: "fileStatus"
148
+ }, props2, emit);
149
+ const handleDownload = () => {
150
+ if (!fileInfo.value) {
151
+ return;
152
+ }
153
+ const fileSize = fileInfo.value.size;
154
+ const fileId = fileInfo.value.id;
155
+ const chunksLength = Math.ceil(fileSize / props2.chunkSize);
156
+ chunks.value = Array.from({
157
+ length: chunksLength
158
+ }, (_, i) => {
159
+ const start = i * props2.chunkSize;
160
+ const end = Math.min(start + props2.chunkSize, fileSize) - 1;
161
+ let downloadedChunk = {};
162
+ if (chunks.value[i] && chunks.value[i].start === start && chunks.value[i].end === end && chunks.value[i].status === Status.done) {
163
+ downloadedChunk = chunks.value[i];
164
+ }
165
+ return {
166
+ start,
167
+ end,
168
+ index: i,
169
+ status: Status.wait,
170
+ fileId,
171
+ fileServiceType: props2.fileServiceType,
172
+ progress: 0,
173
+ ...downloadedChunk
174
+ };
175
+ });
176
+ fileStatus.value = Status.downloading;
177
+ const needDownloadChunks = chunks.value.filter((v) => v.status === Status.wait || v.status === Status.error);
178
+ rChunkFiles(needDownloadChunks).then(() => {
179
+ const blobs = chunks.value.map((item) => {
180
+ return item.data;
181
+ });
182
+ return new Blob(blobs, {
183
+ type: "application/octet-stream"
184
+ });
185
+ }).then((blob) => {
186
+ const url = URL.createObjectURL(blob);
187
+ const a = document.createElement("a");
188
+ a.href = url;
189
+ a.download = fileInfo.value?.realName || "\u672A\u77E5\u6587\u4EF6";
190
+ a.click();
191
+ URL.revokeObjectURL(url);
192
+ }).then(() => {
193
+ fileStatus.value = Status.done;
194
+ }).catch(() => {
195
+ fileStatus.value = Status.error;
196
+ });
197
+ };
198
+ watch(() => fileStatus.value, (newVal) => {
199
+ if (newVal === Status.doDownload) {
200
+ handleDownload();
201
+ }
202
+ });
203
+ function rChunkFiles(chunks2, max = 4, retrys = 10) {
204
+ return new Promise((resolve, reject) => {
205
+ const len = chunks2.length;
206
+ let counter = 0;
207
+ if (len === 0) {
208
+ return resolve(void 0);
209
+ }
210
+ const retryArr = [];
211
+ const start = async () => {
212
+ while (counter < len && max > 0) {
213
+ max--;
214
+ const i = chunks2.findIndex((v) => v.status === Status.wait || v.status === Status.error);
215
+ const currentChunk = chunks2[i];
216
+ if (currentChunk) {
217
+ currentChunk.status = Status.downloading;
218
+ downChunk(currentChunk, {
219
+ onprogress(ev) {
220
+ currentChunk.progress = parseInt(ev.loaded / ev.total * 100 + "");
221
+ },
222
+ xhrs: downloadingXhrs.value
223
+ }).then((res) => {
224
+ currentChunk.status = Status.done;
225
+ currentChunk.data = res.data;
226
+ max++;
227
+ counter++;
228
+ }).then(() => {
229
+ if (counter === len) {
230
+ resolve(void 0);
231
+ } else {
232
+ start();
233
+ }
234
+ }).catch(() => {
235
+ currentChunk.status = Status.error;
236
+ const index = currentChunk.index;
237
+ if (typeof retryArr[index] !== "number") {
238
+ retryArr[index] = 0;
239
+ }
240
+ retryArr[index]++;
241
+ console.warn(index, currentChunk, retryArr[index], "\u6B21\u62A5\u9519");
242
+ currentChunk.progress = -1;
243
+ if (retryArr[index] >= retrys) {
244
+ return reject();
245
+ }
246
+ max++;
247
+ start();
248
+ });
249
+ }
250
+ }
251
+ };
252
+ start();
253
+ });
254
+ }
255
+ const handlePause = () => {
256
+ downloadingXhrs.value.forEach((xhr) => {
257
+ xhr.abort();
258
+ });
259
+ downloadingXhrs.value = [];
260
+ fileStatus.value = Status.pause;
261
+ };
262
+ watch(() => fileStatus.value, (newVal) => {
263
+ if (newVal === Status.doPause) {
264
+ handlePause();
265
+ }
266
+ });
267
+ onBeforeUnmount(() => {
268
+ handlePause();
269
+ });
270
+ return {
271
+ formItemBindProps,
272
+ fileInfo,
273
+ handleDownload,
274
+ handlePause,
275
+ Status,
276
+ chunks,
277
+ fileStatus
278
+ };
279
+ }
280
+ });
281
+
282
+ const _hoisted_1 = {
283
+ class: "vkf-download-plus-main"
284
+ };
285
+ const _hoisted_2 = {
286
+ class: "vkf-download-plus-label"
287
+ };
288
+ const _hoisted_3 = {
289
+ key: 0,
290
+ class: "vkf-download-plus-cube-x"
291
+ };
292
+ function render(_ctx, _cache, $props, $setup, $data, $options) {
293
+ const _component_ElInput = resolveComponent("ElInput");
294
+ const _component_el_button = resolveComponent("el-button");
295
+ const _component_el_button_group = resolveComponent("el-button-group");
296
+ const _component_VkfFormItem = resolveComponent("VkfFormItem");
297
+ return openBlock(), createBlock(
298
+ _component_VkfFormItem,
299
+ mergeProps(_ctx.formItemBindProps, {
300
+ class: "vkf-download-plus"
301
+ }),
302
+ {
303
+ default: withCtx(() => [createElementVNode("div", _hoisted_1, [createElementVNode("label", _hoisted_2, [createVNode(_component_ElInput, {
304
+ "model-value": _ctx.fileInfo?.realName,
305
+ readonly: ""
306
+ }, null, 8, ["model-value"]), _ctx.fileStatus === _ctx.Status.downloading || _ctx.fileStatus === _ctx.Status.pause ? (openBlock(), createElementBlock("div", _hoisted_3, [(openBlock(true), createElementBlock(
307
+ Fragment,
308
+ null,
309
+ renderList(_ctx.chunks, (chunk) => {
310
+ return openBlock(), createElementBlock(
311
+ "div",
312
+ {
313
+ key: chunk.fileId + "-" + chunk.index,
314
+ class: normalizeClass(["vkf-download-plus-cube", {
315
+ "error": chunk.status == _ctx.Status.error
316
+ }]),
317
+ style: normalizeStyle({
318
+ width: 100 / _ctx.chunks.length + "%"
319
+ })
320
+ },
321
+ [createElementVNode(
322
+ "div",
323
+ {
324
+ class: normalizeClass({
325
+ "uploading": chunk.progress > 0 && chunk.progress < 100,
326
+ "success": chunk.progress == 100
327
+ }),
328
+ style: normalizeStyle({
329
+ height: chunk.progress + "%"
330
+ })
331
+ },
332
+ null,
333
+ 6
334
+ /* CLASS, STYLE */
335
+ )],
336
+ 6
337
+ /* CLASS, STYLE */
338
+ );
339
+ }),
340
+ 128
341
+ /* KEYED_FRAGMENT */
342
+ ))])) : createCommentVNode("v-if", true)]), createVNode(_component_el_button_group, {
343
+ class: "vkf-download-plus-btng"
344
+ }, {
345
+ default: withCtx(() => [_ctx.fileStatus === _ctx.Status.downloading ? (openBlock(), createBlock(_component_el_button, {
346
+ key: 0,
347
+ type: "danger",
348
+ onClick: _ctx.handlePause
349
+ }, {
350
+ default: withCtx(() => [createTextVNode(" \u6682\u505C ")]),
351
+ _: 1
352
+ /* STABLE */
353
+ }, 8, ["onClick"])) : (openBlock(), createBlock(_component_el_button, {
354
+ key: 1,
355
+ type: "primary",
356
+ onClick: _ctx.handleDownload
357
+ }, {
358
+ default: withCtx(() => [createTextVNode(" \u4E0B\u8F7D ")]),
359
+ _: 1
360
+ /* STABLE */
361
+ }, 8, ["onClick"]))]),
362
+ _: 1
363
+ /* STABLE */
364
+ })])]),
365
+ _: 1
366
+ /* STABLE */
367
+ },
368
+ 16
369
+ /* FULL_PROPS */
370
+ );
371
+ }
372
+
373
+ script.render = render;
374
+ script.__file = "download-plus/src/index.vue";
375
+
376
+ var types = /*#__PURE__*/Object.freeze({
377
+ __proto__: null
378
+ });
379
+
380
+ script.install = (app) => {
381
+ app.component(script.name || "VkfDownloadPlus", script);
382
+ };
383
+
384
+ export { script as VkfDownloadPlus, types as __VkfDownloadPlus, script as default };
@@ -0,0 +1,13 @@
1
+ import { RestFetch } from '@vunk/core/shared/utils-fetch';
2
+ export declare const restFetch: RestFetch;
3
+ export declare const downChunk: (params: {
4
+ fileId: string;
5
+ start: number;
6
+ end: number;
7
+ fileServiceType?: string;
8
+ }, init?: {
9
+ onprogress?: XMLHttpRequestEventTarget['onprogress'];
10
+ xhrs?: XMLHttpRequest[];
11
+ }) => Promise<{
12
+ data: Blob;
13
+ }>;
@@ -0,0 +1 @@
1
+ import{RestFetch as l}from"@vunk/core/shared/utils-fetch";import{restFetch as u}from"@skzz/platform/shared/fetch/platform";const T={TokenKey:"VUNK_SKZZ_REST_TOKEN",ApplicationKey:"VUNK_SKZZ_REST_APPLICATION",TenantKey:"VUNK_SKZZ_REST_TENANT"};function c(){return localStorage.getItem(T.TokenKey)||""}const i=new l({baseURL:u.baseURL,presetRequestInit:t=>{const s=t.headers,r=c();return r&&s.set("Token",r),t}}),R=(t,s)=>new Promise((r,n)=>{const e=new XMLHttpRequest;let o=`${i.baseURL}/file/downloadByRange?fileId=${t.fileId}`;t.fileServiceType&&(o+=`&fileServiceType=${t.fileServiceType}`,e.setRequestHeader("fileServiceType",t.fileServiceType)),s?.onprogress&&(e.onprogress=s?.onprogress),e.open("GET",o,!0),e.responseType="blob",e.setRequestHeader("Token",c()),e.setRequestHeader("tenant","default"),e.setRequestHeader("application","platform"),e.setRequestHeader("Content-Range",`bytes=${t.start}-${t.end}`),e.setRequestHeader("Accept-Ranges","bytes"),e.onreadystatechange=p=>{const a=p.target;if(e.readyState===4)if(e.status===200||e.status===206){if(s?.xhrs){const d=s.xhrs.findIndex(f=>f===e);s.xhrs.splice(d,1)}r({data:a.response})}else e.status===500&&n(a.response)},e.onerror=()=>{n(e.response)},e.send(),s?.xhrs?.push(e)});export{R as downChunk,i as restFetch};
@@ -0,0 +1,9 @@
1
+ export declare enum Status {
2
+ wait = "wait",
3
+ doPause = "doPause",
4
+ pause = "pause",
5
+ doDownload = "doDownload",
6
+ downloading = "downloading",
7
+ error = "error",
8
+ done = "done"
9
+ }
@@ -0,0 +1 @@
1
+ var d=(o=>(o.wait="wait",o.doPause="doPause",o.pause="pause",o.doDownload="doDownload",o.downloading="downloading",o.error="error",o.done="done",o))(d||{});export{d as Status};
@@ -0,0 +1,83 @@
1
+ import { PropType } from 'vue';
2
+ import { Status } from './const';
3
+ export declare const props: {
4
+ fileId: {
5
+ type: StringConstructor;
6
+ default: string;
7
+ };
8
+ url: {
9
+ type: StringConstructor;
10
+ default: string;
11
+ };
12
+ /**
13
+ * @description 分片大小
14
+ */
15
+ chunkSize: {
16
+ type: NumberConstructor;
17
+ default: number;
18
+ };
19
+ fileServiceType: {
20
+ type: PropType<import("../../upload-plus/src/types").FileServiceType>;
21
+ default: any;
22
+ };
23
+ /**
24
+ * @description
25
+ * v-model:fileStatus 当前文件状态: wait, doPause, pause, doDownload, downloading, error, done
26
+ */
27
+ fileStatus: {
28
+ type: PropType<Status>;
29
+ default: any;
30
+ };
31
+ label: StringConstructor;
32
+ labelWidth: import("element-plus/es/utils").EpPropFinalized<readonly [StringConstructor, NumberConstructor], unknown, unknown, "", boolean>;
33
+ prop: {
34
+ readonly type: PropType<import("element-plus/es/utils").EpPropMergeType<(new (...args: any[]) => string | string[]) | (() => import("element-plus").FormItemProp) | ((new (...args: any[]) => string | string[]) | (() => import("element-plus").FormItemProp))[], unknown, unknown>>;
35
+ readonly required: false;
36
+ readonly validator: (val: unknown) => boolean;
37
+ __epPropKey: true;
38
+ };
39
+ required: import("element-plus/es/utils").EpPropFinalized<BooleanConstructor, unknown, unknown, undefined, boolean>;
40
+ rules: {
41
+ readonly type: PropType<unknown>;
42
+ readonly required: false;
43
+ readonly validator: (val: unknown) => boolean;
44
+ __epPropKey: true;
45
+ };
46
+ error: StringConstructor;
47
+ validateStatus: {
48
+ readonly type: PropType<import("element-plus/es/utils").EpPropMergeType<StringConstructor, "" | "error" | "success" | "validating", unknown>>;
49
+ readonly required: false;
50
+ readonly validator: (val: unknown) => boolean;
51
+ __epPropKey: true;
52
+ };
53
+ for: StringConstructor;
54
+ inlineMessage: import("element-plus/es/utils").EpPropFinalized<readonly [StringConstructor, BooleanConstructor], unknown, unknown, "", boolean>;
55
+ showMessage: import("element-plus/es/utils").EpPropFinalized<BooleanConstructor, unknown, unknown, true, boolean>;
56
+ formItemSize: {
57
+ type: PropType<"default" | "small" | "large">;
58
+ default: "default" | "small" | "large";
59
+ };
60
+ formItemSlots: {
61
+ type: PropType<import("../../form-item/src/types").FormItemSlots>;
62
+ default: any;
63
+ };
64
+ elRef: {
65
+ type: PropType<any>;
66
+ required: boolean;
67
+ };
68
+ inline: {
69
+ type: BooleanConstructor;
70
+ default: boolean;
71
+ };
72
+ readonly: {
73
+ type: BooleanConstructor;
74
+ default: any;
75
+ };
76
+ labelPosition: {
77
+ type: PropType<"right">;
78
+ default: string;
79
+ };
80
+ };
81
+ export declare const emits: {
82
+ 'update:fileStatus': any;
83
+ };
@@ -0,0 +1 @@
1
+ import{_VkfFormItemCtx as t}from"@vunk/form/components/form-item";import{restFetch as e}from"@skzz/platform/shared/fetch/platform";const r={...t.props,fileId:{type:String,default:""},url:{type:String,default:e.baseURL},chunkSize:{type:Number,default:1024*1024*10},fileServiceType:{type:String,default:void 0},fileStatus:{type:String,default:void 0}},i={"update:fileStatus":null};export{i as emits,r as props};