前面有介绍过 React 模板封装之基础模板 BaseTable 和 React 模板封装之拖曳模板 DragTable,今天在这两个模板的基础上实现一个树形模板 TreeTable。目前该模板只支持两个层级。本模板指的是父级表格与子级表格数据格式不一致的情况。
模板说明:
在原先模板的基础上实现一个树形模板 TreeTable。
效果展示:
使用场景:
父表格中嵌套子表格的场景。
参数说明
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;
参考 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文件没贴出来,因文件太多,就不一一贴出,需要的请留言。
树形模板目前只支持两级,即父表格与子表格。并且父级表格与子级表格数据格式不一致。