React 模板封装之树形模板 TreeTable

React 模板封装之树形模板 TreeTable

  • 前言
  • 一、树形模板 TreeTable
  • 二、使用案例
  • 三、API 使用指南
  • 四、源代码
  • 五、总结

前言

前面有介绍过 React 模板封装之基础模板 BaseTable 和 React 模板封装之拖曳模板 DragTable,今天在这两个模板的基础上实现一个树形模板 TreeTable。目前该模板只支持两个层级。本模板指的是父级表格与子级表格数据格式不一致的情况。

一、树形模板 TreeTable

模板说明:
在原先模板的基础上实现一个树形模板 TreeTable。

效果展示:

React 模板封装之树形模板 TreeTable_第1张图片

使用场景:
父表格中嵌套子表格的场景。

二、使用案例

参数说明

  1. modalList :父级表格配置接口对应的字段数据集。
  2. childModalList:子级表格配置接口对应的字段数据集。
  3. actions:父级表格配置接口功能,如配置增删改查接口(url、method、data等)。
  4. childActions:子级表格配置接口功能。
  5. insertModalList:弹出框的表格配置接口对应的字段数据集。
  6. insertActions:弹出框的表格配置接口功能。
  7. isInsert:是否需要插入功能(插入父级对应的子集数据)。
  8. isSort:是否需要拖曳排序功能。
  9. parentIdField:子级表格增删改查时需要上传的父级 id 的字段名。
import React from "react";
import TreeTable from "../../../../template/TreeTable/index";
const modalList = [
  {
     
    label: "ID",
    field: "id",
    renderType: "Input",
    visible: false,
    writable: true,
    isUpdate: true,
    updateField: "id",
  },
  {
     
    label: "期刊名称",
    field: "periodicalName",
    renderType: "Input",
    require: true,
    visible: true,
    isUpdate: true,
    updateField: "periodicalName",
    updateWritable: true,
    updateVisible: true,
  },
  {
     
    label: "主编",
    field: "majorEditor",
    renderType: "Input",
    require: true,
    visible: true,
    isUpdate: true,
    updateField: "majorEditor",
    updateWritable: true,
    updateVisible: true,
  },
  {
     
    label: "编辑",
    field: "editors",
    renderType: "Input",
    require: true,
    visible: true,
    isUpdate: true,
    updateField: "editors",
    updateWritable: true,
    updateVisible: true,
  },
  {
     
    label: "图片",
    field: "picUrl",
    renderType: "Upload",
    visible: true,
    isUpdate: true,
    updateField: "picUrl",
    updateWritable: true,
    updateVisible: true,
  },
  {
     
    label: "是否显示",
    field: "isShow",
    require: true,
    renderType: "Switch",
    visible: true,
    radioOptions: [
      {
      label: "是", key: 1 },
      {
      label: "否", key: 0 },
    ],
    defaultValue: 0,
    isUpdate: true,
    updateField: "isShow",
    updateWritable: true,
    updateVisible: true,
    updateRenderType: "Radio",
    sourceApi: {
      url: "/admin/weeksPeriodical/updateShow", method: "post" },
  },
];
const actions = [
  {
     
    status: "update",
    name: "编辑",
    url: "/admin/weeksPeriodical/update",
    method: "post",
    showColumn: true,
  },
  {
     
    status: "add",
    name: "新增",
    url: "/admin/weeksPeriodical/add",
    method: "post",
    showColumn: false,
  },
  {
     
    status: "query",
    name: "查询",
    url: "/admin/weeksPeriodical/listByPage",
    extraField: "list",
    method: "post",
    showColumn: false,
  },
];
const childModalList = [
  {
     
    label: "栏目ID",
    field: "columnId",
    renderType: "Input",
    visible: true,
    writable: true,
  },
  {
     
    label: "栏目名称",
    field: "columnName",
    renderType: "Input",
    require: true,
    visible: true,
  },
  {
     
    label: "栏目描述",
    field: "description",
    renderType: "Input",
    require: true,
    visible: true,
  },
];
const childActions = [
  {
     
    status: "del",
    name: "删除",
    url: "/admin/weeksPeriodicalColumn/delColumn",
    method: "post",
    showColumn: true,
    data: {
     
      periodicalId: "",
      columnId: "",
    },
  },
  {
     
    status: "sort",
    name: "排序",
    url: "/admin/weeksPeriodicalColumn/sort",
    method: "post",
    showColumn: false,
    data: {
     
      periodicalId: "",
      columnIdList: "",
    },
  },
  {
     
    status: "query",
    name: "查询",
    url: "/admin/weeksPeriodicalColumn/columnList",
    extraField: "list",
    method: "post",
    showColumn: false,
    data: {
     
      periodicalId: "",
    },
  },
  {
     
    status: "insert",
    name: "插入",
    url: "/admin/weeksPeriodicalColumn/addColumn",
    method: "post",
    showColumn: false,
    data: {
     
      periodicalId: "",
      columnIdList: [],
    },
  },
];
const insertModalList = [
  {
      label: "ID", field: "id", renderType: "Input", visible: true },
  {
     
    label: "栏目名称",
    field: "columnName",
    renderType: "Input",
    require: true,
    visible: true,
    width: 250,
  },
  {
     
    label: "栏目描述",
    field: "description",
    renderType: "Input",
    require: true,
    visible: true,
    width: 350,
  },
  {
     
    label: "栏目图片",
    field: "picUrl",
    renderType: "Upload",
    require: true,
    visible: true,
    width: 250,
  },
];
const insertActions = [
  {
     
    status: "query",
    name: "查询",
    url: "/admin/weeksColumn/allList",
    method: "get",
    showColumn: false,
  },
];
function Periodical() {
     
  return (
    <TreeTable
      actions={
     actions}
      modalList={
     modalList}
      childActions={
     childActions}
      childModalList={
     childModalList}
      insertActions={
     insertActions}
      insertModalList={
     insertModalList}
      isInsert={
     true}
      isSort={
     true}
      insertTitle="选择栏目"
      parentIdField="periodicalId"
    />
  );
}
export default Periodical;

