灵感相当于自己对每个日历格进行了样式个性化设置,所以自由度挺高的。
效果图中圈中的地方都是可自定义的
效果图
相关代码
1. 引入相关资源,还需要再建个index.less
import { Calendar, Badge, Typography, Tooltip } from 'antd';
import { createStyles } from 'antd-style';
import classNames from 'classnames';
import type { CalendarProps } from 'antd';
import { ProFormDatePicker, ProForm } from "@ant-design/pro-components";
import moment from 'moment';
import React, { useRef, useState } from 'react';
import './index.less'; // !!!这个是需要的
// 日历格的个性化操作,几乎都在这里研发 这个在组件外
const useStyle = createStyles(({ token, css }) => {
return {
wrapper: css`
width: 450px;
border: 1px solid ${token.colorBorderSecondary};
border-radius: 0px;
padding: 5px;
`,
dateCell: css`
margin-top: 6px;
box-sizing: border-box;
position: relative;
height: 100%;
width:96%;
margin-left: 2%;
text-align: right;
padding:0 6px 6px 6px;
overflow: hidden;
border-top: 2px solid #f0f0f0;
&:before {
content: '';
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
width:100%;
height: 100%;
background: transparent;
transition: background 300ms;
border-radius: ${token.borderRadiusOuter}px;
border: 1px solid transparent;
box-sizing: border-box;
}
&:hover:before {
background: rgba(0, 0, 0, 0.04);
}
`,
dateWeekCell: css`
margin-top: 6px;
box-sizing: border-box;
position: relative;
height: 100%;
width:96%;
margin-left: 2%;
text-align: right;
padding:0 6px 6px 6px;
overflow: hidden;
border-top: 2px solid #f0f0f0;
&:before {
content: '';
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
width:100%;
height: 100%;
background: rgba(251, 194, 28,.1);
transition: background 300ms;
border-radius: ${token.borderRadiusOuter}px;
border: 1px solid transparent;
box-sizing: border-box;
}
&:hover:before {
background: rgba(0, 0, 0, 0.04);
}
`,
today: css`
border-top: 2px solid #0079fe;
&:before {
background: transparent;
}
&:hover:before {
background: rgba(0, 0, 0, 0.04);
}
`,
text: css`
position: relative;
z-index: 1;
`,
current: css`
color: ${token.colorPrimary};
height: 100%;
width:96%;
margin-left: 2%;
border-top: 2px solid #d5e6f0;
&:before {
background: ${token.colorPrimary};
opacity: 0.1;
}
&:hover:before {
background: ${token.colorPrimary};
opacity: 0.1;
}
`,
plan: css`
border: 2px solid ${token.colorError};
`,
title: css`
font-size: 16px;
position: absolute;
z-index: 5;
top:-5px;
right:5px;
height: 20px;
`,
bigTitle: css`
font-size: 20px;
position: absolute;
width:100%;
text-align: center;
z-index: 5;
min-height: 100px;
height: calc(15vh - 20px - 8px);
display: grid;
place-items: center;
`,
weekend: css`
&.gray {
opacity: 0.4;
}
`,
};
});
2. index.less相关代码
.my-calendar .ant-picker-calendar .ant-picker-content td{
min-height: 150px;
height: 15vh;
padding: 0;
box-sizing: border-box;
}
.my-calendar .ant-picker-calendar .ant-picker-cell::before{
width: 100%;
height: 100%;
padding: 0;
}
.my-calendar .calendar-date{
position: absolute;
top: 20px;
overflow: auto;
width: 100%;
min-height: 80px;
height: calc(15vh - 20px - 8px);
text-align: left;
padding-bottom: 10px;
color: #000;
}
3. 相关个性化日历操作代码
1const { styles } = useStyle({ test: true });
const [selectDate, setSelectDate] = useState(moment());
const [calendardata, setCalendarData] = useState<API.LogWindTurbineData | null>(null);
//查询或首次触发的请求当月的日时间数据的函数
const onFinish = async () => {
try {
const values = await formRef.current?.validateFieldsReturnFormatValue?.();
// 一般传月份
const res = await handelList(values); // 自己的请求接口
if (res.data) {
setCalendarData(data)
// data数据格式 {'2023-12-23':[{},{}],2023-12-24':[{},{}]}
} else {
setCalendarData(null)
}
} catch (err) {
console.log('err', err)
}
}
// 事件相关的展示
const dateCellRender = (value: any) => {
const date = value.format('YYYY-MM-DD') + '';
const listData = calendardata ? calendardata[date] ? calendardata[date] : [] : [];
const hasData = listData.length > 0
// warning success error
if (hasData) {
return <Tooltip title={`${date}`}>
<ul className="calendar-date">
{listData.map((item, index) => (
<li key={item.content + index}>
<Badge status="warning" text={item.content} />
</li>
))}
</ul>
</Tooltip>
}
};
// 日历格相关的,所有样式在这里处理
const cellRender: CalendarProps<any>['fullCellRender'] = (date, info) => {
const isWeekend = date.day() === 6 || date.day() === 0;
// 判断这天是否有数据
const hasData = (vdate: any) => {
const fdate = vdate.format('YYYY-MM-DD') + '';
const listData = calendardata ? calendardata[fdate] ? calendardata[fdate] : [] : [];
return listData.length > 0
}
if (info.type === 'date') {
return React.cloneElement(info.originNode, {
...info.originNode.props,
className: classNames(isWeekend ? styles.dateWeekCell : styles.dateCell, {
[styles.current]: selectDate.isSame(date, 'date'),
[styles.today]: date.isSame(moment(), 'date'),
}),
children: (
<div className={styles.text}>
<div
className={classNames({
[styles.weekend]: isWeekend,
[styles.title]: hasData(date),
[styles.bigTitle]: !hasData(date)
})}
>
{date.get('date')}
</div>
{info.type === 'date' && dateCellRender(date)}
</div>
),
});
}
return info.originNode;
};
const disabledDate = (current: any) => {
return current && current > new Date(new Date().getTime());
};
const onPanelChange = (value: any) => {
// 这里是换页时,请求操作,因为我自定义了自定义日历头部内容。
const date = value.format('YYYY-MM') + '';
formRef.current?.setFieldsValue({ 'yearMonth': date });
onFinish()
}
// 点击单个日历格时的操作,会对当前点击日历格的样式发生变化
const onSelectCalendar = (value: any, selectInfo: any) => {
if (selectInfo.source === 'date') {
setSelectDate(value);
}
}
4. 组件使用
return (
<div className='my-calendar'>
<Calendar style={{ padding: '0 20px' }}
fullCellRender={cellRender}
fullscreen={false}
onSelect={onSelectCalendar}
onPanelChange={onPanelChange} disabledDate={disabledDate}
headerRender={({ value, onChange }) => {
return (
<div style={{ padding: 15, display: 'flex', justifyContent: 'spacebetween'}}>
<ProForm submitter={false} autoFocusFirstInput={false} layout='horizontal' formRef={formRef} style={{ display: 'flex' }}>
<ProFormDatePicker.Month
name="yearMonth"
label="月份:"
allowClear={false}
fieldProps={{
format: (value) => value.format('YYYY-MM'),
disabledDate: disabledDate,
onChange: (value) => {
onChange(value)
onFinish()
}
}}
initialValue={value.format('YYYY-MM')}
rules={[
{
required: true,
message: '请选择时间!',
},
]}
/>
</ProForm>
</div>
);
}}
/>
</div>
)