Showing
6 changed files
with
1070 additions
and
154 deletions
| ... | @@ -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", | ... | ... |
src/components/FileUploaderField/Uploader.js
0 → 100644
| 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"> *</span> | 11 | + <text v-if="item.component_props.required"> *</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 }}. {{ file.filename }} {{ (file.size / 1024 / 1024).toFixed(2) }}MB</span> | 30 | + <span>{{ index + 1 }}. {{ file.name }} {{ (file.size / 1024 / 1024).toFixed(2) }}MB</span> |
| 27 | | 31 | |
| 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" | ... | ... |
-
Please register or login to post a comment