实现思路:
- 根据umi的插件plugin-access,引入access的概念,为每个路由页面增加access,增加每选中一个功能模块或者子模块,就将当前模块access传递给当当前用户

/* eslint-disable no-restricted-syntax *//** @Author: ZhaoQianQian* @Date: 2022-03-04 15:54:12* @LastEditTime: 2022-03-10 11:58:59* @FilePath: \admin.page.new\src\pages\websetting\power\deal.tsx* @Description:**/import React, { useState, useEffect } from 'react'import { Checkbox, Tree, Row } from 'antd';import styles from './index.less'interface DealProps {RouteConfig: anychecked?: []onChange?: anystatus?: booleanvalue?: any}const Deal: React.FC<DealProps> = (props) => {const { RouteConfig, value, status } = propsconst [routes, setRoutes] = useState([])const [num, setNum] = useState(0)const [seconddata, setSeconddata] = useState([]) // 第二级展示const [chooseMap, setChooseMap] = useState([]) // 第一级选中const [chooseSecondMap, setChooseSecondMap] = useState([])// 第二级选中const [deleteMap, setDeleteMap] = useState([]) // 第三级可删除选中const [deriveMap, setDeriveMap] = useState([]) // 第三级可导出选中// const [perch, setPerch] = useState('') //占位符// 递归替换数组结构const dealTreeDate = (data, rootNode, rootName) => {const items: any = []data?.forEach(item => {if (item?.access) {items.push({name: item?.name,access: item?.access,rootNode,rootName,path: item?.path,routes: item?.routes ? dealTreeDate(item?.routes, item?.access, item?.name) : []})}})return items}useEffect(() => {const route = dealTreeDate(RouteConfig, null, null)setRoutes(route)setSeconddata(route[0]?.routes)if (value) {// 初始化数据initialize(route)}}, [status])// 每一个节点的选择出发选择数据的变动,传递给父级Form表单useEffect(() => {const data = classify(chooseSecondMap)if (data) {const auth = handleDeal(data)if (auth.length > 0) {props.onChange(auth)}}}, [chooseMap, chooseSecondMap, deleteMap, deriveMap])// 点击一级多选框const onChange = (item) => {// console.log('item', item)if (chooseMap.indexOf(item) > -1) {setChooseMap(chooseMap.filter(v => v !== item))setChooseSecondMap(chooseSecondMap.filter(items => item.routes.indexOf(items) === -1))setDeleteMap(deleteMap.filter(items => item.routes.indexOf(items) === -1)) // 差集setDeriveMap(deriveMap.filter(items => item.routes.indexOf(items) === -1)) // 差集} else {setChooseMap([...chooseMap, item])setChooseSecondMap([...chooseSecondMap, ...item.routes])setDeleteMap([...deleteMap, ...item.routes])setDeriveMap([...deriveMap, ...item.routes])}};// 选中第一级const onClick = (index) => {setSeconddata(routes[index].routes)}// 一级判断是否选中const pitchon = (item) => {// 二级联动判断选中状态const len = chooseSecondMap?.filter(v => v.rootNode === item.access).lengthif (len > 0) {// 原先选择中就没有当前节点if (chooseMap.indexOf(item) === -1) {setChooseMap([...chooseMap, item])}return true}if (len === 0 && chooseMap.indexOf(item) > -1) {setChooseMap(chooseMap.filter(v => v !== item))return false}// 点击一级判断选中状态if (chooseMap?.indexOf(item) > -1) {return true}return false};// 点击二级多选框const onchangtwo = (item) => {if (chooseSecondMap.indexOf(item) > -1) {setChooseSecondMap(chooseSecondMap.filter(v => v !== item))setDeleteMap(deleteMap.filter(v => v !== item))setDeriveMap(deriveMap.filter(v => v !== item))} else {setChooseSecondMap([...chooseSecondMap, item])if (deleteMap?.indexOf(item) === -1) {setDeleteMap([...deleteMap, item])}if (deriveMap?.indexOf(item) === -1) {setDeriveMap([...deriveMap, item])}}}// 二级判断是否选中const pitchontwo = (item) => {if (chooseSecondMap?.indexOf(item) > -1) {return true}return false};// 删除权限是否选中判断const pitchondetele = (item) => {if (deleteMap?.indexOf(item) > -1) {// setDeleteMap(item)return true}return false};// 导出权限是否选中判断const pitchonderive = (item) => {if (deriveMap?.indexOf(item) > -1) {// setDeleteMap(item)return true}return false};// 点击删除const deletechange = (item) => {if (deleteMap?.indexOf(item) === -1) {setDeleteMap([...deleteMap, item])} else {setDeleteMap(deleteMap?.filter(v => v !== item))}if (chooseSecondMap?.indexOf(item) === -1) {setChooseSecondMap([...chooseSecondMap, item])}};// 点击导出const derivechange = (item) => {if (deriveMap?.indexOf(item) === -1) {setDeriveMap([...deriveMap, item])} else {setDeriveMap(deriveMap?.filter(v => v !== item))}if (chooseSecondMap?.indexOf(item) === -1) {setChooseSecondMap([...chooseSecondMap, item])}};// 根据中间第二级选中的数组进行分类const classify = (arr) => {const map = {},dest = [];for (let i = 0; i < arr.length; i += 1) {let ai = arr[i];if (!map[ai.rootNode]) {dest.push({access: ai.rootNode,name: ai.rootName,path: ai.path,routes: [ai]});map[ai.rootNode] = ai;} else {for (let j = 0; j < dest.length; j += 1) {const dj = dest[j];if (dj.access === ai.rootNode) {dj.routes.push(ai);break;}}}}return dest}// 根据删除导出选中的数组对处理分类过后的权限增加可删除可导出的字段const handleDeal = (data) => {const res = data?.map(item => {const obj = {}obj.name = item.nameobj.access = item.accessobj.path = item.pathobj.routes = item.routes?.map(v => ({access: v.access,name: v.name,path: v.path,delete: deleteMap?.indexOf(v) > -1,derive: deriveMap?.indexOf(v) > -1}))return obj})return res// console.log('res', res)}const initialize = (route) => {// 初始化数组扁平化const arrInit = value?.map(v => v.routes)const resInit = arrInit?.reduce((a, b) => a.concat(b))// 路由数组扁平化const arrRoute = route?.map(v => v.routes)const resRoute = arrRoute?.reduce((a, b) => a.concat(b))const second = []const deletes = []const derives = []for (const iterator of resInit) {if (resRoute.filter(v => v.access === iterator.access).length > 0) {second.push(resRoute.filter(v => v.access === iterator.access)[0])}if (resRoute.filter(v => v.access === iterator.access && iterator.delete).length > 0) {deletes.push(resRoute.filter(v => v.access === iterator.access && iterator.delete)[0])}if (resRoute.filter(v => v.key === iterator.key && iterator.derive).length > 0) {derives.push(resRoute.filter(v => v.access === iterator.access && iterator.derive)[0])}}setDeleteMap(deletes)setDeriveMap(derives)setChooseSecondMap(second)// console.log('arr', resInit, resRoute, deletes)}return (<div className={styles.power_wrapper}><div className={styles.power_wrapper_head}><span>功能模块</span><span>子模块</span><span>权限管理</span></div><div className={styles.box_power_content}><div className={styles.box_power_content_card}>{routes.map((v, i) => {return (<span key={i} className={styles.box_power_content_card_span}><CheckboxonChange={(e) => {onChange(v);}}checked={pitchon(v)}/><iclassName={num === i? styles.box_power_content_card_span_i: null}onClick={() => {setNum(i)onClick(i);}}>{v.name}</i></span>);})}</div><div className={styles.box_power_content_card}>{seconddata.map((j, k) => {return (<spankey={k}className={styles.box_power_content_card_span1}><Checkboxchecked={pitchontwo(j)}onChange={() => {onchangtwo(j);}}>{j && j.name ? j.name : ""}</Checkbox></span>);})}</div><div className={styles.box_power_content_card}>{seconddata.map((j, k) => {return (<spankey={k}className={styles.box_power_content_card_span2}><Checkboxchecked={pitchondetele(j)}onChange={() => {deletechange(j);}}>删除</Checkbox><Checkboxchecked={pitchonderive(j)}onChange={() => {derivechange(j);}}>导出</Checkbox></span>);})}</div></div></div >);}export default Deal
