import { useCallback, useEffect, useMemo, useState } from "react"; import { App, Breadcrumb, Button, Card, Descriptions, Empty, Modal, Table, Tag, Tooltip, } from "antd"; import { DeleteOutlined, EditOutlined, EyeOutlined, PlusOutlined } from "@ant-design/icons"; import { useNavigate, useParams } from "react-router"; import DetailHeader from "@/components/DetailHeader"; import { SearchControls } from "@/components/SearchControls"; import useFetchData from "@/hooks/useFetchData"; import { deleteKnowledgeItemByIdUsingDelete, deleteKnowledgeSetByIdUsingDelete, queryKnowledgeItemsUsingGet, queryKnowledgeSetByIdUsingGet, } from "../knowledge-management.api"; import { knowledgeContentTypeOptions, knowledgeStatusMap, mapKnowledgeItem, KnowledgeItemView, } from "../knowledge-management.const"; import { KnowledgeItem, KnowledgeSet, KnowledgeContentType, KnowledgeStatusType, } from "../knowledge-management.model"; import CreateKnowledgeSet from "../components/CreateKnowledgeSet"; import KnowledgeItemEditor from "../components/KnowledgeItemEditor"; import ImportKnowledgeItemsDialog from "../components/ImportKnowledgeItemsDialog"; import { formatDate } from "@/utils/unit"; const MAX_READ_LENGTH = 50000; const KnowledgeSetDetail = () => { const navigate = useNavigate(); const { message } = App.useApp(); const { id } = useParams<{ id: string }>(); const [knowledgeSet, setKnowledgeSet] = useState(null); const [showEdit, setShowEdit] = useState(false); const [itemEditorOpen, setItemEditorOpen] = useState(false); const [currentItem, setCurrentItem] = useState(null); const [readItemId, setReadItemId] = useState(null); const [readModalOpen, setReadModalOpen] = useState(false); const [readContent, setReadContent] = useState(""); const [readTitle, setReadTitle] = useState(""); const fetchKnowledgeSet = useCallback(async () => { if (!id) return; const { data } = await queryKnowledgeSetByIdUsingGet(id); setKnowledgeSet(data); }, [id]); useEffect(() => { fetchKnowledgeSet(); }, [fetchKnowledgeSet]); const { loading, tableData: items, searchParams, pagination, fetchData, setSearchParams, handleFiltersChange, handleKeywordChange, } = useFetchData( (params) => (id ? queryKnowledgeItemsUsingGet(id, params) : Promise.resolve({ data: [] })), mapKnowledgeItem, 30000, false, [], 0 ); const isReadOnly = knowledgeSet?.status === KnowledgeStatusType.ARCHIVED || knowledgeSet?.status === KnowledgeStatusType.DEPRECATED; const handleDeleteSet = async () => { if (!knowledgeSet) return; await deleteKnowledgeSetByIdUsingDelete(knowledgeSet.id); message.success("知识集已删除"); navigate("/data/knowledge-management"); }; const handleDeleteItem = async (item: KnowledgeItemView) => { if (!id) return; await deleteKnowledgeItemByIdUsingDelete(id, item.id); message.success("知识条目已删除"); fetchData(); }; const isReadableItem = (record: KnowledgeItemView) => { return ( record.contentType === KnowledgeContentType.TEXT || record.contentType === KnowledgeContentType.MARKDOWN ); }; const handleReadItem = async (record: KnowledgeItemView) => { setReadItemId(record.id); setReadTitle(record.title || "知识条目"); if (!record.sourceDatasetId || !record.sourceFileId) { const content = record.content || ""; if (content.length > MAX_READ_LENGTH) { setReadContent( `${content.slice(0, MAX_READ_LENGTH)}\n\n... (内容过长,仅显示前 ${MAX_READ_LENGTH} 字符)` ); } else { setReadContent(content); } setReadModalOpen(true); setReadItemId(null); return; } const fileUrl = `/api/data-management/datasets/${record.sourceDatasetId}/files/${record.sourceFileId}/download`; try { const response = await fetch(fileUrl); if (!response.ok) { throw new Error("下载失败"); } const text = await response.text(); if (text.length > MAX_READ_LENGTH) { setReadContent( `${text.slice(0, MAX_READ_LENGTH)}\n\n... (内容过长,仅显示前 ${MAX_READ_LENGTH} 字符)` ); } else { setReadContent(text); } setReadModalOpen(true); } catch (error) { console.error("读取知识条目失败", error); message.error("读取失败,请稍后重试"); } finally { setReadItemId(null); } }; const statusMeta = knowledgeSet?.status ? knowledgeStatusMap[knowledgeSet.status] : undefined; const statistics = useMemo( () => [ { key: "items", icon: , label: "条目数", value: pagination.total || 0, }, { key: "updated", icon: , label: "更新时间", value: knowledgeSet?.updatedAt ? formatDate(knowledgeSet.updatedAt) : "-", }, ], [pagination.total, knowledgeSet?.updatedAt] ); const itemColumns = [ { title: "标题", dataIndex: "title", key: "title", fixed: "left" as const, width: 220, ellipsis: true, }, { title: "状态", dataIndex: "status", key: "status", width: 120, render: (status: KnowledgeItemView["status"]) => ( {status?.label} ), }, { title: "类型", dataIndex: "contentType", key: "contentType", width: 120, render: (contentType: string) => knowledgeContentTypeOptions.find((opt) => opt.value === contentType)?.label || contentType, }, { title: "负责人", dataIndex: "owner", key: "owner", width: 120, ellipsis: true, }, { title: "来源", dataIndex: "sourceType", key: "sourceType", width: 140, ellipsis: true, }, { title: "更新时间", dataIndex: "updatedAt", key: "updatedAt", width: 180, ellipsis: true, }, { title: "操作", key: "actions", width: 200, render: (_: unknown, record: KnowledgeItemView) => (
), }, ]; return (
, onClick: () => setShowEdit(true), danger: false, }, { key: "delete", label: "删除", icon: , danger: true, confirm: { title: "确认删除该知识集吗?", description: "删除后将无法恢复,请谨慎操作。", cancelText: "取消", okText: "删除", okType: "danger", onConfirm: () => handleDeleteSet(), }, }, ]} /> { setShowEdit(false); fetchKnowledgeSet(); }} onClose={() => setShowEdit(false)} /> {knowledgeSet?.domain || "-"} {knowledgeSet?.businessLine || "-"} {knowledgeSet?.owner || "-"} {knowledgeSet?.sensitivity || "-"} {knowledgeSet?.validFrom || "-"} ~ {knowledgeSet?.validTo || "-"} {knowledgeSet?.sourceType || "-"}
setSearchParams({ ...searchParams, filter: { type: [], status: [], tags: [] } })} showViewToggle={false} showReload={false} />
{items.length === 0 ? ( ) : ( )} { setItemEditorOpen(false); setCurrentItem(null); }} onSuccess={() => { setItemEditorOpen(false); setCurrentItem(null); fetchData(); }} /> { setReadModalOpen(false); setReadContent(""); setReadTitle(""); }} footer={[ , ]} >
          {readContent}
        
); }; export default KnowledgeSetDetail;