You've already forked DataMate
feat(knowledge-management): 添加知识管理搜索功能和统计接口
- 新增知识条目搜索查询和响应DTO - 实现知识管理统计功能,包括总数、文件数和总大小 - 添加数据库查询方法支持文件搜索和统计计算 - 创建知识条目搜索控制器提供REST API - 在前端添加知识管理搜索页面和相关组件 - 更新前端路由配置添加搜索页面入口 - 移除RAG索引服务中的重复统计功能 - 优化前端页面统计数据显示和刷新逻辑
This commit is contained in:
@@ -1,48 +1,23 @@
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { Card, Button, Table, Tooltip, message, Statistic } from "antd";
|
||||
import { useState } from "react";
|
||||
import { Card, Button, Table, Tooltip, message } 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, KnowledgeBaseStatistics } from "../knowledge-base.model";
|
||||
import { KnowledgeBaseItem } 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<KnowledgeBaseItem | null>(null);
|
||||
const [statisticsData, setStatisticsData] = useState<StatisticsItem[]>(
|
||||
DEFAULT_STATISTICS
|
||||
);
|
||||
const {
|
||||
loading,
|
||||
tableData,
|
||||
@@ -57,43 +32,11 @@ 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("知识库删除成功");
|
||||
await refreshAll();
|
||||
fetchData();
|
||||
} catch {
|
||||
message.error("知识库删除失败");
|
||||
}
|
||||
@@ -197,7 +140,7 @@ export default function KnowledgeBasePage() {
|
||||
isEdit={isEdit}
|
||||
data={currentKB}
|
||||
onUpdate={() => {
|
||||
refreshAll();
|
||||
fetchData();
|
||||
}}
|
||||
onClose={() => {
|
||||
setIsEdit(false);
|
||||
@@ -207,20 +150,6 @@ export default function KnowledgeBasePage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 gap-4">
|
||||
<Card>
|
||||
<div className="grid grid-cols-3">
|
||||
{statisticsData.map((item) => (
|
||||
<Statistic
|
||||
title={item.title}
|
||||
key={item.title}
|
||||
value={`${item.value}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<SearchControls
|
||||
searchTerm={searchParams.keyword}
|
||||
onSearchChange={handleKeywordChange}
|
||||
@@ -231,7 +160,7 @@ export default function KnowledgeBasePage() {
|
||||
viewMode={viewMode}
|
||||
onViewModeChange={setViewMode}
|
||||
showViewToggle
|
||||
onReload={refreshAll}
|
||||
onReload={fetchData}
|
||||
/>
|
||||
{viewMode === "card" ? (
|
||||
<CardView
|
||||
|
||||
@@ -38,11 +38,6 @@ export function queryKnowledgeBaseFilesSearchUsingGet(params: RequestParams) {
|
||||
return get("/api/knowledge-base/files/search", params);
|
||||
}
|
||||
|
||||
// 获取知识库统计
|
||||
export function getKnowledgeBaseStatisticsUsingGet() {
|
||||
return get("/api/knowledge-base/statistics");
|
||||
}
|
||||
|
||||
// 添加文件到知识库
|
||||
export function addKnowledgeBaseFilesUsingPost(baseId: string, data: RequestPayload) {
|
||||
return post(`/api/knowledge-base/${baseId}/files`, data);
|
||||
|
||||
@@ -25,12 +25,6 @@ export interface KnowledgeBaseItem {
|
||||
chat: never;
|
||||
}
|
||||
|
||||
export interface KnowledgeBaseStatistics {
|
||||
totalKnowledgeBases: number;
|
||||
totalFiles: number;
|
||||
totalSize: number;
|
||||
}
|
||||
|
||||
export interface KBFile {
|
||||
id: string;
|
||||
fileName: string;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { Card, Button, Table, Tooltip, Tag, App } from "antd";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { Card, Button, Table, Tooltip, Tag, App, Statistic } from "antd";
|
||||
import { DeleteOutlined, EditOutlined } from "@ant-design/icons";
|
||||
import { useNavigate } from "react-router";
|
||||
import CardView from "@/components/CardView";
|
||||
@@ -8,6 +8,7 @@ import TagManager from "@/components/business/TagManagement";
|
||||
import useFetchData from "@/hooks/useFetchData";
|
||||
import {
|
||||
deleteKnowledgeSetByIdUsingDelete,
|
||||
getKnowledgeManagementStatisticsUsingGet,
|
||||
queryKnowledgeSetsUsingGet,
|
||||
} from "../knowledge-management.api";
|
||||
import {
|
||||
@@ -15,7 +16,7 @@ import {
|
||||
mapKnowledgeSet,
|
||||
KnowledgeSetView,
|
||||
} from "../knowledge-management.const";
|
||||
import { KnowledgeSet } from "../knowledge-management.model";
|
||||
import { KnowledgeManagementStatistics, KnowledgeSet } from "../knowledge-management.model";
|
||||
import CreateKnowledgeSet from "../components/CreateKnowledgeSet";
|
||||
import {
|
||||
createDatasetTagUsingPost,
|
||||
@@ -23,6 +24,27 @@ import {
|
||||
queryDatasetTagsUsingGet,
|
||||
updateDatasetTagUsingPut,
|
||||
} from "@/pages/DataManagement/dataset.api";
|
||||
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 KnowledgeManagementPage() {
|
||||
const navigate = useNavigate();
|
||||
@@ -31,6 +53,9 @@ export default function KnowledgeManagementPage() {
|
||||
const [isEdit, setIsEdit] = useState(false);
|
||||
const [currentSet, setCurrentSet] = useState<KnowledgeSet | null>(null);
|
||||
const [tags, setTags] = useState<string[]>([]);
|
||||
const [statisticsData, setStatisticsData] = useState<StatisticsItem[]>(
|
||||
DEFAULT_STATISTICS
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchTags = async () => {
|
||||
@@ -75,10 +100,45 @@ export default function KnowledgeManagementPage() {
|
||||
0
|
||||
);
|
||||
|
||||
const fetchStatistics = useCallback(async () => {
|
||||
try {
|
||||
const { data } = await getKnowledgeManagementStatisticsUsingGet();
|
||||
const stats = data as KnowledgeManagementStatistics | undefined;
|
||||
setStatisticsData([
|
||||
{
|
||||
title: "知识集总数",
|
||||
value: stats?.totalKnowledgeSets ?? 0,
|
||||
},
|
||||
{
|
||||
title: "文件总数",
|
||||
value: stats?.totalFiles ?? 0,
|
||||
},
|
||||
{
|
||||
title: "总大小",
|
||||
value: formatBytes(stats?.totalSize ?? 0),
|
||||
},
|
||||
]);
|
||||
} catch {
|
||||
message.error("统计数据加载失败");
|
||||
setStatisticsData(DEFAULT_STATISTICS);
|
||||
}
|
||||
}, [message]);
|
||||
|
||||
const refreshAll = useCallback(
|
||||
async (extraParams: Record<string, unknown> = {}) => {
|
||||
await Promise.all([fetchData(extraParams), fetchStatistics()]);
|
||||
},
|
||||
[fetchData, fetchStatistics]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
fetchStatistics();
|
||||
}, [fetchStatistics]);
|
||||
|
||||
const handleDeleteSet = async (setId: string) => {
|
||||
await deleteKnowledgeSetByIdUsingDelete(setId);
|
||||
message.success("知识集删除成功");
|
||||
fetchData({ pageOffset: 0 });
|
||||
await refreshAll({ pageOffset: 0 });
|
||||
};
|
||||
|
||||
const operations = [
|
||||
@@ -191,6 +251,9 @@ export default function KnowledgeManagementPage() {
|
||||
<div className="flex items-center justify-between">
|
||||
<h1 className="text-xl font-bold">知识管理</h1>
|
||||
<div className="flex gap-2 items-center">
|
||||
<Button onClick={() => navigate("/data/knowledge-management/search")}>
|
||||
全库搜索
|
||||
</Button>
|
||||
<TagManager
|
||||
onCreate={createDatasetTagUsingPost}
|
||||
onDelete={(ids: string) => deleteDatasetTagUsingDelete({ ids })}
|
||||
@@ -201,7 +264,7 @@ export default function KnowledgeManagementPage() {
|
||||
isEdit={isEdit}
|
||||
data={currentSet}
|
||||
onUpdate={() => {
|
||||
fetchData();
|
||||
refreshAll();
|
||||
}}
|
||||
onClose={() => {
|
||||
setIsEdit(false);
|
||||
@@ -211,6 +274,20 @@ export default function KnowledgeManagementPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 gap-4">
|
||||
<Card>
|
||||
<div className="grid grid-cols-3">
|
||||
{statisticsData.map((item) => (
|
||||
<Statistic
|
||||
title={item.title}
|
||||
key={item.title}
|
||||
value={`${item.value}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<SearchControls
|
||||
searchTerm={searchParams.keyword}
|
||||
onSearchChange={handleKeywordChange}
|
||||
@@ -221,7 +298,7 @@ export default function KnowledgeManagementPage() {
|
||||
viewMode={viewMode}
|
||||
onViewModeChange={setViewMode}
|
||||
showViewToggle
|
||||
onReload={fetchData}
|
||||
onReload={refreshAll}
|
||||
/>
|
||||
|
||||
{viewMode === "card" ? (
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
import { App, Breadcrumb, Button, Input, Table } from "antd";
|
||||
import { useNavigate } from "react-router";
|
||||
import {
|
||||
KnowledgeContentType,
|
||||
KnowledgeItemSearchResult,
|
||||
KnowledgeSourceType,
|
||||
} from "../knowledge-management.model";
|
||||
import {
|
||||
knowledgeContentTypeOptions,
|
||||
knowledgeSourceTypeOptions,
|
||||
} from "../knowledge-management.const";
|
||||
import { searchKnowledgeItemsUsingGet } from "../knowledge-management.api";
|
||||
import { formatBytes, formatDateTime } from "@/utils/unit";
|
||||
|
||||
const buildOptionMap = (options: { label: string; value: string }[]) =>
|
||||
options.reduce<Record<string, string>>((acc, option) => {
|
||||
acc[option.value] = option.label;
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
export default function KnowledgeManagementSearch() {
|
||||
const navigate = useNavigate();
|
||||
const { message } = App.useApp();
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
const [activeKeyword, setActiveKeyword] = useState("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [searched, setSearched] = useState(false);
|
||||
const [results, setResults] = useState<KnowledgeItemSearchResult[]>([]);
|
||||
const [pagination, setPagination] = useState({
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
const contentTypeMap = useMemo(
|
||||
() => buildOptionMap(knowledgeContentTypeOptions),
|
||||
[]
|
||||
);
|
||||
const sourceTypeMap = useMemo(
|
||||
() => buildOptionMap(knowledgeSourceTypeOptions),
|
||||
[]
|
||||
);
|
||||
|
||||
const fetchResults = useCallback(
|
||||
async (keyword: string, page?: number, pageSize?: number) => {
|
||||
const resolvedPage = page ?? pagination.current;
|
||||
const resolvedPageSize = pageSize ?? pagination.pageSize;
|
||||
if (!keyword) {
|
||||
setResults([]);
|
||||
setPagination((prev) => ({ ...prev, total: 0, current: resolvedPage }));
|
||||
setSearched(false);
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
try {
|
||||
const { data } = await searchKnowledgeItemsUsingGet({
|
||||
keyword,
|
||||
page: Math.max(resolvedPage - 1, 0),
|
||||
size: resolvedPageSize,
|
||||
});
|
||||
const content = Array.isArray(data?.content) ? data.content : [];
|
||||
setResults(content);
|
||||
setPagination({
|
||||
current: resolvedPage,
|
||||
pageSize: resolvedPageSize,
|
||||
total: data?.totalElements ?? 0,
|
||||
});
|
||||
setSearched(true);
|
||||
} catch (error) {
|
||||
console.error("Failed to search knowledge items:", error);
|
||||
message.error("检索失败,请稍后重试");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
},
|
||||
[message, pagination]
|
||||
);
|
||||
|
||||
const handleSearch = (value?: string) => {
|
||||
const keyword = (value ?? searchTerm).trim();
|
||||
if (!keyword) {
|
||||
message.warning("请输入文件名");
|
||||
return;
|
||||
}
|
||||
setActiveKeyword(keyword);
|
||||
fetchResults(keyword, 1, pagination.pageSize);
|
||||
};
|
||||
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
title: "知识集",
|
||||
dataIndex: "setName",
|
||||
key: "setName",
|
||||
width: 220,
|
||||
ellipsis: true,
|
||||
render: (text: string) => text || "-",
|
||||
},
|
||||
{
|
||||
title: "文件名",
|
||||
dataIndex: "fileName",
|
||||
key: "fileName",
|
||||
width: 220,
|
||||
ellipsis: true,
|
||||
render: (_: string, record: KnowledgeItemSearchResult) =>
|
||||
record.fileName || record.sourceFileId || "-",
|
||||
},
|
||||
{
|
||||
title: "来源类型",
|
||||
dataIndex: "sourceType",
|
||||
key: "sourceType",
|
||||
width: 140,
|
||||
render: (value: KnowledgeSourceType) =>
|
||||
sourceTypeMap[value] || value || "-",
|
||||
},
|
||||
{
|
||||
title: "内容类型",
|
||||
dataIndex: "contentType",
|
||||
key: "contentType",
|
||||
width: 120,
|
||||
render: (value: KnowledgeContentType) =>
|
||||
contentTypeMap[value] || value || "-",
|
||||
},
|
||||
{
|
||||
title: "大小",
|
||||
dataIndex: "fileSize",
|
||||
key: "fileSize",
|
||||
width: 120,
|
||||
render: (value?: number) => formatBytes(value ?? 0),
|
||||
},
|
||||
{
|
||||
title: "更新时间",
|
||||
dataIndex: "updatedAt",
|
||||
key: "updatedAt",
|
||||
width: 180,
|
||||
ellipsis: true,
|
||||
render: (value: string) => formatDateTime(value) || "-",
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
key: "action",
|
||||
width: 120,
|
||||
align: "right" as const,
|
||||
render: (_: unknown, record: KnowledgeItemSearchResult) => (
|
||||
<Button
|
||||
type="link"
|
||||
onClick={() => {
|
||||
navigate(`/data/knowledge-management/detail/${record.setId}`);
|
||||
}}
|
||||
>
|
||||
定位
|
||||
</Button>
|
||||
),
|
||||
},
|
||||
],
|
||||
[contentTypeMap, navigate, sourceTypeMap]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="h-full flex flex-col gap-4">
|
||||
<Breadcrumb>
|
||||
<Breadcrumb.Item>
|
||||
<a onClick={() => navigate("/data/knowledge-management")}>知识管理</a>
|
||||
</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>全库搜索</Breadcrumb.Item>
|
||||
</Breadcrumb>
|
||||
<div className="flex items-center justify-between">
|
||||
<h1 className="text-xl font-bold">知识管理全库检索</h1>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<Input.Search
|
||||
allowClear
|
||||
value={searchTerm}
|
||||
onChange={(event) => setSearchTerm(event.target.value)}
|
||||
onSearch={handleSearch}
|
||||
placeholder="输入文件名,回车或点击搜索"
|
||||
enterButton="搜索"
|
||||
loading={loading}
|
||||
/>
|
||||
</div>
|
||||
<Table
|
||||
rowKey="id"
|
||||
loading={loading}
|
||||
columns={columns}
|
||||
dataSource={results}
|
||||
pagination={{
|
||||
current: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
total: pagination.total,
|
||||
showTotal: (total) => `共 ${total} 条`,
|
||||
onChange: (page, pageSize) => {
|
||||
const nextKeyword = activeKeyword.trim();
|
||||
if (!nextKeyword) {
|
||||
message.warning("请输入文件名");
|
||||
return;
|
||||
}
|
||||
fetchResults(nextKeyword, page, pageSize || pagination.pageSize);
|
||||
},
|
||||
}}
|
||||
locale={{
|
||||
emptyText: searched ? "暂无匹配文件" : "请输入文件名开始检索",
|
||||
}}
|
||||
onRow={(record) => ({
|
||||
onClick: () => {
|
||||
navigate(`/data/knowledge-management/detail/${record.setId}`);
|
||||
},
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -5,6 +5,11 @@ export function queryKnowledgeSetsUsingGet(params?: Record<string, unknown>) {
|
||||
return get("/api/data-management/knowledge-sets", params);
|
||||
}
|
||||
|
||||
// 知识管理统计
|
||||
export function getKnowledgeManagementStatisticsUsingGet() {
|
||||
return get("/api/data-management/knowledge-sets/statistics");
|
||||
}
|
||||
|
||||
// 创建知识集
|
||||
export function createKnowledgeSetUsingPost(data: Record<string, unknown>) {
|
||||
return post("/api/data-management/knowledge-sets", data);
|
||||
@@ -30,6 +35,11 @@ export function queryKnowledgeItemsUsingGet(setId: string, params?: Record<strin
|
||||
return get(`/api/data-management/knowledge-sets/${setId}/items`, params);
|
||||
}
|
||||
|
||||
// 知识条目文件搜索
|
||||
export function searchKnowledgeItemsUsingGet(params?: Record<string, unknown>) {
|
||||
return get("/api/data-management/knowledge-items/search", params);
|
||||
}
|
||||
|
||||
// 创建知识条目
|
||||
export function createKnowledgeItemUsingPost(setId: string, data: Record<string, unknown>) {
|
||||
return post(`/api/data-management/knowledge-sets/${setId}/items`, data);
|
||||
|
||||
@@ -67,3 +67,23 @@ export interface KnowledgeItem {
|
||||
createdBy?: string;
|
||||
updatedBy?: string;
|
||||
}
|
||||
|
||||
export interface KnowledgeManagementStatistics {
|
||||
totalKnowledgeSets: number;
|
||||
totalFiles: number;
|
||||
totalSize: number;
|
||||
}
|
||||
|
||||
export interface KnowledgeItemSearchResult {
|
||||
id: string;
|
||||
setId: string;
|
||||
setName: string;
|
||||
contentType: KnowledgeContentType;
|
||||
sourceType: KnowledgeSourceType;
|
||||
sourceDatasetId?: string;
|
||||
sourceFileId?: string;
|
||||
fileName?: string;
|
||||
fileSize?: number;
|
||||
createdAt?: string;
|
||||
updatedAt?: string;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import DatasetCreate from "@/pages/DataManagement/Create/CreateDataset";
|
||||
import DatasetDetail from "@/pages/DataManagement/Detail/DatasetDetail";
|
||||
import KnowledgeManagementPage from "@/pages/KnowledgeManagement/Home/KnowledgeManagementPage";
|
||||
import KnowledgeSetDetail from "@/pages/KnowledgeManagement/Detail/KnowledgeSetDetail";
|
||||
import KnowledgeManagementSearch from "@/pages/KnowledgeManagement/Search/KnowledgeManagementSearch";
|
||||
|
||||
import DataCleansing from "@/pages/DataCleansing/Home/DataCleansing";
|
||||
import CleansingTaskCreate from "@/pages/DataCleansing/Create/CreateTask";
|
||||
@@ -116,6 +117,10 @@ const router = createBrowserRouter([
|
||||
index: true,
|
||||
Component: KnowledgeManagementPage,
|
||||
},
|
||||
{
|
||||
path: "search",
|
||||
Component: KnowledgeManagementSearch,
|
||||
},
|
||||
{
|
||||
path: "detail/:id",
|
||||
Component: KnowledgeSetDetail,
|
||||
|
||||
Reference in New Issue
Block a user