From a5552dba6b5051d2fb767204400576b5e1af3ea0 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Sun, 26 Jan 2025 20:38:25 +0800 Subject: [PATCH] add12345 --- .../common/uploader/TusUploader.tsx | 331 ++++++++++-------- .../models/post/detail/PostCommentEditor.tsx | 10 +- apps/web/src/hooks/useTusUpload.ts | 12 +- 3 files changed, 192 insertions(+), 161 deletions(-) diff --git a/apps/web/src/components/common/uploader/TusUploader.tsx b/apps/web/src/components/common/uploader/TusUploader.tsx index a7e0244..dd11898 100644 --- a/apps/web/src/components/common/uploader/TusUploader.tsx +++ b/apps/web/src/components/common/uploader/TusUploader.tsx @@ -1,19 +1,29 @@ -import { useCallback, useState } from "react"; +// TusUploader.tsx +import { + useCallback, + useState, + useEffect, + forwardRef, + useImperativeHandle, +} from "react"; import { UploadOutlined, CheckCircleOutlined, DeleteOutlined, } from "@ant-design/icons"; import { Upload, Progress, Button } from "antd"; -import type { UploadFile } from "antd"; import { useTusUpload } from "@web/src/hooks/useTusUpload"; import toast from "react-hot-toast"; -import { getCompressedImageUrl } from "@nice/utils"; + export interface TusUploaderProps { value?: string[]; onChange?: (value: string[]) => void; } +export interface TusUploaderRef { + reset: () => void; +} + interface UploadingFile { name: string; progress: number; @@ -22,164 +32,179 @@ interface UploadingFile { fileKey?: string; } -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, - })) || [] - ); - // 恢复使用 uploadResults 状态跟踪最新结果 - const [uploadResults, setUploadResults] = useState(value || []); - const handleRemoveFile = useCallback( - (fileId: string) => { - setCompletedFiles((prev) => - prev.filter((f) => f.fileId !== fileId) +export const TusUploader = forwardRef( + ({ value = [], onChange }, ref) => { + const { handleFileUpload, uploadProgress } = useTusUpload(); + const [uploadingFiles, setUploadingFiles] = useState( + [] + ); + const [completedFiles, setCompletedFiles] = useState( + [] + ); + + // 同步父组件value到completedFiles + useEffect(() => { + setCompletedFiles( + value.map((fileId) => ({ + name: `文件 ${fileId}`, + progress: 100, + status: "done" as const, + fileId, + })) ); - // 使用函数式更新保证获取最新状态 - setUploadResults((prev) => { - const newValue = prev.filter((id) => id !== fileId); - onChange?.(newValue); // 同步更新父组件 - return newValue; - }); - }, - [onChange] - ); + }, [value]); - const handleBeforeUpload = useCallback( - (file: File) => { - const fileKey = `${file.name}-${Date.now()}`; + // 暴露重置方法 + useImperativeHandle(ref, () => ({ + reset: () => { + setCompletedFiles([]); + setUploadingFiles([]); + }, + })); - setUploadingFiles((prev) => [ - ...prev, - { - name: file.name, - progress: 0, - status: "uploading", - fileKey, - }, - ]); + const handleRemoveFile = useCallback( + (fileId: string) => { + setCompletedFiles((prev) => + prev.filter((f) => f.fileId !== fileId) + ); + onChange?.(value.filter((id) => id !== fileId)); + }, + [onChange, value] + ); - handleFileUpload( - file, - (result) => { - setCompletedFiles((prev) => [ - ...prev, - { - name: file.name, - progress: 100, - status: "done", - fileId: result.fileId, - }, - ]); - - setUploadingFiles((prev) => - prev.filter((f) => f.fileKey !== 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 + const handleRemoveUploadingFile = useCallback((fileKey: string) => { + setUploadingFiles((prev) => + prev.filter((f) => f.fileKey !== fileKey) ); + }, []); - return false; - }, - [handleFileUpload, onChange] - ); + const handleBeforeUpload = useCallback( + (file: File) => { + const fileKey = `${file.name}-${Date.now()}`; - return ( -
- -

- -

-

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

-

支持单个或批量上传文件

+ setUploadingFiles((prev) => [ + ...prev, + { + name: file.name, + progress: 0, + status: "uploading", + fileKey, + }, + ]); - {/* 上传状态展示 */} -
- {/* 上传中的文件 */} - {uploadingFiles.map((file) => ( -
-
- {file.name} + 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 + ); + + return false; + }, + [handleFileUpload, onChange, value] + ); + + return ( +
+ +

+ +

+

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

+

支持单个或批量上传文件

+ +
+ {uploadingFiles.map((file) => ( +
+
+ {file.name} +
+
+ + {file.status === "error" && ( +
- -
- ))} + ))} - {/* 已完成的文件 */} - {completedFiles.map((file) => ( -
-
- - {file.name} + {completedFiles.map((file) => ( +
+
+ + {file.name} +
+
-
- ))} -
-
-
- ); -}; + ))} +
+ +
+ ); + } +); diff --git a/apps/web/src/components/models/post/detail/PostCommentEditor.tsx b/apps/web/src/components/models/post/detail/PostCommentEditor.tsx index bf782b0..61c755d 100644 --- a/apps/web/src/components/models/post/detail/PostCommentEditor.tsx +++ b/apps/web/src/components/models/post/detail/PostCommentEditor.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useState } from "react"; +import React, { useContext, useRef, useState } from "react"; import { motion } from "framer-motion"; import { Button, Input, Tabs } from "antd"; import QuillEditor from "@web/src/components/common/editor/quill/QuillEditor"; @@ -19,6 +19,7 @@ export default function PostCommentEditor() { const [signature, setSignature] = useState(undefined); const [fileIds, setFileIds] = useState([]); const { create } = usePost(); + const uploaderRef = useRef<{ reset: () => void }>(null); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); @@ -46,7 +47,10 @@ export default function PostCommentEditor() { }); toast.success("发布成功!"); setContent(""); - setFileIds([]); + setFileIds([]); // 重置上传组件状态 + // if (uploaderRef.current) { + // uploaderRef.current.reset(); + // } } catch (error) { toast.error("发布失败,请稍后重试"); console.error("Error posting comment:", error); @@ -86,6 +90,8 @@ export default function PostCommentEditor() {
{ console.log("ids", value); setFileIds(value); diff --git a/apps/web/src/hooks/useTusUpload.ts b/apps/web/src/hooks/useTusUpload.ts index 38ff95d..f6fca26 100644 --- a/apps/web/src/hooks/useTusUpload.ts +++ b/apps/web/src/hooks/useTusUpload.ts @@ -45,12 +45,12 @@ export function useTusUpload() { onError: (error: Error) => void, fileKey: string // 添加文件唯一标识 ) => { - if (!file || !file.name || !file.type) { - const error = new Error("不可上传该类型文件"); - setUploadError(error.message); - onError(error); - return; - } + // if (!file || !file.name || !file.type) { + // const error = new Error("不可上传该类型文件"); + // setUploadError(error.message); + // onError(error); + // return; + // } setIsUploading(true); setUploadProgress((prev) => ({ ...prev, [fileKey]: 0 }));