2025-03-22 10:13:42 +08:00
|
|
|
|
import React, { useState, useEffect, useCallback } from 'react';
|
2025-03-04 07:22:05 +08:00
|
|
|
|
import { useNavigate } from 'react-router-dom';
|
2025-03-07 23:59:53 +08:00
|
|
|
|
import { useDispatch, useSelector } from 'react-redux';
|
2025-03-01 08:34:56 +08:00
|
|
|
|
import { showNotification } from '../../store/notification.slice';
|
2025-03-07 23:59:53 +08:00
|
|
|
|
import {
|
|
|
|
|
fetchKnowledgeBases,
|
|
|
|
|
searchKnowledgeBases,
|
|
|
|
|
createKnowledgeBase,
|
2025-03-22 10:13:42 +08:00
|
|
|
|
deleteKnowledgeBase,
|
|
|
|
|
requestKnowledgeBaseAccess,
|
2025-03-07 23:59:53 +08:00
|
|
|
|
} from '../../store/knowledgeBase/knowledgeBase.thunks';
|
2025-03-22 10:13:42 +08:00
|
|
|
|
import { clearSearchResults } from '../../store/knowledgeBase/knowledgeBase.slice';
|
2025-03-01 08:34:56 +08:00
|
|
|
|
import SvgIcon from '../../components/SvgIcon';
|
2025-03-13 09:14:25 +08:00
|
|
|
|
import AccessRequestModal from '../../components/AccessRequestModal';
|
|
|
|
|
import CreateKnowledgeBaseModal from '../../components/CreateKnowledgeBaseModal';
|
|
|
|
|
import Pagination from '../../components/Pagination';
|
|
|
|
|
import SearchBar from '../../components/SearchBar';
|
2025-03-22 10:13:42 +08:00
|
|
|
|
import ApiModeSwitch from '../../components/ApiModeSwitch';
|
2025-02-27 06:54:19 +08:00
|
|
|
|
|
2025-03-07 23:59:53 +08:00
|
|
|
|
// 导入拆分的组件
|
|
|
|
|
import KnowledgeBaseList from './components/KnowledgeBaseList';
|
|
|
|
|
|
2025-02-27 06:54:19 +08:00
|
|
|
|
export default function KnowledgeBase() {
|
2025-03-01 05:48:24 +08:00
|
|
|
|
const dispatch = useDispatch();
|
2025-03-04 07:22:05 +08:00
|
|
|
|
const navigate = useNavigate();
|
|
|
|
|
const [showCreateModal, setShowCreateModal] = useState(false);
|
2025-03-04 08:37:47 +08:00
|
|
|
|
const [showAccessRequestModal, setShowAccessRequestModal] = useState(false);
|
|
|
|
|
const [formErrors, setFormErrors] = useState({});
|
2025-03-13 09:14:25 +08:00
|
|
|
|
const [accessRequestKnowledgeBase, setAccessRequestKnowledgeBase] = useState({
|
2025-03-04 08:37:47 +08:00
|
|
|
|
id: '',
|
|
|
|
|
title: '',
|
|
|
|
|
});
|
2025-03-13 09:14:25 +08:00
|
|
|
|
const [isSubmittingRequest, setIsSubmittingRequest] = useState(false);
|
2025-03-22 10:13:42 +08:00
|
|
|
|
const [createdKnowledgeBaseId, setCreatedKnowledgeBaseId] = useState(null);
|
2025-03-13 09:14:25 +08:00
|
|
|
|
|
|
|
|
|
// 获取当前用户信息
|
|
|
|
|
const currentUser = useSelector((state) => state.auth.user);
|
|
|
|
|
|
2025-03-04 07:22:05 +08:00
|
|
|
|
const [newKnowledgeBase, setNewKnowledgeBase] = useState({
|
2025-03-07 23:59:53 +08:00
|
|
|
|
name: '',
|
|
|
|
|
desc: '',
|
2025-03-13 09:14:25 +08:00
|
|
|
|
type: 'private', // 默认为私有知识库
|
|
|
|
|
department: currentUser?.department || '',
|
|
|
|
|
group: currentUser?.group || '',
|
2025-03-04 07:22:05 +08:00
|
|
|
|
});
|
2025-03-01 05:48:24 +08:00
|
|
|
|
|
2025-03-07 23:59:53 +08:00
|
|
|
|
// Search state
|
|
|
|
|
const [searchKeyword, setSearchKeyword] = useState('');
|
2025-03-23 10:53:37 +08:00
|
|
|
|
const [isSearchDropdownOpen, setIsSearchDropdownOpen] = useState(false);
|
2025-03-07 23:59:53 +08:00
|
|
|
|
|
|
|
|
|
// Pagination state
|
|
|
|
|
const [pagination, setPagination] = useState({
|
|
|
|
|
page: 1,
|
|
|
|
|
page_size: 10,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Get knowledge bases from Redux store
|
2025-03-22 10:13:42 +08:00
|
|
|
|
// 更新为新的Redux状态结构
|
|
|
|
|
const knowledgeBases = useSelector((state) => state.knowledgeBase.knowledgeBases);
|
|
|
|
|
const loading = useSelector((state) => state.knowledgeBase.loading);
|
|
|
|
|
const paginationData = useSelector((state) => state.knowledgeBase.pagination);
|
|
|
|
|
const error = useSelector((state) => state.knowledgeBase.error);
|
|
|
|
|
const operationStatus = useSelector((state) => state.knowledgeBase.editStatus);
|
|
|
|
|
const operationError = useSelector((state) => state.knowledgeBase.error);
|
|
|
|
|
|
|
|
|
|
// 从Redux获取搜索结果和加载状态
|
|
|
|
|
const searchResults = useSelector((state) => state.knowledgeBase.searchResults);
|
|
|
|
|
const searchLoading = useSelector((state) => state.knowledgeBase.searchLoading);
|
2025-03-07 23:59:53 +08:00
|
|
|
|
|
|
|
|
|
// Fetch knowledge bases when component mounts or pagination changes
|
|
|
|
|
useEffect(() => {
|
2025-03-23 10:53:37 +08:00
|
|
|
|
// 无论是否在搜索,都正常获取知识库列表
|
|
|
|
|
dispatch(fetchKnowledgeBases(pagination));
|
|
|
|
|
}, [dispatch, pagination.page, pagination.page_size]);
|
|
|
|
|
|
|
|
|
|
// Show loading state while fetching data
|
|
|
|
|
const isLoading = loading;
|
|
|
|
|
|
|
|
|
|
// Show error notification if fetch fails
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (!isLoading && error) {
|
2025-03-07 23:59:53 +08:00
|
|
|
|
dispatch(
|
2025-03-23 10:53:37 +08:00
|
|
|
|
showNotification({
|
|
|
|
|
message: `获取知识库列表失败: ${error.message || error}`,
|
|
|
|
|
type: 'danger',
|
2025-03-07 23:59:53 +08:00
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
}
|
2025-03-23 10:53:37 +08:00
|
|
|
|
}, [isLoading, error, dispatch]);
|
2025-03-07 23:59:53 +08:00
|
|
|
|
|
2025-03-23 10:53:37 +08:00
|
|
|
|
// Show notification for operation status
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (operationStatus === 'successful') {
|
|
|
|
|
// 操作成功通知由具体函数处理,这里只刷新列表
|
|
|
|
|
|
|
|
|
|
// Refresh the list after successful operation
|
|
|
|
|
dispatch(fetchKnowledgeBases(pagination));
|
|
|
|
|
} else if (operationStatus === 'failed' && operationError) {
|
|
|
|
|
dispatch(
|
|
|
|
|
showNotification({
|
|
|
|
|
message: `操作失败: ${operationError.message || operationError}`,
|
|
|
|
|
type: 'danger',
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}, [operationStatus, operationError, dispatch, pagination]);
|
2025-03-22 10:13:42 +08:00
|
|
|
|
|
2025-03-07 23:59:53 +08:00
|
|
|
|
// Handle search input change
|
|
|
|
|
const handleSearchInputChange = (e) => {
|
2025-03-22 10:13:42 +08:00
|
|
|
|
const value = e.target.value;
|
|
|
|
|
setSearchKeyword(value);
|
|
|
|
|
|
2025-03-23 10:53:37 +08:00
|
|
|
|
// 如果搜索框清空,关闭下拉框
|
|
|
|
|
if (!value.trim()) {
|
2025-03-22 10:13:42 +08:00
|
|
|
|
dispatch(clearSearchResults());
|
2025-03-23 10:53:37 +08:00
|
|
|
|
setIsSearchDropdownOpen(false);
|
2025-03-22 10:13:42 +08:00
|
|
|
|
}
|
2025-03-07 23:59:53 +08:00
|
|
|
|
};
|
|
|
|
|
|
2025-03-23 10:53:37 +08:00
|
|
|
|
// Handle search submit - 只影响下拉框,不影响主列表
|
2025-03-07 23:59:53 +08:00
|
|
|
|
const handleSearch = (e) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
|
|
|
|
if (searchKeyword.trim()) {
|
2025-03-23 10:53:37 +08:00
|
|
|
|
// 只设置下拉框搜索状态,不设置全局isSearching状态
|
2025-03-07 23:59:53 +08:00
|
|
|
|
dispatch(
|
|
|
|
|
searchKnowledgeBases({
|
|
|
|
|
keyword: searchKeyword,
|
|
|
|
|
page: 1,
|
2025-03-23 10:53:37 +08:00
|
|
|
|
page_size: 5, // 下拉框只显示少量结果
|
2025-03-07 23:59:53 +08:00
|
|
|
|
})
|
|
|
|
|
);
|
2025-03-23 10:53:37 +08:00
|
|
|
|
setIsSearchDropdownOpen(true);
|
2025-03-07 23:59:53 +08:00
|
|
|
|
} else {
|
2025-03-23 10:53:37 +08:00
|
|
|
|
// 清空搜索及关闭下拉框
|
2025-03-07 23:59:53 +08:00
|
|
|
|
handleClearSearch();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Handle clear search
|
|
|
|
|
const handleClearSearch = () => {
|
|
|
|
|
setSearchKeyword('');
|
2025-03-23 10:53:37 +08:00
|
|
|
|
// 不影响主列表显示,只关闭下拉框
|
|
|
|
|
setIsSearchDropdownOpen(false);
|
2025-03-22 10:13:42 +08:00
|
|
|
|
dispatch(clearSearchResults());
|
2025-03-07 23:59:53 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Handle pagination change
|
|
|
|
|
const handlePageChange = (newPage) => {
|
|
|
|
|
setPagination((prev) => ({
|
|
|
|
|
...prev,
|
|
|
|
|
page: newPage,
|
|
|
|
|
}));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Handle page size change
|
|
|
|
|
const handlePageSizeChange = (newPageSize) => {
|
|
|
|
|
setPagination({
|
|
|
|
|
page: 1, // Reset to first page when changing page size
|
|
|
|
|
page_size: newPageSize,
|
|
|
|
|
});
|
|
|
|
|
};
|
2025-02-27 06:54:19 +08:00
|
|
|
|
|
2025-03-04 07:22:05 +08:00
|
|
|
|
const handleInputChange = (e) => {
|
|
|
|
|
const { name, value } = e.target;
|
2025-03-25 08:04:35 +08:00
|
|
|
|
const isAdmin = currentUser?.role === 'admin';
|
|
|
|
|
const isLeader = currentUser?.role === 'leader';
|
|
|
|
|
|
|
|
|
|
// 根据用户角色允许修改部门和组别字段
|
2025-03-13 09:14:25 +08:00
|
|
|
|
if (name === 'department' || name === 'group') {
|
2025-03-25 08:04:35 +08:00
|
|
|
|
// 仅管理员可以修改部门
|
|
|
|
|
if (name === 'department' && !isAdmin) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 仅管理员和组长可以修改组别
|
|
|
|
|
if (name === 'group' && !isAdmin && !isLeader) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 更新字段值
|
|
|
|
|
setNewKnowledgeBase((prev) => ({
|
|
|
|
|
...prev,
|
|
|
|
|
[name]: value,
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
// 如果更新部门,重置组别
|
|
|
|
|
if (name === 'department') {
|
|
|
|
|
setNewKnowledgeBase((prev) => ({
|
|
|
|
|
...prev,
|
|
|
|
|
group: '', // 部门变更时重置组别
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-13 09:14:25 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-22 10:13:42 +08:00
|
|
|
|
// 检查用户是否有权限选择指定的知识库类型
|
|
|
|
|
if (name === 'type') {
|
|
|
|
|
const role = currentUser?.role;
|
|
|
|
|
let allowed = false;
|
|
|
|
|
|
|
|
|
|
// 根据角色判断可以选择的知识库类型
|
|
|
|
|
if (role === 'admin') {
|
|
|
|
|
// 管理员可以选择任何类型
|
|
|
|
|
allowed = ['admin', 'leader', 'member', 'private', 'secret'].includes(value);
|
|
|
|
|
} else if (role === 'leader') {
|
|
|
|
|
// 组长只能选择 member 和 private
|
|
|
|
|
allowed = ['member', 'private'].includes(value);
|
|
|
|
|
} else {
|
|
|
|
|
// 普通成员只能选择 private
|
|
|
|
|
allowed = value === 'private';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!allowed) {
|
|
|
|
|
dispatch(
|
|
|
|
|
showNotification({
|
|
|
|
|
message: '您没有权限创建此类型的知识库',
|
|
|
|
|
type: 'warning',
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-04 07:22:05 +08:00
|
|
|
|
setNewKnowledgeBase((prev) => ({
|
|
|
|
|
...prev,
|
|
|
|
|
[name]: value,
|
|
|
|
|
}));
|
2025-03-04 08:37:47 +08:00
|
|
|
|
|
|
|
|
|
// Clear error when user types
|
|
|
|
|
if (formErrors[name]) {
|
|
|
|
|
setFormErrors((prev) => ({
|
|
|
|
|
...prev,
|
|
|
|
|
[name]: '',
|
|
|
|
|
}));
|
|
|
|
|
}
|
2025-03-04 07:22:05 +08:00
|
|
|
|
};
|
|
|
|
|
|
2025-03-04 08:37:47 +08:00
|
|
|
|
const validateCreateForm = () => {
|
|
|
|
|
const errors = {};
|
2025-03-25 08:04:35 +08:00
|
|
|
|
const isAdmin = currentUser?.role === 'admin';
|
|
|
|
|
const isLeader = currentUser?.role === 'leader';
|
|
|
|
|
// 只有member类型知识库需要选择组别,私有知识库不需要
|
|
|
|
|
const needSelectGroup = newKnowledgeBase.type === 'member';
|
|
|
|
|
// 私有知识库不需要选择部门和组别
|
|
|
|
|
const isPrivate = newKnowledgeBase.type === 'private';
|
2025-03-04 08:37:47 +08:00
|
|
|
|
|
2025-03-07 23:59:53 +08:00
|
|
|
|
if (!newKnowledgeBase.name.trim()) {
|
|
|
|
|
errors.name = '请输入知识库名称';
|
2025-03-04 08:37:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-03-07 23:59:53 +08:00
|
|
|
|
if (!newKnowledgeBase.desc.trim()) {
|
|
|
|
|
errors.desc = '请输入知识库描述';
|
2025-03-04 08:37:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-03-13 09:14:25 +08:00
|
|
|
|
if (!newKnowledgeBase.type) {
|
|
|
|
|
errors.type = '请选择知识库类型';
|
2025-03-04 08:37:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-03-25 08:04:35 +08:00
|
|
|
|
// 对于member级别的知识库,检查是否选择了部门和组别
|
|
|
|
|
if (needSelectGroup && !isPrivate) {
|
|
|
|
|
// 管理员必须选择部门
|
|
|
|
|
if (isAdmin && !newKnowledgeBase.department) {
|
|
|
|
|
errors.department = '创建member级别知识库时必须选择部门';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 所有用户创建member级别知识库时必须选择组别
|
|
|
|
|
if (!newKnowledgeBase.group) {
|
|
|
|
|
errors.group = '创建member级别知识库时必须选择组别';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-13 09:14:25 +08:00
|
|
|
|
setFormErrors(errors);
|
2025-03-04 08:37:47 +08:00
|
|
|
|
return Object.keys(errors).length === 0;
|
|
|
|
|
};
|
|
|
|
|
|
2025-03-22 10:13:42 +08:00
|
|
|
|
const handleCreateKnowledgeBase = async () => {
|
2025-03-04 08:37:47 +08:00
|
|
|
|
// Validate form
|
|
|
|
|
if (!validateCreateForm()) {
|
2025-03-04 07:22:05 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-22 10:13:42 +08:00
|
|
|
|
try {
|
2025-03-25 08:04:35 +08:00
|
|
|
|
// 私有知识库不需要部门和组别信息
|
|
|
|
|
const isPrivate = newKnowledgeBase.type === 'private';
|
|
|
|
|
|
2025-03-22 10:13:42 +08:00
|
|
|
|
// Dispatch create knowledge base action
|
|
|
|
|
const resultAction = await dispatch(
|
|
|
|
|
createKnowledgeBase({
|
|
|
|
|
name: newKnowledgeBase.name,
|
|
|
|
|
desc: newKnowledgeBase.desc,
|
|
|
|
|
description: newKnowledgeBase.desc,
|
|
|
|
|
type: newKnowledgeBase.type,
|
2025-03-25 08:04:35 +08:00
|
|
|
|
department: !isPrivate ? newKnowledgeBase.department : '',
|
|
|
|
|
group: !isPrivate ? newKnowledgeBase.group : '',
|
2025-03-22 10:13:42 +08:00
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
console.log('创建知识库返回数据:', resultAction);
|
|
|
|
|
|
|
|
|
|
// Check if the action was successful
|
|
|
|
|
if (createKnowledgeBase.fulfilled.match(resultAction)) {
|
|
|
|
|
console.log('创建成功,payload:', resultAction.payload);
|
|
|
|
|
const { knowledge_base } = resultAction.payload;
|
|
|
|
|
const { id } = knowledge_base;
|
|
|
|
|
// Get ID from payload and navigate
|
|
|
|
|
if (id) {
|
|
|
|
|
console.log('新知识库ID:', id);
|
|
|
|
|
|
|
|
|
|
// 显示成功通知
|
|
|
|
|
dispatch(
|
|
|
|
|
showNotification({
|
|
|
|
|
message: '知识库创建成功',
|
|
|
|
|
type: 'success',
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// 直接导航到新创建的知识库详情页
|
|
|
|
|
navigate(`/knowledge-base/${id}`);
|
|
|
|
|
} else {
|
|
|
|
|
console.error('无法获取新知识库ID:', resultAction.payload);
|
|
|
|
|
dispatch(
|
|
|
|
|
showNotification({
|
|
|
|
|
message: '创建成功,但无法获取知识库ID',
|
|
|
|
|
type: 'warning',
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
console.error('创建知识库失败:', resultAction.error);
|
|
|
|
|
dispatch(
|
|
|
|
|
showNotification({
|
|
|
|
|
message: `创建知识库失败: ${resultAction.error?.message || '未知错误'}`,
|
|
|
|
|
type: 'danger',
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('创建知识库出错:', error);
|
|
|
|
|
dispatch(
|
|
|
|
|
showNotification({
|
|
|
|
|
message: `创建知识库出错: ${error.message || '未知错误'}`,
|
|
|
|
|
type: 'danger',
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
}
|
2025-03-04 07:22:05 +08:00
|
|
|
|
|
|
|
|
|
// Reset form and close modal
|
2025-03-13 09:14:25 +08:00
|
|
|
|
setNewKnowledgeBase({ name: '', desc: '', type: 'private', department: '', group: '' });
|
2025-03-04 08:37:47 +08:00
|
|
|
|
setFormErrors({});
|
2025-03-04 07:22:05 +08:00
|
|
|
|
setShowCreateModal(false);
|
|
|
|
|
};
|
|
|
|
|
|
2025-03-07 23:59:53 +08:00
|
|
|
|
// Handle card click to navigate to knowledge base detail
|
2025-03-13 09:14:25 +08:00
|
|
|
|
const handleCardClick = (id, permissions) => {
|
|
|
|
|
// 检查用户是否有读取权限
|
|
|
|
|
if (!permissions || permissions.can_read === false) {
|
|
|
|
|
dispatch(
|
|
|
|
|
showNotification({
|
|
|
|
|
message: '您没有访问此知识库的权限,请先申请权限',
|
|
|
|
|
type: 'warning',
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 有权限则跳转到详情页
|
2025-03-04 07:22:05 +08:00
|
|
|
|
navigate(`/knowledge-base/${id}/datasets`);
|
|
|
|
|
};
|
|
|
|
|
|
2025-03-04 08:37:47 +08:00
|
|
|
|
const handleRequestAccess = (id, title) => {
|
2025-03-13 09:14:25 +08:00
|
|
|
|
setAccessRequestKnowledgeBase({
|
2025-03-04 08:37:47 +08:00
|
|
|
|
id,
|
|
|
|
|
title,
|
2025-03-13 09:14:25 +08:00
|
|
|
|
});
|
2025-03-04 08:37:47 +08:00
|
|
|
|
setShowAccessRequestModal(true);
|
|
|
|
|
};
|
|
|
|
|
|
2025-03-13 09:14:25 +08:00
|
|
|
|
const handleSubmitAccessRequest = async (requestData) => {
|
|
|
|
|
setIsSubmittingRequest(true);
|
2025-03-04 08:37:47 +08:00
|
|
|
|
|
2025-03-13 09:14:25 +08:00
|
|
|
|
try {
|
|
|
|
|
// 使用权限服务发送请求
|
|
|
|
|
await requestKnowledgeBaseAccess(requestData);
|
2025-03-04 08:37:47 +08:00
|
|
|
|
|
2025-03-13 09:14:25 +08:00
|
|
|
|
dispatch(
|
|
|
|
|
showNotification({
|
|
|
|
|
message: '权限申请已提交',
|
|
|
|
|
type: 'success',
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Close modal
|
|
|
|
|
setShowAccessRequestModal(false);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
dispatch(
|
|
|
|
|
showNotification({
|
|
|
|
|
message: `权限申请失败: ${error.response?.data?.message || '请稍后重试'}`,
|
|
|
|
|
type: 'danger',
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
} finally {
|
|
|
|
|
setIsSubmittingRequest(false);
|
|
|
|
|
}
|
2025-03-04 08:37:47 +08:00
|
|
|
|
};
|
|
|
|
|
|
2025-03-08 07:05:33 +08:00
|
|
|
|
const handleDelete = (e, id) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
e.stopPropagation();
|
2025-03-22 10:13:42 +08:00
|
|
|
|
// Dispatch delete knowledge base action
|
|
|
|
|
dispatch(deleteKnowledgeBase(id))
|
|
|
|
|
.unwrap()
|
|
|
|
|
.then(() => {
|
|
|
|
|
dispatch(
|
|
|
|
|
showNotification({
|
|
|
|
|
message: '知识库已删除',
|
|
|
|
|
type: 'success',
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
})
|
|
|
|
|
.catch((error) => {
|
|
|
|
|
dispatch(
|
|
|
|
|
showNotification({
|
|
|
|
|
message: `删除失败: ${error.message || '未知错误'}`,
|
|
|
|
|
type: 'danger',
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
});
|
2025-03-08 07:05:33 +08:00
|
|
|
|
};
|
|
|
|
|
|
2025-03-07 23:59:53 +08:00
|
|
|
|
// Calculate total pages
|
2025-03-23 10:53:37 +08:00
|
|
|
|
const totalPages = Math.ceil(paginationData.total / pagination.page_size);
|
2025-03-07 23:59:53 +08:00
|
|
|
|
|
2025-03-13 09:14:25 +08:00
|
|
|
|
// 打开创建知识库弹窗
|
|
|
|
|
const handleOpenCreateModal = () => {
|
2025-03-25 08:04:35 +08:00
|
|
|
|
const isAdmin = currentUser?.role === 'admin';
|
|
|
|
|
const isLeader = currentUser?.role === 'leader';
|
|
|
|
|
|
2025-03-22 10:13:42 +08:00
|
|
|
|
// 默认知识库类型基于用户角色
|
|
|
|
|
let defaultType = 'private';
|
|
|
|
|
|
2025-03-25 08:04:35 +08:00
|
|
|
|
// 初始部门和组别
|
|
|
|
|
let department = currentUser?.department || '';
|
|
|
|
|
let group = currentUser?.group || '';
|
|
|
|
|
|
|
|
|
|
setNewKnowledgeBase({
|
|
|
|
|
name: '',
|
|
|
|
|
desc: '',
|
2025-03-22 10:13:42 +08:00
|
|
|
|
type: defaultType,
|
2025-03-25 08:04:35 +08:00
|
|
|
|
department: department,
|
|
|
|
|
group: group,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
setFormErrors({});
|
2025-03-13 09:14:25 +08:00
|
|
|
|
setShowCreateModal(true);
|
|
|
|
|
};
|
|
|
|
|
|
2025-03-22 10:13:42 +08:00
|
|
|
|
// 处理点击搜索结果
|
|
|
|
|
const handleSearchResultClick = (id, permissions) => {
|
|
|
|
|
if (permissions?.can_read) {
|
|
|
|
|
navigate(`/knowledge-base/${id}/datasets`);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-02-27 06:54:19 +08:00
|
|
|
|
return (
|
2025-03-08 07:05:33 +08:00
|
|
|
|
<div className='knowledge-base container my-4'>
|
2025-03-22 10:13:42 +08:00
|
|
|
|
<div className='api-mode-control mb-3'>
|
|
|
|
|
<ApiModeSwitch />
|
|
|
|
|
</div>
|
2025-02-27 06:54:19 +08:00
|
|
|
|
<div className='d-flex justify-content-between align-items-center mb-3'>
|
2025-03-07 23:59:53 +08:00
|
|
|
|
<SearchBar
|
|
|
|
|
searchKeyword={searchKeyword}
|
2025-03-23 10:53:37 +08:00
|
|
|
|
isSearching={isSearchDropdownOpen} // 用于控制下拉框显示
|
2025-03-07 23:59:53 +08:00
|
|
|
|
onSearchChange={handleSearchInputChange}
|
|
|
|
|
onSearch={handleSearch}
|
|
|
|
|
onClearSearch={handleClearSearch}
|
2025-03-13 09:14:25 +08:00
|
|
|
|
placeholder='搜索知识库...'
|
2025-03-22 10:13:42 +08:00
|
|
|
|
searchResults={searchResults}
|
|
|
|
|
isSearchLoading={searchLoading}
|
|
|
|
|
onResultClick={handleSearchResultClick}
|
|
|
|
|
onRequestAccess={handleRequestAccess}
|
2025-03-07 23:59:53 +08:00
|
|
|
|
/>
|
2025-03-13 09:14:25 +08:00
|
|
|
|
<button className='btn btn-dark d-flex align-items-center gap-1' onClick={handleOpenCreateModal}>
|
2025-03-01 08:34:56 +08:00
|
|
|
|
<SvgIcon className={'plus'} />
|
2025-02-27 06:54:19 +08:00
|
|
|
|
新建知识库
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
2025-03-07 23:59:53 +08:00
|
|
|
|
{isLoading ? (
|
|
|
|
|
<div className='d-flex justify-content-center my-5'>
|
|
|
|
|
<div className='spinner-border' role='status'>
|
|
|
|
|
<span className='visually-hidden'>加载中...</span>
|
2025-03-04 07:22:05 +08:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2025-03-07 23:59:53 +08:00
|
|
|
|
) : (
|
|
|
|
|
<>
|
|
|
|
|
<KnowledgeBaseList
|
2025-03-23 10:53:37 +08:00
|
|
|
|
knowledgeBases={knowledgeBases}
|
|
|
|
|
isSearching={false} // 始终为false,因为搜索不影响主列表
|
2025-03-07 23:59:53 +08:00
|
|
|
|
onCardClick={handleCardClick}
|
|
|
|
|
onRequestAccess={handleRequestAccess}
|
2025-03-08 07:05:33 +08:00
|
|
|
|
onDelete={handleDelete}
|
2025-03-07 23:59:53 +08:00
|
|
|
|
/>
|
|
|
|
|
|
2025-03-23 10:53:37 +08:00
|
|
|
|
{/* Pagination - 始终显示 */}
|
2025-03-07 23:59:53 +08:00
|
|
|
|
{totalPages > 1 && (
|
|
|
|
|
<Pagination
|
|
|
|
|
currentPage={pagination.page}
|
|
|
|
|
totalPages={totalPages}
|
|
|
|
|
pageSize={pagination.page_size}
|
|
|
|
|
onPageChange={handlePageChange}
|
|
|
|
|
onPageSizeChange={handlePageSizeChange}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</>
|
2025-03-04 07:22:05 +08:00
|
|
|
|
)}
|
2025-03-04 08:37:47 +08:00
|
|
|
|
|
2025-03-07 23:59:53 +08:00
|
|
|
|
{/* 新建知识库弹窗 */}
|
|
|
|
|
<CreateKnowledgeBaseModal
|
|
|
|
|
show={showCreateModal}
|
|
|
|
|
formData={newKnowledgeBase}
|
|
|
|
|
formErrors={formErrors}
|
2025-03-22 10:13:42 +08:00
|
|
|
|
isSubmitting={loading}
|
2025-03-07 23:59:53 +08:00
|
|
|
|
onClose={() => setShowCreateModal(false)}
|
|
|
|
|
onChange={handleInputChange}
|
|
|
|
|
onSubmit={handleCreateKnowledgeBase}
|
2025-03-22 10:13:42 +08:00
|
|
|
|
currentUser={currentUser}
|
2025-03-07 23:59:53 +08:00
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
{/* 申请权限弹窗 */}
|
2025-03-13 09:14:25 +08:00
|
|
|
|
<AccessRequestModal
|
|
|
|
|
show={showAccessRequestModal}
|
|
|
|
|
knowledgeBaseId={accessRequestKnowledgeBase.id}
|
|
|
|
|
knowledgeBaseTitle={accessRequestKnowledgeBase.title}
|
|
|
|
|
onClose={() => setShowAccessRequestModal(false)}
|
|
|
|
|
onSubmit={handleSubmitAccessRequest}
|
|
|
|
|
isSubmitting={isSubmittingRequest}
|
|
|
|
|
/>
|
2025-02-27 06:54:19 +08:00
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|