/** * 文件上传处理函数 */ import { computed, ref, watch } from 'vue' import { useCipConfig } from '../../../hooks/use-cip-config' import CipMessage from '../../../cip-message' import { useFormInput } from '../../../hooks/form-input' import { isString } from '@cip/utils/util' import { useFormInject } from '../../../hooks/use-form' export const fileTypeList = ['png', 'jpg', 'jpeg', 'jpe', 'gif', 'doc', 'docx', 'ppt', 'pptx', 'pdf', 'xls', 'xlsx', 'zip', '7z', 'rar'] export const uploadProps = (props, context) => { const { proxyValue, securityConfig } = useFormInput(props, context) const cipForm = useFormInject() const cipConfig = useCipConfig() const useStringValue = computed(() => { return securityConfig.value.stringValue }) const objectValue = computed(() => { // 返回的数据是一个对象 return securityConfig.value.objectValue }) const uploadFileFn = computed(() => { // BROKEN: 默认的文件上传方法由cip-config-porvide提供 return securityConfig.value.uploadFn || cipConfig.fileUpload }) const fileSplitKey = computed(() => { return securityConfig.value.splitKey ?? ',' }) const fileList = ref([]) watch(() => props.modelValue, () => { if (props.modelValue) { if (!useStringValue.value) { // 兼容未配置stringValue但存储结果为string的modelValue if (isString(props.modelValue)) { fileList.value = props.modelValue.split(fileSplitKey.value).map(v => ({ url: v })) } else if (objectValue.value) { fileList.value = [props.modelValue] } else { fileList.value = props.modelValue } } else { fileList.value = props.modelValue.split(fileSplitKey.value).map(v => ({ url: v })) } } else { fileList.value = [] } }, { immediate: true }) // 文件上传 const uploadFile = (info) => { let file = info.file const uid = info.file.uid if (securityConfig.value.getFileName) { // 重新命名文件 file = new window.File([file], securityConfig.value.getFileName(file.name, props.dependOnValues, securityConfig.value)) } // 保持uid file.uid = uid const fileObject = { name: file.name, uid: file.uid, percentage: 0, status: 'ready' } const fileXhr = uploadFileFn.value({ file: file, dependOnValues: props.dependOnValues, config: { // 挂载监听钩子 onUploadProgress: progress => { fileUploadProgress(info, { total: progress.total, loaded: progress.loaded, percentage: Math.floor(progress.loaded / progress.total * 100) }) } } }) fileObject.abort = fileXhr.abort fileList.value.push(fileObject) // 限制表单提交 cipForm.uploadQueue[uid] = true fileXhr.send().then((res) => { fileUploadProgress(info, { [props.config.urlKey || 'url']: res.data, status: 'success' }) if (props.config.autoNotify) CipMessage.success(res.message) updateValue() }).catch(e => { fileUploadProgress(info, { status: 'exception' }) setTimeout(() => { fileList.value.splice(fileList.value.findIndex(v => v.uid === info.file.uid), 1) }, 500) }).finally(() => { cipForm.uploadQueue[uid] = false }) } // 单例模式加载message let messageInstance = null const mainMessage = (through, message) => { if (!through) { if (messageInstance) { CipMessage.closeAll() } messageInstance = CipMessage.warning(message) return true } } // 文件数量限制 const countLimit = (file) => { // 加上正在上传的数量 return fileList.value.length + 1 <= (securityConfig.value.limit ?? Infinity) } // 文件类型限制 const typeLimit = (file) => { if (props.config.ignoreFileType) { // 完全不限制类型 return true } const fileType = props.config.fileType && securityConfig.value.fileType.length !== 0 ? securityConfig.value.fileType : fileTypeList const obj = file.name?.split('.') ?? '' return fileType.includes(obj[obj.length - 1].toLowerCase()) } // 文件大小限制 const sizeLimit = (file) => { return file.size <= (securityConfig.value.size ?? Infinity) * 1024 * 1024 } // 修改文件列表某文件的状态 const fileUploadProgress = (info, writeObj) => { return fileList.value.map(i => { if (i.uid === info.file.uid) { // eslint-disable-next-line for (const item in writeObj) { i[item] = writeObj[item] } } return i }) } // 文件列表删除 const removeFile = (file, list) => { const fileIndex = fileList.value.findIndex(v => v.uid === file.uid) fileList.value.splice(fileIndex, 1) updateValue() } const updateValue = () => { let modelValue = fileList.value if (useStringValue.value) { modelValue = fileList.value?.map(v => v.url).join(fileSplitKey.value) } else if (objectValue.value) { modelValue = fileList.value[0] } proxyValue.value = modelValue } const uploadDisabled = computed(() => props.disabled || securityConfig.value.limit <= fileList.value.length) return { uploadFile, removeFile, fileList, mainMessage, countLimit, typeLimit, sizeLimit, uploadDisabled } } export const download = (file) => { file.percentage = '' const download = document.createElement('a') download.setAttribute('href', file.url + '?response-content-type=application/octet-stream') download.setAttribute('download', file.name) download.click() }