diff --git a/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/application/KnowledgeBaseService.java b/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/application/KnowledgeBaseService.java index 6f24f1b..c739774 100644 --- a/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/application/KnowledgeBaseService.java +++ b/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/application/KnowledgeBaseService.java @@ -140,6 +140,18 @@ public class KnowledgeBaseService { return PagedResponse.of(respList, page.getCurrent(), page.getTotal(), page.getPages()); } + public KnowledgeBaseStatisticsResp getStatistics() { + KnowledgeBaseStatisticsResp resp = new KnowledgeBaseStatisticsResp(); + resp.setTotalKnowledgeBases(knowledgeBaseRepository.count()); + + RagFileStatistics fileStatistics = ragFileRepository.getStatistics(); + if (fileStatistics != null) { + resp.setTotalFiles(fileStatistics.getTotalFiles() != null ? fileStatistics.getTotalFiles() : 0L); + resp.setTotalSize(fileStatistics.getTotalSize() != null ? fileStatistics.getTotalSize() : 0L); + } + return resp; + } + @Transactional(rollbackFor = Exception.class) public void addFiles(AddFilesReq request) { KnowledgeBase knowledgeBase = Optional.ofNullable(knowledgeBaseRepository.getById(request.getKnowledgeBaseId())) diff --git a/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/domain/repository/RagFileRepository.java b/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/domain/repository/RagFileRepository.java index 61b86dd..63f3e7a 100644 --- a/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/domain/repository/RagFileRepository.java +++ b/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/domain/repository/RagFileRepository.java @@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.repository.IRepository; import com.datamate.rag.indexer.domain.model.RagFile; import com.datamate.rag.indexer.interfaces.dto.KnowledgeBaseFileSearchReq; import com.datamate.rag.indexer.interfaces.dto.RagFileReq; +import com.datamate.rag.indexer.interfaces.dto.RagFileStatistics; import java.util.List; @@ -24,4 +25,6 @@ public interface RagFileRepository extends IRepository { IPage page(IPage page, RagFileReq request); IPage searchPage(IPage page, KnowledgeBaseFileSearchReq request); + + RagFileStatistics getStatistics(); } diff --git a/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/infrastructure/persistence/impl/RagFileRepositoryImpl.java b/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/infrastructure/persistence/impl/RagFileRepositoryImpl.java index 14b4dd8..77d9aea 100644 --- a/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/infrastructure/persistence/impl/RagFileRepositoryImpl.java +++ b/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/infrastructure/persistence/impl/RagFileRepositoryImpl.java @@ -8,6 +8,7 @@ import com.datamate.rag.indexer.domain.repository.RagFileRepository; import com.datamate.rag.indexer.infrastructure.persistence.mapper.RagFileMapper; import com.datamate.rag.indexer.interfaces.dto.KnowledgeBaseFileSearchReq; import com.datamate.rag.indexer.interfaces.dto.RagFileReq; +import com.datamate.rag.indexer.interfaces.dto.RagFileStatistics; import org.springframework.stereotype.Repository; import org.springframework.util.StringUtils; @@ -60,6 +61,11 @@ public class RagFileRepositoryImpl extends CrudRepository { + @Select("SELECT COUNT(*) AS totalFiles, " + + "COALESCE(SUM(df.file_size), 0) AS totalSize " + + "FROM t_rag_file rf " + + "LEFT JOIN t_dm_dataset_files df ON rf.file_id = df.id") + RagFileStatistics getStatistics(); } diff --git a/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/interfaces/KnowledgeBaseController.java b/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/interfaces/KnowledgeBaseController.java index 3bde7de..8929927 100644 --- a/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/interfaces/KnowledgeBaseController.java +++ b/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/interfaces/KnowledgeBaseController.java @@ -80,6 +80,16 @@ public class KnowledgeBaseController { return knowledgeBaseService.list(request); } + /** + * 获取知识库统计信息 + * + * @return 知识库统计信息 + */ + @GetMapping("/statistics") + public KnowledgeBaseStatisticsResp statistics() { + return knowledgeBaseService.getStatistics(); + } + /** * 添加文件到知识库 * diff --git a/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/interfaces/dto/KnowledgeBaseStatisticsResp.java b/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/interfaces/dto/KnowledgeBaseStatisticsResp.java new file mode 100644 index 0000000..3aaffab --- /dev/null +++ b/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/interfaces/dto/KnowledgeBaseStatisticsResp.java @@ -0,0 +1,15 @@ +package com.datamate.rag.indexer.interfaces.dto; + +import lombok.Getter; +import lombok.Setter; + +/** + * 知识库统计响应 + */ +@Getter +@Setter +public class KnowledgeBaseStatisticsResp { + private Long totalKnowledgeBases = 0L; + private Long totalFiles = 0L; + private Long totalSize = 0L; +} diff --git a/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/interfaces/dto/RagFileStatistics.java b/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/interfaces/dto/RagFileStatistics.java new file mode 100644 index 0000000..0cc06d9 --- /dev/null +++ b/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/interfaces/dto/RagFileStatistics.java @@ -0,0 +1,14 @@ +package com.datamate.rag.indexer.interfaces.dto; + +import lombok.Getter; +import lombok.Setter; + +/** + * 知识库文件统计 + */ +@Getter +@Setter +public class RagFileStatistics { + private Long totalFiles = 0L; + private Long totalSize = 0L; +} diff --git a/frontend/src/pages/KnowledgeBase/Home/KnowledgeBasePage.tsx b/frontend/src/pages/KnowledgeBase/Home/KnowledgeBasePage.tsx index 55ddb53..254aa40 100644 --- a/frontend/src/pages/KnowledgeBase/Home/KnowledgeBasePage.tsx +++ b/frontend/src/pages/KnowledgeBase/Home/KnowledgeBasePage.tsx @@ -1,23 +1,48 @@ -import { useState } from "react"; -import { Card, Button, Table, Tooltip, message } from "antd"; +import { useCallback, useEffect, useState } from "react"; +import { Card, Button, Table, Tooltip, message, Statistic } from "antd"; import { DeleteOutlined, EditOutlined } from "@ant-design/icons"; import { SearchControls } from "@/components/SearchControls"; import { useNavigate } from "react-router"; import CardView from "@/components/CardView"; import { deleteKnowledgeBaseByIdUsingDelete, + getKnowledgeBaseStatisticsUsingGet, queryKnowledgeBasesUsingPost, } from "../knowledge-base.api"; import useFetchData from "@/hooks/useFetchData"; -import { KnowledgeBaseItem } from "../knowledge-base.model"; +import { KnowledgeBaseItem, KnowledgeBaseStatistics } from "../knowledge-base.model"; import CreateKnowledgeBase from "../components/CreateKnowledgeBase"; import { mapKnowledgeBase } from "../knowledge-base.const"; +import { formatBytes } from "@/utils/unit"; + +type StatisticsItem = { + title: string; + value: number | string; +}; + +const DEFAULT_STATISTICS: StatisticsItem[] = [ + { + title: "知识库总数", + value: 0, + }, + { + title: "文件总数", + value: 0, + }, + { + title: "总大小", + value: "0 B", + }, +]; export default function KnowledgeBasePage() { const navigate = useNavigate(); const [viewMode, setViewMode] = useState<"card" | "list">("card"); const [isEdit, setIsEdit] = useState(false); const [currentKB, setCurrentKB] = useState(null); + const [statisticsData, setStatisticsData] = useState( + DEFAULT_STATISTICS + ); const { loading, tableData, @@ -32,11 +57,43 @@ export default function KnowledgeBasePage() { (kb) => mapKnowledgeBase(kb, false) // 在首页不显示索引模型和文本理解模型字段 ); + const fetchStatistics = useCallback(async () => { + try { + const { data } = await getKnowledgeBaseStatisticsUsingGet(); + const stats = data as KnowledgeBaseStatistics | undefined; + setStatisticsData([ + { + title: "知识库总数", + value: stats?.totalKnowledgeBases ?? 0, + }, + { + title: "文件总数", + value: stats?.totalFiles ?? 0, + }, + { + title: "总大小", + value: formatBytes(stats?.totalSize ?? 0), + }, + ]); + } catch { + message.error("统计数据加载失败"); + setStatisticsData(DEFAULT_STATISTICS); + } + }, []); + + const refreshAll = useCallback(async () => { + await Promise.all([fetchData(), fetchStatistics()]); + }, [fetchData, fetchStatistics]); + + useEffect(() => { + fetchStatistics(); + }, [fetchStatistics]); + const handleDeleteKB = async (kb: KnowledgeBaseItem) => { try { await deleteKnowledgeBaseByIdUsingDelete(kb.id); message.success("知识库删除成功"); - fetchData(); + await refreshAll(); } catch { message.error("知识库删除失败"); } @@ -140,7 +197,7 @@ export default function KnowledgeBasePage() { isEdit={isEdit} data={currentKB} onUpdate={() => { - fetchData(); + refreshAll(); }} onClose={() => { setIsEdit(false); @@ -150,6 +207,20 @@ export default function KnowledgeBasePage() { +
+ +
+ {statisticsData.map((item) => ( + + ))} +
+
+
+ {viewMode === "card" ? (