CustomPerm.jsx 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. /* eslint-disable consistent-return */
  2. import { Button, Transfer, Tree } from 'antd'
  3. import React, { useState, useEffect } from 'react'
  4. import styles from './ConnectCompany/index.less'
  5. import { CloseOutlined } from '@ant-design/icons'
  6. import consts from '@/basic/consts'
  7. import { useDispatch } from 'umi'
  8. import { queryDepartmentStaffList } from '@/services/department'
  9. import { useWindowSizeFn } from '@/hooks/event/useWindomSizeFn'
  10. const isChecked = (selectedKeys, eventKey) => selectedKeys.includes(eventKey)
  11. const itemIsChecked = onItemSelectAll => (selectedKeys, checkedKeys, checked, nodeList) => {
  12. if (!checked) {
  13. onItemSelectAll(nodeList, checked)
  14. } else {
  15. const keys = selectedKeys
  16. .filter(({ isDepartment }) => !isDepartment)
  17. .filter(({ key }) => !isChecked(checkedKeys, key))
  18. .map(({ key }) => key)
  19. onItemSelectAll(keys, checked)
  20. }
  21. }
  22. const generateTree = (treeNodes = [], checkedKeys = []) =>
  23. treeNodes.map(({ children, ...props }) => {
  24. const node = {
  25. ...props,
  26. disabled: checkedKeys.length && checkedKeys.includes(props.key),
  27. children: generateTree(children, checkedKeys)
  28. }
  29. if (props.isDepartment) {
  30. node.disabled = children?.every(
  31. item => checkedKeys.includes(item.key) || item.children?.every(u => !u.children?.length)
  32. )
  33. }
  34. return node
  35. })
  36. const CustomPerm = () => {
  37. const [state, setState] = useState({
  38. dataSource: [],
  39. treeKeys: [],
  40. targetKeys: [],
  41. transferDataSource: [],
  42. height: 0
  43. })
  44. function calcTreeHeight() {
  45. const node = document.querySelector('.ant-transfer-list-body')
  46. if (node) {
  47. return node.clientHeight - 56
  48. }
  49. return null
  50. }
  51. useEffect(() => {
  52. const transferDataSource = []
  53. function flatten(list = []) {
  54. list.forEach(item => {
  55. transferDataSource.push({
  56. key: item.key,
  57. title: item.title,
  58. parentId: item.parentId,
  59. children: item.children,
  60. isDepartment: item.isDepartment
  61. })
  62. item.children?.length && flatten(item.children)
  63. })
  64. }
  65. async function fetchList() {
  66. const { code = -1, data = [] } = await queryDepartmentStaffList()
  67. if (code === consts.RET_CODE.SUCCESS) {
  68. const height = calcTreeHeight()
  69. flatten(data)
  70. setState({ ...state, dataSource: data, transferDataSource, height })
  71. }
  72. }
  73. fetchList()
  74. }, [])
  75. useWindowSizeFn(() => {
  76. const height = calcTreeHeight()
  77. setState({ ...state, height })
  78. })
  79. const dispatch = useDispatch()
  80. const closeModal = () => {
  81. dispatch({
  82. type: 'single/changeModal'
  83. })
  84. }
  85. const handleOnSearch = (direction, value) => {
  86. console.log(direction, value)
  87. }
  88. const onChange = (keys, direction, moveKeys) => {
  89. if (direction === 'left') {
  90. const currKeys = state.targetKeys.filter(key => !moveKeys.includes(key))
  91. setState({
  92. ...state,
  93. targetKeys: currKeys,
  94. treeKeys: state.treeKeys.filter(item => {
  95. const node = state.transferDataSource.find(i => i.key === item)
  96. if (node?.isDepartment) {
  97. const childrenKey = node?.children.map(c => c.key).filter(c => !currKeys.includes(c))
  98. if (childrenKey?.every(w => !currKeys.includes(w))) {
  99. return !moveKeys.includes(item) && item !== node.key
  100. }
  101. }
  102. return !moveKeys.includes(item)
  103. })
  104. })
  105. } else {
  106. setState({ ...state, targetKeys: [...state.targetKeys, ...keys] })
  107. }
  108. }
  109. const handleUnCheckItem = (checkedKeys, key) => {
  110. const node = state.transferDataSource.find(item => item.key === key)
  111. if (node?.isDepartment) {
  112. const filterKeys = state.transferDataSource
  113. .filter(item => item.parentId === node.key)
  114. .map(item => item.key)
  115. setState({
  116. ...state,
  117. treeKeys: state.treeKeys.filter(item => ![key, ...filterKeys].includes(item))
  118. })
  119. } else {
  120. const pNode = state.transferDataSource.find(item => item.key === node.parentId)
  121. if (checkedKeys.includes(pNode.key)) {
  122. // 说明 父节点已经被选中
  123. setState({
  124. ...state,
  125. treeKeys: state.treeKeys.filter(item => item !== pNode.key && item !== key)
  126. })
  127. } else {
  128. setState({
  129. ...state,
  130. treeKeys: state.treeKeys.filter(item => item !== key)
  131. })
  132. }
  133. }
  134. }
  135. return (
  136. <div className={['ant-modal-content', styles.modalContainer].join(' ')}>
  137. <div className={styles.modalHeader}>
  138. <span>自定义展示数据</span>
  139. <span className={styles.closeIcon}>
  140. <CloseOutlined onClick={closeModal} />
  141. </span>
  142. </div>
  143. <div className={styles.modalContent}>
  144. <Transfer
  145. showSearch
  146. oneWay={true}
  147. className="h-full"
  148. render={item => item.title}
  149. onSearch={handleOnSearch}
  150. targetKeys={state.targetKeys}
  151. onChange={onChange}
  152. dataSource={state.transferDataSource}
  153. showSelectAll={false}>
  154. {({ direction, onItemSelectAll, onItemSelect }) => {
  155. if (direction === 'left') {
  156. const checkedKeys = [...state.targetKeys, ...state.treeKeys]
  157. return state.dataSource?.length ? (
  158. <Tree
  159. blockNode
  160. checkable
  161. defaultExpandAll
  162. height={state.height}
  163. checkedKeys={checkedKeys}
  164. treeData={generateTree(state.dataSource, state.targetKeys)}
  165. onCheck={(_, { checked, checkedNodes, node: { isDepartment, key } }) => {
  166. if (!checked) {
  167. handleUnCheckItem(checkedKeys, key)
  168. } else {
  169. setState({
  170. ...state,
  171. treeKeys: checkedNodes.map(item => item.key)
  172. })
  173. }
  174. if (isDepartment) {
  175. itemIsChecked(onItemSelectAll)(
  176. checkedNodes,
  177. checkedKeys,
  178. checked,
  179. state.transferDataSource
  180. .filter(item => item.parentId === key)
  181. .map(item => item.key)
  182. )
  183. } else {
  184. onItemSelect(key, !isChecked(checkedKeys, key))
  185. }
  186. }}
  187. onSelect={(_, { checkedNodes, node: { isDepartment, key } }) => {
  188. if (isDepartment) {
  189. itemIsChecked(onItemSelectAll)(checkedNodes, checkedKeys)
  190. } else {
  191. onItemSelect(key, !isChecked(checkedKeys, key))
  192. }
  193. }}
  194. />
  195. ) : null
  196. }
  197. }}
  198. </Transfer>
  199. </div>
  200. <div className={[styles.modalFooter, 'text-right'].join(' ')}>
  201. <Button className="mr-4" onClick={closeModal}>
  202. 取消
  203. </Button>
  204. <Button type="primary">确定</Button>
  205. </div>
  206. </div>
  207. )
  208. }
  209. export default CustomPerm