You've already forked DataMate
feat(data-management): 添加数据集相似度推荐功能
- 在DatasetApplicationService中实现getSimilarDatasets方法,支持基于标签匹配的相似数据集推荐 - 新增normalizeSimilarLimit、normalizeTagNames、countSharedTags等辅助方法用于相似度计算 - 在DatasetRepository接口及其实现类中添加findSimilarByTags方法,支持数据库层面的标签匹配查询 - 在DatasetController中暴露/similar REST API端点,支持按需获取相似数据集 - 在前端Overview组件中展示相似数据集表格,包含名称、标签、类型、文件数和更新时间等信息 - 在DatasetDetail页面集成相似数据集获取逻辑,限制默认返回数量为4条 - 移除KnowledgeItem中的冗余title字段,统一使用其他标识信息 - 优化知识管理相关组件中的标题显示逻辑,移除硬编码标题值
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { Breadcrumb, App, Tabs, Table, Tag } from "antd";
|
||||
import {
|
||||
ReloadOutlined,
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
queryDatasetByIdUsingGet,
|
||||
queryDatasetsUsingGet,
|
||||
queryDatasetTagsUsingGet,
|
||||
querySimilarDatasetsUsingGet,
|
||||
updateDatasetByIdUsingPut,
|
||||
} from "../dataset.api";
|
||||
import DataQuality from "./components/DataQuality";
|
||||
@@ -26,8 +27,10 @@ import DataLineageFlow from "./components/DataLineageFlow";
|
||||
import Overview from "./components/Overview";
|
||||
import { Activity, Clock, File, FileType } from "lucide-react";
|
||||
import EditDataset from "../Create/EditDataset";
|
||||
import ImportConfiguration from "./components/ImportConfiguration";
|
||||
|
||||
import ImportConfiguration from "./components/ImportConfiguration";
|
||||
|
||||
const SIMILAR_DATASET_LIMIT = 4;
|
||||
|
||||
export default function DatasetDetail() {
|
||||
const { id } = useParams(); // 获取动态路由参数
|
||||
const navigate = useNavigate();
|
||||
@@ -39,9 +42,61 @@ export default function DatasetDetail() {
|
||||
const [parentDataset, setParentDataset] = useState<Dataset | null>(null);
|
||||
const [childDatasets, setChildDatasets] = useState<Dataset[]>([]);
|
||||
const [childDatasetsLoading, setChildDatasetsLoading] = useState(false);
|
||||
const [similarDatasets, setSimilarDatasets] = useState<Dataset[]>([]);
|
||||
const [similarDatasetsLoading, setSimilarDatasetsLoading] = useState(false);
|
||||
const [similarTagNames, setSimilarTagNames] = useState<string[]>([]);
|
||||
const similarRequestRef = useRef(0);
|
||||
const filesOperation = useFilesOperation(dataset);
|
||||
|
||||
const [showUploadDialog, setShowUploadDialog] = useState(false);
|
||||
const normalizeTagNames = (
|
||||
tags?: Array<string | { name?: string | null } | null>
|
||||
) => {
|
||||
if (!tags || tags.length === 0) {
|
||||
return [];
|
||||
}
|
||||
const names = tags
|
||||
.map((tag) => (typeof tag === "string" ? tag : tag?.name))
|
||||
.filter((name): name is string => !!name && name.trim().length > 0)
|
||||
.map((name) => name.trim());
|
||||
return Array.from(new Set(names));
|
||||
};
|
||||
const fetchSimilarDatasets = async (currentDataset: Dataset) => {
|
||||
const requestId = similarRequestRef.current + 1;
|
||||
similarRequestRef.current = requestId;
|
||||
if (!currentDataset?.id) {
|
||||
setSimilarDatasets([]);
|
||||
setSimilarTagNames([]);
|
||||
setSimilarDatasetsLoading(false);
|
||||
return;
|
||||
}
|
||||
const tagNames = normalizeTagNames(
|
||||
currentDataset.tags as Array<string | { name?: string }>
|
||||
);
|
||||
setSimilarTagNames(tagNames);
|
||||
setSimilarDatasets([]);
|
||||
if (tagNames.length === 0) {
|
||||
setSimilarDatasetsLoading(false);
|
||||
return;
|
||||
}
|
||||
setSimilarDatasetsLoading(true);
|
||||
try {
|
||||
const { data } = await querySimilarDatasetsUsingGet(currentDataset.id, {
|
||||
limit: SIMILAR_DATASET_LIMIT,
|
||||
});
|
||||
if (similarRequestRef.current !== requestId) {
|
||||
return;
|
||||
}
|
||||
const list = Array.isArray(data) ? data : [];
|
||||
setSimilarDatasets(list.map((item) => mapDataset(item)));
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch similar datasets:", error);
|
||||
} finally {
|
||||
if (similarRequestRef.current === requestId) {
|
||||
setSimilarDatasetsLoading(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
const navigateItems = useMemo(() => {
|
||||
const items = [
|
||||
{
|
||||
@@ -110,6 +165,7 @@ export default function DatasetDetail() {
|
||||
const { data } = await queryDatasetByIdUsingGet(id);
|
||||
const mapped = mapDataset(data);
|
||||
setDataset(mapped);
|
||||
fetchSimilarDatasets(mapped);
|
||||
if (data?.parentDatasetId) {
|
||||
const { data: parentData } = await queryDatasetByIdUsingGet(
|
||||
data.parentDatasetId
|
||||
@@ -351,6 +407,9 @@ export default function DatasetDetail() {
|
||||
filesOperation={filesOperation}
|
||||
fetchDataset={fetchDataset}
|
||||
onUpload={() => setShowUploadDialog(true)}
|
||||
similarDatasets={similarDatasets}
|
||||
similarDatasetsLoading={similarDatasetsLoading}
|
||||
similarTags={similarTagNames}
|
||||
/>
|
||||
)}
|
||||
{activeTab === "children" && (
|
||||
|
||||
Reference in New Issue
Block a user