Ver código fonte

fix(area): 修复区域编码重复时的错误提示显示

当用户尝试将区域编码改为已存在的值时,后端返回唯一性约束错误,
但前端未正确解析和显示后端返回的具体错误消息,导致用户只能看到
模糊的"更新失败,请重试"提示。

修改内容:
- 后端:在更新路由的错误处理中添加唯一性约束错误检测
- 前端:修复所有 CRUD 操作的错误处理,正确解析后端返回的 message 字段

修复后,当编码重复时,页面会正确显示:
"数据已存在,请检查唯一性约束(如编码、名称等是否重复)"

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
yourname 12 horas atrás
pai
commit
a04e50d08e

+ 33 - 41
packages/area-management-ui/src/components/AreaManagement.tsx

@@ -19,18 +19,6 @@ type AreaResponse = InferResponseType<typeof areaClient.index.$get, 200>['data']
 type CreateAreaRequest = InferRequestType<typeof areaClient.index.$post>['json'];
 type UpdateAreaRequest = InferRequestType<typeof areaClient[':id']['$put']>['json'];
 
-// 统一操作处理函数
-const handleOperation = async (operation: () => Promise<void>) => {
-  try {
-    await operation();
-    // toast.success('操作成功');
-  } catch (error) {
-    // toast.error('操作失败,请重试');
-    throw error;
-  }
-};
-
-
 export const AreaManagement: React.FC = () => {
   const queryClient = useQueryClient();
   const [expandedNodes, setExpandedNodes] = useState<Set<number>>(new Set());
@@ -66,10 +54,11 @@ export const AreaManagement: React.FC = () => {
   // 创建省市区
   const createMutation = useMutation({
     mutationFn: async (data: CreateAreaRequest) => {
-      await handleOperation(async () => {
-        const res = await areaClientManager.get().index.$post({ json: data });
-        if (res.status !== 201) throw new Error('创建省市区失败');
-      });
+      const res = await areaClientManager.get().index.$post({ json: data });
+      if (res.status !== 201) {
+        const errorResponse = await res.json();
+        throw new Error(errorResponse.message || '创建省市区失败');
+      }
     },
     onSuccess: async (_, variables) => {
       // 显示成功提示
@@ -99,21 +88,22 @@ export const AreaManagement: React.FC = () => {
       // 等待所有进行中的查询完成
       await queryClient.refetchQueries({ queryKey: ['areas-tree-province'] });
     },
-    onError: () => {
-      toast.error('创建失败,请重试');
+    onError: (error) => {
+      toast.error(error.message || '创建失败,请重试');
     }
   });
 
   // 更新省市区
   const updateMutation = useMutation({
     mutationFn: async ({ id, data }: { id: number; data: UpdateAreaRequest }) => {
-      await handleOperation(async () => {
-        const res = await areaClientManager.get()[':id'].$put({
-          param: { id },
-          json: data
-        });
-        if (res.status !== 200) throw new Error('更新省市区失败');
+      const res = await areaClientManager.get()[':id'].$put({
+        param: { id },
+        json: data
       });
+      if (res.status !== 200) {
+        const errorResponse = await res.json();
+        throw new Error(errorResponse.message || '更新省市区失败');
+      }
     },
     onSuccess: async () => {
       // 显示成功提示
@@ -132,20 +122,21 @@ export const AreaManagement: React.FC = () => {
 
       await queryClient.refetchQueries({ queryKey: ['areas-tree-province'] });
     },
-    onError: () => {
-      toast.error('更新失败,请重试');
+    onError: (error) => {
+      toast.error(error.message || '更新失败,请重试');
     }
   });
 
   // 删除省市区
   const deleteMutation = useMutation({
     mutationFn: async (id: number) => {
-      await handleOperation(async () => {
-        const res = await areaClientManager.get()[':id'].$delete({
-          param: { id }
-        });
-        if (res.status !== 204) throw new Error('删除省市区失败');
+      const res = await areaClientManager.get()[':id'].$delete({
+        param: { id }
       });
+      if (res.status !== 204) {
+        const errorResponse = await res.json();
+        throw new Error(errorResponse.message || '删除省市区失败');
+      }
     },
     onSuccess: async () => {
       // 显示成功提示
@@ -164,21 +155,22 @@ export const AreaManagement: React.FC = () => {
 
       await queryClient.refetchQueries({ queryKey: ['areas-tree-province'] });
     },
-    onError: () => {
-      toast.error('删除失败,请重试');
+    onError: (error) => {
+      toast.error(error.message || '删除失败,请重试');
     }
   });
 
   // 启用/禁用省市区
   const toggleStatusMutation = useMutation({
     mutationFn: async ({ id, isDisabled }: { id: number; isDisabled: number }) => {
-      await handleOperation(async () => {
-        const res = await areaClientManager.get()[':id'].$put({
-          param: { id },
-          json: { isDisabled }
-        });
-        if (res.status !== 200) throw new Error('更新省市区状态失败');
+      const res = await areaClientManager.get()[':id'].$put({
+        param: { id },
+        json: { isDisabled }
       });
+      if (res.status !== 200) {
+        const errorResponse = await res.json();
+        throw new Error(errorResponse.message || '更新省市区状态失败');
+      }
     },
     onSuccess: async () => {
       // 显示成功提示
@@ -197,8 +189,8 @@ export const AreaManagement: React.FC = () => {
 
       await queryClient.refetchQueries({ queryKey: ['areas-tree-province'] });
     },
-    onError: () => {
-      toast.error('状态切换失败,请重试');
+    onError: (error) => {
+      toast.error(error.message || '状态切换失败,请重试');
     }
   });
 

+ 5 - 0
packages/shared-crud/src/routes/generic-crud.routes.ts

@@ -487,6 +487,11 @@ export function createCrudRoutes<
             return c.json({ code: 400, message: '参数验证失败', errors: (zodError as any).errors || error.message }, 400);
           }
 
+          // 处理数据库唯一约束错误
+          if (error instanceof Error && error.message.includes('duplicate key value violates unique constraint')) {
+            return c.json({ code: 400, message: '数据已存在,请检查唯一性约束(如编码、名称等是否重复)' }, 400);
+          }
+
           // 处理权限错误,返回403状态码
           if (error instanceof Error && error.message.includes('无权')) {
             return c.json({