hookehuyr

✨ feat(上传文件控件): 样式和功能调整

...@@ -49,6 +49,8 @@ declare module '@vue/runtime-core' { ...@@ -49,6 +49,8 @@ declare module '@vue/runtime-core' {
49 NutSwiper: typeof import('@nutui/nutui-taro')['Swiper'] 49 NutSwiper: typeof import('@nutui/nutui-taro')['Swiper']
50 NutSwiperItem: typeof import('@nutui/nutui-taro')['SwiperItem'] 50 NutSwiperItem: typeof import('@nutui/nutui-taro')['SwiperItem']
51 NutTextarea: typeof import('@nutui/nutui-taro')['Textarea'] 51 NutTextarea: typeof import('@nutui/nutui-taro')['Textarea']
52 + NutToast: typeof import('@nutui/nutui-taro')['Toast']
53 + NutUploader: typeof import('@nutui/nutui-taro')['Uploader']
52 PhoneField: typeof import('./src/components/PhoneField/index.vue')['default'] 54 PhoneField: typeof import('./src/components/PhoneField/index.vue')['default']
53 PickerField: typeof import('./src/components/PickerField/index.vue')['default'] 55 PickerField: typeof import('./src/components/PickerField/index.vue')['default']
54 RadioField: typeof import('./src/components/RadioField/index.vue')['default'] 56 RadioField: typeof import('./src/components/RadioField/index.vue')['default']
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
38 "dependencies": { 38 "dependencies": {
39 "@babel/runtime": "^7.7.7", 39 "@babel/runtime": "^7.7.7",
40 "@nutui/icons-vue-taro": "^0.0.9", 40 "@nutui/icons-vue-taro": "^0.0.9",
41 - "@nutui/nutui-taro": "^4.0.4", 41 + "@nutui/nutui-taro": "^4.0.5",
42 "@tarojs/components": "3.6.2", 42 "@tarojs/components": "3.6.2",
43 "@tarojs/extend": "^3.6.2", 43 "@tarojs/extend": "^3.6.2",
44 "@tarojs/helper": "3.6.2", 44 "@tarojs/helper": "3.6.2",
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
57 "@tarojs/taro": "3.6.2", 57 "@tarojs/taro": "3.6.2",
58 "@vant/area-data": "^1.4.1", 58 "@vant/area-data": "^1.4.1",
59 "axios-miniprogram": "^2.0.0-rc-2", 59 "axios-miniprogram": "^2.0.0-rc-2",
60 + "browser-md5-file": "^1.1.1",
60 "dayjs": "^1.11.7", 61 "dayjs": "^1.11.7",
61 "pinia": "2.0.10", 62 "pinia": "2.0.10",
62 "taro-plugin-pinia": "^1.0.0", 63 "taro-plugin-pinia": "^1.0.0",
......
1 +var __defProp = Object.defineProperty
2 +var __defNormalProp = (obj, key, value) =>
3 + key in obj
4 + ? __defProp(obj, key, {
5 + enumerable: true,
6 + configurable: true,
7 + writable: true,
8 + value,
9 + })
10 + : (obj[key] = value)
11 +var __publicField = (obj, key, value) => {
12 + __defNormalProp(obj, typeof key !== 'symbol' ? key + '' : key, value)
13 + return value
14 +}
15 +import {
16 + reactive,
17 + computed,
18 + resolveComponent,
19 + openBlock,
20 + createElementBlock,
21 + normalizeClass,
22 + renderSlot,
23 + createTextVNode,
24 + createBlock,
25 + createCommentVNode,
26 + Fragment,
27 + renderList,
28 + createElementVNode,
29 + toDisplayString,
30 + createVNode,
31 +} from 'vue'
32 +import { c as createComponent } from './component-25dcca32.js'
33 +import { f as funInterceptor } from './interceptor-157a0193.js'
34 +import Progress from './Progress.js'
35 +import Button from './Button.js'
36 +import Taro from '@tarojs/taro'
37 +import { Photograph, Failure, Loading, Del, Link } from '@nutui/icons-vue-taro'
38 +import { _ as _export_sfc } from './_plugin-vue_export-helper-cc2b3d55.js'
39 +import '../locale/lang'
40 +class UploadOptions {
41 + constructor() {
42 + __publicField(this, 'url', '')
43 + __publicField(this, 'name', 'file')
44 + __publicField(this, 'fileType', 'image')
45 + __publicField(this, 'formData')
46 + __publicField(this, 'sourceFile')
47 + __publicField(this, 'method', 'post')
48 + __publicField(this, 'xhrState', 200)
49 + __publicField(this, 'timeout', 30 * 1e3)
50 + __publicField(this, 'headers', {})
51 + __publicField(this, 'withCredentials', false)
52 + __publicField(this, 'onStart')
53 + __publicField(this, 'taroFilePath')
54 + __publicField(this, 'onProgress')
55 + __publicField(this, 'onSuccess')
56 + __publicField(this, 'onFailure')
57 + __publicField(this, 'beforeXhrUpload')
58 + }
59 +}
60 +class Uploader {
61 + constructor(options) {
62 + __publicField(this, 'options')
63 + this.options = options
64 + }
65 + upload() {
66 + var _a
67 + const options = this.options
68 + const xhr = new XMLHttpRequest()
69 + xhr.timeout = options.timeout
70 + if (xhr.upload) {
71 + xhr.upload.addEventListener(
72 + 'progress',
73 + (e) => {
74 + var _a2
75 + ;(_a2 = options.onProgress) == null
76 + ? void 0
77 + : _a2.call(options, e, options)
78 + },
79 + false,
80 + )
81 + xhr.onreadystatechange = () => {
82 + var _a2, _b
83 + if (xhr.readyState === 4) {
84 + if (xhr.status == options.xhrState) {
85 + ;(_a2 = options.onSuccess) == null
86 + ? void 0
87 + : _a2.call(options, xhr.responseText, options)
88 + } else {
89 + ;(_b = options.onFailure) == null
90 + ? void 0
91 + : _b.call(options, xhr.responseText, options)
92 + }
93 + }
94 + }
95 + xhr.withCredentials = options.withCredentials
96 + xhr.open(options.method, options.url, true)
97 + for (const [key, value] of Object.entries(options.headers)) {
98 + xhr.setRequestHeader(key, value)
99 + }
100 + ;(_a = options.onStart) == null ? void 0 : _a.call(options, options)
101 + if (options.beforeXhrUpload) {
102 + options.beforeXhrUpload(xhr, options)
103 + } else {
104 + xhr.send(options.formData)
105 + }
106 + } else {
107 + console.warn('浏览器不支持 XMLHttpRequest')
108 + }
109 + }
110 +}
111 +class UploaderTaro extends Uploader {
112 + constructor(options) {
113 + super(options)
114 + }
115 + uploadTaro(uploadFile, env) {
116 + var _a
117 + const options = this.options
118 + if (env === 'WEB') {
119 + this.upload()
120 + } else {
121 + if (options.beforeXhrUpload) {
122 + options.beforeXhrUpload(uploadFile, options)
123 + } else {
124 + const uploadTask = uploadFile({
125 + url: options.url,
126 + filePath: options.taroFilePath,
127 + fileType: options.fileType,
128 + header: {
129 + 'Content-Type': 'multipart/form-data',
130 + ...options.headers,
131 + },
132 + //
133 + formData: options.formData,
134 + name: options.name,
135 + success(response) {
136 + var _a2, _b
137 + if (options.xhrState == response.statusCode) {
138 + ;(_a2 = options.onSuccess) == null
139 + ? void 0
140 + : _a2.call(options, response, options)
141 + } else {
142 + ;(_b = options.onFailure) == null
143 + ? void 0
144 + : _b.call(options, response, options)
145 + }
146 + },
147 + fail(e) {
148 + var _a2
149 + ;(_a2 = options.onFailure) == null
150 + ? void 0
151 + : _a2.call(options, e, options)
152 + },
153 + })
154 + ;(_a = options.onStart) == null ? void 0 : _a.call(options, options)
155 + uploadTask.progress((res) => {
156 + var _a2
157 + ;(_a2 = options.onProgress) == null
158 + ? void 0
159 + : _a2.call(options, res, options)
160 + })
161 + }
162 + }
163 + }
164 +}
165 +const { translate: translate$1 } = createComponent('uploader')
166 +class FileItem {
167 + constructor() {
168 + __publicField(this, 'status', 'ready')
169 + __publicField(this, 'message', translate$1('ready'))
170 + __publicField(this, 'uid', /* @__PURE__ */ new Date().getTime().toString())
171 + __publicField(this, 'name')
172 + __publicField(this, 'url')
173 + __publicField(this, 'type')
174 + __publicField(this, 'path')
175 + __publicField(this, 'percentage', 0)
176 + __publicField(this, 'formData', {})
177 + }
178 +}
179 +const { componentName, create, translate } = createComponent('uploader')
180 +const _sfc_main = create({
181 + components: {
182 + [Progress.name]: Progress,
183 + [Button.name]: Button,
184 + Photograph,
185 + Failure,
186 + Loading,
187 + Del,
188 + Link,
189 + },
190 + props: {
191 + name: { type: String, default: 'file' },
192 + url: { type: String, default: '' },
193 + sizeType: {
194 + type: Array,
195 + default: () => ['original', 'compressed'],
196 + },
197 + sourceType: {
198 + type: Array,
199 + default: () => ['album', 'camera'],
200 + },
201 + mediaType: {
202 + type: Array,
203 + default: () => ['image', 'video', 'mix'],
204 + },
205 + camera: {
206 + type: String,
207 + default: 'back',
208 + },
209 + timeout: { type: [Number, String], default: 1e3 * 30 },
210 + // defaultFileList: { type: Array, default: () => new Array<FileItem>() },
211 + fileList: { type: Array, default: () => [] },
212 + isPreview: { type: Boolean, default: true },
213 + // picture、list
214 + listType: { type: String, default: 'picture' },
215 + isDeletable: { type: Boolean, default: true },
216 + method: { type: String, default: 'post' },
217 + capture: { type: Boolean, default: false },
218 + maximize: { type: [Number, String], default: Number.MAX_VALUE },
219 + maximum: { type: [Number, String], default: 9 },
220 + clearInput: { type: Boolean, default: true },
221 + accept: { type: String, default: '*' },
222 + headers: { type: Object, default: {} },
223 + data: { type: Object, default: {} },
224 + xhrState: { type: [Number, String], default: 200 },
225 + multiple: { type: Boolean, default: true },
226 + disabled: { type: Boolean, default: false },
227 + autoUpload: { type: Boolean, default: true },
228 + maxDuration: { type: Number, default: 10 },
229 + beforeXhrUpload: {
230 + type: Function,
231 + default: null,
232 + },
233 + beforeDelete: {
234 + type: Function,
235 + default: (file, files) => {
236 + return true
237 + },
238 + },
239 + onChange: { type: Function },
240 + },
241 + emits: [
242 + 'start',
243 + 'progress',
244 + 'oversize',
245 + 'success',
246 + 'failure',
247 + 'change',
248 + 'delete',
249 + 'update:fileList',
250 + 'file-item-click',
251 + ],
252 + setup(props, { emit }) {
253 + const fileList = reactive(props.fileList)
254 + let uploadQueue = []
255 + const classes = computed(() => {
256 + const prefixCls = componentName
257 + return {
258 + [prefixCls]: true,
259 + }
260 + })
261 + const chooseImage = () => {
262 + if (props.disabled) {
263 + return
264 + }
265 + if (Taro.getEnv() == 'WEB') {
266 + let el = document.getElementById('taroChooseImage')
267 + if (el) {
268 + el == null ? void 0 : el.setAttribute('accept', props.accept)
269 + } else {
270 + const obj = document.createElement('input')
271 + obj.setAttribute('type', 'file')
272 + obj.setAttribute('id', 'taroChooseImage')
273 + obj.setAttribute('accept', props.accept)
274 + obj.setAttribute(
275 + 'style',
276 + 'position: fixed; top: -4000px; left: -3000px; z-index: -300;',
277 + )
278 + document.body.appendChild(obj)
279 + }
280 + }
281 + if (Taro.getEnv() == 'WEAPP') {
282 + // 上传文件类型
283 + if (props.mediaType.includes('file')) {
284 + wx.chooseMessageFile({
285 + /** 最多可以选择的文件个数 */
286 + count: props.multiple
287 + ? props.maximum * 1 - props.fileList.length
288 + : 1,
289 + type: 'file',
290 + /** 接口调用失败的回调函数 */
291 + fail: (res) => {
292 + emit('failure', res)
293 + },
294 + /** 接口调用成功的回调函数 */
295 + success: onChangeFile,
296 + })
297 + } else {
298 + Taro.chooseMedia({
299 + /** 最多可以选择的文件个数 */
300 + count: props.multiple
301 + ? props.maximum * 1 - props.fileList.length
302 + : 1,
303 + /** 文件类型 */
304 + mediaType: props.mediaType,
305 + /** 图片和视频选择的来源 */
306 + sourceType: props.sourceType,
307 + /** 拍摄视频最长拍摄时间,单位秒。时间范围为 3s 至 30s 之间 */
308 + maxDuration: props.maxDuration,
309 + /** 仅对 mediaType 为 image 时有效,是否压缩所选文件 */
310 + sizeType: [],
311 + /** 仅在 sourceType 为 camera 时生效,使用前置或后置摄像头 */
312 + camera: props.camera,
313 + /** 接口调用失败的回调函数 */
314 + fail: (res) => {
315 + emit('failure', res)
316 + },
317 + /** 接口调用成功的回调函数 */
318 + success: onChangeMedia,
319 + })
320 + }
321 + } else {
322 + Taro.chooseImage({
323 + // 选择数量
324 + count: props.multiple ? props.maximum * 1 - props.fileList.length : 1,
325 + // 可以指定是原图还是压缩图,默认二者都有
326 + sizeType: props.sizeType,
327 + sourceType: props.sourceType,
328 + success: onChangeImage,
329 + fail: (res) => {
330 + emit('failure', res)
331 + },
332 + })
333 + }
334 + }
335 + const onChangeMedia = (res) => {
336 + const { type, tempFiles } = res
337 + const _files = filterFiles(tempFiles)
338 + readFile(_files)
339 + emit('change', {
340 + fileList,
341 + })
342 + }
343 + const onChangeFile = (res) => {
344 + const { type, tempFiles } = res
345 + const _files = filterFiles(tempFiles)
346 + readFile(_files)
347 + emit('change', {
348 + fileList,
349 + })
350 + }
351 + const onChangeImage = (res) => {
352 + const { tempFilePaths, tempFiles } = res
353 + const _files = filterFiles(tempFiles)
354 + readFile(_files)
355 + emit('change', {
356 + fileList,
357 + })
358 + }
359 + const fileItemClick = (fileItem) => {
360 + emit('file-item-click', { fileItem })
361 + }
362 + const executeUpload = (fileItem, index) => {
363 + const uploadOption = new UploadOptions()
364 + uploadOption.name = props.name
365 + uploadOption.url = props.url
366 + uploadOption.fileType = fileItem.type
367 + uploadOption.formData = fileItem.formData
368 + uploadOption.timeout = props.timeout * 1
369 + uploadOption.method = props.method
370 + uploadOption.xhrState = props.xhrState
371 + uploadOption.method = props.method
372 + uploadOption.headers = props.headers
373 + uploadOption.taroFilePath = fileItem.path
374 + uploadOption.beforeXhrUpload = props.beforeXhrUpload
375 + uploadOption.onStart = (option) => {
376 + fileItem.status = 'ready'
377 + fileItem.message = translate('readyUpload')
378 + clearUploadQueue(index)
379 + emit('start', option)
380 + }
381 + uploadOption.onProgress = (event, option) => {
382 + fileItem.status = 'uploading'
383 + fileItem.message = translate('uploading')
384 + fileItem.percentage = event.progress
385 + emit('progress', { event, option, percentage: fileItem.percentage })
386 + }
387 + uploadOption.onSuccess = (data, option) => {
388 + fileItem.status = 'success'
389 + fileItem.message = translate('success')
390 + emit('success', {
391 + data,
392 + responseText: data,
393 + option,
394 + fileItem,
395 + })
396 + emit('update:fileList', fileList)
397 + }
398 + uploadOption.onFailure = (data, option) => {
399 + fileItem.status = 'error'
400 + fileItem.message = translate('error')
401 + emit('failure', {
402 + data,
403 + responseText: data,
404 + option,
405 + fileItem,
406 + })
407 + }
408 + let task = new UploaderTaro(uploadOption)
409 + if (props.autoUpload) {
410 + task.uploadTaro(Taro.uploadFile, Taro.getEnv())
411 + } else {
412 + uploadQueue.push(
413 + new Promise((resolve, reject) => {
414 + resolve(task)
415 + }),
416 + )
417 + }
418 + }
419 + const clearUploadQueue = (index = -1) => {
420 + if (index > -1) {
421 + uploadQueue.splice(index, 1)
422 + } else {
423 + uploadQueue = []
424 + fileList.splice(0, fileList.length)
425 + }
426 + }
427 + const submit = () => {
428 + Promise.all(uploadQueue).then((res) => {
429 + res.forEach((i) => i.uploadTaro(Taro.uploadFile, Taro.getEnv()))
430 + })
431 + }
432 + const readFile = (files) => {
433 + files.forEach((file, index) => {
434 + var _a, _b
435 + let fileType = file.type
436 + let filepath = file.tempFilePath || file.path
437 + const fileItem = reactive(new FileItem())
438 + if (file.fileType) {
439 + fileType = file.fileType
440 + } else {
441 + const imgReg = /\.(png|jpeg|jpg|webp|gif)$/i
442 + if (
443 + !fileType &&
444 + (imgReg.test(filepath) || filepath.includes('data:image'))
445 + ) {
446 + fileType = 'image'
447 + }
448 + }
449 + fileItem.path = filepath
450 + fileItem.name = file.name ? file.name : filepath
451 + fileItem.status = 'ready'
452 + fileItem.message = translate('waitingUpload')
453 + fileItem.type = fileType
454 + if (Taro.getEnv() == 'WEB') {
455 + const formData = new FormData()
456 + for (const [key, value] of Object.entries(props.data)) {
457 + formData.append(key, value)
458 + }
459 + formData.append(props.name, file.originalFileObj)
460 + fileItem.name = (_a = file.originalFileObj) == null ? void 0 : _a.name
461 + fileItem.type = (_b = file.originalFileObj) == null ? void 0 : _b.type
462 + fileItem.formData = formData
463 + } else {
464 + fileItem.formData = props.data
465 + }
466 + if (props.isPreview) {
467 + fileItem.url = fileType == 'video' ? file.thumbTempFilePath : filepath
468 + }
469 + fileList.push(fileItem)
470 + executeUpload(fileItem, index)
471 + })
472 + }
473 + const filterFiles = (files) => {
474 + const maximum = props.maximum * 1
475 + const maximize = props.maximize * 1
476 + const oversizes = new Array()
477 + files = files.filter((file) => {
478 + if (file.size > maximize) {
479 + oversizes.push(file)
480 + return false
481 + } else {
482 + return true
483 + }
484 + })
485 + if (oversizes.length) {
486 + emit('oversize', oversizes)
487 + }
488 + let currentFileLength = files.length + fileList.length
489 + if (currentFileLength > maximum) {
490 + files.splice(files.length - (currentFileLength - maximum))
491 + }
492 + return files
493 + }
494 + const deleted = (file, index) => {
495 + fileList.splice(index, 1)
496 + emit('delete', {
497 + file,
498 + fileList,
499 + index,
500 + })
501 + }
502 + const onDelete = (file, index) => {
503 + clearUploadQueue(index)
504 + funInterceptor(props.beforeDelete, {
505 + args: [file, fileList],
506 + done: () => deleted(file, index),
507 + })
508 + }
509 + return {
510 + onDelete,
511 + fileList,
512 + classes,
513 + chooseImage,
514 + fileItemClick,
515 + clearUploadQueue,
516 + submit,
517 + }
518 + },
519 +})
520 +const _hoisted_1 = {
521 + key: 0,
522 + class: 'nut-uploader__slot',
523 +}
524 +const _hoisted_2 = {
525 + key: 0,
526 + class: 'nut-uploader__preview-img',
527 +}
528 +const _hoisted_3 = {
529 + key: 0,
530 + class: 'nut-uploader__preview__progress',
531 +}
532 +const _hoisted_4 = { class: 'nut-uploader__preview__progress__msg' }
533 +const _hoisted_5 = ['onClick']
534 +const _hoisted_6 = ['onClick', 'src']
535 +const _hoisted_7 = {
536 + key: 3,
537 + class: 'nut-uploader__preview-img__file',
538 +}
539 +const _hoisted_8 = ['onClick']
540 +const _hoisted_9 = { class: 'file__name_tips' }
541 +const _hoisted_10 = { class: 'tips' }
542 +const _hoisted_11 = {
543 + key: 1,
544 + class: 'nut-uploader__preview-list',
545 +}
546 +const _hoisted_12 = ['onClick']
547 +const _hoisted_13 = { class: 'file__name_tips' }
548 +function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
549 + const _component_nut_button = resolveComponent('nut-button')
550 + const _component_Failure = resolveComponent('Failure')
551 + const _component_Loading = resolveComponent('Loading')
552 + const _component_Link = resolveComponent('Link')
553 + const _component_Del = resolveComponent('Del')
554 + const _component_nut_progress = resolveComponent('nut-progress')
555 + const _component_Photograph = resolveComponent('Photograph')
556 + return (
557 + openBlock(),
558 + createElementBlock(
559 + 'view',
560 + {
561 + class: normalizeClass(_ctx.classes),
562 + },
563 + [
564 + _ctx.$slots.default
565 + ? (openBlock(),
566 + createElementBlock('view', _hoisted_1, [
567 + renderSlot(_ctx.$slots, 'default'),
568 + createTextVNode(),
569 + Number(_ctx.maximum) - _ctx.fileList.length
570 + ? (openBlock(),
571 + createBlock(
572 + _component_nut_button,
573 + {
574 + key: 0,
575 + class: 'nut-uploader__input',
576 + onClick: _ctx.chooseImage,
577 + },
578 + null,
579 + 8,
580 + ['onClick'],
581 + ))
582 + : createCommentVNode('', true),
583 + ]))
584 + : createCommentVNode('', true),
585 + createTextVNode(),
586 + (openBlock(true),
587 + createElementBlock(
588 + Fragment,
589 + null,
590 + renderList(_ctx.fileList, (item, index) => {
591 + return (
592 + openBlock(),
593 + createElementBlock(
594 + 'view',
595 + {
596 + class: normalizeClass([
597 + 'nut-uploader__preview',
598 + [_ctx.listType],
599 + ]),
600 + key: item.uid,
601 + },
602 + [
603 + _ctx.listType == 'picture' && !_ctx.$slots.default
604 + ? (openBlock(),
605 + createElementBlock('view', _hoisted_2, [
606 + item.status != 'success'
607 + ? (openBlock(),
608 + createElementBlock('view', _hoisted_3, [
609 + item.status != 'ready'
610 + ? (openBlock(),
611 + createElementBlock(
612 + Fragment,
613 + { key: 0 },
614 + [
615 + item.status == 'error'
616 + ? (openBlock(),
617 + createBlock(_component_Failure, {
618 + key: 0,
619 + color: '#fff',
620 + }))
621 + : (openBlock(),
622 + createBlock(_component_Loading, {
623 + key: 1,
624 + name: 'loading',
625 + color: '#fff',
626 + })),
627 + ],
628 + 64,
629 + ))
630 + : createCommentVNode('', true),
631 + createTextVNode(),
632 + createElementVNode(
633 + 'view',
634 + _hoisted_4,
635 + toDisplayString(item.message),
636 + 1,
637 + ),
638 + ]))
639 + : createCommentVNode('', true),
640 + createTextVNode(),
641 + _ctx.isDeletable
642 + ? (openBlock(),
643 + createElementBlock(
644 + 'view',
645 + {
646 + key: 1,
647 + class: 'close',
648 + onClick: ($event) => _ctx.onDelete(item, index),
649 + },
650 + [
651 + renderSlot(
652 + _ctx.$slots,
653 + 'delete-icon',
654 + {},
655 + () => [createVNode(_component_Failure)],
656 + ),
657 + ],
658 + 8,
659 + _hoisted_5,
660 + ))
661 + : createCommentVNode('', true),
662 + createTextVNode(),
663 + ['image', 'video'].includes(item.type) && item.url
664 + ? (openBlock(),
665 + createElementBlock(
666 + 'img',
667 + {
668 + key: 2,
669 + class: 'nut-uploader__preview-img__c',
670 + mode: 'aspectFit',
671 + onClick: ($event) => _ctx.fileItemClick(item),
672 + src: item.url,
673 + },
674 + null,
675 + 8,
676 + _hoisted_6,
677 + ))
678 + : (openBlock(),
679 + createElementBlock('view', _hoisted_7, [
680 + createElementVNode(
681 + 'view',
682 + {
683 + class:
684 + 'nut-uploader__preview-img__file__name',
685 + onClick: ($event) => _ctx.fileItemClick(item),
686 + },
687 + [
688 + createElementVNode(
689 + 'view',
690 + _hoisted_9,
691 + toDisplayString(item.name),
692 + 1,
693 + ),
694 + ],
695 + 8,
696 + _hoisted_8,
697 + ),
698 + ])),
699 + createTextVNode(),
700 + createElementVNode(
701 + 'view',
702 + _hoisted_10,
703 + toDisplayString(item.name),
704 + 1,
705 + ),
706 + ]))
707 + : _ctx.listType == 'list'
708 + ? (openBlock(),
709 + createElementBlock('view', _hoisted_11, [
710 + createElementVNode(
711 + 'view',
712 + {
713 + class: normalizeClass([
714 + 'nut-uploader__preview-img__file__name',
715 + [item.status],
716 + ]),
717 + onClick: ($event) => _ctx.fileItemClick(item),
718 + },
719 + [
720 + createVNode(_component_Link, {
721 + class: 'nut-uploader__preview-img__file__link',
722 + }),
723 + createTextVNode(),
724 + createElementVNode(
725 + 'view',
726 + _hoisted_13,
727 + toDisplayString(item.name),
728 + 1,
729 + ),
730 + createTextVNode(),
731 + _ctx.isDeletable
732 + ? (openBlock(),
733 + createBlock(
734 + _component_Del,
735 + {
736 + key: 0,
737 + color: '#808080',
738 + class:
739 + 'nut-uploader__preview-img__file__del',
740 + onClick: ($event) =>
741 + _ctx.onDelete(item, index),
742 + },
743 + null,
744 + 8,
745 + ['onClick'],
746 + ))
747 + : createCommentVNode('', true),
748 + ],
749 + 10,
750 + _hoisted_12,
751 + ),
752 + createTextVNode(),
753 + item.status == 'uploading'
754 + ? (openBlock(),
755 + createBlock(
756 + _component_nut_progress,
757 + {
758 + key: 0,
759 + size: 'small',
760 + percentage: item.percentage,
761 + 'stroke-color':
762 + 'linear-gradient(270deg, rgba(18,126,255,1) 0%,rgba(32,147,255,1) 32.815625%,rgba(13,242,204,1) 100%)',
763 + 'show-text': false,
764 + },
765 + null,
766 + 8,
767 + ['percentage'],
768 + ))
769 + : createCommentVNode('', true),
770 + ]))
771 + : createCommentVNode('', true),
772 + ],
773 + 2,
774 + )
775 + )
776 + }),
777 + 128,
778 + )),
779 + createTextVNode(),
780 + _ctx.listType == 'picture' &&
781 + !_ctx.$slots.default &&
782 + Number(_ctx.maximum) - _ctx.fileList.length
783 + ? (openBlock(),
784 + createElementBlock(
785 + 'view',
786 + {
787 + key: 1,
788 + class: normalizeClass([
789 + 'nut-uploader__upload',
790 + [_ctx.listType],
791 + ]),
792 + },
793 + [
794 + renderSlot(_ctx.$slots, 'upload-icon', {}, () => [
795 + createVNode(_component_Photograph, { color: '#808080' }),
796 + ]),
797 + createTextVNode(),
798 + createVNode(
799 + _component_nut_button,
800 + {
801 + class: normalizeClass([
802 + 'nut-uploader__input',
803 + { disabled: _ctx.disabled },
804 + ]),
805 + onClick: _ctx.chooseImage,
806 + },
807 + null,
808 + 8,
809 + ['class', 'onClick'],
810 + ),
811 + ],
812 + 2,
813 + ))
814 + : createCommentVNode('', true),
815 + ],
816 + 2,
817 + )
818 + )
819 +}
820 +const index_taro = /* @__PURE__ */ _export_sfc(_sfc_main, [
821 + ['render', _sfc_render],
822 +])
823 +export { index_taro as default }
1 <!-- 1 <!--
2 * @Date: 2022-08-31 16:16:49 2 * @Date: 2022-08-31 16:16:49
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2023-02-10 11:17:21 4 + * @LastEditTime: 2023-04-12 09:54:33
5 - * @FilePath: /data-table/src/components/FileUploaderField/index.vue 5 + * @FilePath: /custom_form/src/components/FileUploaderField/index.vue
6 * @Description: 文件上传控件 6 * @Description: 文件上传控件
7 --> 7 -->
8 <template> 8 <template>
9 <div v-if="HideShow" class="file-uploader-field"> 9 <div v-if="HideShow" class="file-uploader-field">
10 <div class="label"> 10 <div class="label">
11 - <span v-if="item.component_props.required">&nbsp;*</span> 11 + <text v-if="item.component_props.required">&nbsp;*</text>
12 {{ item.component_props.label }} 12 {{ item.component_props.label }}
13 </div> 13 </div>
14 + <div style="font-size: 12px; color: red; margin-left: 20px;">
15 + <text>最大文件个数为 {{ item.component_props.max_count }} 个</text>,
16 + <text>单个文件最大体积 {{ item.component_props.max_size }} MB</text>
17 + </div>
14 <div 18 <div
15 v-if="item.component_props.note" 19 v-if="item.component_props.note"
16 v-html="item.component_props.note" 20 v-html="item.component_props.note"
17 style="font-size: 0.9rem; margin-left: 1rem; color: gray; padding-bottom: 0.5rem; padding-top: 0.25rem; white-space: pre-wrap;" 21 style="font-size: 0.9rem; margin-left: 1rem; color: gray; padding-bottom: 0.5rem; padding-top: 0.25rem; white-space: pre-wrap;"
18 /> 22 />
19 - <div> 23 + <!-- <div>
20 <p 24 <p
21 v-for="(file, index) in fileList" 25 v-for="(file, index) in fileList"
22 :key="index" 26 :key="index"
23 style="padding-left: 1rem; margin-bottom: 0.5rem" 27 style="padding-left: 1rem; margin-bottom: 0.5rem"
24 > 28 >
25 <p style="font-size: 1rem; word-break: break-all; margin-right: 0.75rem;"> 29 <p style="font-size: 1rem; word-break: break-all; margin-right: 0.75rem;">
26 - <span>{{ index + 1 }}.&nbsp;{{ file.filename }}&nbsp;&nbsp;{{ (file.size / 1024 / 1024).toFixed(2) }}MB</span> 30 + <span>{{ index + 1 }}.&nbsp;{{ file.name }}&nbsp;&nbsp;{{ (file.size / 1024 / 1024).toFixed(2) }}MB</span>
27 &nbsp;&nbsp; 31 &nbsp;&nbsp;
28 <span style="color: #e32525; font-size: 0.85rem" @click="beforeDelete(file)">移除</span> 32 <span style="color: #e32525; font-size: 0.85rem" @click="beforeDelete(file)">移除</span>
29 </p> 33 </p>
30 </p> 34 </p>
31 - </div> 35 + </div> -->
32 - <div style="padding: 1rem"> 36 + <div style="padding: 1rem; padding-top: 0.5rem;">
33 - <van-uploader 37 + <nut-uploader
34 :name="item.name" 38 :name="item.name"
35 - upload-icon="add" 39 + v-model:file-list="defaultFileList"
36 - accept="*" 40 + :maximum="item.component_props.max_count"
37 - :before-read="beforeRead" 41 + :multiple="item.component_props.max_count > 1"
38 - :after-read="afterRead" 42 + :size-type="['compressed']"
39 - :before-delete="beforeDelete" 43 + :media-type="['file']"
40 - :multiple="item.component_props.max_size > 1" 44 + :maximize="max_size"
45 + list-type="list"
46 + :before-xhr-upload="beforeXhrUpload"
47 + @oversize="onOversize"
48 + @success="uploadSuccess"
49 + @failure="uploadFailure"
50 + @delete="onDelete"
51 + @change="onChange"
52 + @file-item-click="fileItemClick"
41 > 53 >
42 - <van-button icon="plus" type="primary">上传文件</van-button> 54 + <nut-button shape="square" type="primary">
43 - </van-uploader> 55 + <template #icon>
56 + <Uploader />
57 + </template>
58 + 上传文件
59 + </nut-button>
60 + </nut-uploader>
44 </div> 61 </div>
45 <!-- <div class="type-text">上传格式:{{ type_text }}</div> --> 62 <!-- <div class="type-text">上传格式:{{ type_text }}</div> -->
46 <div 63 <div
47 - v-if="show_empty" 64 + v-if="show_error"
48 - class="van-field__error-message" 65 + style="padding: 5px 20px; color: red; font-size: 12px;"
49 - style="padding: 0 1rem 1rem 1rem"
50 > 66 >
51 - 文件上传不能为空 67 + {{ error_msg }}
52 </div> 68 </div>
53 - <van-divider /> 69 + <nut-divider :style="{ color: '#ebedf0' }" />
70 + <nut-overlay v-model:visible="loading">
71 + <div class="wrapper" style="color: white; font-size: 15px;">
72 + <Loading />
73 + 上传中...
74 + </div>
75 + </nut-overlay>
76 + <nut-toast :msg="toast_msg" v-model:visible="toast_show" :type="toast_type" />
54 </div> 77 </div>
55 78
56 - <van-overlay :show="loading">
57 - <div class="wrapper" @click.stop>
58 - <van-loading vertical color="#FFFFFF">上传中...</van-loading>
59 - </div>
60 - </van-overlay>
61 </template> 79 </template>
62 80
63 <script setup> 81 <script setup>
64 -/** 82 +import { ref, computed, watch, onMounted, reactive } from "vue";
65 - * 文件上传
66 - * @param name[String] 组件名称
67 - * @param file_type[Array] 文件上传类型
68 - * @param multiple[Boolean] 文件多选
69 - */
70 -import { showSuccessToast, showFailToast, showToast } from "vant";
71 -import _ from "lodash";
72 -import { v4 as uuidv4 } from "uuid";
73 import { qiniuTokenAPI, qiniuUploadAPI, saveFileAPI } from "@/api/common"; 83 import { qiniuTokenAPI, qiniuUploadAPI, saveFileAPI } from "@/api/common";
74 import BMF from "browser-md5-file"; 84 import BMF from "browser-md5-file";
75 -import { useRoute } from "vue-router"; 85 +import { getUrlParams } from "@/utils/tools";
76 -import axios from "axios"; 86 +import { Uploader, Loading } from '@nutui/icons-vue-taro';
77 -import { getEtag } from "@/utils/qetag.js"; // 生成hash值 87 +import Taro from '@tarojs/taro'
78 88
79 -const $route = useRoute();
80 const props = defineProps({ 89 const props = defineProps({
81 item: Object, 90 item: Object,
82 }); 91 });
...@@ -84,20 +93,166 @@ const props = defineProps({ ...@@ -84,20 +93,166 @@ const props = defineProps({
84 const HideShow = computed(() => { 93 const HideShow = computed(() => {
85 return !props.item.component_props.disabled 94 return !props.item.component_props.disabled
86 }) 95 })
96 +
87 const emit = defineEmits(["active"]); 97 const emit = defineEmits(["active"]);
88 -const show_empty = ref(false);
89 98
90 -// 文件类型中文页面显示 99 +// // 文件类型中文页面显示
91 -const type_text = computed(() => { 100 +// const type_text = computed(() => {
92 - return props.item.component_props.file_type; 101 +// return props.item.component_props.file_type;
93 -}); 102 +// });
103 +
94 // 上传文件集合 104 // 上传文件集合
95 -const fileList = ref([ 105 +const fileList = ref([]);
96 - // { url: "https://fastly.jsdelivr.net/npm/@vant/assets/leaf.jpeg" }, 106 +const defaultFileList = ref([])
97 - // Uploader 根据文件后缀来判断是否为文件文件 107 +
98 - // 如果文件 URL 中不包含类型信息,可以添加 isImage 标记来声明 108 +// 上传文件体积
99 - // { url: 'https://cloud-image', isImage: true }, 109 +const max_size = computed(() => {
100 -]); 110 + return props.item.component_props.max_size * 1024 * 1024
111 +})
112 +
113 +const toast_msg = ref('');
114 +const toast_show = ref(false);
115 +const toast_type = ref('success');
116 +
117 +// 超过体积大小回调
118 +const onOversize = (files) => {
119 + toast_msg.value = `最大文件体积为${props.item.component_props.max_size}MB`
120 + toast_show.value = true;
121 + toast_type.value = 'warn';
122 +};
123 +
124 +// 自定义上传逻辑
125 +const beforeXhrUpload = async (xhr, options) => {
126 + // H5环境
127 + if (process.env.TARO_ENV === 'h5') {
128 + // 把本地路径转换成file实体
129 + const imgObj = defaultFileList.value[defaultFileList.value.length - 1];
130 + const imgBlob = await fetch(imgObj.url).then(r => r.blob());
131 + const imgFile = new File([imgBlob], imgObj.name , { type: imgObj.type });
132 + // 上传返回file数据结构
133 + const resImgObj = await handleUpload(imgFile);
134 + // 上传失败提示
135 + if (!resImgObj.src) {
136 + options.onFailure?.(resImgObj, options);
137 + loading.value = false;
138 + } else {
139 + defaultFileList.value[defaultFileList.value.length - 1]['url'] = resImgObj.src;
140 + fileList.value.push({
141 + name: imgFile.name,
142 + url: resImgObj.src,
143 + size: imgFile.size
144 + });
145 + options.onSuccess?.(resImgObj, options);
146 + loading.value = false;
147 + }
148 + } else {
149 + const imgObj = defaultFileList.value[defaultFileList.value.length - 1];
150 + const fs = Taro.getFileSystemManager()
151 + fs.getFileInfo({
152 + filePath: imgObj.url,
153 + success: async (res) => {
154 + const file_info = res;
155 + let suffix = /\.[^\.]+$/.exec(imgObj.name); // 获取后缀
156 + // 获取七牛token
157 + const filename = imgObj.name; // 真实文件名
158 + const getToken = await qiniuTokenAPI({
159 + name: filename,
160 + hash: file_info.digest,
161 + });
162 + // 文件上传七牛云
163 + // 第一次上传
164 + if (getToken.token) {
165 + // 自拍图片上传七牛服务器
166 + Taro.uploadFile({
167 + url: 'https://up.qbox.me',
168 + filePath: imgObj.url,
169 + name: `file`,
170 + formData: {
171 + token: getToken.token,
172 + key: `uploadForm/${formCode}/${file_info.digest}${suffix}`
173 + },
174 + })
175 + .then(async (res) => {
176 + res.data = JSON.parse(res.data);
177 + if (res.data.filekey) {
178 + // 保存文件
179 + const { data } = await saveFileAPI({
180 + name: filename,
181 + filekey: res.data.filekey,
182 + hash: file_info.digest,
183 + // format: image_info.format,
184 + // height: image_info.height,
185 + // width: image_info.width,
186 + });
187 + // 加入上传成功队列
188 + fileList.value.push({
189 + name: filename,
190 + url: data.src,
191 + size: file_info.size
192 + });
193 + options.onSuccess?.(data, options);
194 + }
195 + })
196 + .catch((error) => {
197 + console.error(error)
198 + })
199 + }
200 + // 重复上传
201 + if (getToken.data) {
202 + // 加入上传成功队列
203 + fileList.value.push({
204 + name: filename,
205 + url: getToken.data.src,
206 + size: file_info.size
207 + });
208 + options.onSuccess?.(getToken.data, options);
209 + }
210 + }
211 + })
212 + }
213 +}
214 +
215 +// 上传成功回调
216 +const uploadSuccess = async ({ data, fileItem, option, responseText }) => {
217 + props.item.value = {
218 + key: "file_uploader",
219 + filed_name: props.item.key,
220 + value: fileList.value,
221 + };
222 + // 完整数据回调到表单上
223 + emit("active", props.item.value);
224 + // 校验数据
225 + validFileUploader();
226 +};
227 +
228 +// 上传失败回调
229 +const uploadFailure = async ({ data, fileItem, option, responseText }) => {
230 + console.error("上传失败", "fail");
231 + toast_msg.value = '上传失败,请重新尝试!'
232 + toast_show.value = true;
233 + toast_type.value = 'fail';
234 +};
235 +
236 +// 删除上传队列回调
237 +const onDelete = ({ file }) => {
238 + fileList.value = fileList.value.filter((item) => {
239 + if (item.url !== file.url) return item;
240 + });
241 + props.item.value = {
242 + key: "file_uploader",
243 + filed_name: props.item.key,
244 + value: fileList.value,
245 + };
246 + // 完整数据回调到表单上
247 + emit("active", props.item.value);
248 +}
249 +// 上传成功,点击队列项回调
250 +const fileItemClick = (fileItem) => {
251 + console.warn(fileItem);
252 +}
253 +
254 +const onChange = ({ fileList }) => {
255 +}
101 256
102 // 上传前置处理 257 // 上传前置处理
103 const beforeRead = (file) => { 258 const beforeRead = (file) => {
...@@ -141,82 +296,25 @@ const beforeRead = (file) => { ...@@ -141,82 +296,25 @@ const beforeRead = (file) => {
141 return flag; 296 return flag;
142 }; 297 };
143 298
144 -// 文件读取完成后的回调函数
145 -const afterRead = async (files) => {
146 - if (Array.isArray(files)) {
147 - // 多张文件上传files是一个数组
148 - muliUpload(files);
149 - } else {
150 - const imgUrl = await handleUpload(files);
151 - // 上传失败提示
152 - if (!imgUrl.src) {
153 - files.status = "failed";
154 - files.message = "上传失败";
155 - loading.value = false;
156 - } else {
157 - files.status = "";
158 - files.message = "";
159 - fileList.value.push({
160 - // meta_id: imgUrl.meta_id,
161 - name: files.file.name,
162 - url: imgUrl.src,
163 - size: files.file.size
164 - // isImage: true,
165 - });
166 - loading.value = false;
167 - }
168 - }
169 - // 过滤非包含URL的文件
170 - fileList.value = fileList.value.filter((item) => {
171 - if (item.url) return item;
172 - });
173 - props.item.value = {
174 - key: "file_uploader",
175 - filed_name: props.item.key,
176 - // value: fileList.value.map((item) => item.url),
177 - value: fileList.value,
178 - };
179 - show_empty.value = false;
180 - // 完整数据回调到表单上
181 - emit("active", props.item.value);
182 -};
183 -
184 -// 文件删除前的回调函数
185 -const beforeDelete = (files) => {
186 - fileList.value = fileList.value.filter((item) => {
187 - if (item.url !== files.url) return item;
188 - });
189 - props.item.value = {
190 - key: "file_uploader",
191 - filed_name: props.item.key,
192 - // value: fileList.value.map((item) => item.url),
193 - value: fileList.value,
194 - };
195 - // 完整数据回调到表单上
196 - emit("active", props.item.value);
197 -};
198 -
199 /********** 上传七牛云获取文件地址 ***********/ 299 /********** 上传七牛云获取文件地址 ***********/
200 const loading = ref(false); 300 const loading = ref(false);
201 -const formCode = $route.query.code; // 表单code 301 +const formCode = getUrlParams(location.href) ? getUrlParams(location.href).code : ''; // 表单code
202 302
203 // 上传文件返回文件URL 303 // 上传文件返回文件URL
204 -const handleUpload = async (files) => { 304 +const handleUpload = async (file) => {
205 loading.value = true; 305 loading.value = true;
206 - // 获取HASH值
207 - // const hash = getEtag(files.content);
208 return new Promise((resolve, reject) => { 306 return new Promise((resolve, reject) => {
209 // 获取MD5值 307 // 获取MD5值
210 const bmf = new BMF(); 308 const bmf = new BMF();
211 bmf.md5( 309 bmf.md5(
212 - files.file, 310 + file,
213 async (err, md5) => { 311 async (err, md5) => {
214 if (err) { 312 if (err) {
215 console.log(err); 313 console.log(err);
216 reject(err); 314 reject(err);
217 } 315 }
218 // 获取七牛token 316 // 获取七牛token
219 - const filename = files.file.name; // 真实文件名 317 + const filename = file.name; // 真实文件名
220 const getToken = await qiniuTokenAPI({ 318 const getToken = await qiniuTokenAPI({
221 name: filename, 319 name: filename,
222 hash: md5, 320 hash: md5,
...@@ -225,10 +323,8 @@ const handleUpload = async (files) => { ...@@ -225,10 +323,8 @@ const handleUpload = async (files) => {
225 let imgUrl = ""; 323 let imgUrl = "";
226 // 第一次上传 324 // 第一次上传
227 if (getToken.token) { 325 if (getToken.token) {
228 - files.status = "uploading";
229 - files.message = "上传中...";
230 // 返回数据库真实文件地址 326 // 返回数据库真实文件地址
231 - imgUrl = await uploadQiniu(files.file, getToken.token, filename, md5); 327 + imgUrl = await uploadQiniu(file, getToken.token, filename, md5);
232 } 328 }
233 // 重复上传 329 // 重复上传
234 if (getToken.data) { 330 if (getToken.data) {
...@@ -243,30 +339,6 @@ const handleUpload = async (files) => { ...@@ -243,30 +339,6 @@ const handleUpload = async (files) => {
243 }); 339 });
244 }; 340 };
245 341
246 -// 多选文件上传遍历
247 -var muliUpload = async (files) => {
248 - for (let item of files) {
249 - const res = await handleUpload(item);
250 - // 上传失败提示
251 - if (!res.src) {
252 - item.status = "failed";
253 - item.message = "上传失败";
254 - loading.value = false;
255 - } else {
256 - item.status = "";
257 - item.message = "";
258 - fileList.value.push({
259 - // meta_id: res.meta_id,
260 - name: item.file.name,
261 - url: res.src,
262 - size: files.file.size
263 - // isImage: true,
264 - });
265 - loading.value = false;
266 - }
267 - }
268 -};
269 -
270 // 生成数据库真实文件地址 342 // 生成数据库真实文件地址
271 const uploadQiniu = async (file, token, name, md5) => { 343 const uploadQiniu = async (file, token, name, md5) => {
272 let suffix = /\.[^\.]+$/.exec(name); // 获取后缀 344 let suffix = /\.[^\.]+$/.exec(name); // 获取后缀
...@@ -307,28 +379,34 @@ const uploadQiniu = async (file, token, name, md5) => { ...@@ -307,28 +379,34 @@ const uploadQiniu = async (file, token, name, md5) => {
307 379
308 /****************** END *******************/ 380 /****************** END *******************/
309 381
382 +const show_error = ref(false);
383 +const error_msg = ref('');
384 +
310 // 校验模块 385 // 校验模块
311 const validFileUploader = () => { 386 const validFileUploader = () => {
312 // 必填项 未上传文件 387 // 必填项 未上传文件
313 if (props.item.component_props.required && !fileList.value.length) { 388 if (props.item.component_props.required && !fileList.value.length) {
314 - show_empty.value = true; 389 + show_error.value = true;
390 + error_msg.value = '必填项不能为空'
315 } else { 391 } else {
316 - show_empty.value = false; 392 + show_error.value = false;
393 + error_msg.value = ''
317 } 394 }
318 - return !show_empty.value; 395 + return !show_error.value;
319 }; 396 };
320 397
321 defineExpose({ validFileUploader }); 398 defineExpose({ validFileUploader });
322 </script> 399 </script>
323 400
324 -<style lang="less" scoped> 401 +<style lang="less">
325 .file-uploader-field { 402 .file-uploader-field {
326 .label { 403 .label {
327 - padding: 1rem 1rem 0 1rem; 404 + margin-left: 1rem;
328 - font-size: 0.9rem; 405 + padding-bottom: 20px;
406 + font-size: 26px;
329 font-weight: bold; 407 font-weight: bold;
330 408
331 - span { 409 + text {
332 color: red; 410 color: red;
333 } 411 }
334 } 412 }
......
...@@ -9,7 +9,7 @@ import DatePickerField from '@/components/DatePickerField/index.vue' ...@@ -9,7 +9,7 @@ import DatePickerField from '@/components/DatePickerField/index.vue'
9 import TimePickerField from '@/components/TimePickerField/index.vue' 9 import TimePickerField from '@/components/TimePickerField/index.vue'
10 import DateTimePickerField from '@/components/DateTimePickerField/index.vue' 10 import DateTimePickerField from '@/components/DateTimePickerField/index.vue'
11 // import ImageUploaderField from '@/components/ImageUploaderField/index.vue' 11 // import ImageUploaderField from '@/components/ImageUploaderField/index.vue'
12 -// import FileUploaderField from '@/components/FileUploaderField/index.vue' 12 +import FileUploaderField from '@/components/FileUploaderField/index.vue'
13 import PhoneField from '@/components/PhoneField/index.vue' 13 import PhoneField from '@/components/PhoneField/index.vue'
14 import EmailField from '@/components/EmailField/index.vue' 14 import EmailField from '@/components/EmailField/index.vue'
15 // import SignField from '@/components/SignField/index.vue' 15 // import SignField from '@/components/SignField/index.vue'
...@@ -108,9 +108,9 @@ export function createComponentType(data) { ...@@ -108,9 +108,9 @@ export function createComponentType(data) {
108 // if (item.component_props.tag === 'image_uploader') { 108 // if (item.component_props.tag === 'image_uploader') {
109 // item.component = ImageUploaderField 109 // item.component = ImageUploaderField
110 // } 110 // }
111 - // if (item.component_props.tag === 'file_uploader') { 111 + if (item.component_props.tag === 'file_uploader') {
112 - // item.component = FileUploaderField 112 + item.component = FileUploaderField
113 - // } 113 + }
114 if (item.component_props.tag === 'phone') { 114 if (item.component_props.tag === 'phone') {
115 item.name = item.key 115 item.name = item.key
116 item.component = PhoneField 116 item.component = PhoneField
......
...@@ -1359,10 +1359,10 @@ ...@@ -1359,10 +1359,10 @@
1359 resolved "https://mirrors.cloud.tencent.com/npm/@nutui/icons-vue-taro/-/icons-vue-taro-0.0.9.tgz#b5223eb01e2b987fdbe460e5d0439a66481e54f1" 1359 resolved "https://mirrors.cloud.tencent.com/npm/@nutui/icons-vue-taro/-/icons-vue-taro-0.0.9.tgz#b5223eb01e2b987fdbe460e5d0439a66481e54f1"
1360 integrity sha512-10VYAtFC+o1X0anGs+y2PgF1NWMeLFz2JVMRw4BWLg6wbtVbYy9wukLxyGhZC6Yf6t39DcwaGVda8paV7K6/Ew== 1360 integrity sha512-10VYAtFC+o1X0anGs+y2PgF1NWMeLFz2JVMRw4BWLg6wbtVbYy9wukLxyGhZC6Yf6t39DcwaGVda8paV7K6/Ew==
1361 1361
1362 -"@nutui/nutui-taro@^4.0.4": 1362 +"@nutui/nutui-taro@^4.0.5":
1363 - version "4.0.4" 1363 + version "4.0.5"
1364 - resolved "https://mirrors.cloud.tencent.com/npm/@nutui/nutui-taro/-/nutui-taro-4.0.4.tgz#c5b65431ece527e3e531bc7923ad0a7b499daeeb" 1364 + resolved "https://mirrors.cloud.tencent.com/npm/@nutui/nutui-taro/-/nutui-taro-4.0.5.tgz#67c88d582e921641e81432ae1fd136e10e5bc1ea"
1365 - integrity sha512-v9XyXidgiRgZTH5JofgjhJTGGvQDXhOqkLb/uRjlR2c9eQBSU653rlTO82VjUWOpCterYDxtqXswUZIf+PRbfQ== 1365 + integrity sha512-j7+fKtRarfphYJ0uosdalIWvf3k2+x8eDsmBSSnPDyGEeRHtXqGIw8MIxy8wL5UUnADP+6JVK339vC28oo436g==
1366 dependencies: 1366 dependencies:
1367 "@nutui/icons-vue-taro" "^0.0.9" 1367 "@nutui/icons-vue-taro" "^0.0.9"
1368 sass "^1.50.0" 1368 sass "^1.50.0"
...@@ -3546,6 +3546,13 @@ braces@^3.0.2, braces@~3.0.2: ...@@ -3546,6 +3546,13 @@ braces@^3.0.2, braces@~3.0.2:
3546 dependencies: 3546 dependencies:
3547 fill-range "^7.0.1" 3547 fill-range "^7.0.1"
3548 3548
3549 +browser-md5-file@^1.1.1:
3550 + version "1.1.1"
3551 + resolved "https://mirrors.cloud.tencent.com/npm/browser-md5-file/-/browser-md5-file-1.1.1.tgz#247d63527f662d9667adecbe61808b4961b90dc6"
3552 + integrity sha512-9h2UViTtZPhBa7oHvp5mb7MvJaX5OKEPUsplDwJ800OIV+In7BOR3RXOMB78obn2iQVIiS3WkVLhG7Zu1EMwbw==
3553 + dependencies:
3554 + spark-md5 "^2.0.2"
3555 +
3549 browser-process-hrtime@^1.0.0: 3556 browser-process-hrtime@^1.0.0:
3550 version "1.0.0" 3557 version "1.0.0"
3551 resolved "https://mirrors.cloud.tencent.com/npm/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" 3558 resolved "https://mirrors.cloud.tencent.com/npm/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626"
...@@ -11519,6 +11526,11 @@ sourcemap-codec@^1.4.8: ...@@ -11519,6 +11526,11 @@ sourcemap-codec@^1.4.8:
11519 resolved "https://mirrors.cloud.tencent.com/npm/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" 11526 resolved "https://mirrors.cloud.tencent.com/npm/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
11520 integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== 11527 integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
11521 11528
11529 +spark-md5@^2.0.2:
11530 + version "2.0.2"
11531 + resolved "https://mirrors.cloud.tencent.com/npm/spark-md5/-/spark-md5-2.0.2.tgz#37b763847763ae7e7acef2ca5233d01e649a78b7"
11532 + integrity sha1-N7djhHdjrn56zvLKUjPQHmSaeLc=
11533 +
11522 spdx-correct@^3.0.0: 11534 spdx-correct@^3.0.0:
11523 version "3.2.0" 11535 version "3.2.0"
11524 resolved "https://mirrors.cloud.tencent.com/npm/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" 11536 resolved "https://mirrors.cloud.tencent.com/npm/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c"
......