useUploadImgs.js
7.78 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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
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([])
// 确保 rawImgList 响应式对象的初始值也是空数组
// const rawImgList = ref([]);
/**
* 新增:清空所有图片
* 功能:重置图片列表为空,并触发表单字段校验(如果有表单Ref)
*/
const clearImgs = () => {
imgList.value = [];
// 优化:先判断 formRef 存在,再判断 formRef.value 存在
if (defaultConfig.formRef && defaultConfig.formRef.value && defaultConfig.fieldName) {
defaultConfig.formRef.value.validateField(defaultConfig.fieldName);
}
};
/**
* 删除图片
*/
const deleteImg = (event) => {
const index = Number(event.index);
if (isNaN(index) || index < 0 || index >= imgList.value.length) return;
imgList.value.splice(index, 1);
// 修复:先判断 formRef 存在,再访问 value
if (defaultConfig.formRef && defaultConfig.formRef.value && defaultConfig.fieldName) {
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' })
}
// 上传完成后校验
if (defaultConfig.formRef && defaultConfig.formRef.value && defaultConfig.fieldName) {
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('选择', '')}`))
}
}
/**
* 新增:批量设置图片列表(图片回显核心方法,替代业务页面的setUploadImgsList)
* @param imgUrls 图片URL数组(如:['https://xxx.jpg', 'https://yyy.png'])
* 功能:将纯URL数组转换为u-upload兼容格式,实现静默回显,无数据时不提示
*/
const setImgList = (imgUrls = []) => {
// 容错处理:校验参数有效性,非数组/空数组直接重置
if (!Array.isArray(imgUrls) || imgUrls.length === 0) {
imgList.value = []
return
}
// 转换为u-upload兼容的格式(status: success 标记为已成功上传,可正常显示/删除)
const formatImgList = imgUrls.map(url => ({
url: url,
status: 'success', // 关键:标记为成功状态,兼容后续删除/校验逻辑
message: '',
name: url.substring(url.lastIndexOf('/') + 1), // 从URL截取文件名,优化显示
size: 0 // 历史图片无大小信息,默认0不影响使用
}))
// 额外优化:限制回显数量不超过maxCount,避免异常
const finalImgList = formatImgList.slice(0, defaultConfig.maxCount)
imgList.value = finalImgList
}
return {
imgList: imgList, // 核心修复:返回纯数组(解除响应式代理)
rawImgList: imgList, // 保留响应式引用(内部使用)
uploadImgs,
deleteImg,
clearImgs,
setImgList,
getSuccessImgUrls,
imgValidateRule,
uploadConfig: defaultConfig
}
}