react antd table 自定义表头功能
Ⅰ- 壹 - 功能展示和使用需求
需求描述
基于antd table 实现
自定义 table 的表头 内容 排序 宽度和顺序等 , 可根据自己的需求自己扩展
github:https://github.com/whqgo/ReactAntdTableCustomHeader
功能展示
Ⅱ - 贰 - 封装思路
TaskareaTableColumns: 主要对 弹框内容的封装
app.tsx:使用的方式 和对表头数据的描述
json.ts: 数据文件 主要用于模拟的数据
设计思路
用对象数组描述表格 然后进行解析读取处理 , 这是最原始的数据,
const [taskareaTableColumnsData, setTaskareaTableColumnsData] = useState({
isShow: false, //控制显示隐藏
type: 'taskarea',
fields: fixedFields, // 当前字段的 模型数据 , 目的是为了 对字段的控制, 业务需要,
// 用于修改 和默认
columns: [
// {
// serial: '', //
// lable: '', //表头的名称 多个用 / 隔开
// lableRename: '', //表头的 重命名名称 优先级高于lable
// value: [], // 要读取数据的字段key要读取数据的字段key 和 lable 关系对应
// expression:'',// 表达式,fields存在的才能做计算
// width: '',//宽度
// defaultSortOrder: '',// 数据 的 排序方式
// style:'',//样式
// visible:'',//可视
// noRender:true,// 是否 重写 render
//... 和 antd table columns 配置一样
// }
{
key: 'workDispatchOrdersProcessN.paiGongDanHao',
id: '1', //
serial: '1',
// lable: ['工序名称', '派工单号'], //表头的名称 多个用 / 隔开
lableRename: '工序/单号', //表头的 重命名名称 优先级高于lable
title: '工序/单号', //表头的最终 重命名名称 优先级高于lable
value: ['workDispatchOrdersProcessN', 'paiGongDanHao'], // 要读取数据的字段key 和 lable 关系对应
expression: '',// 表达式,fields存在的才能做计算
width: '',//宽度
visible: true,//可视
defaultSortOrder: '',// 数据 的 排序方式
styleType: 'def',//样式风格 def 默认文本 number 数字样式
style: {},//样式
align: 'center',//表头居中
},
{
key: 'yxfw',
id: '22', //
serial: '22', //
// lable: ['物品名称'], //表头的名称 多个用 / 隔开
lableRename: '规格', //表头的 重命名名称 优先级高于lable
title: '规格',
value: ['yxfw'], // 要读取数据的字段key
expression: '',// 表达式,fields存在的才能做计算
width: '',//宽度
defaultSortOrder: '',// 数据 的 排序方式
visible: true,//可视
styleType: 'def',//样式风格 def 默认文本 number 数字样式
style: { flex: 3 },//样式
align: 'center',//表头居中
},
{
title: '操作',
key: 'action',
serial: '000000',
id: 'aaa111bbb222ccc333',
noRender: true,// 是否 重写 render
align: 'center',//表头居中
visible: true,//可视
width: '300px',
render: (_: any, record: any) => {
return <div className='operation-item-content-taskarea'><div style={{ 'justifyContent': 'space-evenly', flex: '1' }}>
<div className='operation-badge-taskarea1'>
<div style={{}}>
<Button type="primary" onClick={() => {
console.log("操作====按钮触发", record);
}} size={'large'}>
按钮
</Button>
</div>
</div>
</div></div>
},
},
],
severalRows: 3// 控制合并行数
})
我们可以在 useEffect进行动态控制 这里我们对 tableColumns 中的数据进行了二次处理 目的是在 这里就能获取到我当前的表头原始的数据,去控制最终要显示的数据处理,例如他的表头 文字 title,我需要根据两个值去判最终的结果,render中是根据我需求去做的处理
useEffect(() => {
if (!taskareaTableColumnsData?.columns) return
if (workDispatchOrdersData?.length) {
setTableColumns(() => (taskareaTableColumnsData.columns.reduce((preData: any, curData: any) => {
// 判断是否可视
if (curData.visible) {
return curData.noRender ? [...preData, curData] : [...preData, {
...curData,
title: (record: any) => {
let titleStr = curData?.lableRename || (taskareaTableColumnsData.fields.filter((f: any) => curData.value.includes(f.c))).map((f1: any) => f1.n).join('/')
return <div>
{titleStr}
</div>
},
width: curData.width ? !isNaN(curData.width) ? curData.width + 'px' : curData.width : '',
render: (_: any, record: any, index: any) => {
return (
<div className='operation-item-content-taskarea'>
<div>
{
(() => {
switch (curData.styleType) {
case 'def':
return curData?.value?.map((cITem: any, i: number) => {
return <div key={i}> {record[cITem]}</div>
})
case 'number':
let socketMessageWSDataFind = null
// 获取字段 模型的属性
let filterModels = fixedFields.filter((f: any) => curData?.value.includes(f.c))
// 判断是不是 自定义的模型 需要特殊处理
let customDefinitionFind: any = filterModels.find((f: any) => f.sourceDataType == "customDefinition")
return <div style={{ justifyContent: 'start' }}>
{/* <div className='operation-badge-taskarea'>{`${item['dmvl'] || 0}/${item['jiHuaShengChanShuLiang']}`}</div> */}
{/* 没有推送的时候 查询模型 实际生产数量/计划生产数量 */}
<div className='operation-badge-taskarea'>{curData?.expression ? eval(curData.expression) : curData?.value?.reduce((preValData: any, curValData: any) => {
// return preValData + (record[curValData] ? (record[curValData]) : '')
return [...preValData, record[curValData] || 0]
}, []).join('/')}
{/* 审核中 样式样式处理 */}
{
customDefinitionFind && <div className={customDefinitionFind?.className}>{eval(customDefinitionFind?.expression) || ''}</div>
}
</div>
</div>
default:
return curData?.value?.map((cITem: any, i: number) => {
return <div key={i}> {record[cITem]}</div>
})
}
})()
}
</div>
</div>
)
},
onCell: (record: any, index: number) => {
const cIndex = taskareaTableColumnsData.columns.findIndex(cItem => cItem.id === curData.id)
if (curData.styleType === 'def' && cIndex + 1 <= taskareaTableColumnsData.severalRows) {
try {
if (index) { // 不是第一条
const preD = workDispatchOrdersData[index - 1], nextD = workDispatchOrdersData[index];
if (!preD || !nextD) return {}
let preV = '', nextV = '';
curData.value.map((item: string) => {
preV += preD[item]
nextV += nextD[item]
})
if (preV === nextV) { // 上一条和当前条相等,不渲染
return { rowSpan: 0 }
}
}
if (index !== workDispatchOrdersData.length - 1) { // 不是最后一条
let unlikeIndex = workDispatchOrdersData.length - index; // 默认全部相等
for (let i = index; i < workDispatchOrdersData.length; i++) {
const nextD = workDispatchOrdersData[i + 1], currentD = workDispatchOrdersData[i];
if (!nextD) break;
let currentV = '', nextV = '';
curData.value.map((item: string) => {
currentV += currentD[item]
nextV += nextD[item]
})
if (i !== workDispatchOrdersData.length - 1 && nextV !== currentV) { // 当前条和下一条不相等,就是需要合并的数
unlikeIndex = i - index + 1
break;
}
}
return { rowSpan: unlikeIndex }
}
} catch (err) { console.log(err); }
}
return {}
}
}]
} else {
return preData
}
}, [])))
}
}, [workDispatchOrdersData, taskareaTableColumnsData.columns])
在弹框中 TaskareaTableColumns这个组件,就是把taskareaTableColumnsData.columns 中的配置当成数据去处理的,然后对他的内容做了自定义处理,详情看代码
github:https://github.com/whqgo/ReactAntdTableCustomHeader
Ⅲ - 叁 - 主要代码
APP.tsx使用
import { useEffect, useState } from 'react'
import './App.css'
import { Button, Checkbox, Input, InputNumber, Modal, Select, Space, Table } from 'antd';
import TaskareaTableColumns from './TaskareaTableColumns';
import { cloneDeep } from 'lodash'
import { fixedFields, MNData } from './json'
function App() {
const [taskareaTableColumnsData, setTaskareaTableColumnsData] = useState({
isShow: false, //控制显示隐藏
type: 'taskarea',
fields: fixedFields, // 当前字段的 模型数据 , 目的是为了 对字段的控制, 业务需要,
// 用于修改 和默认
columns: [
// {
// serial: '', //
// lable: '', //表头的名称 多个用 / 隔开
// lableRename: '', //表头的 重命名名称 优先级高于lable
// value: [], // 要读取数据的字段key要读取数据的字段key 和 lable 关系对应
// expression:'',// 表达式,fields存在的才能做计算
// width: '',//宽度
// defaultSortOrder: '',// 数据 的 排序方式
// style:'',//样式
// visible:'',//可视
// noRender:true,// 是否 重写 render
//... 和 antd table columns 配置一样
// }
{
key: 'workDispatchOrdersProcessN.paiGongDanHao',
id: '1', //
serial: '1',
// lable: ['工序名称', '派工单号'], //表头的名称 多个用 / 隔开
lableRename: '工序/单号', //表头的 重命名名称 优先级高于lable
title: '工序/单号', //表头的最终 重命名名称 优先级高于lable
value: ['workDispatchOrdersProcessN', 'paiGongDanHao'], // 要读取数据的字段key 和 lable 关系对应
expression: '',// 表达式,fields存在的才能做计算
width: '',//宽度
visible: true,//可视
defaultSortOrder: '',// 数据 的 排序方式
styleType: 'def',//样式风格 def 默认文本 number 数字样式
style: {},//样式
align: 'center',//表头居中
},
{
key: 'workDispatchOrdersItemN',
id: '2', //
serial: '2', //
// lable: ['物品名称'], //表头的名称 多个用 / 隔开
lableRename: '物品', //表头的 重命名名称 优先级高于lable
title: '物品',
value: ['workDispatchOrdersItemN'], // 要读取数据的字段key
expression: '',// 表达式,fields存在的才能做计算
width: '',//宽度
defaultSortOrder: '',// 数据 的 排序方式
visible: true,//可视
styleType: 'def',//样式风格 def 默认文本 number 数字样式
style: { flex: 3 },//样式
align: 'center',//表头居中
},
{
key: 'yxfw',
id: '22', //
serial: '22', //
// lable: ['物品名称'], //表头的名称 多个用 / 隔开
lableRename: '规格', //表头的 重命名名称 优先级高于lable
title: '规格',
value: ['yxfw'], // 要读取数据的字段key
expression: '',// 表达式,fields存在的才能做计算
width: '',//宽度
defaultSortOrder: '',// 数据 的 排序方式
visible: true,//可视
styleType: 'def',//样式风格 def 默认文本 number 数字样式
style: { flex: 3 },//样式
align: 'center',//表头居中
},
{
key: 'oiwo',
id: '222', //
serial: '222', //
// lable: ['物品名称'], //表头的名称 多个用 / 隔开
lableRename: '库存代码', //表头的 重命名名称 优先级高于lable
title: '库存代码',
value: ['oiwo'], // 要读取数据的字段key
expression: '',// 表达式,fields存在的才能做计算
width: '',//宽度
defaultSortOrder: '',// 数据 的 排序方式
visible: true,//可视
styleType: 'def',//样式风格 def 默认文本 number 数字样式
style: { flex: 3 },//样式
align: 'center',//表头居中
},
{
key: 'cqsw',
id: '2222', //
serial: '2222', //
// lable: ['物品名称'], //表头的名称 多个用 / 隔开
lableRename: '客户简称', //表头的 重命名名称 优先级高于lable
title: '客户简称',
value: ['cqsw'], // 要读取数据的字段key
expression: '',// 表达式,fields存在的才能做计算
width: '',//宽度
defaultSortOrder: '',// 数据 的 排序方式
visible: true,//可视
styleType: 'def',//样式风格 def 默认文本 number 数字样式
style: { flex: 3 },//样式
align: 'center',//表头居中
},
{
key: 'frbz.sene',
id: '3',
serial: '3',
// lable: ['主设备名称'], //表头的名称 多个用 / 隔开
lableRename: '主设备/设备部位', //表头的 重命名名称 优先级高于lable
title: '主设备',
value: ['frbz', 'sene'], // 要读取数据的字段key
expression: '',// 表达式,fields存在的才能做计算
width: '',//宽度
defaultSortOrder: '',// 数据 的 排序方式
visible: true,//可视
styleType: 'def',//样式风格 def 默认文本 number 数字样式
style: {},//样式
align: 'center',//表头居中
},
{
key: 'dmvl.jiHuaShengChanShuLiang.mvit',
id: '4',
serial: '4',
lable: ['实际生产数量', '计划生产数量', '审核中'], //表头的名称 多个用 / 隔开
lableRename: '实际生产数量/计划生产数量', //表头的 重命名名称 优先级高于lable
title: '实际生产数量/计划生产数量',
value: ['dmvl', 'jiHuaShengChanShuLiang', 'mvit'], // 要读取数据的字段key
expression: "`${socketMessageWSDataFind ? (socketMessageWSDataFind['dmvl'] || record['dmvl'] || 0) : record['dmvl'] || 0}/${record['jiHuaShengChanShuLiang'] || 0}`",// 表达式,fields存在的才能做计算
width: '',//宽度
defaultSortOrder: '',// 数据 的 排序方式
visible: true,//可视
styleType: 'number',//样式风格 def 默认文本 number 数字样式
style: { textAlign: 'start', flex: 3 },//样式\
align: 'center',//表头居中
},
// {
// key: 'dmvl.jiHuaShengChanShuLiang',
// id: '5',
// serial: '5',
// lable: ['实际生产数量', '计划生产数量'], //表头的名称 多个用 / 隔开
// lableRename: '实际生产数量12/计划生产数量333', //表头的 重命名名称 优先级高于lable
// value: ['dmvl', 'jiHuaShengChanShuLiang'], // 要读取数据的字段key
// expression: "",// 表达式,fields存在的才能做计算
// width: '',//宽度
// defaultSortOrder: '',// 数据 的 排序方式
// visible: true,//可视
// styleType: 'number',//样式风格 def 默认文本 number 数字样式
// style: { textAlign: 'start', flex: 3 },//样式\
// align: 'center',//表头居中
// },
{
title: '操作',
key: 'action',
serial: '000000',
id: 'aaa111bbb222ccc333',
noRender: true,// 是否 重写 render
align: 'center',//表头居中
visible: true,//可视
width: '300px',
render: (_: any, record: any) => {
return <div className='operation-item-content-taskarea'><div style={{ 'justifyContent': 'space-evenly', flex: '1' }}>
<div className='operation-badge-taskarea1'>
<div style={{}}>
<Button type="primary" onClick={() => {
console.log("操作====按钮触发", record);
}} size={'large'}>
按钮
</Button>
</div>
</div>
</div></div>
},
},
],
severalRows: 3// 控制合并行数
})
// 最终的 columns
const [tableColumns, setTableColumns] = useState<any>([])
const taskareaTableColumnsFillData = (FillDatType: any, tableColumnsFillData: any) => {
// console.log(tableColumnsFillData, "===tableColumnsFillData===");
// console.log(FillDatType, "===isShow===");
// console.log(taskareaTableColumnsData, "===isShow===");
if (FillDatType) {
setTaskareaTableColumnsData((taskareaTableColumnsData: any) => {
let _taskareaTableColumnsData = cloneDeep(taskareaTableColumnsData)
_taskareaTableColumnsData.isShow = false
_taskareaTableColumnsData.columns = [...tableColumnsFillData.tableData, _taskareaTableColumnsData.columns[_taskareaTableColumnsData.columns?.length - 1]]
_taskareaTableColumnsData.severalRows = tableColumnsFillData.severalRows
return _taskareaTableColumnsData
})
} else {
setTaskareaTableColumnsData((taskareaTableColumnsData: any) => ({ ...taskareaTableColumnsData, isShow: false }))
}
}
const [workDispatchOrdersData, setWorkDispatchOrdersData] = useState<any>([])//数据
// 初始化数据
const getInit = async () => {
setWorkDispatchOrdersData(() => MNData)
}
useEffect(() => {
if (!taskareaTableColumnsData?.columns) return
// console.log(taskareaTableColumnsData.columns, "====taskareaTableColumnsData.columns===");
// console.log(workDispatchOrdersData, "====taskareaTableColumnsData.columns===");
if (workDispatchOrdersData?.length) {
setTableColumns(() => (taskareaTableColumnsData.columns.reduce((preData: any, curData: any) => {
// 判断是否可视
if (curData.visible) {
return curData.noRender ? [...preData, curData] : [...preData, {
...curData,
title: (record: any) => {
let titleStr = curData?.lableRename || (taskareaTableColumnsData.fields.filter((f: any) => curData.value.includes(f.c))).map((f1: any) => f1.n).join('/')
return <div>
{titleStr}
</div>
},
width: curData.width ? !isNaN(curData.width) ? curData.width + 'px' : curData.width : '',
render: (_: any, record: any, index: any) => {
// console.log(_, record, index);
// console.log(curData)
return (
<div className='operation-item-content-taskarea'>
<div>
{
(() => {
switch (curData.styleType) {
case 'def':
return curData?.value?.map((cITem: any, i: number) => {
return <div key={i}> {record[cITem]}</div>
})
case 'number':
let socketMessageWSDataFind = null
// 获取字段 模型的属性
let filterModels = fixedFields.filter((f: any) => curData?.value.includes(f.c))
// 判断是不是 自定义的模型 需要特殊处理
let customDefinitionFind: any = filterModels.find((f: any) => f.sourceDataType == "customDefinition")
return <div style={{ justifyContent: 'start' }}>
{/* <div className='operation-badge-taskarea'>{`${item['dmvl'] || 0}/${item['jiHuaShengChanShuLiang']}`}</div> */}
{/* 没有推送的时候 查询模型 实际生产数量/计划生产数量 */}
<div className='operation-badge-taskarea'>{curData?.expression ? eval(curData.expression) : curData?.value?.reduce((preValData: any, curValData: any) => {
// return preValData + (record[curValData] ? (record[curValData]) : '')
return [...preValData, record[curValData] || 0]
}, []).join('/')}
{/* 审核中 样式样式处理 */}
{
customDefinitionFind && <div className={customDefinitionFind?.className}>{eval(customDefinitionFind?.expression) || ''}</div>
}
</div>
</div>
default:
return curData?.value?.map((cITem: any, i: number) => {
return <div key={i}> {record[cITem]}</div>
})
}
})()
}
</div>
</div>
)
},
onCell: (record: any, index: number) => {
const cIndex = taskareaTableColumnsData.columns.findIndex(cItem => cItem.id === curData.id)
if (curData.styleType === 'def' && cIndex + 1 <= taskareaTableColumnsData.severalRows) {
try {
if (index) { // 不是第一条
const preD = workDispatchOrdersData[index - 1], nextD = workDispatchOrdersData[index];
if (!preD || !nextD) return {}
let preV = '', nextV = '';
curData.value.map((item: string) => {
preV += preD[item]
nextV += nextD[item]
})
if (preV === nextV) { // 上一条和当前条相等,不渲染
return { rowSpan: 0 }
}
}
if (index !== workDispatchOrdersData.length - 1) { // 不是最后一条
let unlikeIndex = workDispatchOrdersData.length - index; // 默认全部相等
for (let i = index; i < workDispatchOrdersData.length; i++) {
const nextD = workDispatchOrdersData[i + 1], currentD = workDispatchOrdersData[i];
if (!nextD) break;
let currentV = '', nextV = '';
curData.value.map((item: string) => {
currentV += currentD[item]
nextV += nextD[item]
})
if (i !== workDispatchOrdersData.length - 1 && nextV !== currentV) { // 当前条和下一条不相等,就是需要合并的数
unlikeIndex = i - index + 1
break;
}
}
return { rowSpan: unlikeIndex }
}
} catch (err) { console.log(err); }
}
return {}
}
}]
} else {
return preData
}
}, [])))
}
}, [workDispatchOrdersData, taskareaTableColumnsData.columns])
useEffect(() => {
getInit()
}, [])
return (
<div className="App">
{
taskareaTableColumnsData.isShow && <TaskareaTableColumns data={taskareaTableColumnsData} fillData={taskareaTableColumnsFillData} />
}
<div>
<Button onClick={() => {
setTaskareaTableColumnsData((data) => ({ ...data, isShow: true }))
}}> 设置表头</Button>
</div>
{
tableColumns && <Table
bordered
columns={tableColumns as any}
className='taskarea-table-css'
dataSource={workDispatchOrdersData}
pagination={false}
rowKey='id'
/>
}
</div>
)
}
export default App
TaskareaTableColumns 封装
import React, { useState, useEffect, Fragment, useRef, useCallback } from 'react';
import './index.css';
import { Button, Checkbox, Input, InputNumber, Modal, Select, Space, Table } from 'antd';
import update from 'immutability-helper';
import { DndProvider, useDrag, useDrop } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import { cloneDeep } from 'lodash';
interface DraggableBodyRowProps extends React.HTMLAttributes<HTMLTableRowElement> {
index: number;
moveRow: (dragIndex: number, hoverIndex: number) => void;
}
const DraggableBodyRowType = 'DraggableBodyRow';
const DraggableBodyRow = ({
index,
moveRow,
className,
style,
...restProps
}: DraggableBodyRowProps) => {
const ref = useRef<HTMLTableRowElement>(null);
const [{ isOver, dropClassName }, drop] = useDrop({
accept: DraggableBodyRowType,
collect: monitor => {
const { index: dragIndex } = monitor.getItem() || {};
if (dragIndex === index) {
return {};
}
return {
isOver: monitor.isOver(),
dropClassName: dragIndex < index ? ' drop-over-downward' : ' drop-over-upward',
};
},
drop: (item: { index: number }) => {
moveRow(item.index, index);
},
});
const [, drag] = useDrag({
type: DraggableBodyRowType,
item: { index },
collect: monitor => ({
isDragging: monitor.isDragging(),
}),
});
drop(drag(ref));
return (
<tr
ref={ref}
className={`${className}${isOver ? dropClassName : ''}`}
style={{ cursor: 'move', ...style }}
{...restProps}
/>
);
};
const index: any = (props: any) => {
const { fillData, type, model, data } = props;
const [state, setState] = useState<any>({
modalWidth: '60%',
modalHeight: '55vh',
});
const [dataSource, setDataSource] = useState<any[]>([]);
const [severalRows, setSeveralRows] = useState<any>()
useEffect(() => {
console.log(data.severalRows);
setSeveralRows(data.severalRows)
}, [data.severalRows])
// 新增一条
const addTableRow = () => {
setDataSource((dataSource: any) => {
let _dataSource = cloneDeep(dataSource)
_dataSource.push({
id: Date.now(),
serial: _dataSource.length + 1,
lable: null,
visible: true,
align: 'center',//表头居中
})
return _dataSource
})
}
// 最终的 columns
const [tableColumns, setTableColumns] = useState<any>([
{
title: '序号',
key: 'index',
dataIndex: 'index',
width: '60px',
render: (_: any, __: any, index: number) => index + 1, // 使用 index + 1 作为序号值
},
{
title: '字段名称',
dataIndex: 'value',
key: 'value',
noRender: true,
styleType: 'multipleSelect',
},
{
title: '显示名称',
dataIndex: 'lableRename',
key: 'lableRename',
noRender: true,
styleType: 'input',
},
{
title: '可视',
dataIndex: 'visible',
key: 'visible',
styleType: 'checkbox',
noRender: true,
},
{
title: '宽度',
dataIndex: 'width',
key: 'width',
styleType: 'input',
noRender: true,
},
// {
// title: '排序',
// dataIndex: 'defaultSortOrder',
// key: 'defaultSortOrder',
// styleType: 'select',
// noRender: true,
// },
{
title: '操作',
key: 'option',
width: 100,
render: (_: any, record: any) => (
<Space>
<Button type="primary" onClick={() => {
// 删除
setDataSource((dataSource: any) => {
let _dataSource = cloneDeep(dataSource)
let recindex = _dataSource.findIndex((f: any) => f.id == record.id)
_dataSource.splice(recindex, 1)
return _dataSource
})
}} danger>
删除
</Button>
</Space>
),
},
])
const moveRow = useCallback(
(dragIndex: number, hoverIndex: number) => {
const dragRow = dataSource[dragIndex];
setDataSource(
update(dataSource, {
$splice: [
[dragIndex, 1],
[hoverIndex, 0, dragRow],
],
}),
);
},
[dataSource],
);
const onOK = async (type: any) => {
if (type) {
// console.log('%c [ 工作台设置提交 tableColumns] 日志', 'font-size:13px; background:#26A08F; color:#fff;', tableColumns);
// console.log('%c [ 工作台设置提交 dataSource] 日志', 'font-size:13px; background:#26A08F; color:#fff;', dataSource);
if (fillData) fillData(1, { tableData: cloneDeep(dataSource), severalRows })
} else {
if (fillData) fillData(0)
}
}
const h = () => {
if (!data) return
switch (data.type) {
case "taskarea":
return (
<>
<div>前<InputNumber style={{ margin: '0 5px 10px' }} min={1} value={severalRows} onChange={(val) => setSeveralRows(parseInt(val))} />列数值相同的时候,进行单元格合并</div>
{/* 这里必须加个key 不然会报错, 社区给的解决方案就是这样的 */}
<DndProvider key={Math.random()} backend={HTML5Backend}>
<Table
columns={tableColumns}
dataSource={dataSource}
pagination={false}
components={{
body: {
row: DraggableBodyRow,
},
}}
onRow={(_, index) => {
const attr = {
index,
moveRow,
};
return attr as React.HTMLAttributes<any>;
}}
/>
</DndProvider>
</>
)
default:
return <></>
}
}
const getInit = async () => {
// console.log(data, "===getInit===");
// 过滤掉 操作
let newList = data.columns.filter((f: any) => f.id != 'aaa111bbb222ccc333')
setDataSource(() => newList)
// 配置 table columns
setTableColumns(() => (tableColumns.reduce((preData: any, curData: any) => {
return !curData.noRender ? [...preData, curData] : [...preData, {
...curData,
render: (_: any, record: any, index: any) => {
// console.log(_, record, index);
// console.log(curData)
return <Fragment>
{
(() => {
switch (curData.styleType) {
case 'input':
return <Input value={record[curData.dataIndex]} onChange={(e) => {
setDataSource((dataSource: any) => {
let _dataSource = cloneDeep(dataSource)
let recordfind = _dataSource.find((f: any) => f.id === record.id)
recordfind[curData.dataIndex] = e.target.value
return _dataSource
})
}} placeholder={'请输入'}></Input>
case 'checkbox':
return <Checkbox onChange={(e) => {
setDataSource((dataSource: any) => {
let _dataSource = cloneDeep(dataSource)
let recordfind = _dataSource.find((f: any) => f.id === record.id)
recordfind[curData.dataIndex] = e.target.checked
return _dataSource
})
}} checked={record[curData.dataIndex]}></Checkbox>
case 'multipleSelect':
return <Select
mode="multiple"
allowClear
style={{ width: '100%' }}
defaultValue={record[curData.dataIndex] || []}
onChange={(value: any) => {
// console.log('%c [multipleSelect value ] 日志', 'font-size:13px; background:#26A08F; color:#fff;', value);
// 修改
setDataSource((dataSource: any) => {
let _dataSource = cloneDeep(dataSource)
let recordfind = _dataSource.find((f: any) => f.id === record.id)
recordfind[curData.dataIndex] = value
// 判断是不是数值类型 赋值样式 目前
let numberStyle = ['decimal']
let isnumberStyle = data.fields.filter((f: any) => value.includes(f.c)).find((f2: any) => numberStyle.includes(f2.t))
if (isnumberStyle) {
recordfind.styleType = 'def'
} else {
recordfind.styleType = 'number'
}
return _dataSource
})
}}
options={data.fields.map((item: any) => {
return {
value: item.c,
label: item.n,
}
})}
/>
case 'select':
return <Select
defaultValue={record[curData.dataIndex] || ''}
style={{ width: 120 }}
allowClear
onChange={(value: any) => {
// 修改
setDataSource((dataSource: any) => {
let _dataSource = cloneDeep(dataSource)
let recordfind = _dataSource.find((f: any) => f.id === record.id)
recordfind[curData.dataIndex] = value
return _dataSource
})
}}
options={[
{
value: '',
label: '无',
},
{
value: 'descend',
label: '降序',
},
{
value: 'ascend',
label: '升序',
},
]}
/>
default:
return <div>暂无内容</div>
}
})()
}
</Fragment>
}
}]
}, [])))
}
useEffect(() => {
if (!data) return
getInit()
}, [])
useEffect(() => {
// console.log(dataSource, "===dataSource===监听修改");
}, [dataSource])
return (
<>
<Modal
width={state.modalWidth}
style={{ top: 50 }}
destroyOnClose={true}
centered={false}
title={(() => {
return '设置列表'
})()}
open={data?.isShow}
// onOk={onOK}
// onCancel={() => setIsShow(false)}
footer={(() => {
let footer = [
<Button key="quxiao3" onClick={() => onOK(0)} size={'large'}>
取消
</Button>,
<Button key="xinzengyitiao" type="primary" onClick={() => addTableRow()} size={'large'}>
新增一条
</Button>,
<Button key="submit" type="primary" onClick={() => onOK(1)} size={'large'}>
确定
</Button>
]
return footer
})()}
maskClosable={false}
className="TaskareaTableColumnsCss"
closable={false}
bodyStyle={{
height: state.modalHeight,
position: 'relative',
display: 'flex',
overflow: 'auto',
}}
>
<div style={{ width: '100%' }}>
{
(data?.isShow) && h()
}
</div>
</Modal>
</>
);
};
export default index
github:https://github.com/whqgo/ReactAntdTableCustomHeader