Bläddra i källkod

feat: 新增标段管理-成员管理功能

lanjianrong 4 år sedan
förälder
incheckning
70364bd77b

+ 5 - 1
.eslintrc

@@ -3,7 +3,7 @@
     "browser": true,
     "es6": true
   },
-  "extends": ["eslint:recommended", "plugin:react/recommended", "plugin:@typescript-eslint/eslint-recommended", "prettier/@typescript-eslint"],
+  "extends": ["eslint:recommended", "plugin:react/recommended", "plugin:@typescript-eslint/eslint-recommended", "prettier", "prettier/react", "prettier/@typescript-eslint"],
   "globals": {
     "Atomics": "readonly",
     "SharedArrayBuffer": "readonly"
@@ -18,6 +18,10 @@
   },
   "plugins": ["react", "@typescript-eslint", "react-hooks"],
   "rules": {
+    // "react/jsx-uses-react": 2,
+    // "react/jsx-uses-vars": 2,
+    // "react/react-in-jsx-scope": 2,
+    // "react/jsx-filename-extension": [1, { "“extensions”": [".js", ".ts", ".jsx", ".tsx"] }],
     "semi": ["error", "never"],
     "no-multiple-empty-lines": [1, { "max": 2 }], //空行最多不能超过2行
     "comma-dangle": [2, "never"],

+ 1 - 0
package.json

@@ -153,6 +153,7 @@
     "postcss-normalize": "8.0.1",
     "postcss-preset-env": "6.7.0",
     "postcss-safe-parser": "4.0.1",
+    "prettier": "^2.2.1",
     "react-app-polyfill": "^1.0.6",
     "react-dev-utils": "^10.2.1",
     "resolve": "1.15.0",

+ 1 - 1
src/components/AuditContent/index.tsx

@@ -81,7 +81,7 @@ const Index: React.FC<iAuditContentProps> = props => {
     }
   }, [ visible.check, visible.reCheck ])
   const initGroupList = async (serach?: string) => {
-    const data = await getUserGroup(serach)
+    const data = await getUserGroup({ name: serach })
     setGroups(data)
   }
   const handleVisibleChange = (type: string, isShow: boolean) => {

+ 29 - 0
src/components/Button/index.module.scss

@@ -130,3 +130,32 @@
     border-color: #ffc107;
   }
 }
+
+.dangerButton {
+  :global(.ant-btn) {
+    color: #dc3545;
+    background-color: #ffffff;
+    border-color: #dc3545;
+  }
+  :global(.ant-btn:hover) {
+    color: #ffffff;
+    background-color: #dc3545;
+    border-color: #dc3545;
+  }
+  :global(.ant-btn:focus) {
+    color: #ffffff;
+    background-color: #dc3545;
+    border-color: #dc3545;
+  }
+  :global(.ant-btn:active) {
+    color: #ffffff;
+    background-color: #dc3545;
+    border-color: #dc3545;
+  }
+
+  :global(.ant-btn:not(:hover)) {
+    color: #dc3545;
+    background-color: #ffffff;
+    border-color: #dc3545;
+  }
+}

+ 6 - 1
src/components/Button/index.tsx

