useUploadImgs.js
5.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
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
}
}