Просмотр исходного кода

✨ feat(admin): 实现客户审核功能组件化重构

- 新增AuditButtons组件,封装客户审核相关功能
- 从Clients页面中提取审核逻辑,优化代码结构
- 实现审核状态显示与操作按钮的动态切换
- 添加审核确认弹窗,防止误操作
- 优化审核状态样式显示,使用颜色标识不同状态

♻️ refactor(admin): 优化客户列表页面代码结构

- 移除Clients页面中的重复审核逻辑
- 使用AuditButtons组件替换内联审核按钮
- 清理未使用的auditClient mutation hook
- 简化表格列定义中的审核状态渲染逻辑
yourname 8 месяцев назад
Родитель
Сommit
431dcbc6e7
2 измененных файлов с 142 добавлено и 96 удалено
  1. 108 0
      src/client/admin/components/AuditButtons.tsx
  2. 34 96
      src/client/admin/pages/Clients.tsx

+ 108 - 0
src/client/admin/components/AuditButtons.tsx

@@ -0,0 +1,108 @@
+import React from 'react';
+import { Button, Space, message, Modal } from 'antd';
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { clientClient } from '@/client/api';
+import type { InferResponseType } from 'hono/client';
+
+type ClientItem = InferResponseType<typeof clientClient.$get, 200>['data'][0];
+
+interface AuditButtonsProps {
+  recordId: number;
+  currentStatus: number;
+  onSuccess?: () => void;
+}
+
+const AuditButtons: React.FC<AuditButtonsProps> = ({ 
+  recordId, 
+  currentStatus, 
+  onSuccess 
+}) => {
+  const queryClient = useQueryClient();
+
+  // 审核客户
+  const auditClient = useMutation({
+    mutationFn: async ({ id, auditStatus }: { id: number; auditStatus: number }) => {
+      const res = await clientClient[':id'].$put({
+        param: { id },
+        json: { auditStatus },
+      });
+      if (!res.ok) {
+        const errorData = await res.json();
+        throw new Error(errorData.message || '审核操作失败');
+      }
+      return res.json();
+    },
+    onSuccess: () => {
+      message.success('审核操作成功');
+      queryClient.invalidateQueries({ queryKey: ['clients'] });
+      onSuccess?.();
+    },
+    onError: (error) => {
+      message.error(error instanceof Error ? error.message : '审核操作失败,请重试');
+    }
+  });
+
+  const handleAudit = (auditStatus: number) => {
+    const actionText = auditStatus === 1 ? '通过审核' : '拒绝审核';
+    const actionType = auditStatus === 1 ? 'success' : 'error';
+    
+    Modal.confirm({
+      title: '确认审核操作',
+      content: `确定要${actionText}该客户吗?此操作不可撤销。`,
+      okText: '确认',
+      cancelText: '取消',
+      okType: actionType,
+      centered: true,
+      onOk: () => {
+        auditClient.mutate({ id: recordId, auditStatus });
+      },
+      onCancel: () => {
+        // 取消操作,不做任何处理
+      },
+    });
+  };
+
+  if (currentStatus !== 0) {
+    // 非待审核状态,显示对应的状态标签
+    const statusMap = {
+      1: { text: '已通过', color: 'green' },
+      2: { text: '已拒绝', color: 'red' }
+    };
+    const config = statusMap[currentStatus as keyof typeof statusMap] || { text: '-', color: 'default' };
+    
+    return (
+      <span className={`inline-flex items-center px-2 py-1 rounded-full text-xs font-medium
+        ${currentStatus === 1 ? 'bg-green-100 text-green-800' : ''}
+        ${currentStatus === 2 ? 'bg-red-100 text-red-800' : ''}
+      `}>
+        {config.text}
+      </span>
+    );
+  }
+
+  // 待审核状态,显示通过和拒绝按钮
+  return (
+    <Space size="small">
+      <Button
+        size="small"
+        type="primary"
+        onClick={() => handleAudit(1)}
+        loading={auditClient.isPending}
+        disabled={auditClient.isPending}
+      >
+        通过
+      </Button>
+      <Button
+        size="small"
+        danger
+        onClick={() => handleAudit(2)}
+        loading={auditClient.isPending}
+        disabled={auditClient.isPending}
+      >
+        拒绝
+      </Button>
+    </Space>
+  );
+};
+
+export default AuditButtons;

+ 34 - 96
src/client/admin/pages/Clients.tsx

