需求: 开发一个类似的框选表格去排班的功能
备注: 因为是帮助别人评估的,之前没接触过类似的功能,所以只做了简易的前端功能,暂未涉及后端
重点: 表格 框选 排班(类似excel选中多个表格)、日历的查询
分析: 初始以为日历的查询有封装好的库百度了一下发现还是得通过new Date()去实现、表格的框选一开始是想着通过坐标的方式去范围覆盖,但是实施起来比较困难,百度了也没有啥示例,有一个示例也是通过坐标的,代码比较复杂,不易理解
思路: 类似坐标,通过数组的方式来确定选中的范围
例如 选择的坐标是:1-17,4-18,则选中的内容就是第一行的17、18列到第四行的17、18列
效果:
补充微调了表格样式
import React, { useState, useEffect } from 'react';
import { DatePicker } from 'antd';
import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';
dayjs.extend(customParseFormat);
const monthFormat = 'YYYY-MM';
export default function CuxTable() {
const [startCellId, setStartCellId] = useState('');
const [endCellId, setEndCellId] = useState('');
const [dateMonth, setDateMonth] = useState('2024-03');
const [daysList, setDaysList] = useState([]);
// 根据起始和结束的坐标来处理数据
const handleCellData = () => {
// 按照坐标思维
// 鼠标摁下的单元格的行列
const startRow = +startCellId.split('-')[0];
const startCol = +startCellId.split('-')[1];
// 鼠标松开的单元格的行列
const endRow = +endCellId.split('-')[0];
const endCol = +endCellId.split('-')[1];
// 选中单元格id
const selectedCellList = [];
// 双重遍历
// 行遍历
for (let i = startRow; i <= endRow; i++) {
for (let j = startCol; j <= endCol; j++) {
selectedCellList.push(`${i}-${j}`)
}
}
const alertTextList = [];
selectedCellList.forEach(item => {
document.getElementById(item).style.backgroundColor = 'red'
// 这里可以对选中的数据进行赋值之类的
// document.getElementById(item).innerHTML = '1';
alertTextList.push(document.getElementById(item).outerText)
})
setTimeout(() => {
alert(`选择的日期: ${alertTextList}`)
}, 100);
setStartCellId('')
setEndCellId('')
}
const setFun = () => {
// 获取你想要添加鼠标按下事件的元素
const elements = document.getElementsByTagName('td');
// 定义鼠标按下事件的处理函数
function handleMousedown(event) {
// 这里可以添加你想要执行的代码
setStartCellId(event.target.id)
}
// 定义鼠标松开事件的处理函数
function handleMouseup(event) {
// 这里可以添加你想要执行的代码
setEndCellId(event.target.id)
}
// 为元素添加鼠标按下事件的监听器
Array.from(elements).forEach(item => {
item.style.userSelect = 'none';
item.addEventListener('mousedown', handleMousedown);
item.addEventListener('mouseup', handleMouseup);
})
}
const getDaysInMonthWithWeekdays = (year, month) => {
const daysInMonth = new Date(year, month, 0).getDate(); // 获取该月有多少天
const weekdays = []; // 用于存储每一天的数组
for (let day = 1; day <= daysInMonth; day++) {
const date = new Date(year, month, day);
const weekday = date.getDay(); // 获取是星期几,返回0(代表星期日)到6(代表星期六)
weekdays.push({ date: day, weekday: weekday });
}
return weekdays;
}
const onChange = (date, dateString) => {
// console.log(date, dateString);
let year = dateString.split('-')[0]
let month = dateString.split('-')[1]
const monthDaysWithWeekdays = getDaysInMonthWithWeekdays(year, month);
const dayWithWeekdayList = [];
monthDaysWithWeekdays.forEach(day => {
const dayOfWeek = ['日', '一', '二', '三', '四', '五', '六'][day.weekday];
const dayWithWeekday = `${day.date}-${dayOfWeek}`;
dayWithWeekdayList.push(dayWithWeekday)
console.log(`${day.date} is a ${dayOfWeek}`);
});
setDaysList(dayWithWeekdayList);
};
useEffect(() => {
setTimeout(() => {
setFun();
}, 1000);
}, []);
useEffect(() => {
if (startCellId && endCellId) {
handleCellData();
}
onChange('', dateMonth);
}, [startCellId, endCellId])
const renderDayTh = () => {
const dayTh = [];
const name = <th style={{ borderBottom: 'none' }} rowSpan={2}>姓名</th>;
dayTh.push(name);
if (daysList.length) {
daysList.forEach(item => {
dayTh.push(<th style={{ borderBottom: 'none' }}>{item.split('-')[0]}</th>)
})
}
return dayTh
}
const renderWeekTh = () => {
const weekTh = [];
if (daysList.length) {
daysList.forEach(item => {
weekTh.push(<th style={{ borderTop: 'none' }}>{item.split('-')[1]}</th>)
})
}
return weekTh;
}
// 人员的姓名
const userList = ['白一', '紫二', '金三', '黄四', '赤五'];
const renderTd = (item, index) => {
const tdList = [];
const name = <td>{item}</td>;
tdList.push(name);
if (daysList.length) {
daysList.forEach((day, dayIndex) => {
tdList.push(<td id={`${index + 1}-${dayIndex + 1}`} >{`${index + 1}-${dayIndex + 1}`}</td>)
})
}
return tdList;
}
const renderTbody = () => {
const tbodyList = [];
userList.forEach((item, index) => {
// const nameList = [];
const tdList = renderTd(item, index);
const nametbody = <tr>
{
tdList
}
</tr>;
tbodyList.push(nametbody);
})
return tbodyList;
}
console.log(123, startCellId, endCellId);
return (
<div style={{ margin: 10 }}>
<DatePicker defaultValue={dayjs(dateMonth, monthFormat)} format={monthFormat} onChange={onChange} picker="month" />
<table width="100%" border="1" cellspacing="0" cellpadding="4" style={{ marginTop: '10px' }} align="center">
<tr >
{daysList.length > 0 && renderDayTh()}
</tr>
<tr >
{daysList.length > 0 && renderWeekTh()}
</tr>
{daysList.length > 0 && renderTbody()}
</table>
</div>
);
}