91 lines
2.5 KiB
TypeScript
91 lines
2.5 KiB
TypeScript
import React, { useMemo, useCallback } from 'react'
|
||
import { View, Text, Image, ScrollView } from '@tarojs/components'
|
||
import Taro from '@tarojs/taro'
|
||
import './ImageUpload.scss'
|
||
|
||
export interface CoverImage {
|
||
id: string
|
||
url: string
|
||
tempFilePath?: string
|
||
}
|
||
|
||
interface ImageUploadProps {
|
||
images: CoverImage[]
|
||
onChange: (images: CoverImage[]) => void
|
||
maxCount?: number
|
||
}
|
||
|
||
const ImageUpload: React.FC<ImageUploadProps> = ({
|
||
images,
|
||
onChange,
|
||
maxCount = 9
|
||
}) => {
|
||
// 添加封面图片
|
||
const handleAddCoverImage = useCallback(() => {
|
||
if (images.length >= maxCount) {
|
||
Taro.showToast({
|
||
title: `最多只能上传${maxCount}张图片`,
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
Taro.chooseImage({
|
||
count: maxCount - images.length,
|
||
sizeType: ['compressed'],
|
||
sourceType: ['album', 'camera'],
|
||
success: (res) => {
|
||
const newImages = res.tempFilePaths.map((path, index) => ({
|
||
id: Date.now() + index + '',
|
||
url: path,
|
||
tempFilePath: path
|
||
}))
|
||
onChange([...images, ...newImages])
|
||
},
|
||
fail: (err) => {
|
||
console.error('选择图片失败:', err)
|
||
}
|
||
})
|
||
}, [images.length, maxCount, onChange])
|
||
|
||
// 删除封面图片
|
||
const handleDeleteCoverImage = useCallback((id: string) => {
|
||
onChange(images.filter(img => img.id !== id))
|
||
}, [images, onChange])
|
||
|
||
// 判断是否需要居中显示(总项目数不超过3个时居中)
|
||
const shouldCenter = useMemo(() => (images.length + 1) <= 3, [images.length])
|
||
|
||
return (
|
||
<View className='cover-image-upload'>
|
||
<ScrollView className='cover-scroll' scrollX>
|
||
<View className={`cover-list ${shouldCenter ? 'center' : ''}`}>
|
||
{/* 添加按钮 */}
|
||
<View className='cover-item add-btn' onClick={handleAddCoverImage}>
|
||
<View className='add-icon'>+</View>
|
||
<Text className='add-text'>添加活动封面</Text>
|
||
</View>
|
||
|
||
{/* 已选择的图片 */}
|
||
{images.map((image) => (
|
||
<View key={image.id} className='cover-item image-item'>
|
||
<Image
|
||
className='cover-image'
|
||
src={image.url}
|
||
mode='aspectFill'
|
||
/>
|
||
<View
|
||
className='delete-btn'
|
||
onClick={() => handleDeleteCoverImage(image.id)}
|
||
>
|
||
×
|
||
</View>
|
||
</View>
|
||
))}
|
||
</View>
|
||
</ScrollView>
|
||
</View>
|
||
)
|
||
}
|
||
|
||
export default ImageUpload
|