UNPKG

tdesign-vue-next

Version:
1 lines 83.4 kB
{"version":3,"file":"useUpload.mjs","sources":["../../../../common/js/upload/xhr.ts","../../../../common/js/upload/main.ts","../../../../components/upload/hooks/useUpload.ts"],"sourcesContent":["import { isFunction } from 'lodash-es';\n/* eslint-disable no-param-reassign */\nimport log from '../log/log';\nimport { UploadFile, XhrOptions } from './types';\nimport { getCurrentDate } from './utils';\n\nexport default function xhr({\n method = 'POST',\n action,\n withCredentials = false,\n headers = {},\n data = {},\n file,\n files = [],\n name = 'file',\n useMockProgress = true,\n mockProgressDuration = 300,\n formatRequest,\n onError,\n onProgress,\n onSuccess,\n}: XhrOptions) {\n // support files\n const innerFiles: UploadFile[] = files || [];\n let percent = 0;\n\n // eslint-disable-next-line no-shadow\n const xhr = new XMLHttpRequest();\n if (withCredentials) {\n xhr.withCredentials = true;\n }\n\n let timer1: NodeJS.Timeout;\n let timer2: NodeJS.Timeout;\n if (useMockProgress && files[0]?.status === 'progress') {\n // 超过 500 毫秒再开启虚拟进度\n const timer2 = setTimeout(() => {\n // 只有真实进度一直不存在时才需要模拟进度\n timer1 = setInterval(() => {\n if (percent + 10 < 100) {\n percent = Math.max(percent + 10, percent);\n if (files[0] && percent !== files[0].percent) {\n files[0].percent = percent;\n onProgress({\n percent,\n file: file || innerFiles[0],\n files: innerFiles.map((file) => ({ ...file, percent })),\n type: 'mock',\n XMLHttpRequest: xhr,\n });\n }\n } else {\n clearInterval(timer1);\n }\n }, mockProgressDuration);\n clearTimeout(timer2);\n }, mockProgressDuration);\n }\n\n let requestData: { [key: string]: any } = {};\n if (data) {\n const extraData = isFunction(data) ? data(innerFiles) : data;\n Object.assign(requestData, extraData);\n }\n innerFiles.forEach((file, index) => {\n const fileField = innerFiles.length > 1 ? `${name}[${index}]` : name;\n requestData[fileField] = file.raw;\n });\n if (innerFiles.length === 1) {\n requestData[name] = innerFiles[0].raw;\n } else {\n requestData[name] = innerFiles.map((file) => file.raw);\n }\n requestData.length = innerFiles.length;\n\n if (formatRequest) {\n requestData = formatRequest(requestData);\n }\n\n // set send data\n const formData = new FormData();\n Object.keys(requestData).forEach((key) => {\n const dataValue = requestData[key];\n if (Array.isArray(dataValue)) {\n dataValue.forEach((value) => {\n formData.append(key, value);\n });\n } else {\n formData.append(key, dataValue);\n }\n });\n\n xhr.open(method, action, true);\n // custom request headers\n Object.keys(headers).forEach((key) => {\n xhr.setRequestHeader(key, headers[key]);\n });\n\n xhr.onerror = (event: ProgressEvent) => {\n onError({ event, file, files: innerFiles, XMLHttpRequest: xhr });\n clearInterval(timer1);\n clearTimeout(timer2);\n };\n\n xhr.ontimeout = (event) => {\n onError({ event, file, files: innerFiles, XMLHttpRequest: xhr });\n };\n\n if (xhr.upload) {\n xhr.upload.onprogress = (event: ProgressEvent) => {\n let realPercent = 0;\n if (event.total > 0) {\n realPercent = Math.round((event.loaded / event.total) * 100);\n }\n percent = Math.max(realPercent, percent);\n if (percent !== realPercent && innerFiles[0]?.percent !== percent) {\n const progressFiles = innerFiles.map((item) => ({ ...item, percent }));\n onProgress({\n event,\n percent,\n file: file || progressFiles[0],\n files: progressFiles,\n type: 'real',\n XMLHttpRequest: xhr,\n });\n }\n };\n }\n\n // eslint-disable-next-line consistent-return\n xhr.onload = (event: ProgressEvent) => {\n let response: { [key: string]: any } = {};\n response.XMLHttpRequest = xhr;\n const isFail = xhr.status < 200 || xhr.status >= 300;\n if (isFail) {\n return onError({\n event,\n file,\n files: innerFiles,\n response,\n XMLHttpRequest: xhr,\n });\n }\n const text = xhr.responseText || xhr.response;\n try {\n response = JSON.parse(text);\n } catch (e) {\n response = text;\n log.error('Upload', 'response does not a valid json');\n }\n clearInterval(timer1);\n clearTimeout(timer2);\n innerFiles.forEach((file) => {\n file.percent = 100;\n file.status = 'success';\n // 如果上传请求返回结果没有上传日期,则使用电脑当前日期显示\n file.uploadTime = response?.uploadTime || getCurrentDate();\n });\n if (typeof response === 'object') {\n response.XMLHttpRequest = xhr;\n }\n onSuccess({\n event,\n file: file || innerFiles[0],\n files: [...innerFiles],\n XMLHttpRequest: xhr,\n response,\n });\n };\n\n xhr.send(formData);\n // @ts-ignore\n xhr.upload.requestParams = requestData;\n // @ts-ignore\n xhr.upload.requestHeaders = headers;\n\n return xhr;\n}\n","import { isFunction, isNumber } from 'lodash-es';\n/* eslint-disable no-param-reassign */\nimport { getCurrentDate, isOverSizeLimit } from './utils';\nimport xhr from './xhr';\nimport log from '../log/log';\nimport {\n UploadFile,\n SizeLimitObj,\n FileChangeParams,\n FileChangeReturn,\n RequestMethodResponse,\n HandleUploadParams,\n SuccessContext,\n handleSuccessParams,\n UploadTriggerUploadText,\n ErrorContext,\n ResponseType,\n} from './types';\n\nexport interface BeforeUploadExtra {\n /** 图片文件大小限制 */\n sizeLimit?: number | SizeLimitObj;\n /** 上传文件之前的钩子,参数为上传的文件,返回值决定是否上传 */\n beforeUpload?: (file: UploadFile) => boolean | Promise<boolean>;\n}\n\nexport type BeforeUploadPromiseList = [Promise<SizeLimitObj>, undefined | Promise<boolean>];\n\nexport function handleBeforeUpload(file: UploadFile, params: BeforeUploadExtra): Promise<[SizeLimitObj, boolean]> {\n const { sizeLimit, beforeUpload } = params;\n // 文件大小校验\n const sizePromise = new Promise<SizeLimitObj>((resolve) => {\n let result: SizeLimitObj = null;\n if (sizeLimit) {\n const sizeLimitObj: SizeLimitObj = isNumber(sizeLimit) ? { size: sizeLimit, unit: 'KB' } : sizeLimit;\n const limit = isOverSizeLimit(file.size, sizeLimitObj.size, sizeLimitObj.unit);\n if (limit) {\n result = sizeLimitObj;\n }\n }\n resolve(result);\n });\n\n // 自定义校验\n const promiseList: BeforeUploadPromiseList = [sizePromise, undefined];\n if (isFunction(beforeUpload)) {\n const r = beforeUpload(file);\n const p =\n r instanceof Promise\n ? r\n : new Promise<boolean>((resolve) => {\n resolve(r);\n });\n promiseList[1] = p;\n }\n\n // 同时进行文件大小校验和自定义校验函数\n return new Promise((resolve) => {\n Promise.all(promiseList).then((r) => {\n resolve(r);\n });\n });\n}\n\nexport interface OnErrorParams extends ErrorContext {\n formatResponse?: HandleUploadParams['formatResponse'];\n}\n\nexport function handleError(options: OnErrorParams) {\n const { event, files, response, XMLHttpRequest, formatResponse } = options;\n let res = response;\n if (isFunction(formatResponse)) {\n res = formatResponse(response, { file: files[0], currentFiles: files });\n }\n files.forEach((file) => {\n file.status = 'fail';\n file.response = res;\n });\n return { response: res, event, files, XMLHttpRequest };\n}\n\nexport function handleSuccess(params: handleSuccessParams) {\n const { event, files, response, XMLHttpRequest } = params;\n if (files?.length <= 0) {\n log.error('Upload', 'Empty File in Success Callback');\n }\n files.forEach((file) => {\n file.percent = 100;\n file.status = 'success';\n delete file.response?.error;\n });\n const res = response;\n files[0].url = res.url || files[0].url;\n return { response: res, event, files, XMLHttpRequest };\n}\n\nexport type UploadRequestReturn = {\n status?: 'fail' | 'success';\n /** 上传失败的文件,需等待继续上传 */\n failedFiles?: UploadFile[];\n data?: SuccessContext;\n /** 批量文件上传,一个文件一个请求的场景下,响应结果的列表 */\n list?: UploadRequestReturn[];\n};\n\nexport function handleRequestMethodResponse(res: RequestMethodResponse) {\n if (!res) {\n log.error('Upload', '`requestMethodResponse` is required.');\n return false;\n }\n if (!res.status) {\n log.error('Upload', '`requestMethodResponse.status` is missing, which value only can be `success` or `fail`');\n return false;\n }\n if (!['success', 'fail'].includes(res.status)) {\n log.error(\n 'Upload',\n \"`requestMethodResponse.status` must be `success` or `fail`, examples `{ status: 'success', response: { url: '' } }`\"\n );\n return false;\n }\n if (res.status === 'success' && (!res.response || (!res.response.url && !res.response.files))) {\n log.warn(\n 'Upload',\n '`requestMethodResponse.response.url` or `requestMethodResponse.response.files` is required if `status` is `success`'\n );\n }\n return true;\n}\n\n/**\n * 一次上传请求的返回结果\n */\nexport function uploadOneRequest(params: HandleUploadParams): Promise<UploadRequestReturn> {\n const { action, toUploadFiles, requestMethod } = params;\n return new Promise<UploadRequestReturn>((resolve) => {\n if (!action && !requestMethod) {\n log.error('Upload', 'one of action and requestMethod must be exist.');\n resolve({});\n return;\n }\n if (!toUploadFiles || !toUploadFiles.length) {\n log.warn('Upload', 'No files need to be uploaded');\n resolve({});\n return;\n }\n toUploadFiles.forEach((file) => {\n file.status = 'progress';\n });\n // 自定义上传方法\n if (requestMethod) {\n requestMethod(params.multiple ? toUploadFiles : toUploadFiles[0]).then((res) => {\n if (!handleRequestMethodResponse(res)) {\n resolve({});\n return;\n }\n let response = (res.response || {}) as ResponseType;\n if (isFunction(params.formatResponse)) {\n response = params.formatResponse(response, { file: toUploadFiles[0], currentFiles: toUploadFiles });\n }\n if (res.status === 'fail') {\n response.error = res.error || response.error;\n }\n let resultFiles: UploadFile[] = [];\n if (res.status === 'success' && response.files) {\n // 一个请求上传并返回多个文件\n resultFiles = response.files.map((file: UploadFile) => {\n const fileInfo = toUploadFiles.find(\n (toFile) => (file.name && toFile.name === file.name) || (file.raw && toFile.raw === file.raw)\n );\n return {\n ...fileInfo,\n ...file,\n status: res.status,\n response,\n };\n });\n } else {\n // 一个请求上传并返回一个文件\n toUploadFiles.forEach((file) => {\n file.status = res.status;\n file.response = response;\n file.url = response.url;\n file.percent = res.status === 'success' ? 100 : 0;\n // 如果上传请求返回结果没有上传日期,则使用电脑当前日期显示\n file.uploadTime = response?.uploadTime || getCurrentDate();\n });\n resultFiles = toUploadFiles;\n }\n const result = {\n response,\n file: resultFiles[0],\n files: resultFiles,\n };\n if (res.status === 'success') {\n params.onResponseSuccess?.(result);\n } else if (res.status === 'fail') {\n params.onResponseError?.(result);\n }\n resolve({\n status: res.status,\n data: result,\n });\n });\n } else {\n const xhrReq = xhr({\n action: params.action,\n files: params.toUploadFiles,\n useMockProgress: params.useMockProgress,\n mockProgressDuration: params.mockProgressDuration,\n onError: (p: ErrorContext) => {\n const r = handleError({ ...p, formatResponse: params.formatResponse });\n params.onResponseError?.(r);\n resolve({ status: 'fail', data: r });\n },\n onProgress: params.onResponseProgress,\n onSuccess: (p: SuccessContext) => {\n const { formatResponse } = params;\n let res = p.response;\n if (isFunction(formatResponse)) {\n res = formatResponse(p.response, {\n file: p.file,\n currentFiles: p.files,\n });\n }\n if (res.error) {\n const r = handleError({ ...p, response: res });\n params.onResponseError?.(r);\n resolve({ status: 'fail', data: r });\n } else {\n p.file.response = res;\n p.files[0].response = res;\n const r = handleSuccess({ ...p, response: res });\n params.onResponseSuccess?.(r);\n resolve({ status: 'success', data: r });\n }\n },\n formatRequest: params.formatRequest,\n data: params.data,\n name: params.name,\n headers: params.headers,\n withCredentials: params.withCredentials,\n method: params.method,\n });\n params.setXhrObject?.({\n files: params.toUploadFiles,\n xhrReq,\n });\n }\n });\n}\n\nfunction updateUploadedFiles(uploadFiles: UploadFile[], resultFiles: UploadFile[]) {\n const existFiles = uploadFiles.filter((t) => t.url);\n const newFiles = existFiles;\n for (let i = 0, len = resultFiles.length; i < len; i++) {\n const file = resultFiles[i];\n const index = uploadFiles.findIndex(\n (item) => (item.raw && item.raw === file.raw) || (item.name && item.name === file.name)\n );\n const tmpFile = index >= 0 ? { ...uploadFiles[index], ...file } : file;\n newFiles.push(tmpFile);\n }\n return newFiles;\n}\n\n/**\n * 可能单个文件上传,也可能批量文件一次性上传\n * 返回上传成功或上传失败的文件列表\n */\nexport function upload(params: HandleUploadParams): Promise<UploadRequestReturn> {\n const { uploadAllFilesInOneRequest, toUploadFiles, uploadedFiles, isBatchUpload } = params;\n // 一批文件上传,部分文件失败,重新上传失败的文件\n const thisUploadFiles = toUploadFiles.filter((t) => !t.response || (t.response && !t.response.error));\n return new Promise((resolve) => {\n // 所有文件一次性上传\n if (uploadAllFilesInOneRequest || !params.multiple) {\n uploadOneRequest(params).then((r) => {\n if (r.status === 'success') {\n r.data.files =\n isBatchUpload || !params.multiple ? r.data.files : updateUploadedFiles(uploadedFiles, r.data.files);\n }\n const failedFiles = r.status === 'fail' ? r.data.files : [];\n resolve({ ...r, failedFiles });\n });\n return;\n }\n // 一个文件一个文件上传\n const list = thisUploadFiles.map((file) => uploadOneRequest({ ...params, toUploadFiles: [file] }));\n Promise.all(list).then((arr) => {\n const files: UploadFile[] = [];\n const failedFiles: UploadFile[] = [];\n arr.forEach((one) => {\n if (one.status === 'success') {\n files.push(one.data.files[0]);\n } else if (one.status === 'fail') {\n failedFiles.push(one.data.files[0]);\n }\n });\n const tFiles = params.autoUpload ? uploadedFiles.concat(files) : uploadedFiles;\n const newFiles = isBatchUpload || !params.multiple ? files : tFiles;\n resolve({\n status: files.length ? 'success' : 'fail',\n data: {\n files: newFiles,\n },\n // 上传失败的文件,需等待继续上传\n failedFiles,\n list: arr,\n });\n });\n });\n}\n\nexport function formatToUploadFile(\n files: File[],\n format: FileChangeParams['format'],\n status: UploadFile['status'] = undefined,\n percent = 0\n) {\n return files.map((fileRaw: File) => {\n let file: UploadFile = fileRaw;\n if (isFunction(format)) {\n file = format(fileRaw);\n }\n const uploadFile: UploadFile = {\n raw: fileRaw,\n lastModified: fileRaw.lastModified,\n name: fileRaw.name,\n size: fileRaw.size,\n type: fileRaw.type,\n percent,\n status,\n ...file,\n };\n return uploadFile;\n });\n}\n\nexport function validateFile(params: FileChangeParams): Promise<FileChangeReturn> {\n const { files, uploadValue, max, allowUploadDuplicateFile, capture = '' } = params;\n return new Promise((resolve) => {\n // 是否允许相同的文件名存在\n let tmpFiles = files.filter((file) => {\n // capture 明确指定后,一定是调用设备的媒体设备(比如:摄像头)捕获上传文件,该类文件跳过重复文件名校验\n if (allowUploadDuplicateFile || !!capture) return true;\n\n const sameNameFile = uploadValue.find((t) => t.name === file.name);\n return !sameNameFile;\n });\n\n let hasSameNameFile = false;\n if (tmpFiles.length < files.length) {\n hasSameNameFile = true;\n }\n if (!tmpFiles.length) {\n const tFiles = formatToUploadFile(files, params.format, params.autoUpload ? 'progress' : 'waiting');\n resolve({ hasSameNameFile, file: tFiles?.[0], files: tFiles, validateResult: { type: 'FILTER_FILE_SAME_NAME' } });\n return;\n }\n // 上传文件数量限制\n let lengthOverLimit = false;\n if (max && tmpFiles.length && !params.isBatchUpload) {\n const tmpFilesLenToBeAdded = tmpFiles.length;\n tmpFiles = tmpFiles.slice(0, max - uploadValue.length);\n if (tmpFilesLenToBeAdded + uploadValue.length > max) {\n lengthOverLimit = true;\n }\n }\n\n // 格式化文件对象\n const formattedFiles = formatToUploadFile(tmpFiles, params.format, params.autoUpload ? 'progress' : 'waiting');\n\n // 全量文件,一波校验,整体上传 或 终止上传\n let allFileValidatePromise;\n if (params.beforeAllFilesUpload) {\n const r = params.beforeAllFilesUpload?.(formattedFiles);\n allFileValidatePromise =\n r instanceof Promise\n ? r\n : new Promise((resolve) => {\n resolve(r);\n });\n }\n\n // 单文件合法性校验,一个文件校验不通过其他文件可继续上传\n const promiseList = formattedFiles.map(\n (file: UploadFile) =>\n new Promise((resolve) => {\n handleBeforeUpload(file, { beforeUpload: params.beforeUpload, sizeLimit: params.sizeLimit }).then(\n ([sizeResult, customResult]) => {\n if (sizeResult) {\n resolve({ file, validateResult: { type: 'FILE_OVER_SIZE_LIMIT', extra: sizeResult } });\n } else if (customResult === false) {\n resolve({ file, validateResult: { type: 'CUSTOM_BEFORE_UPLOAD' } });\n }\n resolve({ file });\n }\n );\n })\n );\n Promise.all([allFileValidatePromise].concat(promiseList)).then((results) => {\n const [allFilesResult, ...others] = results;\n // 如果 beforeAllFilesUpload 校验未通过\n if (allFilesResult === false) {\n resolve({\n lengthOverLimit,\n hasSameNameFile,\n validateResult: { type: 'BEFORE_ALL_FILES_UPLOAD' },\n files: formattedFiles,\n });\n } else {\n resolve({\n lengthOverLimit,\n hasSameNameFile,\n fileValidateList: others,\n files: formattedFiles,\n });\n }\n });\n });\n}\n\nexport function getFilesAndErrors(\n fileValidateList: FileChangeReturn[],\n getError: (p: { [key: string]: any }) => string\n) {\n const sizeLimitErrors: FileChangeReturn[] = [];\n const beforeUploadErrorFiles: UploadFile[] = [];\n const toFiles: UploadFile[] = [];\n fileValidateList.forEach((oneFile) => {\n if (oneFile.validateResult?.type === 'CUSTOM_BEFORE_UPLOAD') {\n beforeUploadErrorFiles.push(oneFile.file);\n return;\n }\n if (oneFile.validateResult?.type === 'FILE_OVER_SIZE_LIMIT') {\n if (!oneFile.file.response) {\n oneFile.file.response = {};\n }\n oneFile.file.response.error = oneFile.file.response.error || getError(oneFile.validateResult.extra);\n sizeLimitErrors.push(oneFile);\n return;\n }\n toFiles.push(oneFile.file);\n });\n\n return { sizeLimitErrors, beforeUploadErrorFiles, toFiles };\n}\n\n/**\n * 获取文件上传触发元素文本 在全局配置中的字段\n */\nexport function getTriggerTextField(p: {\n status: 'success' | 'fail' | 'progress' | 'waiting';\n multiple: boolean;\n autoUpload: boolean;\n isBatchUpload: boolean;\n}): keyof UploadTriggerUploadText {\n if (p.isBatchUpload && p.status) return 'reupload';\n if (p.status === 'fail') return 'reupload';\n if (p.status === 'progress') return 'uploading';\n if (p.status === 'success' || (!p.autoUpload && p.status === 'waiting')) {\n return p.multiple ? 'continueUpload' : 'reupload';\n }\n return 'fileInput';\n}\n\nexport interface GetDisplayFilesParams {\n multiple: boolean;\n autoUpload: boolean;\n isBatchUpload: boolean;\n uploadValue: UploadFile[];\n toUploadFiles: UploadFile[];\n}\n\n/**\n * 获取文件列表显示\n */\nexport function getDisplayFiles(params: GetDisplayFilesParams) {\n const { multiple, uploadValue, toUploadFiles, autoUpload } = params;\n const waitingUploadFiles = autoUpload ? toUploadFiles : toUploadFiles.filter((file) => file.status !== 'success');\n if (multiple && !params.isBatchUpload) {\n if (!autoUpload) return uploadValue;\n return (waitingUploadFiles.length ? uploadValue.concat(waitingUploadFiles) : uploadValue) || [];\n }\n return (waitingUploadFiles.length ? waitingUploadFiles : uploadValue) || [];\n}\n","import { ref, computed, toRefs } from 'vue';\nimport { merge } from 'lodash-es';\nimport { SizeLimitObj, TdUploadProps, UploadChangeContext, UploadFile, UploadRemoveContext } from '../type';\nimport {\n getFilesAndErrors,\n validateFile,\n upload,\n getTriggerTextField,\n getDisplayFiles,\n formatToUploadFile,\n} from '@tdesign/common-js/upload/main';\nimport { getFileList } from '@tdesign/common-js/upload/utils';\nimport { useVModel, useConfig } from '@tdesign/shared-hooks';\nimport { InnerProgressContext, OnResponseErrorContext, SuccessContext } from '@tdesign/common-js/upload/types';\n\nexport type ValidateParams = Parameters<TdUploadProps['onValidate']>[0];\n\n/**\n * 上传组件全部逻辑,方便脱离 UI,自定义 UI 组件\n */\nexport default function useUpload(props: TdUploadProps): any {\n const inputRef = ref<HTMLInputElement>();\n // TODO: Form 表单控制上传组件是否禁用\n const { disabled, autoUpload, isBatchUpload, multiple, files, modelValue, defaultFiles } = toRefs(props);\n const { globalConfig, t, classPrefix } = useConfig('upload');\n const [uploadValue, setUploadValue] = useVModel(files, modelValue, defaultFiles.value, props.onChange, 'files');\n const xhrReq = ref<{ files: UploadFile[]; xhrReq: XMLHttpRequest }[]>([]);\n const toUploadFiles = ref<UploadFile[]>([]);\n const sizeOverLimitMessage = ref('');\n\n const locale = computed(() => merge({}, globalConfig.value, props.locale));\n\n const tipsClasses = `${classPrefix.value}-upload__tips ${classPrefix.value}-size-s`;\n const errorClasses = [tipsClasses].concat(`${classPrefix.value}-upload__tips-error`);\n const placeholderClass = `${classPrefix.value}-upload__placeholder`;\n\n // 单文件场景:触发元素文本\n const triggerUploadText = computed(() => {\n const field = getTriggerTextField({\n isBatchUpload: isBatchUpload.value,\n multiple: multiple.value,\n status: uploadValue.value?.[0]?.status,\n autoUpload: autoUpload.value,\n }) as keyof typeof locale.value.triggerUploadText;\n return locale.value.triggerUploadText[field];\n });\n\n const uploading = ref(false);\n\n // 文件列表显示的内容(自动上传和非自动上传有所不同)\n const displayFiles = computed(() => {\n return getDisplayFiles({\n multiple: props.multiple,\n toUploadFiles: toUploadFiles.value,\n uploadValue: uploadValue.value,\n autoUpload: autoUpload.value,\n isBatchUpload: isBatchUpload.value,\n });\n });\n\n const uploadFilePercent = (params: { file: UploadFile; percent: number }) => {\n const { file, percent } = params;\n const operationUploadFiles = autoUpload.value ? toUploadFiles : uploadValue;\n const index = operationUploadFiles.value.findIndex((item) => file.raw === item.raw);\n operationUploadFiles.value[index] = { ...operationUploadFiles.value[index], percent };\n };\n\n const updateFilesProgress = () => {\n if (props.autoUpload) {\n toUploadFiles.value = [...toUploadFiles.value];\n }\n };\n\n const onResponseError = (p: OnResponseErrorContext) => {\n if (!p || !p.files || !p.files[0]) return;\n const { response, event, files } = p;\n updateFilesProgress();\n props.onOneFileFail?.({\n e: event,\n file: files?.[0],\n currentFiles: files,\n failedFiles: files,\n response,\n });\n // 单选或多文件替换,需要清空上一次上传成功的文件\n if (!props.multiple || props.isBatchUpload) {\n setUploadValue([], {\n trigger: 'progress-fail',\n e: p.event,\n file: p.files[0],\n });\n }\n };\n\n // 多文件上传场景,单个文件进度\n const onResponseProgress = (p: InnerProgressContext) => {\n updateFilesProgress();\n props.onProgress?.({\n e: p.event,\n file: p.file,\n currentFiles: p.files,\n percent: p.percent,\n type: p.type,\n XMLHttpRequest: p.XMLHttpRequest,\n });\n };\n\n // 多文件上传场景,单个文件上传成功后\n const onResponseSuccess = (p: SuccessContext) => {\n // 只有多个上传请求同时触发时才需 onOneFileSuccess\n if (props.multiple && !props.uploadAllFilesInOneRequest) {\n updateFilesProgress();\n props.onOneFileSuccess?.({\n e: p.event,\n file: p.files[0],\n response: p.response,\n });\n }\n };\n\n function getSizeLimitError(sizeLimitObj: SizeLimitObj) {\n const limit = sizeLimitObj;\n return limit.message\n ? t(limit.message, { sizeLimit: limit.size })\n : `${t(locale.value.sizeLimitMessage, { sizeLimit: limit.size })} ${limit.unit}`;\n }\n\n const handleNotAutoUpload = (toFiles: UploadFile[]) => {\n const tmpFiles = props.multiple && !isBatchUpload.value ? uploadValue.value.concat(toFiles) : toFiles;\n if (!tmpFiles.length) return;\n setUploadValue(tmpFiles, {\n trigger: 'add',\n index: uploadValue.value.length,\n file: toFiles[0],\n files: toFiles,\n });\n toUploadFiles.value = [];\n };\n\n const onFileChange = (files: File[]) => {\n if (disabled.value) return;\n const params = { currentSelectedFiles: formatToUploadFile([...files], props.format) };\n props.onSelectChange?.([...files], params);\n validateFile({\n uploadValue: uploadValue.value,\n // @ts-ignore\n files: [...files],\n allowUploadDuplicateFile: props.allowUploadDuplicateFile,\n max: props.multiple ? props.max : 0,\n sizeLimit: props.sizeLimit,\n isBatchUpload: isBatchUpload.value,\n autoUpload: autoUpload.value,\n format: props.format,\n beforeUpload: props.beforeUpload,\n beforeAllFilesUpload: props.beforeAllFilesUpload,\n }).then((args) => {\n // 自定义全文件校验不通过\n if (args.validateResult?.type === 'BEFORE_ALL_FILES_UPLOAD') {\n const params: ValidateParams = { type: 'BEFORE_ALL_FILES_UPLOAD', files: args.files };\n props.onValidate?.(params);\n return;\n }\n // 文件数量校验不通过\n if (args.lengthOverLimit) {\n const params: ValidateParams = { type: 'FILES_OVER_LENGTH_LIMIT', files: args.files };\n props.onValidate?.(params);\n if (!args.files.length) return;\n }\n // 过滤相同的文件名\n if (args.hasSameNameFile) {\n const params: ValidateParams = { type: 'FILTER_FILE_SAME_NAME', files: args.files };\n props.onValidate?.(params);\n }\n // 文件大小校验结果处理(已过滤超出限制的文件)\n if (args.fileValidateList instanceof Array) {\n const { sizeLimitErrors, beforeUploadErrorFiles, toFiles } = getFilesAndErrors(\n args.fileValidateList,\n getSizeLimitError,\n );\n const tmpWaitingFiles = autoUpload.value ? toFiles : toUploadFiles.value.concat(toFiles);\n toUploadFiles.value = tmpWaitingFiles;\n props.onWaitingUploadFilesChange?.({ files: tmpWaitingFiles, trigger: 'validate' });\n // 文件大小处理\n if (sizeLimitErrors[0]) {\n sizeOverLimitMessage.value = sizeLimitErrors[0].file.response.error;\n props.onValidate?.({ type: 'FILE_OVER_SIZE_LIMIT', files: sizeLimitErrors.map((t) => t.file) });\n } else {\n sizeOverLimitMessage.value = '';\n // 自定义方法 beforeUpload 拦截的文件\n if (beforeUploadErrorFiles.length) {\n const params: ValidateParams = { type: 'CUSTOM_BEFORE_UPLOAD', files: beforeUploadErrorFiles };\n props.onValidate?.(params);\n }\n }\n // 如果是自动上传\n if (autoUpload.value) {\n uploadFiles(tmpWaitingFiles);\n } else {\n handleNotAutoUpload(tmpWaitingFiles);\n }\n }\n });\n\n // 清空 <input type=\"file\"> 元素的文件,避免出现重复文件无法选择的情况\n inputRef.value.value = null;\n };\n\n const onNormalFileChange = (e: InputEvent) => {\n const fileList = getFileList((e.target as HTMLInputElement).files);\n onFileChange?.(fileList);\n };\n\n function onDragFileChange(files: File[]) {\n onFileChange?.(files);\n }\n\n function onPasteFileChange(e: ClipboardEvent) {\n onFileChange?.([...e.clipboardData.files]);\n }\n\n /**\n * 上传文件。对外暴露方法,修改时需谨慎\n * @param toFiles 本地上传的文件列表\n */\n function uploadFiles(toFiles?: UploadFile[]) {\n const notUploadedFiles = uploadValue.value.filter((t) => t.status !== 'success');\n const files = autoUpload.value ? toFiles || toUploadFiles.value : notUploadedFiles;\n if (!files || !files.length) return;\n uploading.value = true;\n xhrReq.value = [];\n upload({\n action: props.action,\n headers: props.headers,\n method: props.method,\n name: props.name,\n withCredentials: props.withCredentials,\n uploadedFiles: uploadValue.value,\n toUploadFiles: files,\n multiple: props.multiple,\n isBatchUpload: isBatchUpload.value,\n autoUpload: props.autoUpload,\n uploadAllFilesInOneRequest: props.uploadAllFilesInOneRequest,\n useMockProgress: props.useMockProgress,\n data: props.data,\n mockProgressDuration: props.mockProgressDuration,\n requestMethod: props.requestMethod,\n formatRequest: props.formatRequest,\n formatResponse: props.formatResponse,\n onResponseProgress,\n onResponseSuccess,\n onResponseError,\n setXhrObject: (xhr) => {\n if (xhr.files[0]?.raw && xhrReq.value.find((item) => item.files[0]?.raw === xhr.files[0].raw)) return;\n xhrReq.value = xhrReq.value.concat(xhr);\n },\n }).then(\n // 多文件场景时,全量文件完成后\n ({ status, data, list, failedFiles }) => {\n uploading.value = false;\n if (status === 'success') {\n setUploadValue([...data.files], {\n trigger: 'add',\n file: data.files[0],\n });\n xhrReq.value = [];\n props.onSuccess?.({\n fileList: data.files,\n currentFiles: files,\n file: files[0],\n // 只有全部请求完成后,才会存在该字段\n results: list?.map((t) => t.data),\n // 单文件单请求有一个 response,多文件多请求有多个 response\n response: data.response || list.map((t) => t.data.response),\n XMLHttpRequest: data.XMLHttpRequest,\n });\n } else if (failedFiles?.[0]) {\n props.onFail?.({\n e: data.event,\n file: failedFiles[0],\n failedFiles,\n currentFiles: files,\n response: data.response,\n XMLHttpRequest: data.XMLHttpRequest,\n });\n }\n\n // 非自动上传,文件都在 uploadValue,不涉及 toUploadFiles\n if (autoUpload.value) {\n toUploadFiles.value = failedFiles;\n props.onWaitingUploadFilesChange?.({ files: failedFiles, trigger: 'uploaded' });\n }\n },\n );\n }\n\n function onInnerRemove(p: UploadRemoveContext) {\n sizeOverLimitMessage.value = '';\n p.e.stopPropagation?.();\n const changePrams: UploadChangeContext = {\n e: p.e,\n trigger: 'remove',\n index: p.index,\n file: p.file,\n };\n // remove all files for batchUpload\n if (props.isBatchUpload || !props.multiple) {\n toUploadFiles.value = [];\n props.onWaitingUploadFilesChange?.({ files: [], trigger: 'remove' });\n setUploadValue([], changePrams);\n } else if (!props.autoUpload) {\n uploadValue.value.splice(p.index, 1);\n setUploadValue([...uploadValue.value], changePrams);\n } else {\n // autoUpload 场景下, p.index < uploadValue.length 表示移除已经上传成功的文件;反之表示移除待上传列表文件\n // eslint-disable-next-line\n if (p.index < uploadValue.value.length) {\n uploadValue.value.splice(p.index, 1);\n setUploadValue([...uploadValue.value], changePrams);\n } else {\n toUploadFiles.value.splice(p.index - uploadValue.value.length, 1);\n toUploadFiles.value = [...toUploadFiles.value];\n props.onWaitingUploadFilesChange?.({ files: [...toUploadFiles.value], trigger: 'remove' });\n }\n }\n props.onRemove?.(p);\n }\n\n const triggerUpload = (e?: MouseEvent) => {\n if (disabled.value || !inputRef.value) return;\n e?.stopPropagation?.();\n (inputRef.value as HTMLInputElement).click();\n };\n\n const cancelUpload = (context?: { file?: UploadFile; e?: MouseEvent }) => {\n xhrReq.value?.forEach((item) => {\n item.xhrReq?.abort();\n });\n uploading.value = false;\n\n // autoUpload do not need to reset to waiting state\n if (autoUpload.value) {\n toUploadFiles.value = [];\n } else {\n setUploadValue(\n uploadValue.value.map((item) => {\n if (item.status !== 'success') {\n return { ...item, status: 'waiting' };\n }\n return item;\n }),\n { trigger: 'abort' },\n );\n }\n\n if (context?.file && !autoUpload.value) {\n onInnerRemove?.({ file: context.file, e: context.e, index: 0 });\n }\n\n props.onCancelUpload?.();\n };\n\n return {\n t,\n locale,\n classPrefix,\n triggerUploadText,\n toUploadFiles,\n uploadValue,\n displayFiles,\n sizeOverLimitMessage,\n uploading,\n tipsClasses,\n errorClasses,\n placeholderClass,\n inputRef,\n disabled,\n xhrReq,\n uploadFilePercent,\n uploadFiles,\n onFileChange,\n onNormalFileChange,\n onDragFileChange,\n onPasteFileChange,\n onInnerRemove,\n triggerUpload,\n cancelUpload,\n };\n}\n"],"names":["xhr","_ref","_files$","_ref$method","method","action","_ref$withCredentials","withCredentials","_ref$headers","headers","_ref$data","data","file","_ref$files","files","_ref$name","name","_ref$useMockProgress","useMockProgress","_ref$mockProgressDura","mockProgressDuration","formatRequest","onError","onProgress","onSuccess","innerFiles","percent","XMLHttpRequest","timer1","timer2","status","setTimeout","setInterval","Math","max","map","type","clearInterval","clearTimeout","requestData","extraData","isFunction","Object","assign","forEach","index","fileField","length","concat","raw","formData","FormData","keys","key","dataValue","Array","isArray","value","append","open","setRequestHeader","onerror","event","ontimeout","upload","onprogress","_innerFiles$","realPercent","total","round","loaded","progressFiles","item","onload","response","isFail","text","responseText","JSON","parse","e","log","error","_response","uploadTime","getCurrentDate","_typeof","_toConsumableArray","send","requestParams","requestHeaders","handleBeforeUpload","params","sizeLimit","beforeUpload","sizePromise","Promise","resolve","result","sizeLimitObj","isNumber","size","unit","limit","isOverSizeLimit","promiseList","r","p","all","then","handleError","options","formatResponse","res","currentFiles","handleSuccess","_file$response","url","handleRequestMethodResponse","includes","warn","uploadOneRequest","toUploadFiles","requestMethod","multiple","resultFiles","fileInfo","find","toFile","_objectSpread","_params$onResponseSuc","onResponseSuccess","call","_params$onResponseErr","onResponseError","_params$setXhrObject","xhrReq","_params$onResponseErr2","onResponseProgress","_params$onResponseErr3","_params$onResponseSuc2","setXhrObject","updateUploadedFiles","uploadFiles","existFiles","filter","t","newFiles","_loop","i","findIndex","tmpFile","push","len","uploadAllFilesInOneRequest","uploadedFiles","isBatchUpload","thisUploadFiles","failedFiles","list","arr","one","tFiles","autoUpload","formatToUploadFile","format","arguments","undefined","fileRaw","uploadFile","lastModified","validateFile","uploadValue","allowUploadDuplicateFile","_params$capture","capture","tmpFiles","sameNameFile","hasSameNameFile","validateResult","lengthOverLimit","tmpFilesLenToBeAdded","slice","formattedFiles","allFileValidatePromise","beforeAllFilesUpload","_params$beforeAllFile","_ref2","_slicedToArray","sizeResult","customResult","extra","results","_results","_toArray","allFilesResult","others","fileValidateList","getFilesAndErrors","getError","sizeLimitErrors","beforeUploadErrorFiles","toFiles","oneFile","_oneFile$validateResu","_oneFile$validateResu2","getTriggerTextField","getDisplayFiles","waitingUploadFiles","useUpload","props","inputRef","ref","_toRefs","toRefs","disabled","modelValue","defaultFiles","_useConfig","useConfig","globalConfig","classPrefix","_useVModel","useVModel","onChange","_useVModel2","setUploadValue","sizeOverLimitMessage","locale","computed","merge","tipsClasses","errorClasses","placeholderClass","triggerUploadText","_uploadValue$value","field","uploading","displayFiles","uploadFilePercent","operationUploadFiles","updateFilesProgress","_props$onOneFileFail","onOneFileFail","trigger","_props$onProgress","_props$onOneFileSucce","onOneFileSuccess","getSizeLimitError","message","sizeLimitMessage","handleNotAutoUpload","onFileChange","_props$onSelectChange","currentSelectedFiles","onSelectChange","args","_args$validateResult","_props$onValidate","onValidate","_props$onValidate2","_props$onValidate3","_props$onWaitingUploa","_getFilesAndErrors","tmpWaitingFiles","onWaitingUploadFilesChange","_props$onValidate4","_props$onValidate5","onNormalFileChange","fileList","getFileList","target","onDragFileChange","onPasteFileChange","clipboardData","notUploadedFiles","_xhr$files$","_item$files$","_props$onSuccess","_props$onFail","onFail","_props$onWaitingUploa2","onInnerRemove","_p$e$stopPropagation","_p$e","_props$onRemove","stopPropagation","changePrams","_props$onWaitingUploa3","splice","_props$onWaitingUploa4","onRemove","triggerUpload","_e$stopPropagation","click","cancelUpload","context","_xhrReq$value","_props$onCancelUpload","_item$xhrReq","abort","onCancelUpload"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMA,SAAwBA,GAAIA,CAAAC,IAAA,EAeb;AAAA,EAAA,IAAAC,OAAA,CAAA;AAAA,EAAA,IAAAC,WAAA,GAAAF,IAAA,CAdbG,MAAS;AAATA,IAAAA,MAAS,GAAAD,WAAA,KAAA,KAAA,CAAA,GAAA,MAAA,GAAAA,WAAA;IACTE,MAAA,GAAAJ,IAAA,CAAAI,MAAA;IAAAC,oBAAA,GAAAL,IAAA,CACAM,eAAkB;AAAlBA,IAAAA,eAAkB,GAAAD,oBAAA,KAAA,KAAA,CAAA,GAAA,KAAA,GAAAA,oBAAA;IAAAE,YAAA,GAAAP,IAAA,CAClBQ;AAAAA,IAAAA,oCAAU,EAAC,GAAAD,YAAA;IAAAE,SAAA,GAAAT,IAAA,CACXU;AAAAA,IAAAA,8BAAO,EAAC,GAAAD,SAAA;IACRE,IAAA,GAAAX,IAAA,CAAAW,IAAA;IAAAC,UAAA,GAAAZ,IAAA,CACAa;AAAAA,IAAAA,uBAAQ,KAAA,CAAA,GAAA,EAAC,GAAAD,UAAA;IAAAE,SAAA,GAAAd,IAAA,CACTe,IAAO;AAAPA,IAAAA,IAAO,GAAAD,SAAA,KAAA,KAAA,CAAA,GAAA,MAAA,GAAAA,SAAA;IAAAE,oBAAA,GAAAhB,IAAA,CACPiB,eAAkB;AAAlBA,IAAAA,eAAkB,GAAAD,oBAAA,KAAA,KAAA,CAAA,GAAA,IAAA,GAAAA,oBAAA;IAAAE,qBAAA,GAAAlB,IAAA,CAClBmB,oBAAuB;AAAvBA,IAAAA,oBAAuB,GAAAD,qBAAA,KAAA,KAAA,CAAA,GAAA,GAAA,GAAAA,qBAAA;IACvBE,aAAA,GAAApB,IAAA,CAAAoB,aAAA;IACAC,OAAA,GAAArB,IAAA,CAAAqB,OAAA;IACAC,UAAA,GAAAtB,IAAA,CAAAsB,UAAA;IACAC,SAAA,GAAAvB,IAAA,CAAAuB,SAAA,CAAA;AAGM,EAAA,IAAAC,UAAA,GAA2BX,SAAS,EAAC,CAAA;EAC3C,IAAIY,OAAU,GAAA,CAAA,CAAA;AAGR1B,EAAAA,IAAAA,IAAAA,GAAM,IAAI2B,cAAe,EAAA,CAAA;AAC/B,EAAA,IAAIpB,eAAiB,EAAA;IACnBP,KAAIO,eAAkB,GAAA,IAAA,CAAA;AACxB,GAAA;AAEI,EAAA,IAAAqB,MAAA,CAAA;AACA,EAAA,IAAAC,MAAA,CAAA;AACJ,EAAA,IAAIX,eAAmB,IAAA,CAAA,CAAAhB,OAAA,GAAAY,KAAA,CAAM,CAAI,CAAA,MAAA,IAAA,IAAAZ,OAAA,KAAVA,KAAAA,CAAAA,GAAAA,KAAAA,CAAAA,GAAAA,OAAA,CAAU4B,MAAA,MAAW,UAAY,EAAA;AAEhDD,IAAAA,IAAAA,OAAAA,GAASE,WAAW,YAAM;MAE9BH,MAAA,GAASI,YAAY,YAAM;AACrB,QAAA,IAAAN,OAAA,GAAU,KAAK,GAAK,EAAA;UACtBA,OAAA,GAAUO,IAAK,CAAAC,GAAA,CAAIR,OAAU,GAAA,EAAA,EAAIA,OAAO,CAAA,CAAA;AACxC,UAAA,IAAIZ,KAAM,CAAA,CAAA,CAAA,IAAMY,OAAY,KAAAZ,KAAA,CAAM,GAAGY,OAAS,EAAA;AAC5CZ,YAAAA,KAAA,CAAM,GAAGY,OAAU,GAAAA,OAAA,CAAA;AACRH,YAAAA,UAAA,CAAA;AACTG,cAAAA,OAAA,EAAAA,OAAA;AACAd,cAAAA,IAAA,EAAMA,QAAQa,UAAW,CAAA,CAAA,CAAA;AACzBX,cAAAA,KAAA,EAAOW,WAAWU,GAAI,CAAA,UAACvB;2DAAeA,KAAM,CAAA,EAAA,EAAA,EAAA;AAAAc,kBAAAA,OAAA,EAAAA,OAAAA;AAAA,iBAAA,CAAA,CAAA;AAAA,eAAU,CAAA;AACtDU,cAAAA,IAAM,EAAA,MAAA;AACNT,cAAAA,cAAgB3B,EAAAA,IAAAA;AAClB,aAAC,CAAA,CAAA;AACH,WAAA;AACF,SAAO,MAAA;UACLqC,aAAA,CAAcT,MAAM,CAAA,CAAA;AACtB,SAAA;SACCR,oBAAoB,CAAA,CAAA;MACvBkB,YAAA,CAAaT,OAAM,CAAA,CAAA;OAClBT,oBAAoB,CAAA,CAAA;AACzB,GAAA;EAEA,IAAImB,cAAsC,EAAC,CAAA;AAC3C,EAAA,IAAI5B,IAAM,EAAA;AACR,IAAA,IAAM6B,YAAYC,UAAW,CAAA9B,IAAI,CAAI,GAAAA,IAAA,CAAKc,UAAU,CAAI,GAAAd,IAAA,CAAA;AACjD+B,IAAAA,MAAA,CAAAC,MAAA,CAAOJ,aAAaC,SAAS,CAAA,CAAA;AACtC,GAAA;AACWf,EAAAA,UAAA,CAAAmB,OAAA,CAAQ,UAAChC,KAAAA,EAAMiC,KAAU,EAAA;AAClC,IAAA,IAAMC,YAAYrB,UAAW,CAAAsB,MAAA,GAAS,CAAI,GAAA,EAAA,CAAAC,MAAA,CAAGhC,kBAAQ6B,KAAW,SAAA7B,IAAA,CAAA;AAChEuB,IAAAA,WAAA,CAAYO,aAAalC,KAAK,CAAAqC,GAAA,CAAA;AAChC,GAAC,CAAA,CAAA;AACG,EAAA,IAAAxB,UAAA,CAAWsB,WAAW,CAAG,EAAA;IACfR,WAAA,CAAAvB,IAAA,CAAA,GAAQS,WAAW,CAAG,CAAA,CAAAwB,GAAA,CAAA;AACpC,GAAO,MAAA;IACLV,WAAA,CAAYvB,QAAQS,UAAW,CAAAU,GAAA,CAAI,UAACvB,KAAAA,EAAAA;MAAAA,OAASA,MAAKqC,GAAG,CAAA;KAAA,CAAA,CAAA;AACvD,GAAA;AACAV,EAAAA,WAAA,CAAYQ,SAAStB,UAAW,CAAAsB,MAAA,CAAA;AAEhC,EAAA,IAAI1B,aAAe,EAAA;AACjBkB,IAAAA,WAAA,GAAclB,cAAckB,WAAW,CAAA,CAAA;AACzC,GAAA;AAGM,EAAA,IAAAW,QAAA,GAAW,IAAIC,QAAS,EAAA,CAAA;EAC9BT,MAAA,CAAOU,IAAK,CAAAb,WAAW,CAAE,CAAAK,OAAA,CAAQ,UAACS,GAAQ,EAAA;AACxC,IAAA,IAAMC,YAAYf,WAAY,CAAAc,GAAA,CAAA,CAAA;AAC1B,IAAA,IAAAE,KAAA,CAAMC,OAAQ,CAAAF,SAAS,CAAG,EAAA;AAClBA,MAAAA,SAAA,CAAAV,OAAA,CAAQ,UAACa,KAAU,EAAA;AAClBP,QAAAA,QAAA,CAAAQ,MAAA,CAAOL,KAAKI,KAAK,CAAA,CAAA;AAC5B,OAAC,CAAA,CAAA;AACH,KAAO,MAAA;AACIP,MAAAA,QAAA,CAAAQ,MAAA,CAAOL,KAAKC,SAAS,CAAA,CAAA;AAChC,KAAA;AACF,GAAC,CAAA,CAAA;EAEDtD,IAAI,CAAA2D,IAAA,CAAKvD,MAAQ,EAAAC,MAAA,EAAQ,IAAI,CAAA,CAAA;EAE7BqC,MAAA,CAAOU,IAAK,CAAA3C,OAAO,CAAE,CAAAmC,OAAA,CAAQ,UAACS,GAAQ,EAAA;IACpCrD,IAAI,CAAA4D,gBAAA,CAAiBP,GAAK,EAAA5C,OAAA,CAAQ4C,GAAI,CAAA,CAAA,CAAA;AACxC,GAAC,CAAA,CAAA;AAEDrD,EAAAA,IAAAA,CAAI6D,OAAU,GAAA,UAACC,KAAyB,EAAA;AACtCxC,IAAAA,OAAA,CAAQ;AAAEwC,MAAAA,KAAO,EAAPA,KAAO;AAAAlD,MAAAA,IAAA,EAAAA,IAAA;AAAME,MAAAA,OAAOW,UAAY;AAAAE,MAAAA,cAAA,EAAgB3B,IAAAA;AAAI,KAAC,CAAA,CAAA;IAC/DqC,aAAA,CAAcT,MAAM,CAAA,CAAA;IACpBU,YAAA,CAAaT,MAAM,CAAA,CAAA;GACrB,CAAA;AAEA7B,EAAAA,IAAAA,CAAI+D,SAAY,GAAA,UAACD,KAAU,EAAA;AACzBxC,IAAAA,OAAA,CAAQ;AAAEwC,MAAAA,KAAO,EAAPA,KAAO;AAAAlD,MAAAA,IAAA,EAAAA,IAAA;AAAME,MAAAA,OAAOW,UAAY;AAAAE,MAAAA,cAAA,EAAgB3B,IAAAA;AAAI,KAAC,CAAA,CAAA;GACjE,CAAA;EAEA,IAAIA,KAAIgE,MAAQ,EAAA;AACdhE,IAAAA,IAAI,CAAAgE,MAAA,CAAOC,UAAa,GAAA,UAACH,KAAyB,EAAA;AAAA,MAAA,IAAAI,YAAA,CAAA;MAChD,IAAIC,WAAc,GAAA,CAAA,CAAA;AACd,MAAA,IAAAL,KAAA,CAAMM,QAAQ,CAAG,EAAA;AACnBD,QAAAA,WAAA,GAAclC,KAAKoC,KAAO,CAAAP,KAAA,CAAMQ,MAAS,GAAAR,KAAA,CAAMM,QAAS,GAAG,CAAA,CAAA;AAC7D,OAAA;MACU1C,OAAA,GAAAO,IAAA,CAAKC,GAAI,CAAAiC,WAAA,EAAazC,OAAO,CAAA,CAAA;AACvC,MAAA,IAAIA,OAAY,KAAAyC,WAAA,IAAe,CAAAD,CAAAA,YAAA,GAAAzC,UAAW,CAAA,CAAA,CAAA,MAAA,IAAA,IAAAyC,YAAA,KAAXA,KAAAA,CAAAA,GAAAA,KAAAA,CAAAA,GAAAA,YAAA,CAAexC,aAAYA,OAAS,EAAA;AAC3D,QAAA,IAAA6C,aAAA,GAAgB9C,WAAWU,GAAI,CAAA,UAACqC;qDAAeA,IAAM,CAAA,EAAA,EAAA,EAAA;AAAA9C,YAAAA,OAAA,EAAAA,OAAAA;AAAA,WAAA,CAAA,CAAA;AAAA,SAAU,CAAA,CAAA;AAC1DH,QAAAA,UAAA,CAAA;AACTuC,UAAAA,KAAA,EAAAA,KAAA;AACApC,UAAAA,OAAA,EAAAA,OAAA;AACAd,UAAAA,IAAA,EAAMA,QAAQ2D,aAAc,CAAA,CAAA,CAAA;AAC5BzD,UAAAA,KAAO,EAAAyD,aAAA;AACPnC,UAAAA,IAAM,EAAA,MAAA;AACNT,UAAAA,cAAgB3B,EAAAA,IAAAA;AAClB,SAAC,CAAA,CAAA;AACH,OAAA;KACF,CAAA;AACF,GAAA;AAGAA,EAAAA,IAAAA,CAAIyE,MAAS,GAAA,UAACX,KAAyB,EAAA;IACrC,IAAIY,WAAmC,EAAC,CAAA;IACxCA,QAAA,CAAS/C,cAAiB3B,GAAAA,IAAAA,CAAAA;AAC1B,IAAA,IAAM2E,MAAS3E,GAAAA,IAAAA,CAAI8B,MAAS,GAAA,GAAA,IAAO9B,KAAI8B,MAAU,IAAA,GAAA,CAAA;AACjD,IAAA,IAAI6C,MAAQ,EAAA;AACV,MAAA,OAAOrD,OAAQ,CAAA;AACbwC,QAAAA,KAAA,EAAAA,KAAA;AACAlD,QAAAA,IAAA,EAAAA,IAAA;AACAE,QAAAA,KAAO,EAAAW,UAAA;AACPiD,QAAAA,QAAA,EAAAA,QAAA;AACA/C,QAAAA,cAAgB3B,EAAAA,IAAAA;AAClB,OAAC,CAAA,CAAA;AACH,KAAA;IACM,IAAA4E,IAAA,GAAO5E,IAAI,CAAA6E,YAAA,IAAgB7E,IAAI,CAAA0E,QAAA,CAAA;IACjC,IAAA;AACSA,MAAAA,QAAA,GAAAI,IAAA,CAAKC,MAAMH,IAAI,CAAA,CAAA;aACnBI,CAAP,EAAA;AACWN,MAAAA,QAAA,GAAAE,IAAA,CAAA;AACPK,MAAAA,GAAA,CAAAC,KAAA,CAAM,UAAU,gCAAgC,CAAA,CAAA;AACtD,KAAA;IACA7C,aAAA,CAAcT,MAAM,CAAA,CAAA;IACpBU,YAAA,CAAaT,MAAM,CAAA,CAAA;AACRJ,IAAAA,UAAA,CAAAmB,OAAA,CAAQ,UAAChC,KAAS,EAAA;AAAA,MAAA,IAAAuE,SAAA,CAAA;MAC3BvE,MAAKc,OAAU,GAAA,GAAA,CAAA;MACfd,MAAKkB,MAAS,GAAA,SAAA,CAAA;AAEdlB,MAAAA,KAAK,CAAAwE,UAAA,GAAa,CAAAD,CAAAA,SAAA,GAAAT,QAAU,MAAA,IAAA,IAAAS,SAAA,KAAA,KAAA,CAAA,GAAA,KAAA,CAAA,GAAVA,SAAA,CAAUC,UAAA,KAAcC,cAAe,EAAA,CAAA;AAC3D,KAAC,CAAA,CAAA;AACG,IAAA,IAAAC,OAAA,CAAOZ,cAAa,QAAU,EAAA;MAChCA,QAAA,CAAS/C,cAAiB3B,GAAAA,IAAAA,CAAAA;AAC5B,KAAA;AACUwB,IAAAA,SAAA,CAAA;AACRsC,MAAAA,KAAA,EAAAA,KAAA;AACAlD,MAAAA,IAAA,EAAMA,QAAQa,UAAW,CAAA,CAAA,CAAA;AACzBX,MAAAA,KAAA,EAAAyE,kBAAA,CAAW9D,UAAU,CAAA;AACrBE,MAAAA,cAAgB3B,EAAAA,IAAAA;AAChB0E,MAAAA,QAAA,EAAAA,QAAAA;AACF,KAAC,CAAA,CAAA;GACH,CAAA;AAEA1E,EAAAA,IAAAA,CAAIwF,KAAKtC,QAAQ,CAAA,CAAA;AAEjBlD,EAAAA,IAAAA,CAAIgE,OAAOyB,aAAgB,GAAAlD,WAAA,CAAA;AAE3BvC,EAAAA,IAAAA,CAAIgE,OAAO0B,cAAiB,GAAAjF,OAAA,CAAA;AAErBT,EAAAA,OAAAA,IAAAA,CAAAA;AACT;;;;ACrJgB,SAAA2F,kBAAAA,CAAmB/E,MAAkBgF,MAA6D,EAAA;AAC1G,EAAA,IAAEC,SAAW,GAAiBD,MAAA,CAA5BC,SAAW;IAAAC,YAAA,GAAiBF,MAAA,CAAjBE,YAAA,CAAA;AAEnB,EAAA,IAAMC,WAAc,GAAA,IAAIC,OAAsB,CAAA,UAACC,OAAY,EAAA;IACzD,IAAIC,MAAuB,GAAA,IAAA,CAAA;AAC3B,IAAA,IAAIL,SAAW,EAAA;AACP,MAAA,IAAAM,YAAA,GAA6BC,SAASP,SAAS,CAAA,GAAI;AAAEQ,QAAAA,IAAM,EAAAR,SAAA;AAAWS,QAAAA,IAAM,EAAA,IAAA;AAAK,OAAI,GAAAT,SAAA,CAAA;AAC3F,MAAA,IAAMU,QAAQC,eAAgB,CAAA5F,IAAA,CAAKyF,MAAMF,YAAa,CAAAE,IAAA,EAAMF,aAAaG,IAAI,CAAA,CAAA;AAC7E,MAAA,IAAIC,KAAO,EAAA;AACAL,QAAAA,MAAA,GAAAC,YAAA,CAAA;AACX,OAAA;AACF,KAAA;IACAF,OAAA,CAAQC,MAAM,CAAA,CAAA;AAChB,GAAC,CAAA,CAAA;AAGK,EAAA,IAAAO,WAAA,GAAuC,CAACV,WAAA,EAAa,KAAS,CAAA,CAAA,CAAA;AAChE,EAAA,IAAAtD,UAAA,CAAWqD,YAAY,CAAG,EAAA;AACtB,IAAA,IAAAY,CAAA,GAAIZ,aAAalF,IAAI,CAAA,CAAA;AAC3B,IAAA,IAAM+F,IACJD,CAAa,YAAAV,OAAA,GACTU,IACA,IAAIV,OAAA,CAAiB,UAACC,OAAY,EAAA;MAChCA,OAAA,CAAQS,CAAC,CAAA,CAAA;AACX,KAAC,CAAA,CAAA;AACPD,IAAAA,WAAA,CAAY,CAAK,CAAA,GAAAE,CAAA,CAAA;AACnB,GAAA;AAGO,EAAA,OAAA,IAAIX,OAAQ,CAAA,UAACC,OAAY,EAAA;IAC9BD,OAAA,CAAQY,GAAI,CAAAH,WAAW,CAAE,CAAAI,IAAA,CAAK,UAACH,CAAM,EAAA;MACnCT,OAAA,CAAQS,CAAC,CAAA,CAAA;AACX,KAAC,CAAA,CAAA;AACH,GAAC,CAAA,CAAA;AACH,CAAA;AAMO,SAASI,YAAYC,OAAwB,EAAA;AAClD,EAAA,IAAQjD,KAAO,GAAoDiD,OAAA,CAA3DjD,KAAO;IAAAhD,KAAA,GAAoDiG,OAAA,CAApDjG,KAAA;IAAO4D,QAAU,GAAmCqC,OAAA,CAA7CrC,QAAU;IAAA/C,cAAA,GAAmCoF,OAAA,CAAnCpF,cAAA;IAAgBqF,iBAAmBD,OAAA,CAAnBC;EAChD,IAAIC,GAAM,GAAAvC,QAAA,CAAA;AACN,EAAA,IAAAjC,UAAA,CAAWuE,cAAc,CAAG,EAAA;AACxBC,IAAAA,GAAA,GAAAD,cAAA,CAAetC,UAAU;AAAE9D,MAAAA,IAAA,EAAME,MAAM,CAAI,CAAA;AAAAoG,MAAAA,YAAA,EAAcpG,KAAAA;AAAM,KAAC,CAAA,CAAA;AACxE,GAAA;AACMA,EAAAA,KAAA,CAAA8B,OAAA,CAAQ,UAAChC,IAAS,EAAA;IACtBA,IAAA,CAAKkB,MAAS,GAAA,MAAA,CAAA;IACdlB,IAAA,CAAK8D,QAAW,GAAAuC,GAAA,CAAA;AAClB,GAAC,CAAA,CAAA;EACD,OAAO;AAAEvC,IAAAA,QAAA,EAAUuC,GAAK;AAAAnD,IAAAA,KAAA,EAAAA,KAAA;AAAOhD,IAAAA,OAAAA;AAAOa,IAAAA,cAAe,EAAfA,cAAAA;GAAe,CAAA;AACvD,CAAA;AAEO,SAASwF,cAAcvB,MAA6B,EAAA;AACzD,EAAA,IAAQ9B,KAAA,GAA2C8B,MAAA,CAA3C9B,KAAA;IAAOhD,KAAO,GAA6B8E,MAAA,CAApC9E,KAAO;IAAA4D,QAAA,GAA6BkB,MAAA,CAA7BlB,QAAA;IAAU/C,iBAAmBiE,MAAA,CAAnBjE;EAC5B,IAAA,CAAAb,KAAA,KAAA,IAAA,IAAAA,KAAA,KAAA,KAAA,CAAA,GAAA,KAAA,CAAA,GAAAA,KAAA,CAAOiC,WAAU,CAAG,EAAA;AAClBkC,IAAAA,GAAA,CAAAC,KAAA,CAAM,UAAU,gCAAgC,CAAA,CAAA;AACtD,GAAA;AACMpE,EAAAA,KAAA,CAAA8B,OAAA,CAAQ,UAAChC,IAAS,EAAA;AAAA,IAAA,IAAAwG,cAAA,CAAA;IACtBxG,IAAA,CAAKc,OAAU,GAAA,GAAA,CAAA;IACfd,IAAA,CAAKkB,MAAS,GAAA,SAAA,CAAA;IACd,CAAAsF,cAAA,GAAOxG,KAAK8D,QAAU,MAAA0C,IAAAA,IAAAA,cAAA,KAAtB,KAAA,CAAA,IAAA,OAAOA,cAAA,CAAelC,KAAA,CAAA;AACxB,GAAC,CAAA,CAAA;EACD,IAAM+B,GAAM,GAAAvC,QAAA,CAAA;AACZ5D,EAAAA,KAAA,CAAM,CAAG,CAAA,CAAAuG,GAAA,GAAMJ,GAAI,CAAAI,GAAA,IAAOvG,MAAM,CAAG,CAAA,CAAAuG,GAAA,CAAA;EACnC,OAAO;AAAE3C,IAAAA,QAAA,EAAUuC,GAAK;AAAAnD,IAAAA,KAAA,EAAAA,KAAA;AAAOhD,IAAAA,OAAAA;AAAOa,IAAAA,cAAe,EAAfA,cAAAA;GAAe,CAAA;AACvD,CAAA;AAWO,SAAS2F,4BAA4BL,GAA4B,EAAA;EACtE,IAAI,CAACA,GAAK,EAAA;AACJhC,IAAAA,GAAA,CAAAC,KAAA,CAAM,UAAU,sCAAsC,CAAA,CAAA;AACnD,IAAA,OAAA,KAAA,CAAA;AACT,GAAA;AACI,EAAA,IAAA,CAAC+B,IAAInF,MAAQ,EAAA;AACXmD,IAAAA,GAAA,CAAAC,KAAA,CAAM,UAAU,wFAAwF,CAAA,CAAA;AACrG,IAAA,OAAA,KAAA,CAAA;AACT,GAAA;AACI,EAAA,IAAA,CAAC,CAAC,SAAW,EAAA,MAAM,EAAEqC,QAAS,CAAAN,GAAA,CAAInF,MAAM,CAAG,EAAA;AACzCmD,IAAAA,GAAA,CAAAC,KAAA,CACF,QAAA,EACA,qHACF,CAAA,CAAA;AACO,IAAA,OAAA,KAAA,CAAA;AACT,GAAA;EACA,IAAI+B,GAAI,CAAAnF,MAAA,KAAW,SAAc,KAAA,CAACmF,GAAI,CAAAvC,QAAA,IAAa,CAACuC,GAAA,CAAIvC,QAAS,CAAA2C,GAAA,IAAO,CAACJ,GAAA,CAAIvC,SAAS5D,KAAS,CAAA,EAAA;AACzFmE,IAAAA,GAAA,CAAAuC,IAAA,CACF,QAAA,EACA,qHACF,CAAA,CAAA;AACF,GAAA;AACO,EAAA,OAAA,IAAA,CAAA;AACT,CAAA;AAKO,SAASC,iBAAiB7B,MAA0D,EAAA;AACzF,EAAA,IAAQvF,MAAA,GAAyCuF,MAAA,CAAzCvF,MAAA;IAAQqH,aAAe,GAAkB9B,MAAA,CAAjC8B,aAAe;IAAAC,aAAA,GAAkB/B,MAAA,CAAlB+B,aAAA,CAAA;AACxB,EAAA,OAAA,IAAI3B,OAA6B,CAAA,UAACC,OAAY,EAAA;AAC/C,IAAA,IAAA,CAAC5F,MAAU,IAAA,CAACsH,aAAe,EAAA;AACzB1C,MAAAA,GAAA,CAAAC,KAAA,CAAM,UAAU,gDAAgD,CAAA,CAAA;MACpEe,OAAA,CAAQ,EAAE,CAAA,CAAA;AACV,MAAA,OAAA;AACF,KAAA;AACA,IAAA,IAAI,CAACyB,aAAA,IAAiB,CAACA,aAAA,CAAc3E,MAAQ,EAAA;AACvCkC,MAAAA,GAAA,CAAAuC,IAAA,CAAK,UAAU,8BAA8B,CAAA,CAAA;MACjDvB,OAAA,CAAQ,EAAE,CAAA,CAAA;AACV,MAAA,OAAA;AACF,KAAA;AACcyB,IAAAA,aAAA,CAAA9E,OAAA,CAAQ,UAAChC,IAAS,EAAA;MAC9BA,IAAA,CAAKkB,MAAS,GAAA,UAAA,CAAA;AAChB,KAAC,CAAA,CAAA;AAED,IAAA,IAAI6F,aAAe,EAAA;AACHA,MAAAA,aAAA,CAAA/B,MAAA,CAAOgC,WAAWF,aAAgB,GAAAA,aAAA,CAAc