发布球局

This commit is contained in:
筱野
2025-08-23 15:14:37 +08:00
parent e5176f4f5f
commit fb150617c6
34 changed files with 679 additions and 602 deletions

View File

@@ -0,0 +1,110 @@
// 在组件SCSS文件中
@use '~@/scss/images.scss' as img;
.cover-image-upload {
margin-bottom: 8px;
.cover-scroll {
white-space: nowrap;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.cover-list {
display: inline-flex;
padding: 0 4px;
min-width: 100%;
transition: justify-content 0.3s ease;
&.center {
justify-content: center;
}
}
.cover-item {
flex-shrink: 0;
width: 108px;
height: 108px;
border-radius: 12px;
margin-right: 6px;
position: relative;
overflow: hidden;
transition: all 0.3s ease;
animation: slideIn 0.3s ease-out;
@keyframes slideIn {
from {
opacity: 0;
transform: scale(0.8);
}
to {
opacity: 1;
transform: scale(1);
}
}
&.add-btn {
border: 2px dashed #d9d9d9;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.add-icon {
font-size: 32px;
color: #999;
margin-bottom: 8px;
}
.add-text {
font-size: 12px;
color: #999;
text-align: center;
line-height: 1.2;
}
}
&.image-item {
.cover-image {
width: 100%;
height: 100%;
border-radius: 12px;
transition: opacity 0.3s ease;
&:not([src]) {
opacity: 0;
}
}
.delete-btn {
position: absolute;
top: 8px;
right: 8px;
width: 20px;
height: 20px;
background: rgba(0, 0, 0, 0.6);
color: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
font-weight: bold;
}
}
}
}
// 暗色模式适配
@media (prefers-color-scheme: dark) {
.cover-image-upload {
.cover-item.add-btn {
background: #2d2d2d;
border-color: #555;
.add-icon,
.add-text {
color: #999;
}
}
}
}

View File

@@ -0,0 +1,91 @@
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

View File

@@ -0,0 +1 @@
export { default, type CoverImage } from './ImageUpload'