import React, { useState, useMemo } from "react"; import { Tabs, Button, message, Image, Row, Col, Modal, Input, Alert, Pagination, Select, Space, Tag, } from "antd"; import { TusUploader } from "@web/src/components/common/uploader/TusUploader"; import { SendOutlined, DeleteOutlined, LoginOutlined } from "@ant-design/icons"; import { api } from "@nice/client"; import dayjs from "dayjs"; import { env } from "@web/src/env"; import { getFileIcon } from "@web/src/components/models/post/detail/utils"; import { formatFileSize, getCompressedImageUrl } from "@nice/utils"; import { ResourceDto, RoleName, ResourceType } from "@nice/common"; import { useAuth } from "@web/src/providers/auth-provider"; const { TabPane } = Tabs; export function VideoContent() { const { isAuthenticated, user, hasSomePermissions } = useAuth(); const [fileIds, setFileIds] = useState([]); const [uploaderKey, setUploaderKey] = useState(0); const [searchTerm, setSearchTerm] = useState(""); const [fileType, setFileType] = useState("all"); // 分页状态 const [imagePage, setImagePage] = useState(1); const [filePage, setFilePage] = useState(1); const pageSize = 12; // 每页显示的数量 // 检查是否为域管理员 const isDomainAdmin = useMemo(() => { return hasSomePermissions("MANAGE_DOM_STAFF", "MANAGE_ANY_STAFF"); }, [hasSomePermissions]); // 获取资源列表 const { data: resources, refetch, isLoading, }: { data: ResourceDto[]; refetch: () => void; isLoading: boolean; } = api.resource.findMany.useQuery({ where: { deletedAt: null, postId: null, }, orderBy: { createdAt: "desc", }, }); // 定义常见文件类型和它们的扩展名 const fileTypes = { all: { label: "全部", extensions: [] }, document: { label: "文档", extensions: ["doc", "docx", "pdf", "txt"] }, spreadsheet: { label: "表格", extensions: ["xls", "xlsx", "csv"] }, presentation: { label: "ppt", extensions: ["ppt", "pptx"] }, video: { label: "音视频", extensions: ["mp4", "avi", "mov", "webm","mp3", "wav", "ogg"] }, archive: { label: "压缩包", extensions: ["zip", "rar", "7z"] }, }; // 修改资源处理逻辑,加入文件类型筛选 const { imageResources, fileResources, imagePagination, filePagination } = useMemo(() => { if (!resources) { return { imageResources: [], fileResources: [], imagePagination: { total: 0, data: [] }, filePagination: { total: 0, data: [] }, }; } const isImage = (url: string) => /\.(png|jpg|jpeg|gif|webp)$/i.test(url); const processedResources = resources .map((resource) => { if (!resource?.url) return null; const original = `http://${env.SERVER_IP}:${env.UPLOAD_PORT}/uploads/${resource.url}`; const isImg = isImage(resource.url); // 提取文件扩展名 const extension = resource.url.split(".").pop()?.toLowerCase() || ""; const displayTitle = resource.title || resource.meta?.filename || "未命名文件"; const searchableFilename = resource.meta?.filename || ""; return { ...resource, url: isImg ? getCompressedImageUrl(original) : original, originalUrl: original, isImage: isImg, title: displayTitle, searchableFilename: searchableFilename, extension: extension, }; }) .filter(Boolean); // 根据搜索词和文件类型筛选 const filteredFileResources = processedResources.filter((res) => { // 首先检查是否符合搜索词 const matchesSearch = res.searchableFilename .toLowerCase() .includes(searchTerm.toLowerCase()); // 然后检查文件类型 const matchesType = fileType === "all" || fileTypes[fileType]?.extensions.includes(res.extension); return !res.isImage && matchesSearch && matchesType; }); const allImageResources = processedResources.filter((res) => res.isImage); // 分页处理 const imageStart = (imagePage - 1) * pageSize; const fileStart = (filePage - 1) * pageSize; return { imageResources: allImageResources.slice( imageStart, imageStart + pageSize ), fileResources: filteredFileResources.slice( fileStart, fileStart + pageSize ), imagePagination: { total: allImageResources.length, data: allImageResources, }, filePagination: { total: filteredFileResources.length, data: filteredFileResources, }, }; }, [resources, imagePage, filePage, searchTerm, fileType]); // 添加fileType依赖 const createMutation = api.resource.create.useMutation({}); const handleSubmit = async () => { if (!isAuthenticated) { message.error("请先登录"); return; } if (!isDomainAdmin) { message.error("只有管理员才能上传文件"); return; } if (!fileIds.length) { message.error("请先上传文件"); return; } try { // 逐个上传文件,而不是使用 Promise.all for (const fileId of fileIds) { try { await createMutation.mutateAsync({ data: { fileId, isPublic: true, }, }); } catch (error) { if ( error instanceof Error && error.message.includes("Unique constraint failed") ) { console.warn(`文件 ${fileId} 已存在,跳过`); continue; } throw error; } } message.success("上传成功!"); setFileIds([]); setUploaderKey((prev) => prev + 1); refetch(); // 刷新列表 } catch (error) { console.error("Error uploading:", error); message.error("上传失败,请稍后重试"); } }; // 删除资源 const deleteMutation = api.resource.softDeleteByIds.useMutation(); const handleDelete = async (id: string) => { if (!isAuthenticated) { message.error("请先登录"); return; } if (!isDomainAdmin) { message.error("只有管理员才能删除文件"); return; } console.log("Delete resource id:", id); try { const confirmed = await new Promise((resolve) => { Modal.confirm({ title: "确认删除", content: "确定要删除这个文件吗?此操作不可恢复。", okText: "确认", cancelText: "取消", onOk: () => resolve(true), onCancel: () => resolve(false), }); }); if (!confirmed) return; await deleteMutation.mutateAsync({ ids: [id], }); } catch (error) { console.error("Delete error:", error); message.error("删除失败,请重试"); } refetch(); message.success("删除成功"); }; return (
{/*

资源上传

*/}

支持视频、excel、文档、ppt等多种格式文件

setSearchTerm(value)} onChange={(e) => setSearchTerm(e.target.value)} style={{ width: 300 }} />