Tree树形控件 创建+回显,并且分父子控件传值

该代码段展示了一个React组件,用于角色管理,包括搜索表单、表格显示、操作列(编辑、查看、分配权限和删除角色)以及相关弹窗功能。页面使用AntDesign组件库,并通过接口获取和处理数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

创建

 回显接口

 

index.tsx

import { Component } from "react";

import React from 'react';

import './index.less';

import SearchForm from './components/SearchForm';

import { BasicStateType } from '@/models/common.d';

import { ConnectProps, connect, Dispatch } from 'umi';

import { message, Popconfirm, Table, Row, Col, Button, Tooltip } from 'antd';

import type { ColumnsType } from 'antd/es/table';

import { EyeOutlined, TeamOutlined } from '@ant-design/icons';

import EditForm from './components/EditForm'

import SeeForm from './components/SeeForm'

import AssignForm from './components/AssignForm'

import Delete from '@/assets/Organization/department/Delete.png'

import Pencil from '@/assets/Organization/department/pencil.png'

import { remove } from '@/service/roleService';

import deleteImg from '@/assets/Organization/Role/delete.png';

import editImg from '@/assets/Organization/Role/edit.png';

import eyeImg from '@/assets/Organization/Role/eye.png';

import peopleImg from '@/assets/Organization/Role/people.png';



const DEFAULT_PAGE: number = 1;

const DEFAULT_PAGE_SIZE: number = 10;



interface DataType {

  id?: number;

  key: React.ReactNode;

  name: string;

  age: number;

  address: string;

  State?: boolean;

  children?: DataType[];

  currentItem?: Role | null;

}

interface IndexPageState {

  page: number;

  pageSize: number;

  queryPayload?: any;

  currentUser?: User;

  currentItem?: Role | null;

  // 弹窗

  detailTeam: boolean,

  seedetailTeam: boolean,

  assigndetailTeam: boolean,

  visible: boolean;

  isEdit: boolean;

}

interface IndexPageProps extends ConnectProps {

  Items: Role[];

  ItemsPerPage: number;

  TotalItems: number;

  TotalPages: number;

  CurrentPage: number;

  loading: boolean;

  dispatch: Dispatch;

  checkStrictly: boolean,



}



class IndexPage extends React.Component<IndexPageProps, IndexPageState>{

  constructor(props: IndexPageProps) {

    super(props);

    this.state = {

      checkStrictly: false,

      detailTeam: false,

      seedetailTeam: false,

      assigndetailTeam: false,

      page: DEFAULT_PAGE,

      pageSize: DEFAULT_PAGE_SIZE,

      currentItem: null,

      visible: false,

      isEdit: true,

    };

  }



  componentDidMount = () => {

    this.onSearch()

  };

  onSearch = () => {

    const { page, pageSize, queryPayload } = this.state;

    this.props.dispatch({

      type: 'roleManagement/fetch',

      payload: {

        currenetPageIndex: page, pageSize: pageSize, ...queryPayload,

      }

    })

  };

  seedetailonEdit = (item?: Role) => {

    this.setState({

      seedetailTeam: true,

      currentItem: item || null,

    })

  }



  detailonEdit = (item?: Role) => {

    console.log(item);

    this.setState({

      detailTeam: true,

      currentItem: item || null,

    })

  }



  assigndetailonEdit = (record: Role,isEdit: boolean) => {

    this.setState({

      assigndetailTeam: true,

      isEdit: isEdit,

      currentItem: record,

    })

  }



  onDelete = async (id: number) => {

    const res = await remove(id)

    if (res?.Success) {

      message.success('Success')

      this.onSearch();

    }

  }



  handlePageChange = (page: number, pageSize: number): void => {

    this.setState({ page, pageSize }, () => {

      this.onSearch();

    });

  };



  handleSearch = (payload: any): void => {

    this.setState({ queryPayload: payload }, () => {

      this.onSearch();

    });

  };



