useUploadImgs.ts
5.46 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
import { ref, type Ref } from 'vue'
import { uploadImages } from '@/common/utils/upload'
import type { UniFormRef } from '@/uni_modules/uview-plus/types'
// 定义上传配置类型
export interface UploadImgConfig {
maxCount?: number // 最大上传数量,默认3
uploadText?: string // 上传按钮文案
sizeType?: UniApp.UploadFileOption['sizeType'] // 图片压缩类型
formRef: Ref<UniFormRef | null> // 表单ref,用于校验
fieldName: string // 表单校验字段名(如problemImgs)
}
// 定义图片项类型
export interface UploadImgItem {
url: string
status: 'uploading' | 'success' | 'failed'
message: string
[key: string]: any // 兼容其他字段
}
/**
* 图片上传组合式函数(支持多实例复用)
* @param config 上传配置
* @returns 上传相关方法和状态
*/
export function useUploadImgs(config: UploadImgConfig) {
// 默认配置
const defaultConfig = {
maxCount: 3,
uploadText: '选择图片',
sizeType: ['compressed'] as UniApp.UploadFileOption['sizeType'],
...config
}
// 图片列表
const imgList = ref<UploadImgItem[]>([])
/**
* 删除图片
*/
const deleteImg = (event: { index: number }) => {
imgList.value.splice(event.index, 1)
// 删除后重新校验
defaultConfig.formRef.value?.validateField(defaultConfig.fieldName)
uni.showToast({ title: '图片删除成功', icon: 'success' })
}
/**
* 上传图片
*/
const uploadImgs = async (event: { file: UniApp.ChooseImageSuccessCallbackResult | UniApp.ChooseImageSuccessCallbackResult[] }) => {
const fileList = Array.isArray(event.file) ? event.file : [event.file]
const targetImgList = imgList.value
// 过滤超出最大数量的图片
if (targetImgList.length + fileList.length > defaultConfig.maxCount) {
uni.showToast({ title: `最多只能上传${defaultConfig.maxCount}张图片`, icon: 'none' })
return
}
const filePaths = fileList.map(item => item.url)
const tempItems = fileList.map(item => ({
...item,
status: 'uploading' as const,
message: '上传中'
}))
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, {
...fileList[index],
status: 'success' as const,
message: '',
url: url
})
}
})
// 处理上传失败的图片
if (uploadResultUrls.length < fileList.length) {
const failCount = fileList.length - uploadResultUrls.length
for (let i = uploadResultUrls.length; i < fileList.length; i++) {
if (targetImgList[startIndex + i]) {
targetImgList.splice(startIndex + i, 1, {
...fileList[i],
status: 'failed' as const,
message: '上传失败'
})
}
}
uni.showToast({ title: `成功上传${uploadResultUrls.length}张,失败${failCount}张`, icon: 'none' })
} else {
uni.showToast({ title: `成功上传${fileList.length}张图片`, icon: 'success' })
}
// 上传完成后校验
defaultConfig.formRef.value?.validateField(defaultConfig.fieldName)
} catch (err) {
console.error(`【${defaultConfig.fieldName}】图片上传失败:`, err)
// 标记所有上传失败
for (let i = 0; i < fileList.length; i++) {
if (targetImgList[startIndex + i]) {
targetImgList.splice(startIndex + i, 1, {
...fileList[i],
status: 'failed' as const,
message: '上传失败'
})
}
}
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: any, value: any, callback: (error?: Error) => void) => {
const hasSuccessImg = imgList.value.some(item => item.status === 'success')
hasSuccessImg ? callback() : callback(new Error(`请上传至少1张${defaultConfig.uploadText.replace('选择', '')}`))
}
}
return {
imgList,
uploadImgs,
deleteImg,
getSuccessImgUrls,
imgValidateRule,
uploadConfig: defaultConfig
}
}