Refactor AIKnowledgeDetail and AIKnowledgeList components to improve user navigation and search functionality. Update deletion logic to navigate back on success and enhance search with debouncing and keyword handling. Adjust API to support keyword filtering in fetchKnowledgeBaseList.

This commit is contained in:
超级老白兔
2025-10-31 16:18:12 +08:00
parent fe347965ff
commit eada5fe8b1
3 changed files with 57 additions and 38 deletions

View File

@@ -225,8 +225,8 @@ const AIKnowledgeDetail: React.FC = () => {
content: "删除成功",
icon: "success",
});
// 刷新素材列表
await fetchMaterialList();
// 删除成功后返回上一页
navigate(-1);
} catch (error) {
Toast.show({
content: "删除失败",
@@ -250,7 +250,8 @@ const AIKnowledgeDetail: React.FC = () => {
content: "删除成功",
icon: "success",
});
setMaterials(prev => prev.filter(m => m.id !== materialId));
// 刷新库内素材列表
await fetchMaterialList();
} catch (error) {
Toast.show({
content: "删除失败",

View File

@@ -24,6 +24,7 @@ export function releaseAIKnowledge(id: number): Promise<any> {
export function fetchKnowledgeBaseList(params: {
page?: number;
limit?: number;
keyword?: string;
}): Promise<KnowledgeBaseListResponse> {
return request("/v1/knowledge/typeList", params, "GET");
}

View File

@@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react";
import React, { useEffect, useState, useCallback, useRef } from "react";
import { useNavigate } from "react-router-dom";
import {
Button,
@@ -18,7 +18,6 @@ import {
GlobalOutlined,
InfoCircleOutlined,
SearchOutlined,
ArrowRightOutlined,
} from "@ant-design/icons";
import Layout from "@/components/Layout/Layout";
import NavCommon from "@/components/NavCommon";
@@ -42,26 +41,20 @@ const AIKnowledgeList: React.FC = () => {
const [enabledCount, setEnabledCount] = useState(0);
const [page, setPage] = useState(1);
const [menuLoadingId, setMenuLoadingId] = useState<number | null>(null);
const [searchValue, setSearchValue] = useState(""); // 搜索内容
const [searchValue, setSearchValue] = useState(""); // 搜索输入内容
const [keyword, setKeyword] = useState(""); // 实际用于搜索的关键词
const isInitialMount = useRef(true); // 标记是否是初始挂载
// 弹窗控制
const [globalPromptVisible, setGlobalPromptVisible] = useState(false);
useEffect(() => {
// 初始化AI功能
initAIKnowledge().catch(err => {
console.warn("初始化AI功能失败", err);
});
fetchList(1);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const fetchList = async (pageNum = 1) => {
const fetchList = useCallback(async (pageNum = 1, searchKeyword = "") => {
setLoading(true);
try {
const res = await fetchKnowledgeBaseList({
page: pageNum,
limit: PAGE_SIZE,
keyword: searchKeyword || undefined,
});
// 转换数据格式,映射接口字段到前端字段
const transformedList = (res?.data || []).map((item: any) => ({
@@ -80,30 +73,46 @@ const AIKnowledgeList: React.FC = () => {
} finally {
setLoading(false);
}
};
}, []);
useEffect(() => {
// 初始化AI功能
initAIKnowledge().catch(err => {
console.warn("初始化AI功能失败", err);
});
fetchList(1, "");
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
// 搜索防抖处理
const debouncedSearch = useCallback(() => {
const timer = setTimeout(() => {
const searchKeyword = searchValue.trim();
setKeyword(searchKeyword);
setPage(1);
fetchList(1, searchKeyword);
}, 500); // 500ms 防抖延迟
return () => clearTimeout(timer);
}, [searchValue, fetchList]);
useEffect(() => {
// 初始挂载时不触发搜索(已在初始化时调用 fetchList
if (isInitialMount.current) {
isInitialMount.current = false;
return;
}
const cleanup = debouncedSearch();
return cleanup;
}, [debouncedSearch]);
const handlePageChange = (p: number) => {
setPage(p);
fetchList(p);
fetchList(p, keyword);
};
const handleRefresh = () => {
fetchList(page);
};
const handleSearch = () => {
setPage(1);
};
const getFilteredList = () => {
const keyword = searchValue.trim().toLowerCase();
if (!keyword) return list;
return list.filter(item => {
return (
item.name.toLowerCase().includes(keyword) ||
(item.description || "").toLowerCase().includes(keyword)
);
});
fetchList(page, keyword);
};
// 菜单点击事件
@@ -342,12 +351,18 @@ const AIKnowledgeList: React.FC = () => {
}}
>
<Input
placeholder="搜索计划名称"
placeholder="搜索知识库名称或描述"
value={searchValue}
onChange={e => setSearchValue(e.target.value)}
prefix={<SearchOutlined />}
allowClear
size="large"
onPressEnter={() => {
const searchKeyword = searchValue.trim();
setKeyword(searchKeyword);
setPage(1);
fetchList(1, searchKeyword);
}}
/>
</div>
</div>
@@ -382,14 +397,16 @@ const AIKnowledgeList: React.FC = () => {
<div style={{ textAlign: "center", padding: "40px 0" }}>
<Spin />
</div>
) : getFilteredList().length > 0 ? (
getFilteredList().map(renderCard)
) : list.length > 0 ? (
list.map(renderCard)
) : (
<div className={style.empty}>
<div className={style.emptyIcon}>
<BookOutlined />
</div>
<div className={style.emptyText}></div>
<div className={style.emptyText}>
{keyword ? "未找到匹配的知识库" : "暂无知识库"}
</div>
</div>
)}
</div>