index.tsx 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. import { addRoleMenu, delRoleMenuByRoleID, updateRoleMenu } from '@/services/permission'
  2. import { isNullOrUnDef } from '@/utils/is'
  3. import {
  4. DeleteOutlined,
  5. FormOutlined,
  6. PlusOutlined,
  7. QuestionCircleOutlined
  8. } from '@ant-design/icons'
  9. import { ModalForm, ProFormText } from '@ant-design/pro-form'
  10. import type { ProFormInstance } from '@ant-design/pro-form'
  11. import type { TreeDataNode } from 'antd'
  12. import { Button, Input, Tree, message, Popconfirm } from 'antd'
  13. import { useRef, useState } from 'react'
  14. import { useRequest } from 'umi'
  15. const { DirectoryTree } = Tree
  16. import './index.less'
  17. export enum RoleType {
  18. SYSTEM = 'system', // 超级管理员
  19. SYSTEM_NORMAL = 'systemNormal', // 普通用户
  20. NORMAL = 'normal' // 手动添加的角色
  21. }
  22. type RoleLeftMenuProps = {
  23. defaultActiveRole?: string
  24. onSelect: (...args) => void
  25. showDelIcon: boolean
  26. onReloadStaff: () => void
  27. }
  28. const RoleLeftMenu: React.FC<RoleLeftMenuProps> = ({
  29. defaultActiveRole,
  30. onSelect,
  31. menuRoles,
  32. showDelIcon,
  33. onReloadStaff
  34. }) => {
  35. const formRef = useRef<ProFormInstance>(null)
  36. const [activeID, setActiveID] = useState<Nullable<string>>(null)
  37. const { run: tryAddRole } = useRequest((params: API.CreateRoleParams) => addRoleMenu(params), {
  38. manual: true,
  39. onSuccess: () => {
  40. onReloadStaff()
  41. }
  42. })
  43. const { run: tryUpdateRole } = useRequest(
  44. (params: Partial<API.UpdateRoleParams>) => updateRoleMenu(params),
  45. {
  46. manual: true,
  47. onSuccess: () => {
  48. message.success('修改成功')
  49. onReloadStaff()
  50. }
  51. }
  52. )
  53. const { run: tryDelRole } = useRequest((ID: string) => delRoleMenuByRoleID({ ID }), {
  54. manual: true,
  55. onSuccess: () => {
  56. message.success('删除成功')
  57. onReloadStaff()
  58. }
  59. })
  60. const handleOnFocus = async (
  61. e: React.FocusEvent<HTMLInputElement> | React.KeyboardEvent<HTMLElement>,
  62. oldTitle: string,
  63. ID: string
  64. ) => {
  65. const val = e.currentTarget.value || e.currentTarget.nodeValue
  66. if (val !== oldTitle) {
  67. await tryUpdateRole({ ID, name: val })
  68. }
  69. setActiveID(null)
  70. }
  71. function renderTreeNode(tree) {
  72. return tree.map((item: TreeDataNode & { roleType: string }) => {
  73. // 系统管理员,系统用户不能删除、编辑
  74. const newItem = {
  75. ...item,
  76. title: [RoleType.SYSTEM, RoleType.SYSTEM_NORMAL].includes(item.roleType) ? (
  77. <span className="department-node py-1">{item.title}</span>
  78. ) : (
  79. <div className="department-node py-1">
  80. {item.key === activeID ? (
  81. <Input
  82. autoFocus
  83. defaultValue={item.title}
  84. bordered={false}
  85. size="small"
  86. style={{ width: '70%', backgroundColor: 'white' }}
  87. onBlur={e => handleOnFocus(e, item.title, item.key)}
  88. onPressEnter={e => handleOnFocus(e, item.title, item.key)}
  89. />
  90. ) : (
  91. item.title
  92. )}
  93. <div className="extra">
  94. <FormOutlined className="pr-2" onClick={() => setActiveID(item.key)} />
  95. <Popconfirm
  96. disabled={!showDelIcon}
  97. title="确认删除吗?"
  98. onText="确认"
  99. cancelText="取消"
  100. onConfirm={() => tryDelRole(item.key)}
  101. icon={<QuestionCircleOutlined style={{ color: 'red' }} />}>
  102. <DeleteOutlined
  103. onClick={() => {
  104. !showDelIcon && message.warning('请先移除该角色下的所有用户')
  105. }}
  106. />
  107. </Popconfirm>
  108. </div>
  109. </div>
  110. )
  111. }
  112. if (newItem.children?.length) {
  113. newItem.children = renderTreeNode(newItem.children)
  114. }
  115. return newItem
  116. })
  117. }
  118. if (!menuRoles?.length || isNullOrUnDef(defaultActiveRole)) return null
  119. return (
  120. <div
  121. className="w-216px rounded-20px"
  122. style={{ height: 'calc(100vh - 122px)', background: '#ffffff' }}>
  123. <div className="menu-title flex items-center justify-around">
  124. <span className="py-5 text-16px text-opacity-85">角色列表</span>
  125. <ModalForm
  126. title="新建角色"
  127. width="30%"
  128. onVisibleChange={visible => !visible && formRef.current?.resetFields()}
  129. layout="horizontal"
  130. isKeyPressSubmit
  131. trigger={
  132. <Button size="small" type="primary" ghost>
  133. <PlusOutlined />
  134. 添加
  135. </Button>
  136. }
  137. onFinish={async values => {
  138. await tryAddRole(values)
  139. message.success('添加成功')
  140. return true
  141. }}>
  142. <ProFormText
  143. name="name"
  144. label="角色名称"
  145. rules={[{ required: true, message: '请输入角色名' }]}
  146. />
  147. </ModalForm>
  148. </div>
  149. <div className="mt-2">
  150. <DirectoryTree
  151. defaultSelectedKeys={[defaultActiveRole]}
  152. onSelect={(keys, node) => keys?.[0] && onSelect(keys[0], node.node.roleType)}
  153. showIcon={false}
  154. treeData={renderTreeNode(menuRoles)}
  155. />
  156. </div>
  157. </div>
  158. )
  159. }
  160. export default RoleLeftMenu