= ({
{/*
+ ghost>
清除行模型缓存
diff --git a/apps/web/src/components/common/uploader/MultiImageUploader.tsx b/apps/web/src/components/common/uploader/MultiImageUploader.tsx
new file mode 100644
index 0000000..5f6d026
--- /dev/null
+++ b/apps/web/src/components/common/uploader/MultiImageUploader.tsx
@@ -0,0 +1,173 @@
+import React, { useState } from 'react';
+import { Upload, Modal, message } from 'antd';
+import { PlusOutlined } from '@ant-design/icons';
+import { useTusUpload } from "@web/src/hooks/useTusUpload";
+import toast from "react-hot-toast";
+
+
+export interface MultiImageUploadProps {
+ value?: string;
+ placeholder?: string;
+ className?: string;
+ onChange?: (value: string) => void;
+ compressed?: boolean;
+ style?: React.CSSProperties; // 添加style属性
+}
+
+interface UploadFile {
+ name: string;
+ progress: number;
+ status: "uploading" | "done" | "error";
+ url?: string;
+ fileKey?: string;
+ uid: string;
+}
+const MultiImageUpload: React.FC = ({
+ value,
+ onChange,
+ compressed = false,
+ className,
+ placeholder = "点击上传",
+ style, // 解构style属性
+}) => {
+ const [fileList, setFileList] = useState(null); // 存储已上传的文件列表
+ const [previewVisible, setPreviewVisible] = useState(false); // 控制预览模态框的显示
+ const [previewImage, setPreviewImage] = useState(''); // 当前预览的图片URL
+ const { handleFileUpload, uploadProgress } = useTusUpload();
+ const [compressedUrl, setCompressedUrl] = useState(value || "");
+ const [url, setUrl] = useState(value || "");
+ const [uploading, setUploading] = useState(false);
+
+ // 处理文件上传前的校验
+ const beforeUpload = (file) => {
+ const isImage = file.type.startsWith('image/');
+ if (!isImage) {
+ message.error('只能上传图片文件!');
+ }
+ const isLt10M = file.size / 1024 / 1024 < 10;
+ if (!isLt10M) {
+ message.error('图片大小不能超过10MB!');
+ }
+ return isImage && isLt10M;
+ };
+
+ // 处理文件列表变化
+ const handleChange = async ({ fileList }) => {
+ //setFileList(fileList);
+ console.log(fileList);
+ const imageUrls = fileList.map(file => {
+ return URL.createObjectURL(file.originFileObj)
+ });
+ console.log("imageUrls", imageUrls);
+
+ const newFileList = fileList.map(file => {
+ return {
+ name: file.name,
+ progress: 0,
+ status: "uploading",
+ //uid: file.uid,
+ fileKey: `${file.name}-${Date.now()}`,
+ //url: file.url,
+ }
+ });
+ console.log("newFileList", newFileList);
+ setUploading(true);
+
+ try {
+ const resFileList = newFileList.map(async (file, index) => {
+ const uploadedUrl = await new Promise((resolve, reject) => {
+ handleFileUpload(
+ fileList[index].originFileObj,
+ (result) => {
+ () => {
+ return {
+ ...newFileList[index],
+ progress: 100,
+ status: "done",
+ fileId: result.fileId,
+ url: result.url,
+ compressedUrl: result.compressedUrl,
+ }
+ }
+ // setFile((prev) => ({
+ // ...prev!,
+ // progress: 100,
+ // status: "done",
+ // fileId: result.fileId,
+ // url: result.url,
+ // compressedUrl: result.compressedUrl,
+ // }));
+ setUrl(result.url);
+ setCompressedUrl(result.compressedUrl);
+ // 直接使用 result 中的最新值
+ resolve(compressed ? result.compressedUrl : result.url);
+ },
+ (error) => {
+ reject(error);
+ },
+ newFileList[index]?.fileKey
+ );
+ });
+ })
+ // await new Promise((resolve) => setTimeout(resolve,4999)); // 方法1:使用 await 暂停执行
+ // 使用 resolved 的最新值调用 onChange
+ // 强制刷新 Avatar 组件
+ // setAvatarKey((prev) => prev + 1); // 修改 key 强制重新挂载
+ onChange?.(resFileList);
+ console.log(resFileList);
+ toast.success("图片上传成功");
+ } catch (error) {
+ console.error("上传错误:", error);
+ toast.error("图片上传失败");
+ // setFile((prev) => ({ ...prev!, status: "error" }));
+ } finally {
+ setUploading(false);
+ }
+ };uploadProgress
+
+ // 处理预览
+ const handlePreview = async (file) => {
+ if (!file.url && !file.preview) {
+ file.preview = await getBase64(file.originFileObj);
+ }
+ setPreviewImage(file.url || file.preview);
+ setPreviewVisible(true);
+ };
+
+ // 关闭预览模态框
+ const handleCancel = () => setPreviewVisible(false);
+
+ // 将文件转换为Base64格式(用于预览)
+ const getBase64 = (file) => {
+ return new Promise((resolve, reject) => {
+ const reader = new FileReader();
+ reader.readAsDataURL(file);
+ reader.onload = () => resolve(reader.result);
+ reader.onerror = (error) => reject(error);
+ });
+ };
+
+ return (
+
+
+
+
+ 点击或拖拽文件到此区域上传
+ 支持单个或批量上传
+
+
+
+
+
+ );
+};
+
+export default MultiImageUpload;
diff --git a/apps/web/src/components/common/uploader/TestUploader.tsx b/apps/web/src/components/common/uploader/TestUploader.tsx
new file mode 100644
index 0000000..d4c196e
--- /dev/null
+++ b/apps/web/src/components/common/uploader/TestUploader.tsx
@@ -0,0 +1,18 @@
+import AvatarUploader from "./AvatarUploader"
+
+
+
+interface TestUploaderProps {
+ value?: string[],
+ onChange?: (value: string[]) => void
+}
+
+export function TestUploader({
+ value,
+ onChange,
+}: TestUploaderProps) {
+
+ return <>
+
+ >
+}
\ No newline at end of file