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:
@@ -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: "删除失败",
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user