import React, { useState, useMemo } from "react"; import { Tabs, Button, message, Image, Row, Col, Modal, Input, Alert, Pagination, } 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 [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 { 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); // 确保 title 存在,优先使用 resource.title,然后是 resource.meta.filename const displayTitle = resource.title || resource.meta?.filename || "未命名文件"; // 用于搜索的名称,确保从 meta.filename 获取(如果存在) const searchableFilename = resource.meta?.filename || ""; return { ...resource, url: isImg ? getCompressedImageUrl(original) : original, originalUrl: original, isImage: isImg, title: displayTitle, // 用于显示 searchableFilename: searchableFilename, // 用于搜索 }; }) .filter(Boolean); // 根据搜索词筛选文件资源 (基于 searchableFilename) const filteredFileResources = processedResources.filter( (res) => !res.isImage && res.searchableFilename .toLowerCase() .includes(searchTerm.toLowerCase()) ); 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]); // searchTerm 作为依赖项 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 }} /> {!isAuthenticated && ( )} {isAuthenticated && !isDomainAdmin && ( )} {/* 上传区域 */}
{ if (!isDomainAdmin) { message.error("只有管理员才能上传文件"); return; } setFileIds(value); }} />
{isDomainAdmin && fileIds.length > 0 && (
)} {/* 文件展示区域 */}
{/* 图片资源展示 */} {/* {imagePagination?.total > 0 && (

图片列表

共 {imagePagination.total} 张图片
*/} {/* {imageResources.map((resource) => (
{resource.title}
{resource.title} {isDomainAdmin && (
))}
*/} {/* 图片分页 */} {/* {imagePagination.total > pageSize && (
setImagePage(page)} showSizeChanger={false} />
)}
)} */} {/* 其他文件资源展示 */} {isLoading ? (
加载中...
) : filePagination?.total > 0 ? (

文件列表

共 {filePagination.total} 个文件
{fileResources.length > 0 && (
{fileResources.map((resource) => (
{getFileIcon(resource.url)}
{resource.title}
{resource.description && (
描述: {resource.description}
)}
{dayjs(resource.createdAt).format("YYYY-MM-DD")} {resource.meta?.size && formatFileSize(resource.meta.size)}
{isDomainAdmin && (
))}
)} {fileResources.length === 0 && searchTerm && (
未找到匹配 "{searchTerm}" 的文件。
)} {/* 文件分页 */} {filePagination.total > pageSize && (
setFilePage(page)} showSizeChanger={false} />
)}
) : (
{searchTerm ? `未找到匹配"${searchTerm}"的文件` : "暂无文件资源"}
)}
); }