diff --git a/apps/frontend/src/components/files/ImageUpload.tsx b/apps/frontend/src/components/files/ImageUpload.tsx index 7eec1328..f606cb52 100644 --- a/apps/frontend/src/components/files/ImageUpload.tsx +++ b/apps/frontend/src/components/files/ImageUpload.tsx @@ -1,7 +1,7 @@ import { CameraOutlined, CloudUploadOutlined, PlusOutlined } from '@ant-design/icons' import { App, Button, Typography, Upload } from 'antd' import type { UploadFile, UploadProps } from 'antd' -import { useEffect, useRef, useState } from 'react' +import { memo, useEffect, useMemo, useRef, useState } from 'react' import type { ChangeEvent, ClipboardEvent, DragEvent, FocusEvent, MouseEvent } from 'react' import { uploadFile } from '@/services/files' @@ -68,7 +68,7 @@ function registerGlobalPasteTarget(target: GlobalPasteTarget): () => void { } } -export default function ImageUpload({ +export default memo(function ImageUpload({ value = [], onChange, scene, @@ -91,13 +91,17 @@ export default function ImageUpload({ const cameraEnabled = resolveCameraEntryEnabled({ isMobile, scope, allowCamera }) const cameraInputProps = cameraCaptureInputProps('image') - 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 fileList: UploadFile[] = useMemo( + () => + value.map((file) => ({ + uid: file.objectKey || file.url, + name: file.filename || '图片', + status: 'done', + url: file.thumbnailUrl || file.url, + thumbUrl: file.thumbnailUrl || file.url, + })), + [value], + ) async function uploadImages(images: File[], source: UploadSource = 'default') { const remaining = maxCount - valueRef.current.length @@ -299,7 +303,7 @@ export default function ImageUpload({ ) : null} ) -} +}) function resolveUploadErrorMessage(error: unknown, source: UploadSource) { const errorMessage = error instanceof Error ? error.message : '上传失败' diff --git a/apps/frontend/src/pages/admin/panels/OrderServicePanel.tsx b/apps/frontend/src/pages/admin/panels/OrderServicePanel.tsx index 111c896e..9de0f50a 100644 --- a/apps/frontend/src/pages/admin/panels/OrderServicePanel.tsx +++ b/apps/frontend/src/pages/admin/panels/OrderServicePanel.tsx @@ -27,7 +27,7 @@ import { Typography, } from 'antd' import { useQuery, useQueryClient } from '@tanstack/react-query' -import { useEffect, useMemo, useState } from 'react' +import { useCallback, useEffect, useMemo, useState } from 'react' import PercentTable from '@/components/common/PercentTable' import ImageUpload from '@/components/files/ImageUpload' @@ -133,6 +133,14 @@ export default function OrderServicePanel() { ).length const selectedCategory = categories.find((item) => item.categoryId === selectedCategoryId) || null const profile = (selectedCategoryId ? profileByCategoryId.get(selectedCategoryId) : null) || null + const guideFiles = useMemo(() => (guideImage ? [guideImage as UploadedFile] : []), [guideImage]) + const handleGuideImageChange = useCallback((files: UploadedFile[]) => { + setGuideImage(files[0] || null) + }, []) + const uploadGuideImage = useCallback( + (file: File, scene: string) => uploadFile(file, scene, 'admin'), + [], + ) useEffect(() => { if (selectedCategoryId !== null || categories.length === 0) return @@ -488,9 +496,9 @@ export default function OrderServicePanel() { scene="order-service" scope="admin" maxCount={1} - value={guideImage ? [guideImage as UploadedFile] : []} - onChange={(files) => setGuideImage(files[0] || null)} - uploader={(file, scene) => uploadFile(file, scene, 'admin')} + value={guideFiles} + onChange={handleGuideImageChange} + uploader={uploadGuideImage} />