|
|
@@ -0,0 +1,220 @@
|
|
|
+/* eslint-disable consistent-return */
|
|
|
+import { Button, Transfer, Tree } from 'antd'
|
|
|
+import React, { useState, useEffect } from 'react'
|
|
|
+import styles from './ConnectCompany/index.less'
|
|
|
+import { CloseOutlined } from '@ant-design/icons'
|
|
|
+import consts from '@/basic/consts'
|
|
|
+import { useDispatch } from 'umi'
|
|
|
+import { queryDepartmentStaffList } from '@/services/department'
|
|
|
+import { useWindowSizeFn } from '@/hooks/event/useWindomSizeFn'
|
|
|
+
|
|
|
+const isChecked = (selectedKeys, eventKey) => selectedKeys.includes(eventKey)
|
|
|
+
|
|
|
+const itemIsChecked = onItemSelectAll => (selectedKeys, checkedKeys, checked, nodeList) => {
|
|
|
+ if (!checked) {
|
|
|
+ onItemSelectAll(nodeList, checked)
|
|
|
+ } else {
|
|
|
+ const keys = selectedKeys
|
|
|
+ .filter(({ isDepartment }) => !isDepartment)
|
|
|
+ .filter(({ key }) => !isChecked(checkedKeys, key))
|
|
|
+ .map(({ key }) => key)
|
|
|
+ onItemSelectAll(keys, checked)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const generateTree = (treeNodes = [], checkedKeys = []) =>
|
|
|
+ treeNodes.map(({ children, ...props }) => {
|
|
|
+ const node = {
|
|
|
+ ...props,
|
|
|
+ disabled: checkedKeys.length && checkedKeys.includes(props.key),
|
|
|
+ children: generateTree(children, checkedKeys)
|
|
|
+ }
|
|
|
+ if (props.isDepartment) {
|
|
|
+ node.disabled = children?.every(
|
|
|
+ item => checkedKeys.includes(item.key) || item.children?.every(u => !u.children?.length)
|
|
|
+ )
|
|
|
+ }
|
|
|
+ return node
|
|
|
+ })
|
|
|
+
|
|
|
+const CustomPerm = () => {
|
|
|
+ const [state, setState] = useState({
|
|
|
+ dataSource: [],
|
|
|
+ treeKeys: [],
|
|
|
+ targetKeys: [],
|
|
|
+ transferDataSource: [],
|
|
|
+ height: 0
|
|
|
+ })
|
|
|
+
|
|
|
+ function calcTreeHeight() {
|
|
|
+ const node = document.querySelector('.ant-transfer-list-body')
|
|
|
+ if (node) {
|
|
|
+ return node.clientHeight - 56
|
|
|
+ }
|
|
|
+ return null
|
|
|
+ }
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ const transferDataSource = []
|
|
|
+ function flatten(list = []) {
|
|
|
+ list.forEach(item => {
|
|
|
+ transferDataSource.push({
|
|
|
+ key: item.key,
|
|
|
+ title: item.title,
|
|
|
+ parentId: item.parentId,
|
|
|
+ children: item.children,
|
|
|
+ isDepartment: item.isDepartment
|
|
|
+ })
|
|
|
+ item.children?.length && flatten(item.children)
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ async function fetchList() {
|
|
|
+ const { code = -1, data = [] } = await queryDepartmentStaffList()
|
|
|
+ if (code === consts.RET_CODE.SUCCESS) {
|
|
|
+ const height = calcTreeHeight()
|
|
|
+ flatten(data)
|
|
|
+ setState({ ...state, dataSource: data, transferDataSource, height })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ fetchList()
|
|
|
+ }, [])
|
|
|
+ useWindowSizeFn(() => {
|
|
|
+ const height = calcTreeHeight()
|
|
|
+ setState({ ...state, height })
|
|
|
+ })
|
|
|
+ const dispatch = useDispatch()
|
|
|
+ const closeModal = () => {
|
|
|
+ dispatch({
|
|
|
+ type: 'single/changeModal'
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ const handleOnSearch = (direction, value) => {
|
|
|
+ console.log(direction, value)
|
|
|
+ }
|
|
|
+
|
|
|
+ const onChange = (keys, direction, moveKeys) => {
|
|
|
+ if (direction === 'left') {
|
|
|
+ const currKeys = state.targetKeys.filter(key => !moveKeys.includes(key))
|
|
|
+ setState({
|
|
|
+ ...state,
|
|
|
+ targetKeys: currKeys,
|
|
|
+ treeKeys: state.treeKeys.filter(item => {
|
|
|
+ const node = state.transferDataSource.find(i => i.key === item)
|
|
|
+ if (node?.isDepartment) {
|
|
|
+ const childrenKey = node?.children.map(c => c.key).filter(c => !currKeys.includes(c))
|
|
|
+ if (childrenKey?.every(w => !currKeys.includes(w))) {
|
|
|
+ return !moveKeys.includes(item) && item !== node.key
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return !moveKeys.includes(item)
|
|
|
+ })
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ setState({ ...state, targetKeys: [...state.targetKeys, ...keys] })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const handleUnCheckItem = (checkedKeys, key) => {
|
|
|
+ const node = state.transferDataSource.find(item => item.key === key)
|
|
|
+ if (node?.isDepartment) {
|
|
|
+ const filterKeys = state.transferDataSource
|
|
|
+ .filter(item => item.parentId === node.key)
|
|
|
+ .map(item => item.key)
|
|
|
+ setState({
|
|
|
+ ...state,
|
|
|
+ treeKeys: state.treeKeys.filter(item => ![key, ...filterKeys].includes(item))
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ const pNode = state.transferDataSource.find(item => item.key === node.parentId)
|
|
|
+ if (checkedKeys.includes(pNode.key)) {
|
|
|
+ // 说明 父节点已经被选中
|
|
|
+ setState({
|
|
|
+ ...state,
|
|
|
+ treeKeys: state.treeKeys.filter(item => item !== pNode.key && item !== key)
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ setState({
|
|
|
+ ...state,
|
|
|
+ treeKeys: state.treeKeys.filter(item => item !== key)
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return (
|
|
|
+ <div className={['ant-modal-content', styles.modalContainer].join(' ')}>
|
|
|
+ <div className={styles.modalHeader}>
|
|
|
+ <span>自定义展示数据</span>
|
|
|
+ <span className={styles.closeIcon}>
|
|
|
+ <CloseOutlined onClick={closeModal} />
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <div className={styles.modalContent}>
|
|
|
+ <Transfer
|
|
|
+ showSearch
|
|
|
+ oneWay={true}
|
|
|
+ className="h-full"
|
|
|
+ render={item => item.title}
|
|
|
+ onSearch={handleOnSearch}
|
|
|
+ targetKeys={state.targetKeys}
|
|
|
+ onChange={onChange}
|
|
|
+ dataSource={state.transferDataSource}
|
|
|
+ showSelectAll={false}>
|
|
|
+ {({ direction, onItemSelectAll, onItemSelect }) => {
|
|
|
+ if (direction === 'left') {
|
|
|
+ const checkedKeys = [...state.targetKeys, ...state.treeKeys]
|
|
|
+ return state.dataSource?.length ? (
|
|
|
+ <Tree
|
|
|
+ blockNode
|
|
|
+ checkable
|
|
|
+ defaultExpandAll
|
|
|
+ height={state.height}
|
|
|
+ checkedKeys={checkedKeys}
|
|
|
+ treeData={generateTree(state.dataSource, state.targetKeys)}
|
|
|
+ onCheck={(_, { checked, checkedNodes, node: { isDepartment, key } }) => {
|
|
|
+ if (!checked) {
|
|
|
+ handleUnCheckItem(checkedKeys, key)
|
|
|
+ } else {
|
|
|
+ setState({
|
|
|
+ ...state,
|
|
|
+ treeKeys: checkedNodes.map(item => item.key)
|
|
|
+ })
|
|
|
+ }
|
|
|
+ if (isDepartment) {
|
|
|
+ itemIsChecked(onItemSelectAll)(
|
|
|
+ checkedNodes,
|
|
|
+ checkedKeys,
|
|
|
+ checked,
|
|
|
+ state.transferDataSource
|
|
|
+ .filter(item => item.parentId === key)
|
|
|
+ .map(item => item.key)
|
|
|
+ )
|
|
|
+ } else {
|
|
|
+ onItemSelect(key, !isChecked(checkedKeys, key))
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ onSelect={(_, { checkedNodes, node: { isDepartment, key } }) => {
|
|
|
+ if (isDepartment) {
|
|
|
+ itemIsChecked(onItemSelectAll)(checkedNodes, checkedKeys)
|
|
|
+ } else {
|
|
|
+ onItemSelect(key, !isChecked(checkedKeys, key))
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ ) : null
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ </Transfer>
|
|
|
+ </div>
|
|
|
+ <div className={[styles.modalFooter, 'text-right'].join(' ')}>
|
|
|
+ <Button className="mr-4" onClick={closeModal}>
|
|
|
+ 取消
|
|
|
+ </Button>
|
|
|
+ <Button type="primary">确定</Button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+export default CustomPerm
|