This commit is contained in:
ditiqi 2025-02-25 17:42:56 +08:00
commit fac9999cf5
6 changed files with 198 additions and 24 deletions

View File

@ -155,7 +155,7 @@ export class UserProfileService {
where: { id },
select: {
id: true,
avatar:true,
avatar: true,
deptId: true,
department: true,
domainId: true,

View File

@ -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() {
<Form.Item
label="运维单位"
name={["appConfig", "slides"]}>
<Input></Input>
<MultiImageUploader></MultiImageUploader>
</Form.Item>
</div>
{/* <div

View File

@ -85,27 +85,6 @@ export default function FilterSection({
})}
<Divider className="my-6" />
<div>
<h3 className="text-lg font-medium mb-4"></h3>
<Radio.Group
value={selectedLevel}
onChange={(e) => onLevelChange(e.target.value)}
className="flex flex-col space-y-3">
{levels.isLoading ? (
<Spin />
) : (
<>
<Radio value=""></Radio>
{levels.categories.map((level) => (
<Radio key={level} value={level}>
{level}
</Radio>
))}
</>
)}
</Radio.Group>
</div>
</div>
);
}

View File

@ -69,6 +69,8 @@ const CategorySection = () => {
const [displayedCategories,setDisplayedCategories] = useState<TermDto[]>([])
useEffect(() => {
console.log(courseCategoriesData);
// 如果 showAll 为 true则显示所有分类数据
// 如果 showAll 为 false则只显示前 8 个分类数据,
if(!isLoading){
if(showAll){
setDisplayedCategories(courseCategoriesData)

View File

@ -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<MultiImageUploadProps> = ({
value,
onChange,
compressed = false,
className,
placeholder = "点击上传",
style, // 解构style属性
}) => {
const [fileList, setFileList] = useState<UploadFile[] | null>(null); // 存储已上传的文件列表
const [previewVisible, setPreviewVisible] = useState(false); // 控制预览模态框的显示
const [previewImage, setPreviewImage] = useState(''); // 当前预览的图片URL
const { handleFileUpload, uploadProgress } = useTusUpload();
const [compressedUrl, setCompressedUrl] = useState<string>(value || "");
const [url, setUrl] = useState<string>(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<string>((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 (
<div>
<Upload.Dragger
listType="picture-card" // 卡片样式
fileList={fileList} // 已上传的文件列表
beforeUpload={beforeUpload} // 上传前的校验
onChange={handleChange} // 文件列表变化时的回调
onPreview={handlePreview} // 预览回调
multiple // 支持多选
// style={{ width: '200px' }}
>
<p className="ant-upload-drag-icon">
</p>
<p className="ant-upload-text"></p>
<p className="ant-upload-hint"></p>
</Upload.Dragger>
<Modal visible={previewVisible} footer={null} onCancel={handleCancel}>
<img alt="预览" style={{ width: '100%' }} src={previewImage} />
</Modal>
</div>
);
};
export default MultiImageUpload;

View File

@ -0,0 +1,18 @@
import AvatarUploader from "./AvatarUploader"
interface TestUploaderProps {
value?: string[],
onChange?: (value: string[]) => void
}
export function TestUploader({
value,
onChange,
}: TestUploaderProps) {
return <>
<AvatarUploader></AvatarUploader>
</>
}