  columns: ColumnsType<Role> = [

    {

      title: 'Role name',

      dataIndex: 'Name',

      key: 'Rolename',

      fixed: 'left',



    },

    {

      title: 'Role code',

      dataIndex: 'Code',

      key: 'Rolecode',

    },



    {

      title: 'State',

      dataIndex: 'State',

      key: 'State',

      render: (value: Boolean) => value === true ? 'Enable' : 'Disable',

      // render: (any, record: Role) => { return ( this.handleStatus(State))}

    },

    {

      title: 'Role description',

      dataIndex: 'Description',

      key: 'Roledescription',

    },

    {

      title: 'Creation time',

      dataIndex: 'InputDate',

      key: 'Creationtime',

    },

    {

      title: 'Action',

      dataIndex: 'action',

      key: 'action',

      render: (any, record: Role) => {

        return <>

          <p>

            <Tooltip title={'Assign permissions'}>

              <span style={{ color: 'rgba(0, 0, 0, 0.6)' }}

                onClick={() => { this.assigndetailonEdit(record, false) }}

              ><img src={peopleImg} style={{ width: 20, height: 20 }} alt="" /></span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

            </Tooltip>



            <Tooltip title={'See permissions'}>

              <span style={{ color: 'rgba(0, 0, 0, 0.6)' }}

                onClick={() => { this.seedetailonEdit(record) }}

              ><img src={eyeImg} style={{ width: 20, height: 20 }} alt="" /></span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

            </Tooltip>



            <Tooltip title={'Edit'}>

              <span style={{ color: 'rgba(0, 0, 0, 0.6)' }}

                onClick={() => {

                  this.detailonEdit(record);

                }}

              ><img src={editImg} style={{ width: 20, height: 20 }} alt="" />

              </span>

            </Tooltip>



            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

            <Tooltip title={'Delete'}>

              <span style={{ color: 'red' }} >

                <Popconfirm

                  title='Are you sure delete this item ?'

                  onConfirm={() => {

                    this.onDelete(record.Id)

                  }}

                  okText='Delete'

                  cancelText='Cancle'

                  className='deleterole'

                >

                  <img src={deleteImg} style={{ width: 20, height: 20 }} alt="" />

                </Popconfirm>

              </span>

            </Tooltip>



          </p>

        </>;

      }

    }

  ];



  data: DataType[] = [

    {

      key: 1,

      Name: 'John Brown sr.',

      Code: '000000',

      Description: 'Admin',

      Creationtime: '2022-12-12  10:25',

      State: 'Disable',

    },

    {

      key: 2,

      Name: 'OM',

      Code: '0000000',

      Description: 'OM',

      Creationtime: '2022-12-12  10:25',

      State: 'Disable',

    },

    {

      key: 3,

      Name: 'TM',

      Code: '111111',

      Description: 'TM',

      Creationtime: '2022-12-12  10:25',

      State: 'Disable',

    },

  ];



  filterMenu = (menus: Role[]) => {

    return menus?.filter((menu: any) => {

      return menu.ParentId === 0;

    });

  };



  render() {

    const { isEdit,detailTeam, seedetailTeam, assigndetailTeam, currentItem } = this.state;

    const { checkStrictly, Items, loading, TotalItems, CurrentPage, ItemsPerPage, } = this.props;



    return (

      <div className='Role'>

        <div className="Role-search">

          <Row>

            <Col span={22}>

              <SearchForm

                onSearch={(values) => {

                  this.setState(

                    {

                      page: DEFAULT_PAGE,

                      queryPayload: {

                        filter: {

                          ...values,

                        },

                      },

                    },

                    () => {

                      this.onSearch();

                    }

                  );

                }}

              />

            </Col>

            <Col span={2} className='SearchFormbuttom' style={{ textShadow: 'none !important', boxShadow: 'none !important', justifyContent: 'end', paddingRight: '24px', display: 'flex', alignItems: 'center' }}>

              <Button onClick={() => { this.detailonEdit() }} type="primary" htmlType="submit" style={{ textShadow: 'none !important', boxShadow: 'none !important', justifyContent: 'end', paddingRight: '24px', borderRadius: '4px', height: '32px', backgroundColor: 'rgba(69, 87, 255, 1)', borderColor: 'rgba(69, 87, 255, 1)', color: '#fff' }}>Add role</Button>

            </Col>

          </Row>



        </div>



        <div className="Role-list">

          <Table<Role>

            rowKey={(record) => record.Id}

            columns={this.columns}

            dataSource={Items}

            loading={loading}

            pagination={

              {

                total: TotalItems,

                current: CurrentPage,

                // pageSize: ItemsPerPage,

                  pageSize: DEFAULT_PAGE_SIZE,



              }

            }

            onChange={(pagination) => {

              const { current, pageSize } = pagination;

              this.handlePageChange(

                current ?? DEFAULT_PAGE,

                pageSize ?? DEFAULT_PAGE_SIZE

              );

            }}

          />



        </div>

        {

          seedetailTeam &&

          <SeeForm

            visible={seedetailTeam}

            onSubmit={() => {

              this.setState({ seedetailTeam: false },

                () => {

                  this.onSearch()

                });

            }}

            onCancel={() => {

              this.setState({ seedetailTeam: false });

            }}

            dataItem={currentItem}



          />

        }




        {

          assigndetailTeam &&

          <AssignForm

            visible={assigndetailTeam}

            isEdit={isEdit}

            onSubmit={() => {

              this.setState({ assigndetailTeam: false },

                () => {

                  this.onSearch()

                });

            }}

            onCancel={() => {

              this.setState({ assigndetailTeam: false , currentItem: null}, () => {

                  this.onSearch()

                });

            }}

            dataItem={currentItem}

            currentItem={currentItem}

          />

        }






      </div>

    )



  }

}



