实现思路:

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

    image.png

    1. /* eslint-disable no-restricted-syntax */
    2. /*
    3. * @Author: ZhaoQianQian
    4. * @Date: 2022-03-04 15:54:12
    5. * @LastEditTime: 2022-03-10 11:58:59
    6. * @FilePath: \admin.page.new\src\pages\websetting\power\deal.tsx
    7. * @Description:
    8. *
    9. */
    10. import React, { useState, useEffect } from 'react'
    11. import { Checkbox, Tree, Row } from 'antd';
    12. import styles from './index.less'
    13. interface DealProps {
    14. RouteConfig: any
    15. checked?: []
    16. onChange?: any
    17. status?: boolean
    18. value?: any
    19. }
    20. const Deal: React.FC<DealProps> = (props) => {
    21. const { RouteConfig, value, status } = props
    22. const [routes, setRoutes] = useState([])
    23. const [num, setNum] = useState(0)
    24. const [seconddata, setSeconddata] = useState([]) // 第二级展示
    25. const [chooseMap, setChooseMap] = useState([]) // 第一级选中
    26. const [chooseSecondMap, setChooseSecondMap] = useState([])// 第二级选中
    27. const [deleteMap, setDeleteMap] = useState([]) // 第三级可删除选中
    28. const [deriveMap, setDeriveMap] = useState([]) // 第三级可导出选中
    29. // const [perch, setPerch] = useState('') //占位符
    30. // 递归替换数组结构
    31. const dealTreeDate = (data, rootNode, rootName) => {
    32. const items: any = []
    33. data?.forEach(item => {
    34. if (item?.access) {
    35. items.push({
    36. name: item?.name,
    37. access: item?.access,
    38. rootNode,
    39. rootName,
    40. path: item?.path,
    41. routes: item?.routes ? dealTreeDate(item?.routes, item?.access, item?.name) : []
    42. })
    43. }
    44. })
    45. return items
    46. }
    47. useEffect(() => {
    48. const route = dealTreeDate(RouteConfig, null, null)
    49. setRoutes(route)
    50. setSeconddata(route[0]?.routes)
    51. if (value) {
    52. // 初始化数据
    53. initialize(route)
    54. }
    55. }, [status])
    56. // 每一个节点的选择出发选择数据的变动,传递给父级Form表单
    57. useEffect(() => {
    58. const data = classify(chooseSecondMap)
    59. if (data) {
    60. const auth = handleDeal(data)
    61. if (auth.length > 0) {
    62. props.onChange(auth)
    63. }
    64. }
    65. }, [chooseMap, chooseSecondMap, deleteMap, deriveMap])
    66. // 点击一级多选框
    67. const onChange = (item) => {
    68. // console.log('item', item)
    69. if (chooseMap.indexOf(item) > -1) {
    70. setChooseMap(chooseMap.filter(v => v !== item))
    71. setChooseSecondMap(chooseSecondMap.filter(items => item.routes.indexOf(items) === -1))
    72. setDeleteMap(deleteMap.filter(items => item.routes.indexOf(items) === -1)) // 差集
    73. setDeriveMap(deriveMap.filter(items => item.routes.indexOf(items) === -1)) // 差集
    74. } else {
    75. setChooseMap([...chooseMap, item])
    76. setChooseSecondMap([...chooseSecondMap, ...item.routes])
    77. setDeleteMap([...deleteMap, ...item.routes])
    78. setDeriveMap([...deriveMap, ...item.routes])
    79. }
    80. };
    81. // 选中第一级
    82. const onClick = (index) => {
    83. setSeconddata(routes[index].routes)
    84. }
    85. // 一级判断是否选中
    86. const pitchon = (item) => {
    87. // 二级联动判断选中状态
    88. const len = chooseSecondMap?.filter(v => v.rootNode === item.access).length
    89. if (len > 0) {
    90. // 原先选择中就没有当前节点
    91. if (chooseMap.indexOf(item) === -1) {
    92. setChooseMap([...chooseMap, item])
    93. }
    94. return true
    95. }
    96. if (len === 0 && chooseMap.indexOf(item) > -1) {
    97. setChooseMap(chooseMap.filter(v => v !== item))
    98. return false
    99. }
    100. // 点击一级判断选中状态
    101. if (chooseMap?.indexOf(item) > -1) {
    102. return true
    103. }
    104. return false
    105. };
    106. // 点击二级多选框
    107. const onchangtwo = (item) => {
    108. if (chooseSecondMap.indexOf(item) > -1) {
    109. setChooseSecondMap(chooseSecondMap.filter(v => v !== item))
    110. setDeleteMap(deleteMap.filter(v => v !== item))
    111. setDeriveMap(deriveMap.filter(v => v !== item))
    112. } else {
    113. setChooseSecondMap([...chooseSecondMap, item])
    114. if (deleteMap?.indexOf(item) === -1) {
    115. setDeleteMap([...deleteMap, item])
    116. }
    117. if (deriveMap?.indexOf(item) === -1) {
    118. setDeriveMap([...deriveMap, item])
    119. }
    120. }
    121. }
    122. // 二级判断是否选中
    123. const pitchontwo = (item) => {
    124. if (chooseSecondMap?.indexOf(item) > -1) {
    125. return true
    126. }
    127. return false
    128. };
    129. // 删除权限是否选中判断
    130. const pitchondetele = (item) => {
    131. if (deleteMap?.indexOf(item) > -1) {
    132. // setDeleteMap(item)
    133. return true
    134. }
    135. return false
    136. };
    137. // 导出权限是否选中判断
    138. const pitchonderive = (item) => {
    139. if (deriveMap?.indexOf(item) > -1) {
    140. // setDeleteMap(item)
    141. return true
    142. }
    143. return false
    144. };
    145. // 点击删除
    146. const deletechange = (item) => {
    147. if (deleteMap?.indexOf(item) === -1) {
    148. setDeleteMap([...deleteMap, item])
    149. } else {
    150. setDeleteMap(deleteMap?.filter(v => v !== item))
    151. }
    152. if (chooseSecondMap?.indexOf(item) === -1) {
    153. setChooseSecondMap([...chooseSecondMap, item])
    154. }
    155. };
    156. // 点击导出
    157. const derivechange = (item) => {
    158. if (deriveMap?.indexOf(item) === -1) {
    159. setDeriveMap([...deriveMap, item])
    160. } else {
    161. setDeriveMap(deriveMap?.filter(v => v !== item))
    162. }
    163. if (chooseSecondMap?.indexOf(item) === -1) {
    164. setChooseSecondMap([...chooseSecondMap, item])
    165. }
    166. };
    167. // 根据中间第二级选中的数组进行分类
    168. const classify = (arr) => {
    169. const map = {},
    170. dest = [];
    171. for (let i = 0; i < arr.length; i += 1) {
    172. let ai = arr[i];
    173. if (!map[ai.rootNode]) {
    174. dest.push({
    175. access: ai.rootNode,
    176. name: ai.rootName,
    177. path: ai.path,
    178. routes: [ai]
    179. });
    180. map[ai.rootNode] = ai;
    181. } else {
    182. for (let j = 0; j < dest.length; j += 1) {
    183. const dj = dest[j];
    184. if (dj.access === ai.rootNode) {
    185. dj.routes.push(ai);
    186. break;
    187. }
    188. }
    189. }
    190. }
    191. return dest
    192. }
    193. // 根据删除导出选中的数组对处理分类过后的权限增加可删除可导出的字段
    194. const handleDeal = (data) => {
    195. const res = data?.map(item => {
    196. const obj = {}
    197. obj.name = item.name
    198. obj.access = item.access
    199. obj.path = item.path
    200. obj.routes = item.routes?.map(v => ({
    201. access: v.access,
    202. name: v.name,
    203. path: v.path,
    204. delete: deleteMap?.indexOf(v) > -1,
    205. derive: deriveMap?.indexOf(v) > -1
    206. }))
    207. return obj
    208. })
    209. return res
    210. // console.log('res', res)
    211. }
    212. const initialize = (route) => {
    213. // 初始化数组扁平化
    214. const arrInit = value?.map(v => v.routes)
    215. const resInit = arrInit?.reduce((a, b) => a.concat(b))
    216. // 路由数组扁平化
    217. const arrRoute = route?.map(v => v.routes)
    218. const resRoute = arrRoute?.reduce((a, b) => a.concat(b))
    219. const second = []
    220. const deletes = []
    221. const derives = []
    222. for (const iterator of resInit) {
    223. if (resRoute.filter(v => v.access === iterator.access).length > 0) {
    224. second.push(resRoute.filter(v => v.access === iterator.access)[0])
    225. }
    226. if (resRoute.filter(v => v.access === iterator.access && iterator.delete).length > 0) {
    227. deletes.push(resRoute.filter(v => v.access === iterator.access && iterator.delete)[0])
    228. }
    229. if (resRoute.filter(v => v.key === iterator.key && iterator.derive).length > 0) {
    230. derives.push(resRoute.filter(v => v.access === iterator.access && iterator.derive)[0])
    231. }
    232. }
    233. setDeleteMap(deletes)
    234. setDeriveMap(derives)
    235. setChooseSecondMap(second)
    236. // console.log('arr', resInit, resRoute, deletes)
    237. }
    238. return (
    239. <div className={styles.power_wrapper}>
    240. <div className={styles.power_wrapper_head}>
    241. <span>功能模块</span>
    242. <span>子模块</span>
    243. <span>权限管理</span>
    244. </div>
    245. <div className={styles.box_power_content}>
    246. <div className={styles.box_power_content_card}>
    247. {routes.map((v, i) => {
    248. return (
    249. <span key={i} className={styles.box_power_content_card_span}>
    250. <Checkbox
    251. onChange={(e) => {
    252. onChange(v);
    253. }}
    254. checked={pitchon(v)}
    255. />
    256. <i
    257. className={
    258. num === i
    259. ? styles.box_power_content_card_span_i
    260. : null
    261. }
    262. onClick={() => {
    263. setNum(i)
    264. onClick(i);
    265. }}
    266. >
    267. {v.name}
    268. </i>
    269. </span>
    270. );
    271. })}
    272. </div>
    273. <div className={styles.box_power_content_card}>
    274. {
    275. seconddata.map((j, k) => {
    276. return (
    277. <span
    278. key={k}
    279. className={styles.box_power_content_card_span1}
    280. >
    281. <Checkbox
    282. checked={pitchontwo(j)}
    283. onChange={() => {
    284. onchangtwo(j);
    285. }}
    286. >
    287. {j && j.name ? j.name : ""}
    288. </Checkbox>
    289. </span>
    290. );
    291. })
    292. }
    293. </div>
    294. <div className={styles.box_power_content_card}>
    295. {
    296. seconddata.map((j, k) => {
    297. return (
    298. <span
    299. key={k}
    300. className={styles.box_power_content_card_span2}
    301. >
    302. <Checkbox
    303. checked={pitchondetele(j)}
    304. onChange={() => {
    305. deletechange(j);
    306. }}
    307. >
    308. 删除
    309. </Checkbox>
    310. <Checkbox
    311. checked={pitchonderive(j)}
    312. onChange={() => {
    313. derivechange(j);
    314. }}
    315. >
    316. 导出
    317. </Checkbox>
    318. </span>
    319. );
    320. })}
    321. </div>
    322. </div>
    323. </div >
    324. );
    325. }
    326. export default Deal