三、API 使用指南

参考 React 模板封装之基础模板 BaseTable

四、源代码

在 TreeTable 目录中包含如下文件。

index.js

import React from "react";
import {
      Modal, message, Button } from "antd";
import {
      addAPI, getListAPI,editAPI} from "utils/commonApi";
import DragTable from "../DragTable/index";
import BaseTable from "../BaseTable";
import {
      useState, useRef } from "react";
function onExpand(newChildActions,props,setActions,setCurrentId, expanded, record) {
     
  let {
     parentIdField,modalList } = props;
  let field = modalList[0].field;
  newChildActions.map((item)=>{
     
      let data = item.data;
      data[parentIdField] = record[field];
  })  
  if (expanded) {
       
    setActions(newChildActions);
    setCurrentId(record[field]);
  }
}
function getDataSource(newChildActions,childModalList, cb) {
      
  let queryAction = newChildActions.filter((item) => item.status === "query")[0];
  getListAPI(queryAction, childModalList, {
     }, "", (state) => {
     
    if (cb) {
     
      cb(state.dataSource);
    }
  });
}
function insertColumn(
  newChildActions,childModalList,
  setShowSelectionColumn,
  setSelectedRowKeys,
  setDisabledKeys
) {
     
  setShowSelectionColumn(true);
  getDataSource(newChildActions,childModalList, (expandData) => {
     
    if (expandData && expandData.length > 0) {
     
      let selectedRowKeys = [];
      expandData.map((item) => {
     
        selectedRowKeys.push(item.columnId);
      });
      setDisabledKeys(selectedRowKeys);
      setSelectedRowKeys(selectedRowKeys);
    } else {
     
      setDisabledKeys([]);
      setSelectedRowKeys([]);
    }
  });
}

function onSelectChange(setSelectedRowKeys, selectedRowKeys) {
     
  setSelectedRowKeys(selectedRowKeys);
}

async function addColumns(
  newChildActions,childModalList,
  selectedRowKeys,
  setShowSelectionColumn, 
  dragTable
) {
     
  let childAction = newChildActions.filter(
    (item) => item.status === "insert"
  )[0];
  addAPI(
    childAction,
    childModalList,
    {
      columnIdList: selectedRowKeys },
    () => {
     
      getDataSource(newChildActions,childModalList, (dataSource)=>{
     
        let setDataSource = dragTable.current.setDataSource;
        setDataSource(dataSource);
        setShowSelectionColumn(false);
        message.success("添加成功");
      });
    }
  );
}
function checkBox(disabledKeys, record) {
     
  return {
     
    disabled: disabledKeys.includes(record.id),
  };
}

