/** * 知识库配置管理 Hook * * 提供地区-知识库绑定管理功能 */ import { useState, useEffect, useCallback, useMemo } from 'react'; import { getMyDatasets, getAllDatasets, getAvailableAreas, createDatasetBinding, updateDatasetBinding, deleteDatasetBinding, type AreaDataset, type CreateDatasetRequest, type UpdateDatasetRequest, } from '~/api/v3/dify/area-datasets'; import { message } from 'antd'; import { usePermission } from '~/hooks/usePermission'; // ==================== Type Definitions ==================== export interface UseAreaDatasetConfigReturn { // 数据 datasets: AreaDataset[]; loading: boolean; total: number; userArea: string; userRole: string; areas: string[]; areasLoading: boolean; // 筛选 - 支持多选 filterAreas: string[]; setFilterAreas: (areas: string[]) => void; page: number; setPage: (page: number) => void; pageSize: number; // 表单状态 modalVisible: boolean; setModalVisible: (visible: boolean) => void; editingId: number | null; setEditingId: (id: number | null) => void; submitLoading: boolean; // 操作方法 loadDatasets: () => Promise; loadAreas: () => Promise; handleCreate: (data: CreateDatasetRequest) => Promise; handleUpdate: (id: number, data: UpdateDatasetRequest) => Promise; handleDelete: (id: number) => Promise; // 权限 canManageDataset: boolean; } // 角色名称映射 const ROLE_LABELS: Record = { common: '普通用户', admin: '市级管理员', provincial_admin: '省级管理员', }; // ==================== Hook Implementation ==================== export function useAreaDatasetConfig(): UseAreaDatasetConfigReturn { // 权限控制 const { hasPermission, userRole: permissionUserRole, permissions, permissionMap } = usePermission(); // 根据权限判断是否可以管理知识库配置 // 权限键:dify:bind:update(知识库绑定更新权限) // 降级方案:如果 permissionMap 中没有配置权限,usePermission 会自动降级为角色判断 const canManageDataset = hasPermission('dify:config:manage'); const canViewDataset = true; // 所有登录用户都可以查看 // 🔍 调试日志(修复后可删除) if (typeof window !== 'undefined') { console.log('[DatasetConfig] 权限检查:', { currentPath: window.location.pathname, userRole: permissionUserRole, hasDifyBindUpdate: hasPermission('dify:bind:update'), currentPermissions: permissions, canManageDataset, }); } // ==================== 错误处理工具函数 ==================== /** * 统一处理 API 错误 * @param error 错误对象 * @param operation 操作名称(创建/更新/删除) */ const handleApiError = (error: any, operation: string) => { console.error(`${operation}知识库绑定失败:`, error); // 提取错误信息的优先级: // 1. error.response.data.msg (axios 响应格式) // 2. error.data.msg (其他格式) // 3. error.msg (直接错误对象) // 4. error.response.data.message (备用字段) // 5. error.message (标准错误对象) const errorMsg = error?.response?.data?.msg || error?.data?.msg || error?.msg || error?.response?.data?.message || error?.message; // 检查是否为403权限不足错误 const is403 = error?.response?.status === 403 || error?.status === 403 || error?.code === 403; if (is403) { // 403 错误:显示具体的权限错误信息 message.error(errorMsg || `无权限操作:您没有${operation}知识库绑定的权限`); } else { // 其他错误:显示具体的错误信息或通用提示 message.error(errorMsg || `${operation}失败,请稍后重试`); } }; // ==================== 数据状态 ==================== // 数据状态 const [datasets, setDatasets] = useState([]); const [allDatasets, setAllDatasets] = useState([]); // 保存所有数据用于提取地区 const [loading, setLoading] = useState(false); const [total, setTotal] = useState(0); const [userArea, setUserArea] = useState(''); const [apiAreas, setApiAreas] = useState([]); // API 返回的地区列表 const [areasLoading, setAreasLoading] = useState(false); // 筛选状态 - 支持多选 const [filterAreas, setFilterAreas] = useState([]); const [page, setPage] = useState(1); const pageSize = 20; // 表单状态 const [modalVisible, setModalVisible] = useState(false); const [editingId, setEditingId] = useState(null); const [submitLoading, setSubmitLoading] = useState(false); // 从数据集中提取地区列表 const extractedAreas = useMemo(() => { const areaSet = new Set(); allDatasets.forEach(ds => { if (ds.area) { areaSet.add(ds.area); } }); return Array.from(areaSet).sort(); }, [allDatasets]); // 合并 API 返回的地区和从数据中提取的地区 const areas = useMemo(() => { const areaSet = new Set([...apiAreas, ...extractedAreas]); return Array.from(areaSet).sort(); }, [apiAreas, extractedAreas]); // 获取角色显示名称 const userRoleLabel = ROLE_LABELS[permissionUserRole] || permissionUserRole || '未知角色'; // ==================== Data Loading ==================== /** * 加载知识库列表 */ const loadDatasets = useCallback(async () => { if (!canViewDataset) { message.warning('您没有查看知识库的权限'); return; } setLoading(true); try { let response; if (canManageDataset) { // 省级管理员:获取所有知识库 // 如果有多个地区筛选,用逗号分隔传递 const areaFilter = filterAreas.length > 0 ? filterAreas.join(',') : undefined; response = await getAllDatasets({ area: areaFilter, only_enabled: false, // 管理员可以看到所有状态 page, page_size: pageSize, }); } else { // 普通用户/市级管理员:获取我的知识库 response = await getMyDatasets(); } console.log('[AreaDatasetConfig] API响应:', response); if (response && response.code === 0 && response.data) { const dataList = Array.isArray(response.data.data) ? response.data.data : []; setDatasets(dataList); setTotal(response.data.total || dataList.length); // 如果没有筛选,保存所有数据用于提取地区 if (filterAreas.length === 0) { setAllDatasets(dataList); } // 如果是 my 接口,保存用户信息 if ('user_area' in response.data) { setUserArea((response.data as any).user_area || ''); } } else { console.error('[AreaDatasetConfig] API响应格式错误:', response); message.error(`加载失败: ${response?.message || '未知错误'}`); } } catch (error: any) { console.error('加载知识库失败:', error); message.error('加载知识库失败,请稍后重试'); } finally { setLoading(false); } }, [canManageDataset, canViewDataset, filterAreas, page, pageSize]); /** * 加载地区列表(仅省级管理员) */ const loadAreas = useCallback(async () => { if (!canManageDataset) return; setAreasLoading(true); try { const areasList = await getAvailableAreas(); console.log('[AreaDatasetConfig] 地区列表响应:', areasList); if (Array.isArray(areasList)) { setApiAreas(areasList); } else { console.warn('[AreaDatasetConfig] 地区列表不是数组:', areasList); setApiAreas([]); } } catch (error: any) { console.error('加载地区列表失败:', error); // 不显示错误提示,因为可以从数据中提取地区 } finally { setAreasLoading(false); } }, [canManageDataset]); // ==================== Operations ==================== /** * 创建知识库绑定 */ const handleCreate = useCallback( async (data: CreateDatasetRequest): Promise => { if (!canManageDataset) { message.error('您没有创建知识库绑定的权限'); return false; } setSubmitLoading(true); try { const response = await createDatasetBinding(data); if (response.code === 0) { message.success('创建成功'); await loadDatasets(); return true; } else { message.error(`创建失败: ${response.message}`); return false; } } catch (error: any) { handleApiError(error, '创建'); return false; } finally { setSubmitLoading(false); } }, [canManageDataset, loadDatasets] ); /** * 更新知识库绑定 */ const handleUpdate = useCallback( async (id: number, data: UpdateDatasetRequest): Promise => { if (!canManageDataset) { message.error('您没有编辑知识库绑定的权限'); return false; } setSubmitLoading(true); try { const response = await updateDatasetBinding(id, data); if (response.code === 0) { message.success('更新成功'); await loadDatasets(); return true; } else { message.error(`更新失败: ${response.message}`); return false; } } catch (error: any) { handleApiError(error, '更新'); return false; } finally { setSubmitLoading(false); } }, [canManageDataset, loadDatasets] ); /** * 删除知识库绑定 */ const handleDelete = useCallback( async (id: number): Promise => { if (!canManageDataset) { message.error('您没有删除知识库绑定的权限'); return false; } try { const response = await deleteDatasetBinding(id); if (response.code === 0) { message.success('删除成功'); await loadDatasets(); return true; } else { message.error(`删除失败: ${response.message}`); return false; } } catch (error: any) { handleApiError(error, '删除'); return false; } }, [canManageDataset, loadDatasets] ); // ==================== Effects ==================== // 初始加载数据 useEffect(() => { loadDatasets(); }, []); // 只在挂载时加载一次 // 加载地区列表 useEffect(() => { loadAreas(); }, [loadAreas]); // 监听筛选条件和页码变化 useEffect(() => { loadDatasets(); }, [filterAreas, page]); return { // 数据 datasets, loading, total, userArea, userRole: userRoleLabel, areas, areasLoading, // 筛选 filterAreas, setFilterAreas, page, setPage, pageSize, // 表单状态 modalVisible, setModalVisible, editingId, setEditingId, submitLoading, // 操作方法 loadDatasets, loadAreas, handleCreate, handleUpdate, handleDelete, // 权限 canManageDataset, }; }