react 后台管理权限路由选择框,antd表格魔改,实现将选中和半选中的权限框的id传给后端

react 后台管理权限路由选择框,antd表格魔改,实现将选中和半选中的权限框的id传给后端,第1张

首先看一下效果:

然后再说一下数据的格式和字段

其中IsObtain为是否选中字段,halfchecked为半选状态,permission_id为id,permission_pid为父id,其他的根据自己的业务需求来。

然后看一下层级关系

 最后,废话不多说,直接上代码

其中一到三步就是对antd表格的魔改,就对应自己数据的字段改一下就ok,不用去深究。

为了方便大家看懂,代码里大量的注释,并且先看哪个方法的步骤都已标明,所以我就步赘述了,直接上完整代码:

index.tsx: 数据是自己造的

import React, { useState } from 'react'
import Child from "./Child"
// import Child1 from "./Child1"

export default function Index() {
  const [data, stedata] = useState([
    {
      IsObtain: false,
      halfchecked: false,
      permission_id: "1",
      permission_name: "权限1",
      permission_pid: null,
      childPermissions: [
        {
          IsObtain: false,
          halfchecked: false,
          permission_id: "1-1",
          permission_name: "权限1-1",
          permission_pid: "1",
          childPermissions: [
            {
              IsObtain: false,
              halfchecked: false,
              permission_id: "1-1-1",
              permission_name: "权限1-1-1",
              permission_pid: "1-1",
              childPermissions: [
                {
                  IsObtain: false,
                  halfchecked: false,
                  permission_id: "1-1-1-1",
                  permission_name: "权限1-1-1-1",
                  permission_pid: "1-1-1",
                  childPermissions: null
                },
                {
                  IsObtain: false,
                  halfchecked: false,
                  permission_id: "1-1-1-2",
                  permission_name: "权限1-1-1-2",
                  permission_pid: "1-1-1",
                  childPermissions: null
                }
              ]
            },
            {
              IsObtain: false,
              halfchecked: false,
              permission_id: "1-1-2",
              permission_name: "权限1-1-2",
              permission_pid: "1-1",
              childPermissions: null
            }
          ]
        },
        {
          IsObtain: false,
          halfchecked: false,
          permission_id: "1-2",
          permission_name: "权限1-2",
          permission_pid: "1",
          childPermissions: [
            {
              IsObtain: false,
              halfchecked: false,
              permission_id: "1-2-1",
              permission_name: "权限1-2-1",
              permission_pid: "1-2",
              childPermissions: null
            }
          ]
        },
      ],
    },
    {
      IsObtain: false,
      halfchecked: false,
      permission_id: "2",
      permission_name: "权限2",
      permission_pid: null,
      childPermissions: [
        {
          IsObtain: false,
          halfchecked: false,
          permission_id: "2-1",
          permission_name: "权限2-1",
          permission_pid: "2",
          childPermissions: [
            {
              IsObtain: false,
              halfchecked: false,
              permission_id: "2-1-1",
              permission_name: "权限2-1-1",
              permission_pid: "2-1",
              childPermissions: null
            },
            {
              IsObtain: false,
              halfchecked: false,
              permission_id: "2-1-2",
              permission_name: "权限1-1-2",
              permission_pid: "2-1",
              childPermissions: null
            }
          ]
        },
      ],
    }
  ]);
  return (
    
      
      {/*  */}
    
  )
}

 Child.tsx:

//@ts-nocheck
import { useEffect, useState } from "react";
import { Checkbox, Table, Button, message } from "antd";
// import { postaddpermission } from "../../../api/permissionGroup";
export default function RoleList(props) {
  const [dataSource1, setdataSource] = useState()
  const [columns1, setcolumns] = useState()
  const [ccType, setccType] = useState(false)
  const columnWidthArray = ["10%", "10%", "30%", "25%", "25%"]

  //第二步,编码Data, 转成表格格式
  const encodeData = (data, i = 0, addData = {}) => {
    let ret = [];
    // eslint-disable-next-line array-callback-return
    data?.map((item) => {
      let next = Object.assign({ [i]: item.permission_id }, addData);
      //如果有子数据
      if (item.childPermissions) {
        ret.push(...encodeData(item.childPermissions, i + 1, next));
      } else {
        ret.push(next);
      }
    });
    return ret;
  };

  //第三步,获取最深的深度以确定列数
  const getMaxDepth = (data) => {
    let max = 1;
    data?.map((item) => {
      if (item.childPermissions) {
        let childDepth = getMaxDepth(item.childPermissions);
        if (max < 1 + childDepth) max = 1 + childDepth;
      }
    });
    return max;
  };

  //第一步,这里面就是将antd表格改成权限组选择想要的样子,并且调了一下方法
  const generateData = (list) => {
    //转换格式后生成的表格数据
    const dataSource = encodeData(list);
    //最大深度, 用于确认表格列数
    const max = getMaxDepth(list);
    const columns = [];
    for (let i = 0; i < max; i++) {
      columns.push({
        key: i,
        dataIndex: i,
        title: i,
        width: columnWidthArray[i],
        render: (t, r, rowIndex) => {
          const obj = {
            children: t ? getCheckBox(t, list) : "",
            props: {},
          };
          //列合并
          if (r[i] === undefined) {
            obj.props.colSpan = 0;
          } else if (r[i + 1] === undefined && i < max - 1) {
            obj.props.colSpan = max - i;
          }
          //行合并
          if (
            dataSource[rowIndex - 1] &&
            dataSource[rowIndex - 1][i] === dataSource[rowIndex][i]
          ) {
            obj.props.rowSpan = 0;
          } else {
            let rowSpan = 1;
            for (
              let j = 1;
              dataSource[rowIndex + j] &&
              dataSource[rowIndex + j][i] === dataSource[rowIndex][i];
              j++
            ) {
              rowSpan++;
            }
            obj.props.rowSpan = rowSpan;
          }
          return obj;
        },
      });
    }
    setdataSource(dataSource)
    setcolumns(columns)
  };

  //第五步,利用id获取整个对象
  //obj:传入的一个空对象
  //id:传入的数据id
  //list:整个权限的数据,是一个数组对象的格式
  const mapData = (obj, id, list) => {
    list.map(item => {
      //如果id相等,则把整个对象赋给ogj,否则如果有子数据就递归
      if (item.permission_id === id) {
        obj = item
      } else if (item.childPermissions) {
        obj = mapData(obj, id, item.childPermissions)
      }
    })
    //最后将对象返回
    return obj
  }

  //第九步,半选
  //list:总数据
  const halfchecked = (list) => {
    list.map(item => {
      if (item.childPermissions) {
        // 用数组的方法,有一个为true就为true,这里一定要加上|| item.halfchecked,因为如果是半选状态,它的父级也应该是半选状态,不加会导致三个层级以上出现bug
        let flag = item.childPermissions.some(item => item.IsObtain || item.halfchecked)
        item.halfchecked = flag
        // 再递归
        halfchecked(item.childPermissions)
      }
    })
  }

  //第八步,反选
  //list:总数据
  const reversecheck = (list) => {
    list.map(item => {
      if (item.childPermissions) {
        // 用数组的方法,全部都为true才为true
        let flag = item.childPermissions.every(item => item.IsObtain)
        item.IsObtain = flag
        // 再递归
        reversecheck(item.childPermissions)
      }
    })
  }

  //第七步,全选
  //checked:选择框状态,data:数据
  const checkAllbtn = (checked, data) => {
    data.map(item => {
      item.IsObtain = checked
      if (item.childPermissions) {
        checkAllbtn(checked, item.childPermissions)
      }
    })
  }

  //第六步,点击选择框
  //data:总数据,checked:选择框的状态,id:当前数据的id
  const checkedItem = (data, checked, id) => {
    //把传过来的数据进行遍历
    return data.map(item => {
      //如果id相等就把数据的IsObtain字段改成当前选择框的状态
      if (item.permission_id === id) {
        item.IsObtain = checked
        //全选,如果有子数据就调全选的方法
        if (item.childPermissions) {
          checkAllbtn(checked, item.childPermissions)
        }
        //如果父id不会空,那就说明点击的是子选择框,就要进行反选和半选
        if (item.permission_pid !== "null") {
          //反选/半选
          reversecheck(props.dataList)
          halfchecked(props.dataList)
        }
      }
      //递归,如果有子数据就进行递归
      else if (item.childPermissions) {
        checkedItem(item.childPermissions, checked, id)
      }
      return item
    })
  }


  //第四步,渲染选择框
  //t:当前数据的id, data:总的数据
  const getCheckBox = (t, data) => {
    let obj = {}
    // //页面加载的时候调用一次
    // halfchecked(props.dataList)
    // reversecheck(props.dataList)
    return (
       {
          // ccType这个的作用就是在点击选择框后重新渲染一下,默认是false,然后每次取反,在useEffect里面监听ccType,就可以取到强制刷新的作用了
          setccType(!ccType)
          //点击选择框后调用的方法
          checkedItem(data, e.target.checked, mapData(obj, t, props.dataList).permission_id)
          // console.log(props.dataList);
          //每次点击完都会改变数据里面IsObtain和halfchecked的状态,所有需要再重置一下数据,如果在useEffect里面也监听了props.dataList,就可以不用上面那个ccType了,我是两个都保留了
          props.setdataList(props.dataList)
        }}
      >
        {/*这里显示权限的名字*/}
        {mapData(obj, t, props.dataList).permission_name}
      
    );
  };

  //挂载
  useEffect(() => {
    //初始化页面将数据传入
    generateData(props.dataList)
    //页面加载的时候调用一次
    halfchecked(props.dataList)
    reversecheck(props.dataList)
  }, [props.dataList, ccType]);

  //第十一步,获取选择的数据id
  //list,总数据,arr:空数组
  const getData = (list, arr) => {
    list.map(item => {
      if (item.IsObtain || item.halfchecked) {
        arr.push(item.permission_id)
      }
      if (item.childPermissions) {
        getData(item.childPermissions, arr)
      }
    })
  }

  //第十步,点击保存,这里就是点击保存将全选或者半选的id都传给后端
  const addPermission = async () => {
    const arr = []
    getData(props.dataList, arr)
    //打印获取到的id
    console.log(arr);
  }

  return (
    
      {
          position: "sticky",
          textAlign: "right",
          height: "40px",
          lineHeight: "40px",
        }}
      >
        
      
      
        { y: true }}
          showHeader={false}
          dataSource={dataSource1}
          columns={columns1}
        />
      
    
  )
}