export default connect(

  (

    { roleManagement }:

      { roleManagement: BasicStateType<Role> }) => ({

        ...roleManagement,

      })

)(IndexPage);

调接口

1.设置baseUrl.ts


 2.定义接口变量名

 

 3.设置接口路径(动态的)

model.tsx

import { Effect, Reducer, StateType, Subscription } from 'umi';

import { trim } from 'lodash';

import { query } from '@/service/roleService';

import { BasicEffect } from '@/models/common';



interface MenuEffect extends BasicEffect {



}

export interface ModelType {

 namespace: string;

 state: any;

 effects: MenuEffect;

 subscriptions: { setup: Subscription };

 reducers: {

  save: Reducer<StateType>;

 };

}



const Model: ModelType = {

 namespace: 'roleManagement',

 state: {

  items: [],

  meta: { page: 1, pageSize: 10, total: 0 },

 },

 effects: {

  *fetch({ payload }, { call, put }) {

   const response =  yield call(query, payload);

   const { ResData } = response;



   yield put({

    type: 'save',

    payload: ResData,

   });

  },



 },







 subscriptions: {

  setup({ dispatch, history }) {

   return history.listen(({ pathname }) => {



   });

  },

 },

 reducers: {

  save(state, { payload }) {

   return { ...state, ...payload };

  },

 },

};



export default Model;



AssginFrom.tsx

import React, { useEffect, useState } from 'react';

import { useIntl } from 'umi';

import { Modal, Input, Checkbox, message, Button } from 'antd';

import './AssignForm.less';

import { SearchOutlined } from '@ant-design/icons';

import type { CheckboxChangeEvent } from 'antd/es/checkbox';

import type { CheckboxValueType } from 'antd/es/checkbox/Group';

import closeImg from '@/assets/system/close.png';

import TreePermissions from './Tree';

import { getAllDepartmentUsers } from '@/service/departmentService';

import { create, update, get } from '@/service/agentService';

import { Role } from '@typings/model';

import { getCurrentUser } from '@/utils/authority';

import { AssignRolePermissions } from '@/service/permission';

import { query as Menuquery } from '@/service/menuService';



interface AddAgentsProps {

    visible: boolean;

    onSubmit: () => void;

    onCancel: () => void;

    isEdit?: boolean;

    dataItem?: any;

    currentItem?: any;

}

let members: Member[] = [];

const page: number = 1;

const pageSize: number = 99;