@@ -3,6 +3,7 @@ import { Table, Button, Space, Input, Modal, Form ,Select} from 'antd';
 import { App } from 'antd';
 import AreaTreeSelect from '@/client/admin/components/AreaTreeSelect';
 import UserSelect from '@/client/admin/components/UserSelect';
+import AuditButtons from '@/client/admin/components/AuditButtons';
 import { PlusOutlined, EditOutlined, DeleteOutlined, SearchOutlined } from '@ant-design/icons';
 import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
 import { clientClient, areaClient } from '@/client/api';
@@ -229,24 +230,6 @@ const Clients: React.FC = () => {
     }
   });
   
-  // 审核客户
-  const auditClient = useMutation({
-    mutationFn: async ({ id, auditStatus }: { id: number; auditStatus: number }) => {
-      const res = await clientClient[':id'].$put({
-        param: { id },
-        json: { auditStatus } as any,
-      });
-      if (!res.ok) {
-        throw new Error('审核操作失败');
-      }
-      return res.json();
-    },
-    onSuccess: () => {
-      message.success('审核操作成功');
-      queryClient.invalidateQueries({ queryKey: ['clients'] });
-    }
-  });
-  
   const handleDelete = async (id: number) => {
     try {
       await deleteClient.mutateAsync(id);
@@ -254,87 +237,42 @@ const Clients: React.FC = () => {
       message.error('删除失败,请重试');
     }
   };
-
-  const handleAudit = (id: number, auditStatus: number) => {
-    const actionText = auditStatus === 1 ? '通过审核' : '拒绝审核';
-    Modal.confirm({
-      title: '确认审核',
-      content: `确定要${actionText}该客户吗?`,
-      okText: '确定',
-      cancelText: '取消',
-      onOk: async () => {
-        try {
-          await auditClient.mutateAsync({ id, auditStatus });
-        } catch (error) {
-          message.error('审核操作失败,请重试');
-        }
-      },
-    });
-  };
   
   // 表格列定义
   const columns = [
-    {
-      title: '项目名称',
-      dataIndex: 'companyName',
-      key: 'companyName',
-      width: 200,
-      ellipsis: true,
-    },
-    {
-      title: '省份',
-      dataIndex: 'areaId',
-      key: 'province',
-      width: 100,
-      render: (areaId: number) => getAreaDisplay(areaId, 'province'),
-    },
-    {
-      title: '地区',
-      dataIndex: 'areaId',
-      key: 'region',
-      width: 100,
-      render: (areaId: number) => getAreaDisplay(areaId, 'region'),
-    },
-    {
-      title: '登记审核',
-      dataIndex: 'auditStatus',
-      key: 'auditStatus',
-      width: 150,
-      render: (status: number, record: ClientItem) => {
-        const statusMap = {
-          0: { text: '待审核', color: 'orange' },
-          1: { text: '已审核', color: 'green' },
-          2: { text: '已拒绝', color: 'red' }
-        };
-        const config = statusMap[status as keyof typeof statusMap] || { text: '-', color: 'default' };
-        
-        return (
-          <div className="flex items-center space-x-2">
-            <span style={{ color: config.color }}>{config.text}</span>
-            {status === 0 && (
-              <Space size="small">
-                <Button
-                  size="small"
-                  type="primary"
-                  onClick={() => handleAudit(record.id, 1)}
-                  loading={auditClient.isPending}
-                >
-                  通过
-                </Button>
-                <Button
-                  size="small"
-                  danger
-                  onClick={() => handleAudit(record.id, 2)}
-                  loading={auditClient.isPending}
-                >
-                  拒绝
-                </Button>
-              </Space>
-            )}
-          </div>
-        );
-      },
-    },
+  {
+    title: '项目名称',
+    dataIndex: 'companyName',
+    key: 'companyName',
+    width: 200,
+    ellipsis: true,
+  },
+  {
+    title: '省份',
+    dataIndex: 'areaId',
+    key: 'province',
+    width: 100,
+    render: (areaId: number) => getAreaDisplay(areaId, 'province'),
+  },
+  {
+    title: '地区',
+    dataIndex: 'areaId',
+    key: 'region',
+    width: 100,
+    render: (areaId: number) => getAreaDisplay(areaId, 'region'),
+  },
+  {
+    title: '登记审核',
+    dataIndex: 'auditStatus',
+    key: 'auditStatus',
+    width: 150,
+    render: (status: number, record: ClientItem) => (
+      <AuditButtons
+        recordId={record.id}
+        currentStatus={status}
+      />
+    ),
+  },
     {
       title: '主产品/合同估额',
       dataIndex: 'description',