diff --git a/apps/server/src/auth/utils.ts b/apps/server/src/auth/utils.ts index b1b2a88..ef8968d 100755 --- a/apps/server/src/auth/utils.ts +++ b/apps/server/src/auth/utils.ts @@ -155,7 +155,7 @@ export class UserProfileService { where: { id }, select: { id: true, - avatar:true, + avatar: true, deptId: true, department: true, domainId: true, diff --git a/apps/web/src/app/admin/base-setting/page.tsx b/apps/web/src/app/admin/base-setting/page.tsx index eb43d6b..c0aed70 100755 --- a/apps/web/src/app/admin/base-setting/page.tsx +++ b/apps/web/src/app/admin/base-setting/page.tsx @@ -3,6 +3,7 @@ import { useContext, useEffect, useState } from "react"; import { Button, Form, Input, message, theme } from "antd"; import { useAppConfig } from "@nice/client"; import { useAuth } from "@web/src/providers/auth-provider"; +import MultiImageUploader from "@web/src/components/common/uploader/MultiImageUploader"; import FixedHeader from "@web/src/components/layout/fix-header"; import { useForm } from "antd/es/form/Form"; @@ -26,6 +27,7 @@ export default function BaseSettingPage() { const { user, hasSomePermissions } = useAuth(); const context = useContext(MainLayoutContext); const pageWidth = context?.pageWidth; + // const [meta,setMeta ] = useState<>(baseSetting); function handleFieldsChange() { setIsFormChanged(true); } @@ -129,7 +131,7 @@ export default function BaseSettingPage() { - + {/*
+ ghost> 清除行模型缓存
diff --git a/apps/web/src/app/main/courses/components/FilterSection.tsx b/apps/web/src/app/main/courses/components/FilterSection.tsx index 5ffc49d..69fd828 100755 --- a/apps/web/src/app/main/courses/components/FilterSection.tsx +++ b/apps/web/src/app/main/courses/components/FilterSection.tsx @@ -85,27 +85,6 @@ export default function FilterSection({ })} - -
-

难度等级

- onLevelChange(e.target.value)} - className="flex flex-col space-y-3"> - {levels.isLoading ? ( - - ) : ( - <> - 全部难度 - {levels.categories.map((level) => ( - - {level} - - ))} - - )} - -
); } diff --git a/apps/web/src/app/main/home/components/CategorySection.tsx b/apps/web/src/app/main/home/components/CategorySection.tsx index e06a5da..d0735fa 100755 --- a/apps/web/src/app/main/home/components/CategorySection.tsx +++ b/apps/web/src/app/main/home/components/CategorySection.tsx @@ -69,6 +69,8 @@ const CategorySection = () => { const [displayedCategories,setDisplayedCategories] = useState([]) useEffect(() => { console.log(courseCategoriesData); + // 如果 showAll 为 true,则显示所有分类数据, +// 如果 showAll 为 false,则只显示前 8 个分类数据, if(!isLoading){ if(showAll){ setDisplayedCategories(courseCategoriesData) 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