完善接单平台上传与物品规则
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
import { Image, Typography } from 'antd'
|
||||
|
||||
import type { UploadedFile } from '@/types/worker-platform'
|
||||
|
||||
type ImagePreviewListProps = {
|
||||
files?: UploadedFile[]
|
||||
imageUrls?: string[]
|
||||
size?: number
|
||||
}
|
||||
|
||||
export default function ImagePreviewList({
|
||||
files = [],
|
||||
imageUrls = [],
|
||||
size = 56,
|
||||
}: ImagePreviewListProps) {
|
||||
const items = normalizePreviewItems(files, imageUrls)
|
||||
if (items.length === 0) {
|
||||
return <Typography.Text type="secondary">-</Typography.Text>
|
||||
}
|
||||
|
||||
return (
|
||||
<Image.PreviewGroup>
|
||||
<div className="image-preview-list">
|
||||
{items.map((item) => (
|
||||
<Image
|
||||
key={item.url}
|
||||
src={item.thumbnailUrl || item.url}
|
||||
preview={{ src: item.mediumUrl || item.url }}
|
||||
width={size}
|
||||
height={size}
|
||||
className="image-preview-item"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</Image.PreviewGroup>
|
||||
)
|
||||
}
|
||||
|
||||
function normalizePreviewItems(files: UploadedFile[], imageUrls: string[]) {
|
||||
const normalizedFiles = files
|
||||
.map((file) => ({
|
||||
url: file.url || file.mediumUrl || file.thumbnailUrl,
|
||||
thumbnailUrl: file.thumbnailUrl || file.url,
|
||||
mediumUrl: file.mediumUrl || file.url,
|
||||
}))
|
||||
.filter((item) => Boolean(item.url))
|
||||
const fileUrlSet = new Set(normalizedFiles.map((item) => item.url))
|
||||
const normalizedUrls = imageUrls
|
||||
.map((url) => String(url || '').trim())
|
||||
.filter((url) => url && !fileUrlSet.has(url))
|
||||
.map((url) => ({ url, thumbnailUrl: url, mediumUrl: url }))
|
||||
return [...normalizedFiles, ...normalizedUrls]
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
import { PlusOutlined } from '@ant-design/icons'
|
||||
import { App, Upload } from 'antd'
|
||||
import type { UploadFile, UploadProps } from 'antd'
|
||||
|
||||
import { uploadFile } from '@/services/files'
|
||||
import type { UploadedFile } from '@/types/worker-platform'
|
||||
|
||||
type ImageUploadProps = {
|
||||
value?: UploadedFile[]
|
||||
onChange?: (files: UploadedFile[]) => void
|
||||
scene: string
|
||||
scope: 'admin' | 'worker'
|
||||
maxCount?: number
|
||||
}
|
||||
|
||||
export default function ImageUpload({
|
||||
value = [],
|
||||
onChange,
|
||||
scene,
|
||||
scope,
|
||||
maxCount = 6,
|
||||
}: ImageUploadProps) {
|
||||
const { message } = App.useApp()
|
||||
const fileList: UploadFile[] = value.map((file) => ({
|
||||
uid: file.objectKey || file.url,
|
||||
name: file.filename || '图片',
|
||||
status: 'done',
|
||||
url: file.thumbnailUrl || file.url,
|
||||
thumbUrl: file.thumbnailUrl || file.url,
|
||||
}))
|
||||
|
||||
const customRequest: UploadProps['customRequest'] = async (options) => {
|
||||
try {
|
||||
const uploaded = await uploadFile(options.file as File, scene, scope)
|
||||
onChange?.([...value, uploaded].slice(-maxCount))
|
||||
options.onSuccess?.(uploaded)
|
||||
} catch (error) {
|
||||
message.error(error instanceof Error ? error.message : '上传失败')
|
||||
options.onError?.(error instanceof Error ? error : new Error('上传失败'))
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Upload
|
||||
accept="image/jpeg,image/png,image/webp"
|
||||
listType="picture-card"
|
||||
fileList={fileList}
|
||||
maxCount={maxCount}
|
||||
customRequest={customRequest}
|
||||
onRemove={(file) => {
|
||||
onChange?.(
|
||||
value.filter((item) => (item.objectKey || item.url) !== file.uid),
|
||||
)
|
||||
return true
|
||||
}}
|
||||
showUploadList={{ showPreviewIcon: false }}
|
||||
>
|
||||
{value.length >= maxCount ? null : (
|
||||
<button className="image-upload-trigger" type="button">
|
||||
<PlusOutlined />
|
||||
<span>上传</span>
|
||||
</button>
|
||||
)}
|
||||
</Upload>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user