需求:
1.下拉列表第一级选中的,二级不能再选中,三级不能选中一二级选中的,以此类推
2. 点击添加优先级,至多添加6个优先级
3. 最后一层优先级的删除功能
主要使用技术:React + typescript
思路:根据优先级获取对应的下拉列表数据源,当触发onChange事件的时候,对数据源信息进行筛选
代码范例
·index.tsx
import React, {
useState,
useEffect,
Fragment,
useImperativeHandle,
} from 'react';
import { Select } from 'antd';
import { useRequest } from 'ahooks';
import { ExclamationCircleFilled } from '@ant-design/icons';
import { dealConfig, dealSelect } from './utils';
import { request } from '../../../utils/request';
import './index.less';
import search from '../search';
const { Option } = Select;
// 数字转化
const SortPanel = React.forwardRef((props: any, ref) => {
const { searchData } = props;
// console.log("searchData", searchData)
const iconStyle = {
color: '#1658dc',
height: 11,
width: 11,
};
// 需要展示的 fieldConfigList
const [fieldConfigList, setFieldConfigList] = useState([]);
// 下拉列表框数据源 fieldList
const [fieldList, setFieldList] = useState<any>([]);
// 下拉列表框 每一个优先级对应的数据源 fieldListObj
const [fieldListObj, setFieldListObj] = useState<any>({});
// 添加按钮的 展示隐藏
const [visible, setIsVisible] = useState(true);
// 排序的回调,当弹窗点击确定时。当弹窗点击确定时需要发送请求
useImperativeHandle(ref, () => ({
submit: () => {
// console.log('====submit fieldConfigList===', fieldConfigList);
editReportFieldsConfig.run();
return true;
},
}));
// 联动,更改 下拉选择列表的数据源
const changeFieldConfig = (
fieldConfig: any,
fieldList: any,
priority?: number,
) => {
let obj = dealConfig(fieldConfig, fieldList, priority, fieldListObj);
// console.log('changeFieldConfig setFieldListObj', obj);
setFieldListObj(obj);
};
// 初始化弹框数据回调函数
const setManualReportFieldsConfig = (data: any) => {
// console.log("setManualReportFieldsConfig", data)
// 设置fieldConfigList
setFieldConfigList(data.fieldConfigList);
// 设置fieldList
setFieldList(data.fieldList);
// 初始化下拉选择数据 处理
changeFieldConfig(data.fieldConfigList, data.fieldList);
};
// 调用接口初始化排序弹框数据
// const queryManualReportFieldsConfig = request(
// {
// url: 'queryManualReportFieldsConfig',
// source: 'cbooking',
// accountId: searchData.accountId,
// monthReportType: searchData.monthReportType,
// accountPayType: searchData.accountPayType,
// },
// setManualReportFieldsConfig,
// );
const queryManualReportFieldsConfig = useRequest(
{
url: '/Front/Cbooking/API/Cbooking/queryManualReportFieldsConfig',
method: 'GET',
headers: new Headers({
'Content-Type': 'application/json',
}),
},
{
manual: true,
throwOnError: true,
onSuccess: (data: any, params: any) => {
//console.log('queryBatch', data, params);
// 设置fieldConfigList
setFieldConfigList(data.fieldConfigList);
// 设置fieldList
setFieldList(data.fieldList);
// 初始化下拉选择数据 处理
changeFieldConfig(data.fieldConfigList, data.fieldList);
},
},
);
// 调用接口获取报表字段更新回调函数
const setEditReportFieldsConfig = (data: any) => {
console.log('setEditReportFieldsConfig', data);
};
// 调用接口获取报表字段更新
const editReportFieldsConfig = request(
{
url: 'editReportFieldsConfig',
source: 'cbooking',
accountId: searchData.accountId,
list: fieldConfigList,
},
setEditReportFieldsConfig,
);
useEffect(() => {
queryManualReportFieldsConfig.run();
}, []);
// select 下拉列表触发事件,实现多级联动,即前面选中的项目后面不可以再选择
const fieldListChange = (value: string, priority: any) => {
// console.log(`selected ${value}`);
// 拷贝fieldConfigList到新数组
let newfieldConfigList: any = dealSelect(value, priority, fieldConfigList);
// 设置configList select后,值需要更新
setFieldConfigList(newfieldConfigList);
// 修改configList
changeFieldConfig(newfieldConfigList, fieldList, priority);
};
// 添加优先级
const addPriority = () => {
let newFieldConfigList: any = [...fieldConfigList];
let num: number = newFieldConfigList.length - 1;
if (newFieldConfigList.length >= 5) {
setIsVisible(false);
}
if (newFieldConfigList.length >= 6) {
return;
}
let newObj: any = { ...newFieldConfigList[num] };
newObj.priority += 1;
newObj.fieldName = '';
newFieldConfigList.push(newObj);
setFieldConfigList(newFieldConfigList);
// 联动,下拉选择列表的数据源
changeFieldConfig(newFieldConfigList, fieldList);
};
// 抽离select 组件,附上对应的数据源。
const SelectCom = (fieldName: any, priority: any) => {
const fieldListArr = fieldListObj[priority];
return (
<Select
value={fieldName}
onChange={(val) => fieldListChange(val, priority)}
className="selectComponent"
>
{fieldListArr?.map((item: any, index: number) => {
return (
<Option value={item.fieldName} key={`${item.fieldName}-${index}`}>
{item.fieldNameCn}
</Option>
);
})}
</Select>
);
};
// 删除 list
const deleteList = (index: number) => {
let newFieldConfigList: any = [...fieldConfigList];
// 删除操作
newFieldConfigList.splice(index, 1);
// 更新fieldConfigList
setFieldConfigList(newFieldConfigList);
// 展示添加优先级按钮
if (newFieldConfigList.length <= 5) {
setIsVisible(true);
}
};
return (
<Fragment>
<div className="warning">
<i style={iconStyle}>
<ExclamationCircleFilled />
</i>
至多添加6个优先级
</div>
{fieldConfigList.map((fieldConfigListItem: any, idx: number) => {
return (
<div className="fieldList" key={fieldConfigListItem.priority}>
<span className="priority">
第{fieldConfigListItem.priority}优先级
</span>
{SelectCom(
fieldConfigListItem.fieldName,
fieldConfigListItem.priority,
)}
{idx == fieldConfigList.length - 1 &&
fieldConfigList.length !== 1 ? (
<span className="delete" onClick={() => deleteList(idx)}>
删除
</span>
) : (
''
)}
</div>
);
})}
{visible ? (
<p className="addPriority" onClick={() => addPriority()}>
+添加优先级
</p>
) : (
''
)}
</Fragment>
);
});
export default SortPanel;
util.ts
export const dealConfig = (
fieldConfigList: any,
fieldList: any,
curPriority?: number,
curSelectObj?: any,
) => {
const selectObj: any = curSelectObj ? { ...curSelectObj } : {};
const fieldNameArr: any = [];
fieldConfigList.forEach((config: any) => {
let priority = config.priority;
// 把前面优先级的 选择项保存下来
if (priority == 1) {
selectObj[priority] = fieldList;
} else {
// on select change,比优先级低的selectList发生变化
if (!curPriority || (curPriority && priority > curPriority))
selectObj[priority] = addPriority(fieldNameArr, fieldList);
}
fieldNameArr.push(config.fieldName);
// 新增操作时
let len = fieldNameArr.length;
if (priority && priority == len && fieldNameArr[len - 1] == '') {
selectObj[priority] = addPriority(fieldNameArr, fieldList);
}
});
return selectObj;
};
// 过滤已选则的filedList
export const addPriority = (fieldNameArr: any, fieldList: any) => {
let newFieldList = [...fieldList];
newFieldList = newFieldList.filter((item: any, index: number) => {
return fieldNameArr.indexOf(item.fieldName) == -1;
});
return newFieldList;
};
export const dealSelect = (
fieldName: string,
priority: number,
fieldConfigList: any,
) => {
if (fieldConfigList && fieldConfigList.length == 0) return [];
let newfieldConfigList = [...fieldConfigList];
newfieldConfigList.forEach((item: any, index: number) => {
if (priority == item.priority) item.fieldName = fieldName;
});
// 若前面优先级选择了后面的fieldName,那么后面优先级的fieldName置为空
let len = newfieldConfigList.length;
for (let i = 0; i < len; i++) {
// 从左到右
for (let j = len - 1; j < len && j > i; j--) {
// 从右到左
if (newfieldConfigList[i].fieldName == newfieldConfigList[j].fieldName) {
// todo list 这里虽然fieldName置为空了,但是select上还有默认显示的原始值
newfieldConfigList[j].fieldName = '';
}
}
}
// console.log('newfieldConfigList', newfieldConfigList);
return newfieldConfigList;
};
index.less
.warning {
color: #4d5580;
font-family: 'PingFang SC';
font-size: 14px;
font-weight: normal;
height: 22px;
padding-bottom: 50px;
}
.fieldList {
margin-bottom: 20px;
.priority {
color: #1b234d;
font-family: 'PingFang SC';
font-size: 14px;
font-weight: 500;
height: 22px;
width: 70px;
}
.selectComponent {
background: #ffffff;
border-radius: 1px 1px 1px 1px;
border: 1px solid #ebebf5;
height: 32px;
width: 250px;
margin-left: 14px;
}
.delete {
color: #3d6af2;
font-family: 'PingFang SC';
font-size: 12px;
font-weight: normal;
height: 20px;
letter-spacing: px;
width: 24px;
cursor: pointer;
padding-left: 8px;
}
}
.addPriority {
color: #3d6af2;
font-family: 'PingFang SC';
font-size: 12px;
font-weight: normal;
height: 20px;
margin: 25px 0 26px 0;
cursor: pointer;
}
数据模拟:
let queryManualReportFieldsConfig = {
ResponseStatus: {
Timestamp: '/Date(1623831946825+0800)/',
Ack: 'Success',
Errors: [],
Extension: [],
},
responseCode: 20000,
responseDesc: 'Success',
fieldConfigList: [
{
accountId: 3558,
department: 'flight',
priority: 1,
fieldName: 'PassengerName',
},
{
accountId: 3558,
department: 'flight',
priority: 2,
fieldName: 'OrderID',
},
{
accountId: 3558,
department: 'flight',
priority: 3,
fieldName: 'Sequence',
},
],
fieldList: [
{
fieldName: 'OrderID',
fieldNameCn: '订单号',
},
{
fieldName: 'PassengerName',
fieldNameCn: '乘机人',
},
{
fieldName: 'Sequence',
fieldNameCn: '航段号',
},
{
fieldName: 'Dept1',
fieldNameCn: '部门1',
},
{
fieldName: 'Dept2',
fieldNameCn: '部门2',
},
{
fieldName: 'Dept3',
fieldNameCn: '部门3',
},
{
fieldName: 'Dept4',
fieldNameCn: '部门4',
},
{
fieldName: 'Dept5',
fieldNameCn: '部门5',
},
{
fieldName: 'Dept6',
fieldNameCn: '部门6',
},
{
fieldName: 'CostCenter',
fieldNameCn: '成本中心1',
},
{
fieldName: 'CostCenter2',
fieldNameCn: '成本中心2',
},
{
fieldName: 'CostCenter3',
fieldNameCn: '成本中心3',
},
{
fieldName: 'CostCenter4',
fieldNameCn: '成本中心4',
},
{
fieldName: 'CostCenter5',
fieldNameCn: '成本中心5',
},
{
fieldName: 'CostCenter6',
fieldNameCn: '成本中心6',
},
],
};
export default {
'GET /Front/Cbooking/API/Cbooking/queryManualReportFieldsConfig': queryManualReportFieldsConfig,
};