fullcalendar日历插件实现工作记录表格
1. 看下效果图
- 表头为2栏,分为计划、记录;
- 左侧栏是一天中具体时间点,具体到分钟;
- 按钮栏分为日周月,三种视图切换:
- 顶部、左侧固定,都支持滑动滚动条
- 文本超出,加入鼠标悬浮效果。
2. 用到插件
日历插件fullcalendar :使用v6版本:https://fullcalendar.io/docs/initialize-globals
官方文档:https://fullcalendar.io/
鼠标悬浮插件:Tippy.js
官方文档:https://tippyjs.bootcss.com/getting-started/
3. 实现步骤
(1)实现表头
(2)事件数据套入字段
(3)我的需求是事件有不同状态,对应不同颜色(背景色/文字颜色/边框等)
(4)最后加入鼠标悬浮功能
4. 具体代码:
使用的js、jq原生写法(...jsp项目)
(1)引入
<%-- 公共鼠标悬浮样式文件--%>
<link rel="stylesheet" href="${ctxStatic}/customTippy/customtippy.css">
<%-- 公共日历插件样式文件--%>
<link rel="stylesheet" href="${ctxStatic}/fullcalendar/customCalendar.css">
// 官方下载的源码包 放在本地文件夹的
<script src="${ctxStatic}/fullcalendar/index.global.js" type="text/javascript"></script>
// 下面2个是鼠标悬浮用到 <script src="https://unpkg.com/popper.js@1"></script> <script src="https://unpkg.com/tippy.js@5"></script>
(2)html部分
<div class="tabbable"> <div id="calendar"></div> </div>
(3)js部分
<script> // 文字颜色 var colorMap = { 1:'#234299', 2:'#a05eb5', 3:'#226f56', 98:'#ed9235', 100:'#9b9646' // 计划 } // 背景颜色 var colorBgMap = { 1:'#ecf4ff', 2:'#fceefe', 3:'#e2f7f2', 98:'#ffefdf', 100:'#fefdea' // 计划 } // 对应类名 var colorMapClass = { 1:'planDColor1', 2:'planDColor2', 3:'planDColor3', 98:'planDColor98', 100:'planDColor100' // 计划 } document.addEventListener("DOMContentLoaded", function () { var calendarEl = document.getElementById("calendar"); var calendar = new FullCalendar.Calendar(calendarEl, { locale: "zh-cn", // 使用中文语言包 timeZone: "Asia/Shanghai", initialDate: "${initYTD}", // 设置初始显示的日期 initialView: "resourceTimeGridDay", // resourceTimeGridDay日期表格 allDaySlot: false, // 禁用 all-day 行 headerToolbar: { // 自定义工具栏 left:'', center: "title,prev,next", right: "today,resourceTimeGridDay,resourceTimeGridFourDay,dayGridMonth", }, firstDay: 1, datesAboveResources: true, views: { resourceTimeGridFourDay: { type: 'resourceTimeGrid', duration: { days: 7 }, buttonText: '周' } }, buttonText: { // 自定义按钮文本 today: "今天", month: "月", week: "周", day: "日", }, slotLabelFormat: { // 格式化Y轴时间为24小时制 hour: "2-digit", minute: "2-digit", hour12: false, // 24小时制 }, eventTimeFormat: { // 格式化节点时间为24小时制 hour: "2-digit", minute: "2-digit", hour12: false, // 24小时制 }, slotMinTime: "09:00:00", // 最小时间 slotMaxTime: "24:00:00", // 最大时间 resources: [ { id: "${tPerform.userId}", title: "计划", }, { id: "${tPerform.userId}perform", title: "工作记录", }, ], // 日期网格数据 events: function (fetchInfo, successCallback, failureCallback) { $.ajax({ url: "${ctx}/perform/tPerform/showPerformData", type: "GET", data: { id: "${tPerform.id}", userId: "${tPerform.userId}", // 传递当前视图的起始和结束日期 startTime: fetchInfo.startStr, endTime: fetchInfo.endStr, }, success: function (data) { // 将获取到的事件数据传递给日历 重构插件所需的字段 data.data?.map((v)=>{ if(v.type==='perform'){ v.resourceId = v.resourceId+'perform' v.title = '【工作记录】'+v.title // 100 值对应工作计划 v.className=colorMapClass[Number(v.approvalState||100)] }else{ v.title = '【计划】'+v.title v.className= colorMapClass[Number(v.approvalState||100)] } v.backgroundColor= colorBgMap[Number(v.approvalState||100)] }) successCallback(data.data); }, error: function () { // 如果发生错误,调用 failureCallback failureCallback(); }, }); }, // 这里是鼠标悬浮 eventDidMount: function (info) { tippy(info.el, { placement: "bottom", theme: "custom", content: info.event.extendedProps.contents , }); }, }); calendar.render(); }); </script>
(4)css部分
<style> .fc .fc-col-header-cell-cushion, .fc .fc-daygrid-day-number { color: black; } /*日-周-视图*/ .fc-timegrid-event-harness { .planDColor1, .planDColor2, .planDColor3, .planDColor98, .planDColor100 { border: none; line-height: 22px; font-size: 12px; border-radius: 0; } .recordDColor1, .recordDColor2, .recordDColor3, .recordDColor98, .recordDColor100 { border: none; line-height: 22px; font-size: 12px; border-radius: 0; } } .planDColor1, .recordDColor1 { .fc-event-main { color: #234299 !important; border-top: 2px solid #234299; } a { color: #234299 !important; } } .planDColor2, .recordDColor2 { .fc-event-main { color: #a05eb5 !important; border-top: 2px solid #a05eb5; } a { color: #a05eb5 !important; } } .planDColor3, .recordDColor3 { .fc-event-main { border-top: 2px solid #226f56; color: #226f56 !important; } a { color: #226f56 !important; } } .planDColor98, .recordDColor98 { .fc-event-main { border-top: 2px solid #ed9235; color: #ed9235 !important; } a { color: #ed9235 !important; } } .planDColor100, .recordDColor100 { .fc-event-main { border-top: 2px solid #9b9646; color: #9b9646 !important; } a { color: #9b9646 !important; } } /*月视图*/ .fc-daygrid-event-harness { .fc-daygrid-dot-event .fc-event-title{ font-weight: 400; } .planCssDayWeek { border: none; border-top: 2px solid transparent; line-height: 22px; font-size: 12px; border-radius: 0; } /*月份 小圆点颜色*/ .planCssDayWeek .fc-daygrid-event-dot { /*border-color:#00a8dd !important;*/ } .recordCssDayWeek { border: none; border-top: 2px solid transparent; line-height: 22px; font-size: 12px; border-radius: 0; } /*月份 小圆点颜色*/ .recordCssDayWeek .fc-daygrid-event-dot { /*border-color:#0052d9 !important;*/ } .planDColor1, .recordDColor1 { font-size: 12px; color: #234299 !important; } .planDColor2, .recordDColor2 { font-size: 12px; color: #a05eb5 !important; } .planDColor3, .recordDColor3 { font-size: 12px; color: #226f56 !important; } .planDColor98, .recordDColor98 { font-size: 12px; color: #ed9235 !important; } .planDColor100, .recordDColor100 { font-size: 12px; color: #9b9646 !important; } } /*自定义按钮*/ .fc-direction-ltr .fc-button-group > .fc-button { background-color: rgb(231 231 231); color: rgb(0 0 0 / 60%); border-radius: 0.25em; padding: 0.2em 1.2em; font-size: 14px; } .fc .fc-button-primary:focus, .fc .fc-button-primary:not(:disabled).fc-button-active:focus, .fc .fc-button-primary:not(:disabled):active:focus { box-shadow: none; } .fc .fc-button-primary { border: none; } .fc-direction-ltr .fc-button-group > .fc-button:not(:last-child), .fc-direction-ltr .fc-button-group > .fc-button:not(:first-child) { border-bottom-right-radius: 0.25em; border-top-right-radius: 0.25em; } .fc .fc-button-primary:not(:disabled).fc-button-active:focus, .fc .fc-button-primary:not(:disabled).fc-button-active { color: #0052D9; border-radius: 0.25em; } .fc .fc-button-primary:not(:disabled).fc-button-active, .fc .fc-button-primary:not(:disabled):active { background-color: #fff; border: none; border-radius: 0.25em; } .fc .fc-button-group { background-color: rgb(231 231 231); color: rgb(0 0 0 / 60%); padding: 3px; border-radius: 0.25em; position: relative; } .fc-today-button { position: absolute !important; top: 0; left: -67px; padding: 0.4em 1.2em !important; } .fc-next-button, .fc-prev-button, .fc-toolbar-title { color: rgb(0 0 0 / 60%) !important; margin-right: 0 !important; } .fc .fc-button-primary:not(:disabled):active { padding: 0.2em 1.2em; margin-right: 0px; margin-bottom: 0px; font-size: 14px; } .fc .fc-button .fc-icon { font-size: 2em; } .fc .fc-next-button:active:focus, .fc .fc-prev-button:active:focus { background-color: transparent; color: rgb(0 0 0 / 60%) !important; border: none; box-shadow: none; padding: 0; margin-bottom: 8px; font-size: 16px; } </style>
(5)自定义公共样式文件
customCalendar.css
/*统一自定义 fullcalendar 插件 样式*/ /*头部标题*/ .fc .fc-toolbar-title { color: black; margin-right: 10px; display: inline-block; } /* 修改 prev 按钮的样式 */ /* 修改 next 按钮的样式 */ button.fc-prev-button.fc-button.fc-button-primary , button.fc-next-button.fc-button.fc-button-primary, .fc .fc-button-primary:not(:disabled):active { background-color: white; border: none; color: black; padding:0; margin-right: 5px; margin-bottom: 8px; font-size: 16px; box-shadow: none; } /*去掉阴影*/ .fc button.fc-prev-button.fc-button-primary:not(:disabled).fc-button-active:focus, .fc button.fc-next-button.fc-button-primary:not(:disabled):active:focus, .fc button.fc-next-button.fc-button-primary:not(:disabled).fc-button-active:focus, .fc button.fc-prev-button.fc-button-primary:not(:disabled):active:focus{ box-shadow: none; }
(6)下载的源码文件
官方下载地址:https://fullcalendar.io/docs/initialize-globals