目录
- 背景
- 实现
- 日历组件
- 父组件
- 数据
- 效果
- 最后
背景
项目中需要实现一个日历组件,并且需要展示月,日所对应的数据(因为项目需求问题,就不统计年数据总量)。网上找了一堆,基本都不大符合项目需求,且改动麻烦(方便以后项目新需求改动),另外很少做这种需求,所以好奇心下,决定自己单独写一个组件。
实现
日历组件
import { useEffect, useState } from 'react';
import {LeftOutlined,RightOutlined,DoubleLeftOutlined,DoubleRightOutlined,CalendarOutlined,} from '@ant-design/icons';
import './index.less';
const weekData = ['一', '二', '三', '四', '五', '六', '日'];
const CustomDatePickerModalPage = (props: any) => {
const { title, dataSource, onChange } = props;
// 公共获取当前日期
const publicGetCurrentDateFn = () => {
const date = new Date();
const Y = date.getFullYear();
const M = date.getMonth() + 1;
const D = date.getDate();
return {
Y,
M,
D,
};
};
// 获取年基础年份
const publicGetBaseYear = (YEAR: number) => {
const yearToStr = YEAR.toString();
const prefixYearToStr = yearToStr.slice(0, -1);
return Number(prefixYearToStr + '0');
};
const [datePickerState, setDatePickerState] = useState<string>('day');
// 展示年
const [yearArry, setYearArry] = useState<any[]>([]);
const [baseYear, setBaseYear] = useState<number>(() => {
const { Y } = publicGetCurrentDateFn();
return publicGetBaseYear(Y);
});
// 展示月
const [monthArry, setMonthArry] = useState<any[]>([]);
const [baseMonth, setBaseMonth] = useState<number>(() => {
const { M } = publicGetCurrentDateFn();
return M;
});
// 展示当前月,上个月末尾及下个月开头日期
const [monthDay, setMonthDay] = useState<any[]>([]);
// 设置当前年
const [currentYear, setCurrentYear] = useState<number>(() => {
const { Y } = publicGetCurrentDateFn();
return Y;
});
// 设置当前月份
const [currentMonth, setCurrentMonth] = useState<number>(() => {
const { M } = publicGetCurrentDateFn();
return M;
});
// 设置当前时间
const [currentDay, setCurrentDay] = useState<number>(() => {
const { D } = publicGetCurrentDateFn();
return D;
});
// 公共获取时间
const publicGetDateFn = (TYPE: string = 'day',YEAR: number,MONTH: number): any => {
const monthDayCount = 42;
let prefixMonthDay: number[] = [];
let currentMonthDay: number[] = [];
let suffixMonthDay: number[] = [];
prefixMonthDay.length = 0;
currentMonthDay.length = 0;
suffixMonthDay.length = 0;
switch (TYPE) {
case 'year':
// 根据基准年计算10年间年度区间
const initYearNum: number = publicGetBaseYear(YEAR);
const prefixYearNum: number = initYearNum - 1;
const currentYearNum: number[] = [];
for (let i = 0; i < 10; i++) {
currentYearNum.push(initYearNum + i);
}
const LastCurrentYearNum: number =
currentYearNum[currentYearNum.length - 1] + 1;
const computedAllYear: number[] = [
prefixYearNum,
...currentYearNum,
LastCurrentYearNum,
];
return computedAllYear;
case 'month':
// 一年固定12个月
const monthArry: { month: number; year: number }[] = [];
for (let i = 0; i < 12; i++) {
monthArry.push({ month: i + 1, year: YEAR });
}
return monthArry;
case 'day':
const step: Date = new Date(YEAR, MONTH, 0);
const monthDayLen: number = step.getDate();
const monthOneToWeek: number = new Date(`${YEAR}-${MONTH}-1`).getDay();
if (monthOneToWeek === 1) {
// 星期一
// 当前月份天数
for (let i = 0; i < monthDayLen; i++) {
currentMonthDay.push(i + 1);
}
// 下个月天数
for (let i = 0; i < monthDayCount - monthDayLen; i++) {
suffixMonthDay.push(i + 1);
}
} else {
// 星期二到星期日
// 获取上个月的总天数
const step = new Date(YEAR, MONTH - 1, 0);
const prefixMonthDayLen = step.getDate();
// 上个月展示天数
const prefixNum = monthOneToWeek === 0 ? 6 : monthOneToWeek - 1;
const prefixDayNum = prefixMonthDayLen - prefixNum;
for (let i = prefixDayNum; i < prefixMonthDayLen; i++) {
prefixMonthDay.push(i + 1);
}
// 当前月份展示天数
for (let i = 0; i < monthDayLen; i++) {
currentMonthDay.push(i + 1);
}
// 下个月展示天数
for (let i = 0; i < monthDayCount - monthDayLen - prefixNum; i++) {
suffixMonthDay.push(i + 1);
}
}
const formatPrefixMonthDay: {
type: string;
day: number;
month: number;
year: number;
}[] = [];
const formatCurrentMonthDay: {
type: string;
day: number;
month: number;
year: number;
}[] = [];
const formatSuffixMonthDay: {
type: string;
day: number;
month: number;
year: number;
}[] = [];
prefixMonthDay?.length > 0 &&
prefixMonthDay.forEach((item: number) =>
formatPrefixMonthDay.push({
type: 'up',
day: item,
month: MONTH,
year: YEAR,
}),
);
currentMonthDay?.length > 0 &&
currentMonthDay.forEach((item: number) =>
formatCurrentMonthDay.push({
type: 'current',
day: item,
month: MONTH,
year: YEAR,
}),
);
suffixMonthDay?.length > 0 &&
suffixMonthDay.forEach((item: number) =>
formatSuffixMonthDay.push({
type: 'lower',
day: item,
month: MONTH,
year: YEAR,
}),
);
const computedAllMonthDay: {
type: string;
day: number;
month: number;
year: number;
}[] = [
...formatPrefixMonthDay,
...formatCurrentMonthDay,
...formatSuffixMonthDay,
];
return computedAllMonthDay;
}
};
// 展示年份
const handleYearFn = (
type: string,
value: number = publicGetCurrentDateFn()['Y'],
) => {
if (type === '1') {
setDatePickerState('year');
if (currentYear === baseYear) {
const data = publicGetDateFn('year', baseYear, currentMonth);
setYearArry(data);
} else {
const data = publicGetDateFn('year', baseYear, currentMonth);
setYearArry(data);
}
}
if (type === '2') {
setDatePickerState('month');
setCurrentYear(value);
const data = publicGetDateFn('month', value, currentMonth);
setMonthArry(data);
onChange('month', `${value}`);
}
};
// 展示月份, 1:点击头,2:点击每一月
const handleMonthFn = (type: string, value: number = 0) => {
if (type === '1') {
setDatePickerState('month');
const data = publicGetDateFn('month', currentYear, value);
setMonthArry(data);
onChange('month', `${currentYear}`);
}
if (type === '2') {
setDatePickerState('day');
setCurrentMonth(value);
const data = publicGetDateFn('day', currentYear, value);
setMonthDay(data);
onChange('day', `${currentYear}-${value}`);
}
};
// 展示每天
const handleDateFn = (value: number) => {
setDatePickerState('day');
// const data = publicGetDateFn('day', ,value);
};
// 左右 icon 图标年份切换
const publicGetYearToDateFn = (TYPE: string) => {
if (TYPE === 'UP') {
if (datePickerState === 'year') {
const computedBaseYear = publicGetBaseYear(baseYear - 1);
setBaseYear(computedBaseYear);
const data = publicGetDateFn('year', computedBaseYear, currentMonth);
setYearArry(data);
} else {
const computedCurrentYear = currentYear - 1;
setCurrentYear(computedCurrentYear);
if (datePickerState === 'day') {
const data = publicGetDateFn(
'day',
computedCurrentYear,
currentMonth,
);
setMonthDay(data);
onChange('day', `${computedCurrentYear}-${currentMonth}`);
} else {
onChange('month', `${computedCurrentYear}`);
}
}
}
if (TYPE === 'LOWER') {
if (datePickerState === 'year') {
const computedBaseYear = publicGetBaseYear(baseYear + 10);
setBaseYear(computedBaseYear);
const data = publicGetDateFn('year', computedBaseYear, currentMonth);
setYearArry(data);
} else {
const computedCurrentYear = currentYear + 1;
setCurrentYear(computedCurrentYear);
if (datePickerState === 'day') {
const data = publicGetDateFn(
'day',
computedCurrentYear,
currentMonth,
);
setMonthDay(data);
onChange('day', `${computedCurrentYear}-${currentMonth}`);
} else {
onChange('month', `${computedCurrentYear}`);
}
}
}
};
// 左右 icon 图标月份切换
const publicGetMonthToDateFn = (TYPE: string) => {
let computedCurrentMonth = currentMonth;
if (TYPE === 'UP') {
if (currentMonth - 1 > 0) {
computedCurrentMonth = currentMonth - 1;
}
}
if (TYPE === 'LOWER') {
if (currentMonth + 1 <= 12) {
computedCurrentMonth = currentMonth + 1;
}
}
setCurrentMonth(computedCurrentMonth);
const data = publicGetDateFn('day', currentYear, computedCurrentMonth);
setMonthDay(data);
onChange('day', `${currentYear}-${computedCurrentMonth}`);
};
useEffect(() => {
const { Y, M, D } = publicGetCurrentDateFn();
setBaseYear(publicGetBaseYear(Y));
setBaseMonth(M);
setCurrentYear(Y);
setCurrentMonth(M);
setCurrentDay(D);
const data = publicGetDateFn('day', Y, M);
console.log('初始化时间:', data);
setMonthDay(data);
}, []);
// 设置系统当前天高亮
const getCurrentDayMaskFn = ({ type, day, month, year }: any) => {
const { Y, M, D } = publicGetCurrentDateFn();
if (type === 'current' && day === D && month === M && year === Y)
return 'tbody-td-active';
else return '';
};
// 设置系统当前月高亮
const getCurrentMonthMaskFn = ({
month,
year,
}: {
month: number;
year: number;
}) => {
const { Y, M } = publicGetCurrentDateFn();
if (year === Y && month === M) return 'tbody-td-active';
else return '';
};
// 设置系统当前年高亮
const getCurrentYearMaskFn = (year: number) => {
const { Y, M } = publicGetCurrentDateFn();
if (year === Y) return 'tbody-td-active';
else return '';
};
// 获取当前时间,主要用来获取对应日期数据
const getCurrentDateFn = (value: number): number => {
switch (datePickerState) {
// case 'day':
// return Number(`${currentYear}${currentMonth < 10 ? `0${currentMonth}` : currentMonth}${value < 10 ? `0${value}` : value}`);
case 'month':
return Number(`${currentYear}${value < 10 ? `0${value}` : value}`);
case 'year':
return Number(`${value}`);
default:
return Number(
`${currentYear}${
currentMonth < 10 ? `0${currentMonth}` : currentMonth
}${value < 10 ? `0${value}` : value}`,
);
}
};
return (
<>
{/* <CalendarOutlined /> */}
<div className="customDatePickerWrp">
<div className="header-Wrp">
<div className="header-title">{title}</div>
<ul className="header-operate-wrp">
<li key={0} onClick={() => publicGetYearToDateFn('UP')}>
<DoubleLeftOutlined />
</li>
{datePickerState === 'day' && (
<li key={1} onClick={() => publicGetMonthToDateFn('UP')}>
<LeftOutlined />
</li>
)}
<li key={2} className="yearMonthWrp">
{datePickerState === 'year' && (
<div onClick={() => handleYearFn('1')}>
{baseYear} - {baseYear + 9}
</div>
)}
{datePickerState !== 'year' && (
<div onClick={() => handleYearFn('1')}>{currentYear}年</div>
)}
{datePickerState === 'day' && (
<div onClick={() => handleMonthFn('1')}>{currentMonth}月</div>
)}
</li>
{datePickerState === 'day' && (
<li key={3} onClick={() => publicGetMonthToDateFn('LOWER')}>
<RightOutlined />
</li>
)}
<li key={4} onClick={() => publicGetYearToDateFn('LOWER')}>
<DoubleRightOutlined />
</li>
</ul>
</div>
<div className="content-Wrp">
{
// 展示日期
datePickerState === 'day' && (
<>
<ul className="table-thead-wrp">
{weekData.map((item: string, index: number) => (
<li className="table-td" key={index}>
{item}
</li>
))}
</ul>
<ul className="table-tbody-wrp">
{monthDay.map((item, index: number) => {
return (
<li
key={index}
className={`tbody-td ${
item['type'] !== 'current'
? 'tbody-otherMonthDay-td'
: ''
} ${getCurrentDayMaskFn(item)}`}
>
<div>{item['day']}</div>
<div>{dataSource[getCurrentDateFn(item['day'])]}</div>
</li>
);
})}
</ul>
</>
)
}
{
// 展示月份
datePickerState === 'month' && (
<ul className="table-tbody-month-wrp">
{monthArry?.length > 0 &&
monthArry.map((item, index: number) => {
return (
<li
key={index}
className={`tbody-month-td ${getCurrentMonthMaskFn(
item,
)}`}
onClick={() => handleMonthFn('2', item['month'])}
>
<div>{item['month']}月</div>
<div>{dataSource[getCurrentDateFn(item['month'])]}</div>
</li>
);
})}
</ul>
)
}
{
// 展示年份
datePickerState === 'year' && (
<ul className="table-tbody-year-wrp">
{yearArry?.length > 0 &&
yearArry.map((item, index: number) => {
return (
<li
key={index}
className={`tbody-year-td ${getCurrentYearMaskFn(
item,
)}`}
onClick={() => handleYearFn('2', item)}
>
<div>{item}年</div>
<div>{dataSource[getCurrentDateFn(item)]}</div>
</li>
);
})}
</ul>
)
}
</div>
</div>
</>
);
};
export default CustomDatePickerModalPage;
父组件
const parentModalPage = () => {
// 请查看月/日数据
const customDatePickerData = {
"202301": 286687680,
"202302": 55312480,
"202303": 61211920,
"202304": 59266360,
"202305": 61211920,
"202306": 59245440,
"202307": 61211920,
"202308": 206082920,
"202309": 812388661.2,
"202310": 778804150,
"202311": 487160,
"202312": 43771360
};
return (
<div style={{ width: '100%', height: '100%', padding: '0 20px 20px 20px' }}>
<CustomDatePicker title="历史用能日历" dataSource={customDatePickerData} onChange={(type: string, value: string) => {
console.log('历史用能日历::', type, value, typeof value, customDatePickerData);
// 调用接口获取数据
getEnergyUsageStatsFn(true, {
granularity: type,
startDate: publicGetCurrentDateFn(type, value.toString())['startDate'],
endDate: publicGetCurrentDateFn(type, value.toString())['endDate'],
});
}} />
</div>
)
};
数据
-
月数据
// 返回数据格式-月份数据 const customDatePickerData = { "202301": 286687680, "202302": 55312480, "202303": 61211920, "202304": 59266360, "202305": 61211920, "202306": 59245440, "202307": 61211920, "202308": 206082920, "202309": 812388661.2, "202310": 778804150, "202311": 487160, "202312": 43771360 };
-
日数据
const customDatePickerData = { "20231001": 5920360, "20231002": 5920360, "20231003": 5920360, "20231004": 5941280, "20231005": 5920360, "20231006": 5920360, "20231007": 5920360, "20231008": 5941280, "20231009": 0, "20231010": 203030378.2, "20231011": 5920360, "20231012": 32453714, "20231013": 35985720, "20231014": 29342320, "20231015": 49822720, "20231016": 23248120, "20231017": 37049520, "20231018": 477835490.2, "20231019": 740848323.8, "20231020": 168360, "20231021": 159280, "20231022": 169960, "20231023": 14413760, "20231024": 14705280, "20231025": 287880, "20231026": 30342680, "20231027": 8178880, "20231028": 422400, "20231029": 28487040, "20231030": 9168480, "20231031": 29014320 }
效果
-
月度数据
-
年度数据
-
年统计:
注意:目前年度总数据暂未统计展示,不过可以根据自己的需求进行修改。
最后
将上面的组件引入应该是开箱即用,如果有问题请评论区多多留言。
如果对大家有所帮助,请咚咚大家的【发财黄金手指:】 点赞
,收藏
。