打印出来的id是一个数组

如果大家觉得对表格的魔改不太喜欢或者看不懂的,又想要自己写亿点点样式的,(手动狗头),我还有另一种方法,这种可是自己纯手工打造的,但是我懒得写样式,就放弃了,其实核心代码都差不多。

先看看效果吧:

 丑是丑了点,但这可是纯手工打造的,如果谁能把样式改好记得@我一下哟

代码奉上,Child1.tsx

//@ts-nocheck
import { useEffect, useState } from "react";
import { Checkbox, Button, message } from "antd";

const AllPermission = (props: any) => {
  const [ccType, setccType] = useState(false)

  //半选
  const halfchecked = (list) => {
    list.map(item => {
      if (item.childPermissions) {
        let flag = item.childPermissions.some(item => item.IsObtain || item.halfchecked)
        item.halfchecked = flag
        halfchecked(item.childPermissions)
      }
    })
  }

  //反选
  const reversecheck = (list) => {
    list.map(item => {
      if (item.childPermissions) {
        let flag = item.childPermissions.every(item => item.IsObtain)
        item.IsObtain = flag
        reversecheck(item.childPermissions)
      }
    })
  }

  //全选
  const checkAllbtn = (checked, data) => {
    data.map(item => {
      item.IsObtain = checked
      if (item.childPermissions) {
        checkAllbtn(checked, item.childPermissions)
      }
    })
  }

  //点击选择框
  const checkedItem = (data, checked, id) => {
    return data.map(item => {
      if (item.permission_id === id) {
        item.IsObtain = checked
        //全选
        if (item.childPermissions) {
          checkAllbtn(checked, item.childPermissions)
        }
        if (item.permission_pid !== "null") {
          //反选/半选
          reversecheck(props.dataList)
          halfchecked(props.dataList)
        }
      }
      //递归
      if (item.childPermissions) {
        checkedItem(item.childPermissions, checked, id)
        //反选/半选 这里不能少
        reversecheck(props.dataList)
        halfchecked(props.dataList)
      }
      //反选/半选 这里不能少
      reversecheck(props.dataList)
      halfchecked(props.dataList)
      return item
    })
  }

  //渲染选择框
  const treeMethod = (data: any) => {
    // let a=[]
    return data?.map((item: any, index: any) => {
      if (item.childPermissions) {
        return (
          { border: "1px solid black", display: "flex", boxSizing: "border-box" }}>
            
               {
                  setccType(!ccType)
                  checkedItem(data, e.target.checked, item.permission_id)
                  props.setdataList(props.dataList)
                }}
              >{item.permission_name}
              
            
            {treeMethod(item.childPermissions)}
          
        )
      } else {
        return (
          { border: "1px solid black" }}>
             {
                setccType(!ccType)
                checkedItem(data, e.target.checked, item.permission_id)
                console.log(props.dataList);
                props.setdataList(props.dataList)
              }}
            >{item.permission_name}
          
        );
      }
    });
  };

  useEffect(() => {
    //页面加载的时候调用一次
    halfchecked(props.dataList)
    reversecheck(props.dataList)
  }, [ccType]);

  //获取选择的数据id
  const getData = (list, arr) => {
    list.map(item => {
      if (item.IsObtain || item.halfchecked) {
        arr.push(item.permission_id)
      }
      if (item.childPermissions) {
        getData(item.childPermissions, arr)
      }
    })
  }

  //点击保存
  const addData = async () => {
    const arr = []
    getData(props.dataList, arr)
    console.log(arr);
  }

  return (
    
      
      {treeMethod(props.dataList)}
    
  );
};
export default AllPermission;

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1320551.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-11
下一篇 2022-06-11

发表评论

登录后才能评论

评论列表(0条)