浏览代码

Merge branch 'dev' of http://192.168.1.41:3000/lanjianrong/financial_audit_console into dev

outaozhen 3 年之前
父节点
当前提交
fa8eeb70b8

+ 7 - 3
src/pages/Permission/Role/components/ConnectModal/index.tsx

@@ -1,14 +1,16 @@
 import TreeNodeSelect from '@/pages/Project/Management/List/components/TreeNodeSelect'
-import { LinkRoleAccountItem } from '@/services/permission'
+import { linkRoleAccount } from '@/services/permission'
 import { PlusOutlined } from '@ant-design/icons'
 import ProForm, { ModalForm } from '@ant-design/pro-form'
 import { Button, message } from 'antd'
-import React from 'react'
+import { useRef } from 'react'
+import type { ProFormInstance } from '@ant-design/pro-form'
 import { useRequest } from 'umi'
 
 const ConnectModal = ({ dataId, onReload }) => {
+  const formRef = useRef<ProFormInstance>(null)
   const { run: tryConnectRoleAccount } = useRequest(
-    (params: API.LinkAccountItem) => LinkRoleAccountItem(params),
+    (params: API.LinkAccountParams) => linkRoleAccount(params),
     {
       manual: true,
       onSuccess: async () => {
@@ -18,10 +20,12 @@ const ConnectModal = ({ dataId, onReload }) => {
   )
   return (
     <ModalForm
+      formRef={formRef}
       title="添加用户"
       width="500px"
       labelCol={{ span: 4 }}
       wrapperCol={{ span: 16 }}
+      onVisibleChange={visible => !visible && formRef.current?.resetFields()}
       layout="horizontal"
       trigger={
         <Button size="small" type="primary" ghost>

+ 1 - 0
src/pages/Permission/Role/components/RoleLeftMenu/index.less

@@ -2,6 +2,7 @@
   box-shadow: inset 0 -1px 0 1px #f0f0f0;
 }
 .department-node {
+  min-height: 32px;
   @apply flex justify-between items-center;
   .extra {
     display: none;

+ 86 - 49
src/pages/Permission/Role/components/RoleLeftMenu/index.tsx

@@ -1,4 +1,5 @@
-import { addRoleMenu, delRoleMenu, updateRoleMenu } from '@/services/permission'
+import { addRoleMenu, delRoleMenuByRoleID, updateRoleMenu } from '@/services/permission'
+import { isNullOrUnDef } from '@/utils/is'
 import {
   DeleteOutlined,
   FormOutlined,
@@ -6,25 +7,46 @@ import {
   QuestionCircleOutlined
 } from '@ant-design/icons'
 import { ModalForm, ProFormText } from '@ant-design/pro-form'
+import type { ProFormInstance } from '@ant-design/pro-form'
+import type { TreeDataNode } from 'antd'
 import { Button, Input, Tree, message, Popconfirm } from 'antd'
-import React, { useEffect, useState } from 'react'
+import { useRef, useState } from 'react'
 import { useRequest } from 'umi'
-import './index.less'
 const { DirectoryTree } = Tree
+import './index.less'
+
+export enum RoleType {
+  SYSTEM = 'system', // 超级管理员
+  SYSTEM_NORMAL = 'systemNormal', // 普通用户
+  NORMAL = 'normal' // 手动添加的角色
+}
+
+type RoleLeftMenuProps = {
+  defaultActiveRole?: string
+  onSelect: (...args) => void
+  showDelIcon: boolean
+  onReloadStaff: () => void
+}
+
+const RoleLeftMenu: React.FC<RoleLeftMenuProps> = ({
+  defaultActiveRole,
+  onSelect,
+  menuRoles,
+  showDelIcon,
+  onReloadStaff
+}) => {
+  const formRef = useRef<ProFormInstance>(null)
+  const [activeID, setActiveID] = useState<Nullable<string>>(null)
 
-const RoleLeftMenu = ({ onSelect, menuRoles, onReloadStaff }) => {
-  const [state, setState] = useState({
-    value: ''
-  })
   const { run: tryAddRole } = useRequest((params: API.CreateRoleParams) => addRoleMenu(params), {
     manual: true,
-    onSuccess: () => {}
+    onSuccess: () => {
+      onReloadStaff()
+    }
   })
-  const onChangeName = value => {
-    setState({ ...state, name: value })
-  }
+
   const { run: tryUpdateRole } = useRequest(
-    (ID: string, name: string) => updateRoleMenu({ ID, name }),
+    (params: Partial<API.UpdateRoleParams>) => updateRoleMenu(params),
     {
       manual: true,
       onSuccess: () => {
@@ -33,45 +55,63 @@ const RoleLeftMenu = ({ onSelect, menuRoles, onReloadStaff }) => {
       }
     }
   )
-  const { run: tryDelRole } = useRequest((ID: string) => delRoleMenu({ ID }), {
+
+  const { run: tryDelRole } = useRequest((ID: string) => delRoleMenuByRoleID({ ID }), {
     manual: true,
     onSuccess: () => {
       message.success('删除成功')
       onReloadStaff()
     }
   })
+  const handleOnFocus = async (
+    e: React.FocusEvent<HTMLInputElement> | React.KeyboardEvent<HTMLElement>,
+    oldTitle: string,
+    ID: string
+  ) => {
+    const val = e.currentTarget.value || e.currentTarget.nodeValue
+    if (val !== oldTitle) {
+      await tryUpdateRole({ ID, name: val })
+    }
+    setActiveID(null)
+  }
+
   function renderTreeNode(tree) {
-    return tree.map(item => {
+    return tree.map((item: TreeDataNode & { roleType: string }) => {
+      // 系统管理员,系统用户不能删除、编辑
       const newItem = {
         ...item,
-        title: (
+        title: [RoleType.SYSTEM, RoleType.SYSTEM_NORMAL].includes(item.roleType) ? (
+          <span className="department-node py-1">{item.title}</span>
+        ) : (
           <div className="department-node py-1">
-            <div>{item.title}</div>
+            {item.key === activeID ? (
+              <Input
+                autoFocus
+                defaultValue={item.title}
+                bordered={false}
+                size="small"
+                style={{ width: '70%', backgroundColor: 'white' }}
+                onBlur={e => handleOnFocus(e, item.title, item.key)}
+                onPressEnter={e => handleOnFocus(e, item.title, item.key)}
+              />
+            ) : (
+              item.title
+            )}
             <div className="extra">
-              {item.roleType !== 'system' ? (
-                <>
-                  <Popconfirm
-                    title={
-                      <Input
-                        placeholder="角色名称"
-                        onChange={e => onChangeName(e.currentTarget.value)}
-                      />
-                    }
-                    okText="确定"
-                    cancelText="取消"
-                    onConfirm={() => tryUpdateRole(item.key, state.name)}>
-                    <FormOutlined className="pr-2" />
-                  </Popconfirm>
-                  <Popconfirm
-                    title="确认删除吗?"
-                    onText="确认"
-                    cancelText="取消"
-                    onConfirm={() => tryDelRole(item.key)}
-                    icon={<QuestionCircleOutlined style={{ color: 'red' }} />}>
-                    <DeleteOutlined />
-                  </Popconfirm>
-                </>
-              ) : null}
+              <FormOutlined className="pr-2" onClick={() => setActiveID(item.key)} />
+              <Popconfirm
+                disabled={!showDelIcon}
+                title="确认删除吗?"
+                onText="确认"
+                cancelText="取消"
+                onConfirm={() => tryDelRole(item.key)}
+                icon={<QuestionCircleOutlined style={{ color: 'red' }} />}>
+                <DeleteOutlined
+                  onClick={() => {
+                    !showDelIcon && message.warning('请先移除该角色下的所有用户')
+                  }}
+                />
+              </Popconfirm>
             </div>
           </div>
         )
@@ -82,22 +122,20 @@ const RoleLeftMenu = ({ onSelect, menuRoles, onReloadStaff }) => {
       return newItem
     })
   }
-  useEffect(() => {
-    onReloadStaff()
-  }, [])
 
+  if (!menuRoles?.length || isNullOrUnDef(defaultActiveRole)) return null
   return (
     <div
       className="w-216px rounded-20px"
       style={{ height: 'calc(100vh - 122px)', background: '#ffffff' }}>
-      <div className="p-5 menu-title flex items-center justify-around">
-        <span className="text-16px text-opacity-85">角色列表</span>
+      <div className="menu-title flex items-center justify-around">
+        <span className="py-5 text-16px text-opacity-85">角色列表</span>
         <ModalForm
           title="新建角色"
-          width="500px"
-          labelCol={{ span: 4 }}
-          wrapperCol={{ span: 16 }}
+          width="30%"
+          onVisibleChange={visible => !visible && formRef.current?.resetFields()}
           layout="horizontal"
+          isKeyPressSubmit
           trigger={
             <Button size="small" type="primary" ghost>
               <PlusOutlined />
@@ -109,7 +147,6 @@ const RoleLeftMenu = ({ onSelect, menuRoles, onReloadStaff }) => {
             message.success('添加成功')
             return true
           }}>
-          <ProFormText name="" hidden />
           <ProFormText
             name="name"
             label="角色名称"

+ 31 - 22
src/pages/Permission/Role/index.tsx

@@ -1,23 +1,18 @@
-import {
-  fetchRoleListByMenu,
-  // fetchRoleListByMenu,
-  fetchRoleListByRoleId,
-  UnLinkRoleAccountItem
-} from '@/services/permission'
+import { fetchRoleList, unLinkRoleAccount, fetchRoleStaffListByRoleId } from '@/services/permission'
 import { DeleteOutlined } from '@ant-design/icons'
 import { PageContainer } from '@ant-design/pro-layout'
-import { message, Popconfirm, Table, Tabs } from 'antd'
-import type { ColumnsType } from 'antd/lib/table'
-import React, { useState } from 'react'
+import { message, Popconfirm, Spin, Table, Tabs } from 'antd'
+import { useState } from 'react'
 import { useRequest } from 'umi'
 import ConnectModal from './components/ConnectModal'
 import RoleLeftMenu from './components/RoleLeftMenu'
 import PermTabs from './components/PermTabs'
+import type { ColumnsType } from 'antd/lib/table'
 const { TabPane } = Tabs
 
 const Role = () => {
   const [state, setState] = useState({
-    currentRoleID: '',
+    currentRoleID: null,
     roleType: '',
     frontPermission: [],
     roleStaff: [],
@@ -25,8 +20,8 @@ const Role = () => {
   })
 
   const [menuRoles, setMenuRoles] = useState<API.MenuRoleItem[]>([])
-  const { run: tryGetRoleStaffList } = useRequest(
-    (roleID: string) => fetchRoleListByRoleId({ roleID }),
+  const { run: tryGetRoleStaffList, loading: staffListLoading } = useRequest(
+    (roleID: string) => fetchRoleStaffListByRoleId({ roleID }),
     {
       manual: true,
       onSuccess: result => {
@@ -35,7 +30,7 @@ const Role = () => {
     }
   )
   const { run: tryUnLinkRoleAccount } = useRequest(
-    (params: API.LinkAccountItem) => UnLinkRoleAccountItem(params),
+    (params: API.LinkAccountParams) => unLinkRoleAccount(params),
     {
       manual: true,
       onSuccess: async () => {
@@ -46,12 +41,12 @@ const Role = () => {
   )
 
   const onSelect = (currentRoleID: string, roleType: string, frontPermission: []) => {
+    if (state.currentRoleID === currentRoleID) return
     setState({ ...state, currentRoleID, roleType, frontPermission })
     tryGetRoleStaffList(currentRoleID)
   }
 
-  const { run: tryFetchRoleListByMenu } = useRequest(() => fetchRoleListByMenu(), {
-    manual: true,
+  const { run: tryFetchRoleListByMenu } = useRequest(fetchRoleList, {
     onSuccess: result => {
       setMenuRoles(
         result.map(item => ({
@@ -61,10 +56,16 @@ const Role = () => {
           frontPermission: item?.frontPermission
         }))
       )
-      result?.length && onSelect?.(result[0]?.ID)
+      result?.length && onSelect?.(state.currentRoleID ?? result[0]?.ID)
     }
   })
 
+  const delRoleValidFn = (ID: string) => {
+    if (state.roleStaff.length) {
+      return message.warning('请先移除该角色下的所有用户')
+    }
+    tryDelRole(ID)
+  }
   const columns: ColumnsType<API.MenuByRoleIdItem> = [
     {
       title: '账号',
@@ -91,7 +92,9 @@ const Role = () => {
           title="确定移除吗?"
           okText="确定"
           cancelText="取消"
-          onConfirm={() => tryUnLinkRoleAccount({ ID: state.currentRoleID, accountID: record.ID })}>
+          onConfirm={() => {
+            tryUnLinkRoleAccount({ ID: state.currentRoleID, accountID: record.ID })
+          }}>
           <span className="text-hex-fd3995 cursor-pointer hover:text-hex-e7026e">
             <DeleteOutlined />
           </span>
@@ -99,13 +102,17 @@ const Role = () => {
       )
     }
   ]
+
   return (
     <PageContainer title={false}>
       <div className="h-full w-full flex flex-row">
         <RoleLeftMenu
+          defaultActiveRole={state.currentRoleID ?? menuRoles[0]?.ID}
           onSelect={onSelect}
           menuRoles={menuRoles}
+          showDelIcon={!state.roleStaff.length}
           onReloadStaff={() => tryFetchRoleListByMenu()}
+          delRoleValidFn={delRoleValidFn}
         />
         <div className="w-6/7 ml-8 bg-white p-4 rounded-20px relative">
           <div className="absolute right-4 top-4 z-100">
@@ -118,11 +125,13 @@ const Role = () => {
           </div>
           <Tabs>
             <TabPane tab="用户列表" key="1">
-              <Table<API.MenuByRoleIdItem>
-                columns={columns}
-                dataSource={state.roleStaff}
-                rowKey={row => row.id}
-              />
+              <Spin spinning={staffListLoading}>
+                <Table<API.MenuByRoleIdItem>
+                  columns={columns}
+                  dataSource={state.roleStaff}
+                  rowKey={row => row.id}
+                />
+              </Spin>
             </TabPane>
             <TabPane tab="功能权限" key="2">
               <PermTabs

+ 2 - 2
src/services/api/typings.d.ts

@@ -319,7 +319,7 @@ declare namespace API {
     ID: string
   }
 
-  type MenuByRoleIdItem = {
+  type RoleStaffItem = {
     account: string
     name: string
     institution: {
@@ -328,7 +328,7 @@ declare namespace API {
     }
   }
 
-  type LinkAccountItem = {
+  type LinkAccountParams = {
     ID: string
     accountID: string
   }

+ 6 - 6
src/services/permission.ts

@@ -1,7 +1,7 @@
 import { request } from 'umi'
 
 /** 获取单菜单下的角色列表 */
-export async function fetchRoleListByMenu(params) {
+export async function fetchRoleList(params) {
   return request<API.MenuRoleItem[]>('/role/list', {
     params
   })
@@ -16,7 +16,7 @@ export async function addRoleMenu(params: API.CreateRoleParams) {
 }
 
 /** 编辑菜单下角色 */
-export async function updateRoleMenu(params: API.UpdateRoleParams) {
+export async function updateRoleMenu(params: Partial<API.UpdateRoleParams>) {
   return request('/role/update', {
     method: 'POST',
     data: params
@@ -24,7 +24,7 @@ export async function updateRoleMenu(params: API.UpdateRoleParams) {
 }
 
 /** 删除菜单下角色 */
-export async function delRoleMenu(params: API.DelRoleParams) {
+export async function delRoleMenuByRoleID(params: API.DelRoleParams) {
   return request('/role/delete', {
     method: 'POST',
     data: params
@@ -32,7 +32,7 @@ export async function delRoleMenu(params: API.DelRoleParams) {
 }
 
 /** 获取角色下员工列表 */
-export async function fetchRoleListByRoleId(params) {
+export async function fetchRoleStaffListByRoleId(params) {
   return request<API.MenuByRoleIdItem[]>('/account/list', {
     method: 'POST',
     data: params
@@ -40,7 +40,7 @@ export async function fetchRoleListByRoleId(params) {
 }
 
 /** 角色下关联账号 */
-export async function LinkRoleAccountItem(params: API.LinkAccountItem) {
+export async function linkRoleAccount(params: API.LinkAccountParams) {
   return request('/role/link/account', {
     method: 'POST',
     data: params
@@ -48,7 +48,7 @@ export async function LinkRoleAccountItem(params: API.LinkAccountItem) {
 }
 
 /** 角色下移除账号 */
-export async function UnLinkRoleAccountItem(params: API.LinkAccountItem) {
+export async function unLinkRoleAccount(params: API.LinkAccountParams) {
   return request('/role/unlink/account', {
     method: 'POST',
     data: params