function onExpandedRowsChange(setExpandedRowKeys, expandedRows) {
     
  if (expandedRows.length > 1) {
     
    let id = expandedRows.pop();
    setExpandedRowKeys([id]);
  } else {
     
    setExpandedRowKeys(expandedRows);
  }
}
function sortSuccess( newChildActions,childModalList,columnIdList){
     
  let action = newChildActions.filter((item) => item.status === "sort")[0]; 
  let option = {
     columnIdList};
  editAPI(action, childModalList, option);
}
function TreeTable(props) {
     
  let {
     
    modalList,
    actions,
    insertActions,
    childActions,
    childModalList,
    isInsert,
    isSort,
    insertTitle,
    insertModalList
  } = props;
  const [showSelectionColumn, setShowSelectionColumn] = useState(false);
  const [selectedRowKeys, setSelectedRowKeys] = useState([]);
  const [disabledKeys, setDisabledKeys] = useState([]);
  const [expandedRowKeys, setExpandedRowKeys] = useState([]);
  const [currentId,setCurrentId] = useState("");
  const [newChildActions,setActions] = useState(childActions);
  const dragTable = useRef();
  const rowSelection = {
     
    selectedRowKeys,
    onChange: onSelectChange.bind(this, setSelectedRowKeys),
    getCheckboxProps: checkBox.bind(this, disabledKeys),
  };
  const expandedRowRender = (row) => {
     
    let {
      modalList } = props;
    let field = modalList[0].field;
    if(row[field] === currentId){
     
      return (
        <div>
          {
     isSort? (
            <DragTable
              actions={
     newChildActions}
              modalList={
     childModalList}                       
              ref={
     dragTable}
              sortSuccess={
     sortSuccess.bind(this, newChildActions,childModalList)}
            />
          ) : (
            <BaseTable
              actions={
     newChildActions}
              pagination={
     false}
              modalList={
     childModalList}                     
              ref={
     dragTable}
            />
          )}
          {
     isInsert ? (
            <div className="cm-cursor-p" style={
     {
      color: "#1790FF" }}>
              <Button
                icon="plus"
                block          
                primary                     
                type="dashed"
                size="large"
                onClick={
     () =>
                  insertColumn(
                    newChildActions,
                    childModalList,
                    setShowSelectionColumn,
                    setSelectedRowKeys,              
                    setDisabledKeys
                  )
                }
              >
                插入
              </Button>
            </div>
          ) : null}
        </div>
      );
    }
  };
  return (
    <div>
      <BaseTable
        actions={
     actions}
        modalList={
     modalList}
        onExpand={
     onExpand.bind(this, newChildActions,props,setActions,setCurrentId)}
        expandedRowRender={
     expandedRowRender}
        onExpandedRowsChange={
     onExpandedRowsChange.bind(
          this,
          setExpandedRowKeys
        )}
        expandedRowKeys={
     expandedRowKeys}
      />
      <Modal
        bodyStyle={
     {
      padding: 0 }}       
        title={
     insertTitle}
        visible={
     showSelectionColumn}
        onOk={
     () =>
          addColumns(
            newChildActions,childModalList,
            selectedRowKeys,
            setShowSelectionColumn,           
            dragTable
          )
        }
        onCancel={
     () => setShowSelectionColumn(false)}
      >
        <BaseTable
          actions={
     insertActions}
          rowSelection={
     rowSelection}
          modalList={
     insertModalList}
          expandedRowKeys={
     expandedRowKeys}
        />
      </Modal>
    </div>
  );
}
export default React.forwardRef(TreeTable);

以上可能有部分关联的JS文件没贴出来,因文件太多,就不一一贴出,需要的请留言。

五、总结

树形模板目前只支持两级,即父表格与子表格。并且父级表格与子级表格数据格式不一致。

你可能感兴趣的:(#,React,通用组件封装)