wsj
3 days ago 0d9778720a5258876079d02bb8603dd202e6b1a8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import { useCallback, useMemo, useRef, useState } from 'react';
import { ProTable } from '@ant-design/pro-components';
import type { ActionType } from '@ant-design/pro-components';
import { App as AntdApp, Descriptions, Drawer, Tag } from 'antd';
import { createRoleColumns, getRoleStatusMeta, getRoleTypeMeta } from './columns';
import { getRoleDetail, getRoleList, toggleRoleStatus } from './service';
import type { RoleListQuery, RoleVO } from './types';
 
const Roles = () => {
  const actionRef = useRef<ActionType>();
  const { message, modal } = AntdApp.useApp();
  const [detail, setDetail] = useState<RoleVO | null>(null);
  const [detailOpen, setDetailOpen] = useState(false);
  const [detailLoading, setDetailLoading] = useState(false);
 
  const handleDetail = useCallback(async (record: RoleVO) => {
    setDetailOpen(true);
    setDetailLoading(true);
 
    try {
      const data = await getRoleDetail({ id: record.id });
      setDetail(data);
    } catch {
      // 错误已由 request 统一提示
      setDetailOpen(false);
    } finally {
      setDetailLoading(false);
    }
  }, []);
 
  const handleToggle = useCallback(
    (record: RoleVO) => {
      const nextAction = record.status === 'ENABLED' ? '禁用' : '启用';
      modal.confirm({
        title: `${nextAction}角色`,
        content: `确定要${nextAction}角色「${record.roleName}」吗?`,
        okText: nextAction,
        cancelText: '取消',
        okButtonProps: { danger: record.status === 'ENABLED' },
        onOk: async () => {
          await toggleRoleStatus({ id: record.id });
          message.success(`角色已${nextAction}`);
          actionRef.current?.reload();
        },
      });
    },
    [message, modal],
  );
 
  const columns = useMemo(
    () => createRoleColumns({ onDetail: handleDetail, onToggle: handleToggle }),
    [handleDetail, handleToggle],
  );
 
  return (
    <div className="role-page">
      <ProTable<RoleVO, RoleListQuery>
        rowKey="id"
        actionRef={actionRef}
        columns={columns}
        cardProps={{ className: 'table-card' }}
        search={{ labelWidth: 'auto', defaultCollapsed: false }}
        scroll={{ x: 960 }}
        options={false}
        pagination={{
          defaultPageSize: 10,
          showSizeChanger: true,
          hideOnSinglePage: false,
          showTotal: (total) => `共 ${total} 条`,
        }}
        request={async (params) => {
          const { current = 1, pageSize = 10, roleName, status } = params;
          const keyword = roleName?.trim().toLowerCase();
          const list = await getRoleList();
          const filtered = list.filter((role) => {
            const matchesKeyword =
              !keyword ||
              role.roleName.toLowerCase().includes(keyword) ||
              role.roleCode.toLowerCase().includes(keyword);
            const matchesStatus = !status || role.status === status;
            return matchesKeyword && matchesStatus;
          });
          const start = (current - 1) * pageSize;
 
          return {
            data: filtered.slice(start, start + pageSize),
            total: filtered.length,
            success: true,
          };
        }}
      />
 
      <Drawer
        title="角色详情"
        width={460}
        open={detailOpen}
        loading={detailLoading}
        onClose={() => {
          setDetailOpen(false);
          setDetail(null);
        }}
      >
        {detail && (
          <Descriptions column={1} bordered size="small">
            <Descriptions.Item label="角色名称">{detail.roleName}</Descriptions.Item>
            <Descriptions.Item label="角色编码">{detail.roleCode}</Descriptions.Item>
            <Descriptions.Item label="角色类型">
              <Tag color={getRoleTypeMeta(detail.roleType).color} bordered={false}>
                {getRoleTypeMeta(detail.roleType).text}
              </Tag>
            </Descriptions.Item>
            <Descriptions.Item label="状态">
              <Tag color={getRoleStatusMeta(detail.status).color} bordered={false}>
                {getRoleStatusMeta(detail.status).text}
              </Tag>
            </Descriptions.Item>
            <Descriptions.Item label="描述">{detail.description || '-'}</Descriptions.Item>
          </Descriptions>
        )}
      </Drawer>
    </div>
  );
};
 
export default Roles;