import React, { useState, useMemo } from "react"; import { Tabs, Button, message, Image, Row, Col, Modal, Input, Alert, } 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 } from "packages/common/dist"; 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 [description, setDescription] = useState(''); // 检查是否为域管理员 const isDomainAdmin = useMemo(() => { return hasSomePermissions("MANAGE_DOM_STAFF", "MANAGE_ANY_STAFF"); // 使用权限检查而不是角色名称 }, [hasSomePermissions]); // 获取资源列表 const { data: resources, refetch, }: { data: ResourceDto[]; refetch: () => void } = api.resource.findMany.useQuery({ where: { deletedAt: null, postId: null, }, orderBy: { createdAt: "desc", }, }); // 处理资源数据 const { imageResources, fileResources } = useMemo(() => { if (!resources) return { imageResources: [], fileResources: [] }; 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); return { ...resource, url: isImg ? getCompressedImageUrl(original) : original, originalUrl: original, isImage: isImg, }; }) .filter(Boolean); return { imageResources: processedResources.filter((res) => res.isImage), fileResources: processedResources.filter((res) => !res.isImage), }; }, [resources]); 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, // description: description.trim(), isPublic: true, }, }); } catch (error) { if ( error instanceof Error && error.message.includes("Unique constraint failed") ) { console.warn(`文件 ${fileId} 已存在,跳过`); continue; } throw error; } } message.success("上传成功!"); setFileIds([]); // setDescription(''); 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 (

锦囊资源上传

支持视频、图片、文档、PPT等多种格式文件

{!isAuthenticated && ( )} {isAuthenticated && !isDomainAdmin && ( )} {/* 上传区域 */}
{ if (!isDomainAdmin) { message.error("只有管理员才能上传文件"); return; } setFileIds(value); }} /> {/* {!isDomainAdmin && (
只有管理员才能使用上传功能
)} */}
{isDomainAdmin && fileIds.length > 0 && (
)} {/* 文件展示区域 */}
{/* 图片资源展示 */} {imageResources?.length > 0 && (

图片列表

{imageResources.map((resource) => (
{resource.title}
{resource.title} {isDomainAdmin && (
))}
)} {/* 其他文件资源展示 */} {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 && (
))}
)}
); }