const AddAgents: React.FC<AddAgentsProps> = (props) => {

    const { currentItem, visible, isEdit, onSubmit, onCancel } = props;

    const [indeterminate, setIndeterminate] = useState(true);

    const [checkedList, setCheckedList] = useState<CheckboxValueType[]>([]);

    const [checkAll, setCheckAll] = useState(false);

    const [plainOptions, setPlainOptions] = useState<any[]>([]);

    const [searchVal, setSearchVal] = useState('');

    const [assignMenus, setAssignMenus] = useState<React.Key[]>([]);

    const [assignPermissions, setAssignPermissions] = useState<React.Key[]>([]);

    const currentUser = getCurrentUser()



    useEffect(() => {

        // props.visible && MenuFunc()

        !currentItem && MenuFunc()

    }, []);



    const MenuFunc = async () => {

        const query = {

            currenetPageIndex: page,

            pageSize: pageSize,

        }

        const res = await Menuquery(query)

        connectUser(res?.ResData)

        setPlainOptions(members)

    }

    const mapToModel = (values: any): any => {

        return {

            // MemberId: currentItem?.RoleId,

            // UserIds: checkedList,

            Permissions: assignPermissions,

            Menus: assignMenus,

            RoleId: currentItem?.Id,



        }

    }

    const onInsert = (value: any) => {

        if (!checkedList.length && !currentItem) return

        if (!assignPermissions.length && !assignMenus.length && !isEdit) return

        const server = currentItem?.Id ? AssignRolePermissions : AssignRolePermissions;

        server(mapToModel(value)).then((res) => {

            const { Success } = res;

            if (Success) {

                onSubmit();

                members = [];

                message.success('success');

            } else {

                message.error('Fail');

            }

        })

    }

    const connectUser = (data: any) => {

        data?.map((item: any) => {

            if (item?.SubMenu) {

                connectUser(item?.SubMenu)

            } else {

                item?.UserInfos?.map((User, idx) => members?.push(User))

            }

        })

    }

    const onCheckAllChange = (e: CheckboxChangeEvent) => {

        setCheckedList(e.target.checked ? filterUser(plainOptions).map((item => item.Id)) : []);

        setIndeterminate(false);

        setCheckAll(e.target.checked);

    }

    const onChange = (list: CheckboxValueType[]) => {

        setCheckedList(list);

        setIndeterminate(!!list.length && list.length < plainOptions.length);

        setCheckAll(list.length === plainOptions.length);

    }

    const filterUser = (users: Member[]) => {




        return users?.filter(option => {

            if (!isNaN(Number(searchVal))) {



                return '10003'?.includes(searchVal)

            } else {

                return option?.Name?.toLocaleUpperCase()?.includes(searchVal)

            }

        })

    }

    // EnglishName

    const toUpper = (ename: string) => {

        return ename.substring(0, 2).toLocaleUpperCase()

    }



    const modalProps = !isEdit && { footer: isEdit, width: '35%', title: "Assign permissions" }



    const rightStyles = (!isEdit || currentItem) && { style: { width: '100%', marginBottom: 16 } }



    const modalPropsEdit = (isEdit && currentItem) && { width: '35%', title: "Assign permissions" }



    return (



        <Modal

            title="Assign permissions"

            width={'30%'}

            onOk={onInsert}

            onCancel={() => {

                members = []

                onCancel()

            }}

            visible={visible}

            okText="Save"

            className="add_agents_modal"

            {...modalPropsEdit}

        >

            <section className="add_agents_sec" {...rightStyles}>



                <section className="agents_right_sec" {...rightStyles}>

                    {

                        !modalProps && !currentItem ? <header className="agents_head">Assign permissions</header> : null

                    }

                    <div className="permissions_content">

                        {

                            (isEdit || currentItem) &&

                            <TreePermissions

                                currentItem={currentItem}

                                isEdit={isEdit}

                                onSuccess={(menus, permissions) => {

                                    setAssignMenus(menus)

                                    setAssignPermissions(permissions)

                                }}

                            />

                        }

                    </div>

                </section>



            </section>



        </Modal >

    );

};

export default AddAgents;

Tree.tsx

import { Input, Tree } from 'antd';

import type { DataNode } from 'antd/es/tree';

import React, { useEffect, useState } from 'react';

import { query as queryPermissions } from '@/service/menuService';

import { SearchOutlined } from '@ant-design/icons';

import { getCurrentUser } from '@/utils/authority';

import { GetPermissionsAsync } from '@/service/permission';




import { Role } from '@typings/model';

import { map } from 'lodash';

const page: number = 1;

const pageSize: number = 99;

let keys = [];

interface TreePermissionsProps {

  onSuccess: (Menus: any[], Permissions: any[]) => void;

  currentItem?: Role | null;

  isEdit?: boolean;

}

