From 7e6424e9ac17c4a28a381c22758953dee6098c0f Mon Sep 17 00:00:00 2001 From: Wenyan Date: Thu, 22 Jan 2026 19:02:44 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=9F=A5=E8=AF=86?= =?UTF-8?q?=E5=BA=93=E9=85=8D=E7=BD=AE=E7=AE=A1=E7=90=86=E7=9A=84=E6=9D=83?= =?UTF-8?q?=E9=99=90=E6=A3=80=E6=9F=A5=E5=92=8C=E9=94=99=E8=AF=AF=E6=8F=90?= =?UTF-8?q?=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 权限检查优化 - 使用 hasPermission('dify:bind:update') 替代硬编码的角色判断 - 支持细粒度的权限控制,市级管理员可以通过授权获得编辑权限 - 保留降级方案,provincial_admin 角色自动拥有所有权限 2. 错误处理优化 - 新增统一的 handleApiError 错误处理函数 - 优先显示后端返回的具体错误信息(error.response.data.msg) - 支持多种错误格式的提取(axios、fetch、自定义格式) - 简化 handleCreate、handleUpdate、handleDelete 的错误处理代码 3. 调试支持 - 添加权限检查的调试日志,便于排查问题 - 输出当前路由、用户角色、权限列表等关键信息 修复问题: - 市级管理员被授予 dify:bind:update 权限后,编辑按钮仍不显示 - 403 错误只显示通用提示,无法看到后端返回的具体错误原因 Co-Authored-By: Claude Sonnet 4.5 --- app/hooks/use-area-dataset-config.ts | 83 +++++++++++++++++++--------- 1 file changed, 57 insertions(+), 26 deletions(-) diff --git a/app/hooks/use-area-dataset-config.ts b/app/hooks/use-area-dataset-config.ts index 23b8bfe..f0d27e1 100644 --- a/app/hooks/use-area-dataset-config.ts +++ b/app/hooks/use-area-dataset-config.ts @@ -67,14 +67,63 @@ const ROLE_LABELS: Record = { export function useAreaDatasetConfig(): UseAreaDatasetConfigReturn { // 权限控制 - const { userRole: permissionUserRole } = usePermission(); + const { hasPermission, userRole: permissionUserRole, permissions, permissionMap } = usePermission(); - // 根据 userRole 判断权限 - // provincial_admin 可以管理所有知识库配置 - // 其他角色只能查看自己地区的配置 - const canManageDataset = permissionUserRole === 'provincial_admin' || permissionUserRole.toLowerCase().includes('provin'); + // 根据权限判断是否可以管理知识库配置 + // 权限键:dify:bind:update(知识库绑定更新权限) + // 降级方案:如果 permissionMap 中没有配置权限,usePermission 会自动降级为角色判断 + const canManageDataset = hasPermission('dify:bind:update'); 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([]); // 保存所有数据用于提取地区 @@ -221,13 +270,7 @@ export function useAreaDatasetConfig(): UseAreaDatasetConfigReturn { return false; } } catch (error: any) { - console.error('创建知识库绑定失败:', error); - // 检查是否为403权限不足错误 - if (error?.response?.status === 403 || error?.status === 403 || error?.code === 403) { - message.error('无权限操作:您没有创建知识库绑定的权限'); - } else { - message.error('创建失败,请稍后重试'); - } + handleApiError(error, '创建'); return false; } finally { setSubmitLoading(false); @@ -259,13 +302,7 @@ export function useAreaDatasetConfig(): UseAreaDatasetConfigReturn { return false; } } catch (error: any) { - console.error('更新知识库绑定失败:', error); - // 检查是否为403权限不足错误 - if (error?.response?.status === 403 || error?.status === 403 || error?.code === 403) { - message.error('无权限操作:您没有编辑知识库绑定的权限'); - } else { - message.error('更新失败,请稍后重试'); - } + handleApiError(error, '更新'); return false; } finally { setSubmitLoading(false); @@ -296,13 +333,7 @@ export function useAreaDatasetConfig(): UseAreaDatasetConfigReturn { return false; } } catch (error: any) { - console.error('删除知识库绑定失败:', error); - // 检查是否为403权限不足错误 - if (error?.response?.status === 403 || error?.status === 403 || error?.code === 403) { - message.error('无权限操作:您没有删除知识库绑定的权限'); - } else { - message.error('删除失败,请稍后重试'); - } + handleApiError(error, '删除'); return false; } },