diff --git a/apps/web/src/components/common/uploader/AvatarUploader.tsx b/apps/web/src/components/common/uploader/AvatarUploader.tsx index 8cc6161..cfcecc5 100644 --- a/apps/web/src/components/common/uploader/AvatarUploader.tsx +++ b/apps/web/src/components/common/uploader/AvatarUploader.tsx @@ -33,12 +33,13 @@ const AvatarUploader: React.FC = ({ }) => { const { handleFileUpload, uploadProgress } = useTusUpload(); const [file, setFile] = useState(null); - + const avatarRef = useRef(null); const [previewUrl, setPreviewUrl] = useState(value || ""); const [url, setUrl] = useState(value || ""); const [uploading, setUploading] = useState(false); const inputRef = useRef(null); - + // 在组件中定义 key 状态 + const [avatarKey, setAvatarKey] = useState(0); const { token } = theme.useToken(); const handleChange = async (event: React.ChangeEvent) => { @@ -77,7 +78,10 @@ const AvatarUploader: React.FC = ({ file?.fileKey ); }); + // await new Promise((resolve) => setTimeout(resolve, 5000)); // 方法1:使用 await 暂停执行 // 使用 resolved 的最新值调用 onChange + // 强制刷新 Avatar 组件 + setAvatarKey((prev) => prev + 1); // 修改 key 强制重新挂载 onChange?.(uploadedUrl); message.success("头像上传成功"); } catch (error) { @@ -111,6 +115,8 @@ const AvatarUploader: React.FC = ({ /> {previewUrl ? ( void; -} - -export interface TusUploaderRef { - reset: () => void; + value?: string[]; + onChange?: (value: string[]) => void; } interface UploadingFile { - name: string; - progress: number; - status: "uploading" | "done" | "error"; - fileId?: string; - fileKey?: string; + name: string; + progress: number; + status: "uploading" | "done" | "error"; + fileId?: string; + fileKey?: string; } -export const TusUploader = forwardRef( - ({ value = [], onChange }, ref) => { - const { handleFileUpload, uploadProgress } = useTusUpload(); - const [uploadingFiles, setUploadingFiles] = useState( - [] - ); - const [completedFiles, setCompletedFiles] = useState( - [] - ); +export const TusUploader = ({ value = [], onChange }: TusUploaderProps) => { + const { handleFileUpload, uploadProgress } = useTusUpload(); + const [uploadingFiles, setUploadingFiles] = useState([]); + const [completedFiles, setCompletedFiles] = useState( + () => + value?.map((fileId) => ({ + name: `文件 ${fileId}`, + progress: 100, + status: "done" as const, + fileId, + })) || [] + ); + const [uploadResults, setUploadResults] = useState(value || []); - // 同步父组件value到completedFiles - useEffect(() => { - setCompletedFiles( - value.map((fileId) => ({ - name: `文件 ${fileId}`, - progress: 100, - status: "done" as const, - fileId, - })) - ); - }, [value]); + const handleRemoveFile = useCallback( + (fileId: string) => { + setCompletedFiles((prev) => prev.filter((f) => f.fileId !== fileId)); + setUploadResults((prev) => { + const newValue = prev.filter((id) => id !== fileId); + onChange?.(newValue); + return newValue; + }); + }, + [onChange] + ); - // 暴露重置方法 - useImperativeHandle(ref, () => ({ - reset: () => { - setCompletedFiles([]); - setUploadingFiles([]); - }, - })); + // 新增:处理删除上传中的失败文件 + const handleRemoveUploadingFile = useCallback((fileKey: string) => { + setUploadingFiles((prev) => prev.filter((f) => f.fileKey !== fileKey)); + }, []); - const handleRemoveFile = useCallback( - (fileId: string) => { - setCompletedFiles((prev) => - prev.filter((f) => f.fileId !== fileId) - ); - onChange?.(value.filter((id) => id !== fileId)); - }, - [onChange, value] - ); + const handleBeforeUpload = useCallback( + (file: File) => { + const fileKey = `${file.name}-${Date.now()}`; - const handleRemoveUploadingFile = useCallback((fileKey: string) => { - setUploadingFiles((prev) => - prev.filter((f) => f.fileKey !== fileKey) - ); - }, []); + setUploadingFiles((prev) => [ + ...prev, + { + name: file.name, + progress: 0, + status: "uploading", + fileKey, + }, + ]); - const handleBeforeUpload = useCallback( - (file: File) => { - const fileKey = `${file.name}-${Date.now()}`; + handleFileUpload( + file, + (result) => { + setCompletedFiles((prev) => [ + ...prev, + { + name: file.name, + progress: 100, + status: "done", + fileId: result.fileId, + }, + ]); - setUploadingFiles((prev) => [ - ...prev, - { - name: file.name, - progress: 0, - status: "uploading", - fileKey, - }, - ]); + setUploadingFiles((prev) => + prev.filter((f) => f.fileKey !== fileKey) + ); - handleFileUpload( - file, - (result) => { - const newValue = [...value, result.fileId]; - onChange?.(newValue); - setUploadingFiles((prev) => - prev.filter((f) => f.fileKey !== fileKey) - ); - }, - (error) => { - console.error("上传错误:", error); - toast.error( - `上传失败: ${error instanceof Error ? error.message : "未知错误"}` - ); - setUploadingFiles((prev) => - prev.map((f) => - f.fileKey === fileKey - ? { ...f, status: "error" } - : f - ) - ); - }, - fileKey - ); + setUploadResults((prev) => { + const newValue = [...prev, result.fileId]; + onChange?.(newValue); + return newValue; + }); + }, + (error) => { + console.error("上传错误:", error); + toast.error( + `上传失败: ${error instanceof Error ? error.message : "未知错误"}` + ); + setUploadingFiles((prev) => + prev.map((f) => + f.fileKey === fileKey ? { ...f, status: "error" } : f + ) + ); + }, + fileKey + ); - return false; - }, - [handleFileUpload, onChange, value] - ); + return false; + }, + [handleFileUpload, onChange] + ); - return ( -
- -

- -

-

- 点击或拖拽文件到此区域进行上传 -

-

支持单个或批量上传文件

+ return ( +
+ +

+ +

+

点击或拖拽文件到此区域进行上传

+

支持单个或批量上传文件

-
- {uploadingFiles.map((file) => ( -
-
- {file.name} -
-
- - {file.status === "error" && ( -
-
- ))} +
+ {uploadingFiles.map((file) => ( +
+
+ {file.name} +
+
+ + {file.status === "error" && ( +
+
+ ))} - {completedFiles.map((file) => ( -
-
- - {file.name} -
-
- ))} -
- -
- ); - } -); + {completedFiles.map((file) => ( +
+
+ + {file.name} +
+
+ ))} +
+
+
+ ); +}; \ No newline at end of file diff --git a/apps/web/src/components/layout/element/usermenu/user-form.tsx b/apps/web/src/components/layout/element/usermenu/user-form.tsx index 61eacc8..6f8ade0 100644 --- a/apps/web/src/components/layout/element/usermenu/user-form.tsx +++ b/apps/web/src/components/layout/element/usermenu/user-form.tsx @@ -121,9 +121,7 @@ export default function StaffForm() { { - console.log(value); - }} + style={{ width: "120px", height: "150px", diff --git a/apps/web/src/components/models/post/detail/PostCommentCard.tsx b/apps/web/src/components/models/post/detail/PostCommentCard.tsx index 97cecb4..0c43642 100644 --- a/apps/web/src/components/models/post/detail/PostCommentCard.tsx +++ b/apps/web/src/components/models/post/detail/PostCommentCard.tsx @@ -34,6 +34,9 @@ export default function PostCommentCard({ layout>
+ {/* + {post.author?.meta?.photoUrl} + */} (undefined); const [fileIds, setFileIds] = useState([]); const { create } = usePost(); - const uploaderRef = useRef<{ reset: () => void }>(null); + const [uploaderKey, setUploaderKey] = useState(0); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); @@ -48,9 +48,7 @@ export default function PostCommentEditor() { toast.success("发布成功!"); setContent(""); setFileIds([]); // 重置上传组件状态 - // if (uploaderRef.current) { - // uploaderRef.current.reset(); - // } + setUploaderKey(uploaderKey + 1); } catch (error) { toast.error("发布失败,请稍后重试"); console.error("Error posting comment:", error); @@ -90,7 +88,7 @@ export default function PostCommentEditor() {
{ console.log("ids", value); diff --git a/apps/web/src/components/models/post/editor/form/LetterBasicForm.tsx b/apps/web/src/components/models/post/editor/form/LetterBasicForm.tsx index f088c91..9dd655f 100644 --- a/apps/web/src/components/models/post/editor/form/LetterBasicForm.tsx +++ b/apps/web/src/components/models/post/editor/form/LetterBasicForm.tsx @@ -81,12 +81,12 @@ export function LetterBasicForm() {
+ onChange={async (resources) => { form.setFieldValue( "resources", resources - ) - } + ); + }} />