const TreePermissions: React.FC<TreePermissionsProps> = (props: TreePermissionsProps) => {

  const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([]);

  const [checkedKeys, setCheckedKeys] = useState<React.Key[]>([]);

  const [selectedKeys, setSelectedKeys] = useState<React.Key[]>([]);

  const [autoExpandParent, setAutoExpandParent] = useState<boolean>(true);

  const [searchValue, setSearchValue] = useState('');

  const [treeData, setTreeData] = useState([]);

  const [defaultCheckedKeys, setDefaultCheckedKeys] = useState<React.Key[]>([]);

  const currentUser = getCurrentUser()

  useEffect(() => {

    props?.currentItem ? keys = [] : null;

    queryPermissionsFunc();

  }, [])

  // 获取展示数据

  const Filter = {

    Id: props?.currentItem?.Id

  }

  const queryPermissionsFunc = async () => {

    const query = {

      currenetPageIndex: page,

      pageSize: pageSize,

      // Filter: !props?.isEdit ? Filter : null

    }

    const res = await queryPermissions(query)

    const { Success } = res

    if (!Success) return

    const resTreeData = treeDataFunc(res?.ResData?.Items)

    if (props?.isEdit || props?.currentItem) {

      // const resSelectData = await queryPermissions({ ...query, Filter: { Id: props?.currentItem?.Id } })

      // reserveDataFunc(resSelectData?.ResData?.Items)



      const resSelectData = await GetPermissionsAsync(props?.currentItem?.Id)  

      reserveDataFunc(resSelectData?.ResData)

    }

    setTreeData(resTreeData)

  }

  const treeDataFunc = (treeData: any) => {

    return treeData?.map((item: any) => {

      return {

        key: item?.hasOwnProperty('Path') ? `${item.Id},Menus` : `${item.Id},Permissions`,

        title: item.Name,

        children: (item.SubMenu || item?.Permissions) ? treeDataFunc(item.SubMenu || item?.Permissions) : []

      }

    })

  }



  const reserveDataFunc = (treeData: any) => {

    // ['1,Menus' , '2,Permissions']

    // item?.hasOwnProperty('Path') ? `${item.Id},Menus` : `${item.Id},Permissions`

    treeData?.forEach((item: any) => {

      if (!item?.SubMenu && !item?.Permissions?.length) {

        keys.push(`${item.Id},Menus`)

      } else if (item?.SubMenu && !item?.Permissions?.length) {

        reserveDataFunc(item?.SubMenu)

      } else if (!item?.SubMenu && item?.Permissions?.length) {

        item?.Permissions?.forEach((pms) => {

          keys.push(`${pms.Id},Permissions`)

        })

      }

    })

    setCheckedKeys(keys)

  }

  const getIds = (checkedKeys: any[], str: string) => {

    const MenusId = checkedKeys?.filter(key => key?.includes(str))

    return MenusId?.map(menu => Number(menu.split(',')[0]))

  }

  const onExpand = (expandedKeysValue: React.Key[]) => {



    setExpandedKeys(expandedKeysValue);

    setAutoExpandParent(false);

  }



  const onCheck = (checkedKeysValue: React.Key[]) => {



    let expandKey = checkedKeysValue.length === 1 ? checkedKeysValue : expandedKeys



    const exKeys = getIds(expandKey, 'Menus');

    console.log('expandedKeys', expandedKeys)

    console.log('expandKey', expandKey)



    const Menus = getIds(checkedKeysValue, 'Menus');

    console.log('checkedKeysValue', checkedKeysValue);



    const Permissions = getIds(checkedKeysValue, 'Permissions');

    console.log('Permissions', Permissions)



    props?.onSuccess(Menus.concat(exKeys), Permissions)

    setCheckedKeys(checkedKeysValue);






  }



  const onSelect = (selectedKeysValue: React.Key[], info: any) => {

    setSelectedKeys(selectedKeysValue);

  }

  const dataList: { key: React.Key; title: string }[] = [];

  const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {

    const { value } = e.target;

    const newExpandedKeys = dataList

      .map(item => {



        if (item.title.indexOf(value) > -1) {

          return getParentKey(item.key, treeData);

        }

        return null;

      })

      .filter((item, i, self) => item && self.indexOf(item) === i);

    setExpandedKeys(newExpandedKeys as React.Key[]);

    setSearchValue(value);

    setAutoExpandParent(true);

  }

  const getParentKey = (key: React.Key, tree: DataNode[]): React.Key => {

    let parentKey: React.Key;

    for (let i = 0; i < tree.length; i++) {

      const node = tree[i];

      if (node.children) {

        if (node.children.some(item => item.key === key)) {

          parentKey = node.key;

        } else if (getParentKey(key, node.children)) {

          parentKey = getParentKey(key, node.children);

        }

      }

    }

    return parentKey!;

  }



  const generateList = (data: DataNode[]) => {

    for (let i = 0; i < data.length; i++) {

      const node = data[i];

      const { key, title } = node;

      dataList.push({ key, title: title as string });

      if (node.children) {

        generateList(node.children);

      }

    }

  }

  // generateList(treeData);



  return (

    <>

      {/* <Input

        prefix={<SearchOutlined style={{ color: '#999' }} />}

        style={{ borderRadius: 4, marginBottom: 16, width: '105%' }}

        placeholder="Search" onChange={onChange} /> */}

      <Tree

        checkable

        onExpand={onExpand}

        expandedKeys={expandedKeys}

        autoExpandParent={autoExpandParent}

        onCheck={onCheck}

        // checkStrictly={true}

        checkedKeys={checkedKeys}

        onSelect={onSelect}

        selectedKeys={selectedKeys}

        treeData={treeData}

      />

    </>

  );

};



export default TreePermissions;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值