@@ -22,6 +22,10 @@ const ZhUploadButton:React.FC<ButtonProps> = props => {
 const ZhAuditBackButton:React.FC<ButtonProps> = props => {
   return <div className={styles.auditBackButton}><Button {...props}></Button></div>
 }
+
+const ZhDangerButton:React.FC<ButtonProps> = props => {
+  return <div className={styles.dangerButton}><Button {...props}></Button></div>
+}
 interface iExpandProps {
   onExpand: () => void
   expanded: boolean
@@ -37,6 +41,7 @@ export {
   ZhSubmitButton,
   ZhUploadButton,
   ExpandButton,
-  ZhAuditBackButton
+  ZhAuditBackButton,
+  ZhDangerButton
 }
 

+ 1 - 1
src/pages/Login/index.tsx

@@ -51,7 +51,7 @@ class NormalLoginForm extends Component<iLoginProps, iState> {
       <Form
         name="normal_login"
         className={styles.loginForm}
-        initialValues={{ password: '123456', code : '234' }}
+        // initialValues={{ password: '123456', code : '234' }}
         onFinish={this.onFinish}
       >
         <h4>纵横工程建设项目管理系统</h4>

+ 1 - 16
src/pages/Management/Setting/index.tsx

@@ -32,22 +32,7 @@ export default function Info() {
     telephone: ''
   }
   const { Search } = Input
-  const [ userList, setUserList ] = useState<iUserInfo[]>([ {
-    "account": "",
-    "accountGroup": 0,
-    "company": "",
-    "csrf": "",
-    "enable": 0,
-    "id": "",
-    "isAdmin": 0,
-    "mobile": "",
-    "name": "",
-    "password": "",
-    "position": "",
-    "projectId": "",
-    "role": "",
-    "telephone": ""
-  } ])
+  const [ userList, setUserList ] = useState<iUserInfo[]>([])
   const initData = async () => {
     const { code = -1, data } = await apiAccountList()
     if (code === consts.RET_CODE.SUCCESS) {

+ 1 - 1
src/pages/Management/Tender/List/components/ModalForm.tsx

@@ -104,7 +104,7 @@ const ModalForm: React.FC<iModalFormProps> = ({
         }).catch(info => {
           message.error(`Validate Failed:${info}`)
         })
-    }}>
+      }}>
       <Form form={form} layout="vertical">
         <Form.Item name={type === 'tender' ? 'folderId' : 'id'} hidden ><Input></Input></Form.Item>
         {

+ 36 - 1
src/pages/Management/Tender/Member/api.ts

@@ -1,4 +1,4 @@
-import request from "@/utils/common/request"
+import request from '@/utils/common/request'
 
 /**
  * 获取标段账号列表
@@ -18,3 +18,38 @@ export async function apiCreateBidAccount(bidsectionId: string, accountId: strin
   const { data } = await request.post('/api/projectSetting/bid/account/create', { bidsectionId, accountId })
   return data
 }
+
+/**
+ * 设置成员权限
+ * @param payload 权限
+ * @param accountId 账号id
+ * @param bidsectionId 标段id
+ */
+export async function apiUpdateBidAccountAuth(payload: {[key: string]: string[]}, accountId: string, bidsectionId: string) {
+  const newPayload = {}
+  for (const key in payload) {
+    if (Object.prototype.hasOwnProperty.call(payload, key)) {
+      const permissions = payload[key]
+      permissions.forEach(item => {
+        newPayload[key + toHumpWord(item)] = 1
+      })
+    }
+  }
+  const { data } = await request.post('/api/projectSetting/bid/account/auth', { ...newPayload, accountId, bidsectionId })
+  return data
+}
+
+/** 将单词开头装换为大写 */
+function toHumpWord(str: string) {
+  return str.toLowerCase().replace(/( |^)[a-z]/g, L => L.toUpperCase())
+}
+
+/**
+ * 移除标段成员账号
+ * @param bidsectionId 标段id
+ * @param accountId 账号id
+ */
+export async function apiDelBidAccount(bidsectionId: string, accountId: string) {
+  const { data } = await request.del('/api/projectSetting/bid/account', { bidsectionId, accountId })
+  return data
+}

+ 10 - 0
src/pages/Management/Tender/Member/index.scss

@@ -0,0 +1,10 @@
+.permission-text {
+  & > :not(:last-of-type) {
+    &::after {
+      content: '、';
+    }
+  }
+  & > :not(:first-of-type) {
+    margin-left: 2px;
+  }
+}

+ 229 - 37
src/pages/Management/Tender/Member/index.tsx

@@ -1,33 +1,81 @@
 import { GroupItem } from '@/components/AuditContent'
+import { ZhButton, ZhDangerButton } from '@/components/Button'
 import Header from '@/components/Header'
 import Slot from '@/components/Header/slot'
 import SvgIcon from '@/components/SvgIcon'
 import { userStore } from '@/store/mobx'
-import { iAccountGroupItem, iUserInfo } from '@/types/setting'
+import { iAccountGroupItem, iPermissionData, iUserInfo } from '@/types/setting'
 import { getUserGroup } from '@/utils/common/user'
 import consts from '@/utils/consts'
 import { Button, Input, message, Popover, Table } from 'antd'
+import { ColumnsType } from 'antd/lib/table'
 import { observer } from 'mobx-react'
-import React, { useState, useEffect, ChangeEvent } from 'react'
+import React, { useState, useEffect, ChangeEvent, useMemo } from 'react'
 import { useActivate } from 'react-activation'
 import { RouteComponentProps } from 'react-router'
-import { apiCreateBidAccount, apiGetSettingAccount } from './api'
-
-
+import { apiCreateBidAccount, apiDelBidAccount, apiGetSettingAccount, apiUpdateBidAccountAuth } from './api'
+import PermissionModal from './modal'
+import './index.scss'
+import { Store } from 'antd/lib/form/interface'
 interface iPopoverState {
   visible: boolean
   searchValue: string
 }
-const Member: React.FC<RouteComponentProps> = (props) => {
-  const { id = '', name = '' }: {id: string, name: string} = props.location.state as any
-  const [ groups, setGroups ] = useState<Array<iAccountGroupItem>>([])
-  const [ popoverState, setPopoverState ] = useState<iPopoverState>({ visible: false, searchValue: '' })
+
+interface PermissionType {
+  access: number
+  add: number
+  delete: number
+}
+
+interface iTableDataState extends iUserInfo {
+  contractPermission: string
+  qualityPermission: string
+  safePermission: string
+}
+
+interface iPermissionModalState {
+  visible: boolean
+  loading: boolean
+  permissionObj: {
+    contract: string
+    quality: string
+    safe: string
+  }
+  id: string
+}
+interface iState {
+  loading: boolean
+  groups: iAccountGroupItem[]
+  popover: iPopoverState
+  dataSource: iTableDataState[]
+  permissionModal: iPermissionModalState
+}
+
+const Member: React.FC<RouteComponentProps> = props => {
+  const { id = '', name = '' }: { id: string; name: string } = props.location.state as any
+  const [ state, setState ] = useState<iState>({
+    groups: [],
+    loading: false,
+    popover: { visible: false, searchValue: '' },
+    dataSource: [],
+    permissionModal: {
+      visible: false,
+      loading: false,
+      permissionObj: {
+        contract: '',
+        safe: '',
+        quality: ''
+      },
+      id: ''
+    }
+  })
   useEffect(() => {
-    popoverState.visible && (initGroupList())
+    state.popover.visible && initGroupList()
     if (!userStore.groupList.length) {
       userStore.getGroupList()
     }
-  }, [ popoverState.visible ])
+  }, [ state.popover.visible ])
 
   useEffect(() => {
     initData()
@@ -35,22 +83,114 @@ const Member: React.FC<RouteComponentProps> = (props) => {
 
   useActivate(() => initData())
   const initData = async () => {
+    setState({ ...state, loading: true })
     const { code = -1, data } = await apiGetSettingAccount(id)
     if (code === consts.RET_CODE.SUCCESS) {
-      console.log(data)
+      setState({ ...state, loading: false, dataSource: data, permissionModal: { ...state.permissionModal, visible: false, loading: false }  })
+    }
+  }
 
+  const openPermissionModal = (id: string, permissionObj: { contract: string; quality: string; safe: string }) => {
+    setState({ ...state, permissionModal: { ...state.permissionModal, visible: true, permissionObj, id } })
+  }
+
+  const deleteSettingMenmber = async (bid: string, id: string) => {
+    const { code = -1 } = await apiDelBidAccount(bid, id)
+    if (code === consts.RET_CODE.SUCCESS) {
+      const newData = state.dataSource.filter(item => item.id !== id)
+      setState({ ...state, dataSource: newData })
+    }
+  }
+  const renderPermissionText = (permission: PermissionType | undefined): React.ReactNode => {
+    if (permission) {
+      let textNode = ''
+      for (const key in permission) {
+        if (Object.prototype.hasOwnProperty.call(permission, key)) {
+          const perm = permission[key]
+          switch (key) {
+            case 'access':
+              perm && (textNode += '<span>创建</span>')
+              break
+            case 'add':
+              perm && (textNode += '<span>删除</span>')
+              break
+            case 'delete':
+              perm && (textNode += '<span>查看所有</span>')
+              break
+            default:
+              break
+          }
+        }
+      }
+      return <div className="permission-text" dangerouslySetInnerHTML={{ __html: textNode }}></div>
     }
   }
+  const columns: ColumnsType<iTableDataState> = [
+    {
+      title: '成员名称',
+      key: 'name',
+      dataIndex: 'name',
+      width: '17%'
+    },
+    {
+      title: '合同管理权限',
+      key: 'contractPermission',
+      dataIndex: 'contractPermission',
+      width: '22%',
+      render: (text: string) => {
+        const contractJson: PermissionType | undefined = text && JSON.parse(text)
+        return renderPermissionText(contractJson)
+      }
+    },
+    {
+      title: '质量管理权限',
+      key: 'qualityPermission',
+      dataIndex: 'qualityPermission',
+      width: '22%',
+      render: (text: string) => {
+        const qualityJson: PermissionType | undefined = text && JSON.parse(text)
+        return renderPermissionText(qualityJson)
+      }
+    },
+    {
+      title: '安全管理权限',
+      key: 'safePermission',
+      dataIndex: 'safePermission',
+      width: '22%',
+      render: (text: string) => {
+        const safeJson: PermissionType | undefined = text && JSON.parse(text)
+        return renderPermissionText(safeJson)
+      }
+    },
+    {
+      title: '操作',
+      dataIndex: 'opreate',
+      key: 'opreate',
+      width: '17%',
+      // eslint-disable-next-line react/display-name
+      render: (_: any, record: iTableDataState) => {
+        const { contractPermission: contract = '', qualityPermission: quality = '', safePermission: safe = '' } = record
+        return (
+          <div className="pi-flex">
+            <ZhButton size="small" className="pi-mg-right-5" onClick={() => openPermissionModal(record.id, { contract, quality, safe })}>
+              权限
+            </ZhButton>
+            <ZhDangerButton size="small" danger onClick={() => deleteSettingMenmber(id, record.id)}>
+              移除
+            </ZhDangerButton>
+          </div>
+        )
+      }
+    }
+  ]
   const initGroupList = async (serach?: string) => {
-    const data = await getUserGroup(serach)
-    console.log(data)
-
-    setGroups(data)
+    const data = await getUserGroup({ name: serach, hasOwner: false })
+    setState({ ...state, groups: data })
   }
 
   const search = (value: string) => {
-    if (value != popoverState.searchValue) {
-      setPopoverState({ ...popoverState, searchValue: value })
+    if (value != state.popover.searchValue) {
+      setState({ ...state, popover: { ...state.popover, searchValue: value } })
       initGroupList(value)
     }
   }
@@ -63,46 +203,98 @@ const Member: React.FC<RouteComponentProps> = (props) => {
     }
   }
 
+  const permissionData = useMemo(() => {
+    const permissionArr: iPermissionData[] = []
+    if (state.permissionModal.visible) {
+      for (const key in state.permissionModal.permissionObj) {
+        if (Object.prototype.hasOwnProperty.call(state.permissionModal.permissionObj, key)) {
+          const modalData: iPermissionData = { label: '', permissions: [], type: key }
+          switch (key) {
+            case 'contract':
+              modalData.label = '合同管理'
+              break
+            case 'quality':
+              modalData.label = '安全巡检'
+              break
+            default:
+              modalData.label = '质量巡检'
+              break
+          }
+          const permission: PermissionType | undefined = state.permissionModal.permissionObj[key] && JSON.parse(state.permissionModal.permissionObj[key])
+          if (permission) {
+            for (const type in permission) {
+              if (Object.prototype.hasOwnProperty.call(permission, type)) {
+                const perm = permission[type]
+                if (perm) {
+                  modalData.permissions.push(type)
+                }
+              }
+            }
+          }
+          permissionArr.push(modalData)
+        }
+      }
+    }
+    return { permissionArr, visible: state.permissionModal.visible, loading: state.permissionModal.loading }
+  }, [ state.permissionModal ])
+
   const itemSelectHandler = async (item: iUserInfo) => {
-    setPopoverState({ ...popoverState, visible: false })
+    setState({ ...state, popover: { ...state.popover, visible: false, searchValue: '' } })
     const { code = -1, msg = '添加成员账号失败!' } = await apiCreateBidAccount(id, item.id)
     if (code === consts.RET_CODE.SUCCESS) {
-      await initGroupList(id)
+      await initData()
       return message.success('创建成功!')
     }
     return message.error(msg)
   }
 
   const handleVisibleChange = (visible: boolean) => {
-    setPopoverState({ ...popoverState, visible })
+    setState({ ...state, popover: { ...state.popover, visible } })
   }
 
   const showPopover = () => {
-    setPopoverState({ ...popoverState, visible: true })
+    setState({ ...state, popover: { ...state.popover, visible: true } })
+  }
+
+  const onModalConfirm = async (values: Store) => {
+    setState({ ...state, permissionModal: { ...state.permissionModal, loading: true } })
+    const { code = -1 } = await apiUpdateBidAccountAuth(values, state.permissionModal.id, id)
+    if (code === consts.RET_CODE.SUCCESS) {
+      initData()
+      return message.success('成员权限更新成功!')
+    }
+    setState({ ...state, permissionModal: { ...state.permissionModal, loading: false } })
+    return message.error('更新失败,请重试!')
+  }
+
+  const onModalCancel = () => {
+    setState({ ...state, permissionModal: { ...state.permissionModal, visible: false } })
   }
   return (
     <div className="wrap-contaniner">
       <Header title={`${name} 成员管理`}>
         <Slot position="right">
-        <Popover
-          title={<Input.Search size="small" placeholder="姓名/手机 检索" onSearch={search} onChange={e => change(e)}></Input.Search>}
-          content={groups.map(item => (
-            <GroupItem {...item} key={item.value} onSelect={(item: iUserInfo) => itemSelectHandler(item)}></GroupItem>
-          ))}
-          overlayClassName="popover-card"
-          trigger="click"
-          visible={popoverState.visible}
-          onVisibleChange={handleVisibleChange}
-          placement="bottomRight">
-          <Button type="primary" size="small" onClick={showPopover}>
-            <span>添加成员</span><SvgIcon type="xxh-caret-down"></SvgIcon>
-          </Button>
-        </Popover>
+          <Popover
+            title={<Input.Search size="small" placeholder="姓名/手机 检索" onSearch={search} onChange={e => change(e)}></Input.Search>}
+            content={state.groups.map(item => (
+              <GroupItem {...item} key={item.value} onSelect={(item: iUserInfo) => itemSelectHandler(item)}></GroupItem>
+            ))}
+            overlayClassName="popover-card"
+            trigger="click"
+            visible={state.popover.visible}
+            onVisibleChange={handleVisibleChange}
+            placement="bottomRight">
+            <Button type="primary" size="small" onClick={showPopover}>
+              <span>添加成员</span>
+              <SvgIcon type="xxh-caret-down"></SvgIcon>
+            </Button>
+          </Popover>
         </Slot>
       </Header>
       <div className="wrap-content">
-        <Table></Table>
+        <Table<iTableDataState>  loading={state.loading} dataSource={state.dataSource} columns={columns} rowKey={record => record.id}  bordered></Table>
       </div>
+      <PermissionModal data={permissionData} onCreate={onModalConfirm} onCancel={onModalCancel}></PermissionModal>
     </div>
   )
 }

+ 82 - 0
src/pages/Management/Tender/Member/modal.tsx

@@ -0,0 +1,82 @@
+import { ZhCloseButton } from '@/components/Button'
+import { iPermissionData } from '@/types/setting'
+import { Button, Checkbox, Form, Modal, Table } from 'antd'
+import { CheckboxOptionType } from 'antd/lib/checkbox'
+import { Store } from 'antd/lib/form/interface'
+import { ColumnsType } from 'antd/lib/table'
+import React, { memo } from 'react'
+
+interface iPermissionSettingProps {
+  onCreate: (values: Store) => void
+  onCancel: () => void
+  data: {
+    permissionArr: iPermissionData[]
+    visible: boolean
+    loading: boolean
+  }
+}
+const PermissionSettingModal: React.FC<iPermissionSettingProps> = ({ onCreate, onCancel, data: { permissionArr, visible, loading } }) => {
+  const checkboxOptions: CheckboxOptionType[] = [
+    { label: '创建', value: 'add' },
+    { label: '删除', value: 'delete' },
+    { label: '查看', value: 'access' }
+  ]
+  const [ form ] = Form.useForm()
+  const columns: ColumnsType<iPermissionData> = [
+    {
+      title: '栏目',
+      dataIndex: 'label',
+      width: '20%',
+      align: 'center'
+    },
+    {
+      title: '权限',
+      dataIndex: 'permissionArr',
+      width: '80%',
+      // eslint-disable-next-line react/display-name
+      render: (_, record) => {
+        return (
+          <Form.Item key={record.type} name={record.type} initialValue={record.permissions}>
+            <Checkbox.Group options={checkboxOptions}></Checkbox.Group>
+          </Form.Item>
+        )
+      }
+    }
+  ]
+  return (
+    <Modal
+      title="权限设置"
+      visible={visible}
+      onCancel={onCancel}
+      getContainer={false}
+      footer={
+        <div className="pi-justify-end">
+          <ZhCloseButton size="small" onClick={onCancel} className="pi-mg-right-5">
+            取消
+          </ZhCloseButton>
+          <Button
+            size="small"
+            type="primary"
+            loading={loading}
+            onClick={() => {
+              form
+                .validateFields()
+                .then(values => {
+                  onCreate(values)
+                })
+                .catch(err => {
+                  console.log(err)
+                })
+            }}>
+            确认修改
+          </Button>
+        </div>
+      }>
+      <Form form={form}>
+        <Table<iPermissionData> dataSource={permissionArr} columns={columns} rowKey={record => record.label} pagination={false} bordered></Table>
+      </Form>
+    </Modal>
+  )
+}
+
+export default memo(PermissionSettingModal)

+ 3 - 2
src/pages/Management/index.tsx

@@ -2,12 +2,13 @@ import LeftSide from '@/components/LeftSide'
 import Guards from '@/components/Navigation'
 import { NavigationGuardsProps } from '@/types/router'
 import React from 'react'
-import { Switch } from 'react-router-dom'
+import { Switch, useLocation } from 'react-router-dom'
 const Management:React.FC<NavigationGuardsProps> = props => {
   const { routeConfig, match, location } = props
+  const locationRef = useLocation()
   return (
     <>
-      <LeftSide childRoutes={routeConfig} location={location}></LeftSide>
+      <LeftSide childRoutes={routeConfig} location={locationRef}></LeftSide>
       <div className="panel-content">
         <Switch>
             <Guards routeConfig={routeConfig} match={match} location={location}></Guards>

+ 1 - 1
src/pages/Quality/Content/Info/Detail/components/Modal/index.tsx

@@ -105,7 +105,7 @@ const AuditModal: React.FC<iAuditModalProps> = props => {
     }
   }, [ visible ])
   const initGroupList = async (serach?: string) => {
-    const data = await getUserGroup(serach)
+    const data = await getUserGroup({ name: serach })
     setGroups(data)
   }
 

+ 1 - 1
src/pages/Safe/Content/Info/Detail/components/Modal/index.tsx

@@ -105,7 +105,7 @@ const AuditModal: React.FC<iAuditModalProps> = props => {
     }
   }, [ visible ])
   const initGroupList = async (serach?: string) => {
-    const data = await getUserGroup(serach)
+    const data = await getUserGroup({ name: serach })
     setGroups(data)
   }
 

+ 8 - 0
src/types/setting.d.ts

@@ -1,3 +1,5 @@
+import { Store } from "antd/lib/form/interface"
+
 export interface iAccountCreatePayload {
   account: string
   password: string
@@ -53,3 +55,9 @@ export interface iGroup {
   key: number
   value: string
 }
+
+export interface iPermissionData {
+  label: string
+  permissions: string[]
+  type: string
+}

+ 11 - 2
src/utils/common/user.ts

@@ -39,14 +39,23 @@ export const getUserGroupName = (key: number): iGroup | undefined =>{
   return userStore.groupList.find((item: iGroup) => item.key === key)
 }
 
+interface UserGroupQuery {
+  name?: string
+  hasOwner?: boolean
+}
 // 根据group对用户列表进行分组
-export const getUserGroup = async (name?: string) => {
+export const getUserGroup = async ({ name = '', hasOwner = true } : UserGroupQuery) => {
   const { code = -1, data = [] } = await apiGetAccountWithSearch(name)
   const accountGroup: iAccountGroupItem[] = []
   if (code === consts.RET_CODE.SUCCESS) {
     for (const group of userStore.groupList) {
       const groupItem = { value: group.value, children: [] }
-      const items = data.filter((item: iUserInfo) => item.accountGroup === group.key)
+      const items = data.filter((item: iUserInfo) => {
+        if (!hasOwner && item.id === userStore.userInfo.id) {
+          return
+        }
+        return item.accountGroup === group.key
+      })
       groupItem.children = items
       accountGroup.push(groupItem)
     }