import { ref } from 'vue' import { uploadImages } from '@/common/utils/upload' /** * 图片上传组合式函数(兼容非TS环境,纯数组格式) * @param config 上传配置 * @returns 上传相关方法和状态 */ export function useUploadImgs(config) { // 默认配置 const defaultConfig = { maxCount: 3, uploadText: '选择图片', sizeType: ['compressed'], ...config } // 核心修复:初始化为纯数组,且格式适配u-upload const imgList = ref([]) /** * 删除图片 */ const deleteImg = (event) => { // 确保index是有效数字 const index = Number(event.index) if (isNaN(index) || index < 0 || index >= imgList.value.length) return imgList.value.splice(index, 1) // 删除后重新校验 defaultConfig.formRef.value?.validateField(defaultConfig.fieldName) uni.showToast({ title: '图片删除成功', icon: 'success' }) } /** * 上传图片(适配u-upload的file格式) */ const uploadImgs = async (event) => { // 核心修复:标准化file数据格式 const rawFile = event.file || {} const fileList = Array.isArray(rawFile) ? rawFile : [rawFile] // 过滤无效文件 const validFiles = fileList.filter(file => file && file.url) if (validFiles.length === 0) { uni.showToast({ title: '请选择有效图片', icon: 'none' }) return } const targetImgList = imgList.value // 校验最大数量 if (targetImgList.length + validFiles.length > defaultConfig.maxCount) { uni.showToast({ title: `最多只能上传${defaultConfig.maxCount}张图片`, icon: 'none' }) return } // 核心修复:转换为u-upload兼容的格式 const filePaths = validFiles.map(item => item.url) const tempItems = validFiles.map(item => ({ url: item.url, status: 'uploading', message: '上传中', name: item.name || '', size: item.size || 0 })) const startIndex = targetImgList.length targetImgList.push(...tempItems) try { const uploadResultUrls = await uploadImages({ filePaths: filePaths, ignoreError: true }) // 更新上传成功的图片 uploadResultUrls.forEach((url, index) => { if (targetImgList[startIndex + index]) { targetImgList.splice(startIndex + index, 1, { url: url, status: 'success', message: '', name: validFiles[index].name || '', size: validFiles[index].size || 0 }) } }) // 处理上传失败的图片 if (uploadResultUrls.length < validFiles.length) { const failCount = validFiles.length - uploadResultUrls.length for (let i = uploadResultUrls.length; i < validFiles.length; i++) { if (targetImgList[startIndex + i]) { targetImgList.splice(startIndex + i, 1, { url: validFiles[i].url, status: 'failed', message: '上传失败', name: validFiles[i].name || '', size: validFiles[i].size || 0 }) } } uni.showToast({ title: `成功上传${uploadResultUrls.length}张,失败${failCount}张`, icon: 'none' }) } else { uni.showToast({ title: `成功上传${validFiles.length}张图片`, icon: 'success' }) } // 上传完成后校验 defaultConfig.formRef.value?.validateField(defaultConfig.fieldName) } catch (err) { console.error(`【${defaultConfig.fieldName}】图片上传失败:`, err) // 标记所有上传失败 for (let i = 0; i < validFiles.length; i++) { if (targetImgList[startIndex + i]) { targetImgList.splice(startIndex + i, 1, { url: validFiles[i].url, status: 'failed', message: '上传失败', name: validFiles[i].name || '', size: validFiles[i].size || 0 }) } } uni.showToast({ title: '图片上传失败,请重试', icon: 'none' }) // 上传失败后校验 defaultConfig.formRef.value?.validateField(defaultConfig.fieldName) } } /** * 获取成功上传的图片URL列表 */ const getSuccessImgUrls = () => { return imgList.value.filter(item => item.status === 'success').map(item => item.url) } /** * 图片校验规则(供表单使用) */ const imgValidateRule = { required: true, message: `请上传${defaultConfig.uploadText.replace('选择', '')}`, trigger: 'change', validator: (rule, value, callback) => { const hasSuccessImg = imgList.value.some(item => item.status === 'success') hasSuccessImg ? callback() : callback(new Error(`请上传至少1张${defaultConfig.uploadText.replace('选择', '')}`)) } } return { imgList: imgList.value, // 核心修复:返回纯数组(解除响应式代理) rawImgList: imgList, // 保留响应式引用(内部使用) uploadImgs, deleteImg, getSuccessImgUrls, imgValidateRule, uploadConfig: defaultConfig } }