Files
leaudit-platform-frontend/app/hooks/use-area-dataset-config.ts
T
TanWenyan a4479971a8 feat: 统一403错误提示为'无权限操作'
修改内容:
1. handleCreate: 捕获403错误,显示'无权限操作:您没有创建知识库绑定的权限'
2. handleUpdate: 捕获403错误,显示'无权限操作:您没有编辑知识库绑定的权限'
3. handleDelete: 捕获403错误,显示'无权限操作:您没有删除知识库绑定的权限'

检查逻辑:
- error?.response?.status === 403
- error?.status === 403
- error?.code === 403

优势:用户能清楚知道是权限问题,而不是系统错误
2025-12-08 16:12:01 +08:00

364 lines
10 KiB
TypeScript

/**
* 知识库配置管理 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<void>;
loadAreas: () => Promise<void>;
handleCreate: (data: CreateDatasetRequest) => Promise<boolean>;
handleUpdate: (id: number, data: UpdateDatasetRequest) => Promise<boolean>;
handleDelete: (id: number) => Promise<boolean>;
// 权限
canManageDataset: boolean;
}
// 角色名称映射
const ROLE_LABELS: Record<string, string> = {
common: '普通用户',
admin: '市级管理员',
provincial_admin: '省级管理员',
};
// ==================== Hook Implementation ====================
export function useAreaDatasetConfig(): UseAreaDatasetConfigReturn {
// 权限控制
const { userRole: permissionUserRole } = usePermission();
// 根据 userRole 判断权限
// provincial_admin 可以管理所有知识库配置
// 其他角色只能查看自己地区的配置
const canManageDataset = permissionUserRole === 'provincial_admin' || permissionUserRole.toLowerCase().includes('provin');
const canViewDataset = true; // 所有登录用户都可以查看
// 数据状态
const [datasets, setDatasets] = useState<AreaDataset[]>([]);
const [allDatasets, setAllDatasets] = useState<AreaDataset[]>([]); // 保存所有数据用于提取地区
const [loading, setLoading] = useState<boolean>(false);
const [total, setTotal] = useState<number>(0);
const [userArea, setUserArea] = useState<string>('');
const [apiAreas, setApiAreas] = useState<string[]>([]); // API 返回的地区列表
const [areasLoading, setAreasLoading] = useState<boolean>(false);
// 筛选状态 - 支持多选
const [filterAreas, setFilterAreas] = useState<string[]>([]);
const [page, setPage] = useState<number>(1);
const pageSize = 20;
// 表单状态
const [modalVisible, setModalVisible] = useState<boolean>(false);
const [editingId, setEditingId] = useState<number | null>(null);
const [submitLoading, setSubmitLoading] = useState<boolean>(false);
// 从数据集中提取地区列表
const extractedAreas = useMemo(() => {
const areaSet = new Set<string>();
allDatasets.forEach(ds => {
if (ds.area) {
areaSet.add(ds.area);
}
});
return Array.from(areaSet).sort();
}, [allDatasets]);
// 合并 API 返回的地区和从数据中提取的地区
const areas = useMemo(() => {
const areaSet = new Set<string>([...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<boolean> => {
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) {
console.error('创建知识库绑定失败:', error);
// 检查是否为403权限不足错误
if (error?.response?.status === 403 || error?.status === 403 || error?.code === 403) {
message.error('无权限操作:您没有创建知识库绑定的权限');
} else {
message.error('创建失败,请稍后重试');
}
return false;
} finally {
setSubmitLoading(false);
}
},
[canManageDataset, loadDatasets]
);
/**
* 更新知识库绑定
*/
const handleUpdate = useCallback(
async (id: number, data: UpdateDatasetRequest): Promise<boolean> => {
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) {
console.error('更新知识库绑定失败:', error);
// 检查是否为403权限不足错误
if (error?.response?.status === 403 || error?.status === 403 || error?.code === 403) {
message.error('无权限操作:您没有编辑知识库绑定的权限');
} else {
message.error('更新失败,请稍后重试');
}
return false;
} finally {
setSubmitLoading(false);
}
},
[canManageDataset, loadDatasets]
);
/**
* 删除知识库绑定
*/
const handleDelete = useCallback(
async (id: number): Promise<boolean> => {
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) {
console.error('删除知识库绑定失败:', error);
// 检查是否为403权限不足错误
if (error?.response?.status === 403 || error?.status === 403 || error?.code === 403) {
message.error('无权限操作:您没有删除知识库绑定的权限');
} else {
message.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,
};
}