自定义实现排序按钮和删除按钮,当点了save按钮才是真正的保存成功。
table组件处的代码
<Table
bordered={true}
rowKey={'id'}
columns={getColumns}
dataSource={_.sortBy(_.filter(dataSource||[], item=>item.typeN !== 'delete'), ['sort'])}
pagination={{
current:pageNum,
total:totalData?.length,
hideOnSinglePage:false,
showSizeChanger:true,
onChange:pageNo=>{setPageNum(pageNo)},
showTotal: showTotal=>`Total ${showTotal} data`,
onShowSizeChange:current=>{
setPageSize(current.size);
setPageNum(current.current);
},
}}
/>
先来看一下dataSource大致有哪些数据
表格信息处的代码
const getColumns =()=>{
const columnData = _.get(modelData, 'column'); //modelData是redux存下来的数据
const data = _.filter(dataSource, item=>item.typeN !== 'delete');
const maxSort = _.get(_.maxBy(data, 'sort'), 'sort') || data.length;
const minSort = _.get(_.minBy(data, 'sort'), 'sort') || 1;
let columns = [];
if(!_.isEmpty(columnData)){
columns = _.map(columnData, key=>({
title: key.columnEn,
dataIndex: key.propertyName,
render: (value, record)=>{
const {type} = key;
if(type === 'input'){
if(key.propertyName === 'fieldFormulaApproval'){ // 这里是groove编辑脚本
return (
<div className={styles.field}>
<Input
id={`${record.id}_${key.propertyName}`}
value={value}
disabled={true}
maxLengrh={50}
/>
<span
className={styles.fieldBtn}
onClick={()=>handleClickEditFormulaButton(key,record)}
>
...
</span>
</div>
);
}
return (
<Input
id={`${record.id}_${key.propertyName}`}
value={value}
maxLengrh={50}
onChange={(e)=>handleChangeField({key, value: e.target.value},record)}
/>
)
}
return value;
},
}));
}
columns.push({
title: 'Operation',
width: '15%',
render: record=>(
<div>
<span
style={{
paddingRight: 12,
color: '#255FF2',
}}
onClick={()=>handleRemoveField(record)}
title={'Delete'}
>
<DeleteOutlined />
</span>
<span
style={{
pointerEvents: record.sort === minSort ? 'none' : 'auto',
cursor: record.sort === minSort ? 'not-allowed' : 'pointer',
paddingRight: 12,
color: record.sort === minSort ? '#ddd' : '#255FF2',
}}
onClick={()=>handleMoveField(record, 'up')}
title={'Up'}
>
<UpCircleOutlined />
</span>
<span
style={{
pointerEvents: record.sort === maxSort ? 'none' : 'auto',
cursor: record.sort === maxSort ? 'not-allowed' : 'pointer',
color: record.sort === maxSort ? '#ddd' : '#255FF2',
}}
onClick={()=>handleMoveField(record, 'down')}
title={'Down'}
>
<DownCircleOutlined />
</span>
</div>
),
});
return columns;
}
表格删除处的代码
const handleRemoveField =(record)=>{
if(_.find(dataSource, item=>String(item.id).tirm() === String(record.id).tirm())){
// 删除的数据都拼上typeN作标记
setDataSource(_.filter(dataSource, item=>String(item.id).tirm() !== String(record.id).tirm()).concat({...record, typeN: 'delete'}))
}else{
setDataSource(_.filter(dataSource, item=>String(item.id).tirm() !== String(record.id).tirm()))
}
}
判断表格内的Input输入框是否变化,变化的话type就要变成update
const handleChangeField =(params, record)=>{
// 找到修改当条数据的id index
const fieldIndex = _.findIndex(dataSource, item=>String(item.id).trim() === String(record.id).trim());
const newFieldData = {
...record,
[params.key.propertyName]: params.value,
type: record.type || 'update',
// blockly生成的xml给后端,需要回显
...(params.xmlText ? {[`${params.key.propertyName}Xml`]: params.xmlText} : {})
}
setDataSource(dataSource.slice(0, fieldIndex).concat(newFieldData).concat(dataSource.slice(fieldIndex + 1)))
}
移动按钮(上,下)的实现逻辑
import helperByOpsexcel from '../../config/helper'
const handleMoveField = (record, moveDirection)=>{
// 过滤出typeN为delete的数据
const deletedData = _.filter(dataSource || [], item=>item.typeN === 'delete');
// 过滤出typeN不为delete的数据(需要处理移动的数据)
const data = _.filter(dataSource || [], item=>item.typeN !== 'delete');
let newData = [];
// 找到当条移动的数据的index
const current = _.findIndex(data, item=>String(item.id).trim() === String(record.id).trim());
//对数据进行分组
const groupBygroup = _.groupBy(data, o=>o.group);
if(current > -1){
// 向下移动的处理
if(moveDirection === 'down'){
const nextIndex = _.findIndex(data, (item, index)=>index > current);
const nextGroup = _.get(_.find(data, o=>o.flag === nextIndex), 'group');
const sortData = _.orderBy(data, 'sort', 'asc');
_.each(data, (item,index)=>{
if(index === current && ((!item.group && !nextGroup) || item.group === nextGroup )){
// 点击的和下一条是同级的情况(目前项目只需要用到这一种情况即可)
newData = helperByOpsexcel.getPeersMoveData(sortData, item, nextIndex);
}else if(index === current && !item.group && nextGroup){
//点击的是没有group的,下一条是有group的情况
const groupLength = helperByOpsexcel.getLengthByGroup(groupBygroup, nextGroup);
newData = helperByOpsexcel.getAfterMoveData(sortData, groupLength, item, nextIndex, nextGroup);
}else if(index === current && item.group && !nextGroup){
//点击的是有group的,下一条是没有group的情况
const groupLength = helperByOpsexcel.getLengthByGroup(groupBygroup, item.group);
newData = helperByOpsexcel.getAfterMoveData(sortData, groupLength, item, nextIndex);
}else if(index === current && item.group && nextGroup && item.group !== nextGroup){
//当前点击的和下一条点击的都有group并且group不同
const currentGroupLength = helperByOpsexcel.getLengthByGroup(groupBygroup, item.group);
const nextGroupLength = helperByOpsexcel.getLengthByGroup(groupBygroup, nextGroup);
newData = helperByOpsexcel.getAfterMoveData(sortData, currentGroupLength, item, nextIndex, nextGroup, nextGroupLength);
}
});
}else if(moveDirection === 'up'){
// 向上移动的处理
const prevIndex = _.findLastIndex(data, (item, index)=> index < current);
const prevGroup = _.get(_.find(data, o=>o.flag === prevIndex), 'group');
const sortData = _.orderBy(data, 'sort', 'asc');
_.each(data, (item,index)=>{
if(index === current && ((!item.group && !prevGroup) || item.group === prevGroup)){
// 点击的和上一条是同级的情况(目前项目只需要用到这一种情况即可)
newData = helperByOpsexcel.getPeersMoveData(sortData, item, prevIndex, 'up');
}else if(index === current && !item.group && prevGroup){
//点击的是没有group的,上一条是有group的情况
const groupLength = helperByOpsexcel.getLengthByGroup(groupBygroup, prevGroup);
newData = helperByOpsexcel.getUpAfterMoveData(sortData, groupLength, item, prevIndex, prevGroup);
}else if(index === current && item.group && !prevGroup){
//点击的是有group的,上一条是没有group的情况
const groupLength = helperByOpsexcel.getLengthByGroup(groupBygroup, item.group);
newData = helperByOpsexcel.getUpAfterMoveData(sortData, groupLength, item, prevIndex);
}else if(index === current && item.group && prevGroup && item.group !== prevGroup){
//当前点击的和上一条点击的都有group并且group不同
const currentGroupLength = helperByOpsexcel.getLengthByGroup(groupBygroup, item.group);
const prevGroupLength = helperByOpsexcel.getLengthByGroup(groupBygroup, prevGroup);
newData = helperByOpsexcel.getUpAfterMoveData(sortData, currentGroupLength, item, index, prevGroup, prevGroupLength);
}
});
}
setDataSource(_.sortBy(newData, ['sort']).concat(deletedData));
}
}
上面用到的一些方法是封装过的
import _ from 'lodash';
const helper = {
//获取平级的移动数据
getPeersMoveData(data, item, Index, direction){
return _.map(data, (o, i)=>{
if(o.id === item.id){
// 点中的当条数据的sort变化
return {...o, sort: _.get(data, `[${Index}].sort`), type: o.type ? o.type : 'update'}
}
if(i === Index){
// 点中的当条的上(下)一条数据的sort变化
return {...o, sort: item.sort, type: o.type ? o.type : 'update'}
}
return o;
})
}
// 获取点击数据有group的长度
getLengthByGroup(groupBygroup, group){
let groupLength;
for(const key in groupBygroup){
if(key === group){
groupLength = groupBygroup[key].length;
}
}
return groupLength;
}
}
脚本编辑框的一些代码
新增一条数据需要造一条空的数据
const handleAddField = () =>{
const newData = {
type: 'add',
id: new Date().getTime(), // 新增多个如果不加id填值会跟着一起变化
sort: (_.get(_.maxBy(_.filter(dataSource, item=>item.typeN !== 'delete'), 'sort'), 'sort') || 0) + 1,
// ... 需要传给后端的字段
isAdd: true, // 判断是否是新增,如果是,在调接口的时去掉新增时的id
}
if(typeof dataSource === 'undefined'){
setDataSource([newData])
}else{
setDataSource([...dataSource, newData])
}
//新增时跳到最后一页
const currentPage = Math.ceil((modelData?.length + 1) / pageSize) || 1;
setPageNum(currentPage);
}