Vue使用FullCalendar实现日历/周历/月历
Vue使用FullCalendar实现日历/周历/月历
需求背景:项目上遇到新需求,要求实现工单以日/周/月历形式展示。而且要求不同工单根据状态显示不同颜色,一个工单内部,需要以不同颜色显示三个阶段。
效果图
日历
周历
月历
安装插件
"@fullcalendar/core": "^6.1.14","@fullcalendar/daygrid": "^6.1.14","@fullcalendar/interaction": "^6.1.14","@fullcalendar/timegrid": "^6.1.14","@fullcalendar/vue": "^6.1.14","moment": "^2.30.1",
部分代码
html
<!-- 日程部分--><div style="box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);padding: 10px;"><FullCalendar :options="calendarOptions" ref="FullCalendar"><template v-slot:eventContent='arg'><el-tooltipclass="box-item"effect="dark"placement="top-start"><template #content><span >{{ formmatTime(arg.event.start) }}~{{ formmatTime(arg.event.end) }} {{ arg.event.extendedProps.reportId }} {{ arg.event.title }}</span></template><div class="test-div" v-if="viewType!='dayGridMonth'"><div class="info-part"><div class="info-desc">{{ formmatTime(arg.event.start) }}~{{ formmatTime(arg.event.end) }}</div><div class="info-desc">{{ arg.event.extendedProps.reportId }}</div><div class="info-desc">{{ arg.event.title }}</div></div><div class="mid-block" v-if="arg.event.id == 1||arg.event.id == 5||arg.event.id == 6" :style="getStandLen(arg.event,'top')">去程</div><div class="mid-block" v-if="arg.event.id == 1||arg.event.id == 5||arg.event.id == 6" :style="getStandLen(arg.event,'mid')">工作</div><div class="mid-block" v-if="arg.event.id == 1||arg.event.id == 5||arg.event.id == 6" :style="getStandLen(arg.event,'bottom')">返程</div></div><div class="test-div test-div22" v-if="viewType=='dayGridMonth'"><div class="info-part-month" :style="{background:arg.event.backgroundColor}">{{ formmatTime(arg.event.start) }}~{{ formmatTime(arg.event.end) }}<!-- {{ arg.event.start }}~{{ arg.event.end }} --></div></div></el-tooltip></template></FullCalendar><!-- 点击会议弹窗内容 --><div v-if="selectedEvent"><el-dialog :close-on-click-modal="true" :visible="this.showDialog" @close="closeDialog()" title="日程详情"><h3>{{ this.selectedEvent.title }}</h3><p>开始时间:{{ this.selectedEvent.start }}</p><p>结束时间:{{ this.selectedEvent.end }}</p><p>内容:{{ this.selectedEvent.context }}</p><p>职位:{{ this.selectedEvent.zw }}</p><p>性别:{{ this.selectedEvent.sex }}</p><p>年龄:{{ this.selectedEvent.age }}</p></el-dialog></div>
data&&methods
data() {return {//监听到的当前view模式viewType:'',//普通查询时间queryStartDate: null,//日程弹窗开关showDialog: false,//日程弹窗内容selectedEvent: null,//抽屉窗开关drawer: false,//日程内容集合meetingArr:meetingArr,calendarOptions: {allDaySlot:false,//是否在日历上方显示all-day(全天)axisFormat:'h(:mm)tt',// 加载的视图plugins: [dayGridPlugin, timeGridPlugin, interactionPlugin],// 视图类型 初始显示的视图 视图名称规则 比如dayGridPlugin去掉Plugin 加上Month或者Week或者DayinitialView: 'dayGridMonth',//dayGridMonth timeGridWeek timeGridDay// 语言选项 设置为中文后 部分文本会替换为中文 但是不全面locale: 'zh-cn',firstDay: 1,firstHour:1, //无用// slotMinutes:10,//在agenda的视图中, 两个时间之间的间隔(分钟) 无用handleWindowResize:true,//是否随浏览器窗口大小变化而自动contentHeight:'600px', //设置日历主体内容的高度,不包括header部分aspectRatio:2,//日历单元格宽高比dayMaxEvents:true,//时间中网格内容高度超出单元格高度时,是否折叠,如果选择false,则会完全展开网格内容,并自动撑开日历单元格高度eventLimit:true,// 设置月日程,与all-day slot 的最大显示数量,超过的通过弹窗展示selectEventOverlap:false,// 相同时间段的多个日程视觉上是否允许重叠,默认为true,允许 无用slotEventOverlap:false,//设置视图中的事件显示是否可以重叠覆盖 有用// 配置日历头部// 按钮: prev为切换(上)下一月(/周/日) next today 跳转到今天 // 文本: title 年月(YYYY-MM)// 按钮: dayGridMonth月 timeGridWeek周 timeGridDay日headerToolbar: {left: 'prev,next today',center: 'title',right: 'dayGridMonth,timeGridWeek,timeGridDay',},eventTimeFormat: {// like '14:30:00'hour: "2-digit",minute: "2-digit",meridiem: false,hour12: false, // 设置时间为24小时},// 设置各种按钮的文字 默认是英文的buttonText: {today: '今天',month: '月',week: '周',day: '日',list: '表'},customButtons: {prev: {click: () => {this.prevWeekClick();}},next: {click: () => {this.nextWeekClick();}}},// 初始就存在的事件【日程内容】initialEvents: [],// 是否可拖拽editable: false,// 是否可选择添加selectable: true,datesSet:this.datesSet, //日期渲染;修改日期范围后触发// 选择时触发函数select: this.handleDateSelect,// 点击事项触发函数eventClick: this.handleEventClick,// 移动事项或者拓展事项时间触发函数eventsSet: this.handleEvents,// 全天行 的文本显示内容// allDayText: '全天',// 最小时间slotMinTime: '00:00:00',// 最大时间slotMaxTime: '23:59:59',// 是否可以进行(拖动、缩放)修改//editable: false,},};},
methods: {datesSet(info) { //注意:该方法在页面初始化时就会触发一次console.log('间接监听view的变化',info.view.type)this.viewType = info.view.type// this.search() //请求本页数据Message.success('当前模式'+info.view.type);},// 向前点击prevWeekClick(){let calendarApi = this.$refs['FullCalendar'].getApi();calendarApi.prev();const startTime = calendarApi.view.activeStart;const endTime = calendarApi.view.activeEnd;console.log(startTime,endTime);},// 向后点击nextWeekClick(){let calendarApi = this.$refs['FullCalendar'].getApi();calendarApi.next();const startTime = calendarApi.view.activeStart;const endTime = calendarApi.view.activeEnd;console.log(startTime,endTime);},//UTC时间去掉TformmatTime(time){const utcTimestamp = time;const date = new Date(utcTimestamp);const year = date.getUTCFullYear();const month = String(date.getUTCMonth() + 1).padStart(2, '0');const day = String(date.getUTCDate()).padStart(2, '0');const hours = String(date.getUTCHours()).padStart(2, '0');const minutes = String(date.getUTCMinutes()).padStart(2, '0');const seconds = String(date.getUTCSeconds()).padStart(2, '0');const formattedDateTime = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;return formattedDateTime},//计算距离起点时间的距离getStandLen(obj,type){let styleObj = {top:0,left:0,height:0,background:''}let startTime = new Date(obj.start).getTime();let endTime = new Date(obj.end).getTime();let specificTime = 0let intervalEndTime = 0if(type=='top'){specificTime = new Date(obj.extendedProps.topSt).getTime();intervalEndTime = new Date(obj.extendedProps.topEt).getTime();styleObj.background='rgba(204, 204, 204,0.4)'}else if(type=='mid'){specificTime = new Date(obj.extendedProps.midSt).getTime();intervalEndTime = new Date(obj.extendedProps.midEt).getTime();styleObj.background='rgba(255,255,0,0.4)'}else if(type=='bottom'){specificTime = new Date(obj.extendedProps.bottomSt).getTime();intervalEndTime = new Date(obj.extendedProps.bottomEt).getTime();styleObj.background='rgba(229, 229, 229,0.4)'}let elapsedTimePercentage = ((specificTime - startTime) / (endTime - startTime)) * 100;let intervalPercentage = ((intervalEndTime - specificTime) / (endTime - startTime)) * 100;styleObj.top = elapsedTimePercentage?elapsedTimePercentage+'%':0styleObj.height = intervalPercentage?intervalPercentage+'%':0console.log('top:'+elapsedTimePercentage);// console.log(`Percentage of time interval from 03:00:00 to 04:00:00: ${intervalPercentage.toFixed(2)}%`);return styleObj},/* 普通查询方法*/quertStart() {let calendarApi = this.$refs.FullCalendar.getApi()//非空if (this.queryStartDate != null) {// gotoDate方法是让当前视图跳转到指定日期的位置calendarApi.gotoDate(this.queryStartDate)} else {//跳转到今日calendarApi.today()}},/* 获取指定日期范围的所有日程信息 */toClick() {// 获取 FullCalendar 实例const calendar = this.$refs.FullCalendar.getApi();// 定义搜索范围的起始和结束时间const startDate = moment("2015-06-06");const endDate = moment("2028-06-08");// 获取日历中的所有事件const events = calendar.getEvents();// 根据范围条件筛选事件const filteredEvents = events.filter(event => {// 获取事件的开始时间和结束时间const eventStart = moment(event.start);const eventEnd = moment(event.end);// 判断事件是否在范围内return eventStart.isBetween(startDate, endDate, null, '[]') || eventEnd.isBetween(startDate,endDate, null, '[]');});// 处理筛选出的事件console.log(filteredEvents);},/* 点击会议弹窗具体内容*/handleEventClick(info) {// 获取点击的事件对象const event = info.event;// 更新选中的事件this.selectedEvent = {title: event.title,start: moment(event.start).format('YYYY-MM-DD HH:mm'),end: moment(event.end).format('YYYY-MM-DD HH:mm'),zw: event.extendedProps.zw,context: event.extendedProps.context,age: event.extendedProps.age,sex: event.extendedProps.sex};console.info(info)console.info(this.selectedEvent)//开启弹窗this.showDialog = true},//handleDateSelect(info){const event = info.event;console.log('信息',info)Message.success('点击日期'+info.startStr+'-'+info.endStr);},/* 关闭日程弹窗方法*/closeDialog() {this.showDialog = false},/* 申请会议按钮 */toMeetingClick() {//根据自己的业务进行处理...}},
event事件数据
const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, '0');
const day = String(today.getDate()).padStart(2, '0');const formattedDate = `${year}-${month}-${day}`;
const formattedDateTomrrow = `${year}-${month}-${Number(day)+1}`
const formattedDateAfterTomrrow = `${year}-${month}-${Number(day)+2}`
const formattedDateYestoday = `${year}-${month}-${Number(day)-1}`
const formattedDateBeforeYestoday = `${year}-${month}-${Number(day)-2}`let meetingArr = [{id: 1,reportId:'SR20240527435908',title: `机器维修单`,start: formattedDate + 'T00:00:00',end: formattedDate + 'T23:59:59',context: '自定义的内容',color:'rgba(43,177,76,0.8)',textColor:'#fff', age: 18,sex: '男',zw: '董事长',// 开始时段topSt:formattedDate + 'T02:30:00',topEt:formattedDate + 'T03:00:00',//中间时段midSt:formattedDate + 'T03:30:00',midEt:formattedDate + 'T04:30:00',//结束时段bottomSt:formattedDate + 'T05:30:00',bottomEt:formattedDate + 'T06:00:00',},{id: 5,reportId:'SR20240527435999',title: `机器维修单`,start: formattedDate + 'T01:30:00',end: formattedDate + 'T06:30:00',context: '自定义的内容',color:'rgba(43,177,76,0.8)',textColor:'#fff', age: 18,sex: '男',zw: '董事长',// 开始时段topSt:formattedDate + 'T02:30:00',topEt:formattedDate + 'T03:00:00',//中间时段midSt:formattedDate + 'T03:30:00',midEt:formattedDate + 'T04:30:00',//结束时段bottomSt:formattedDate + 'T05:30:00',bottomEt:formattedDate + 'T06:00:00',},{id: 6,reportId:'SR20240527435777',title: `机器维修单`,start: formattedDate + 'T01:30:00',end: formattedDate + 'T06:30:00',context: '自定义的内容',color:'rgba(43,177,76,0.8)',textColor:'#fff', age: 18,sex: '男',zw: '董事长',// allDay:true,// 开始时段topSt:formattedDate + 'T02:30:00',topEt:formattedDate + 'T03:00:00',//中间时段midSt:formattedDate + 'T03:30:00',midEt:formattedDate + 'T04:30:00',//结束时段bottomSt:formattedDate + 'T05:30:00',bottomEt:formattedDate + 'T06:00:00',},{id: 7,reportId:'IN202405094357333',title: `机器安装单`,color:'rgba(63,72,204,0.8)',start: formattedDate + 'T07:30:00',end: formattedDate + 'T08:30:00',},{id: 2,reportId:'IN20240509435732',title: `机器安装单`,color:'rgba(63,72,204,0.8)',start: formattedDate + 'T13:00:00',end: formattedDate + 'T14:20:00',},{id: 3,reportId:'CIN20240604436001',title: `合同加装单`,color:'rgba(112,146,190,0.8)',start: formattedDate + 'T15:10:00',end: formattedDate + 'T16:10:00',},{id: 3,reportId:'PLF2023032415233400000111',title: `客户报修单`,color:'rgba(43,177,76,0.8)',start: formattedDate + 'T16:00:00',end: formattedDate + 'T17:10:00',},{id: 4,reportId:'CIN20240604436001',title: `合同加装单`,color:'rgba(112,146,190,0.8)',start: formattedDate + 'T17:30:00',end: formattedDate + 'T18:10:00',},//明天{id: 8,reportId:'SR20240527435908',title: `机器维修单`,start: formattedDateTomrrow + 'T00:00:00',end: formattedDateTomrrow + 'T23:59:59',context: '自定义的内容',color:'rgba(43,177,76,0.8)',textColor:'#fff', age: 18,sex: '男',zw: '董事长',// 开始时段topSt:formattedDateTomrrow + 'T02:30:00',topEt:formattedDateTomrrow + 'T03:00:00',//中间时段midSt:formattedDateTomrrow + 'T03:30:00',midEt:formattedDateTomrrow + 'T04:30:00',//结束时段bottomSt:formattedDateTomrrow + 'T05:30:00',bottomEt:formattedDateTomrrow + 'T06:00:00',},{id: 9,reportId:'SR20240527435999',title: `机器维修单`,start: formattedDateTomrrow + 'T01:30:00',end: formattedDateTomrrow + 'T06:30:00',context: '自定义的内容',color:'rgba(43,177,76,0.8)',textColor:'#fff', age: 18,sex: '男',zw: '董事长',// 开始时段topSt:formattedDateTomrrow + 'T02:30:00',topEt:formattedDateTomrrow + 'T03:00:00',//中间时段midSt:formattedDateTomrrow + 'T03:30:00',midEt:formattedDateTomrrow + 'T04:30:00',//结束时段bottomSt:formattedDateTomrrow + 'T05:30:00',bottomEt:formattedDateTomrrow + 'T06:00:00',},{id: 10,reportId:'IN202405094357333',title: `机器安装单`,color:'rgba(63,72,204,0.8)',start: formattedDateTomrrow + 'T07:30:00',end: formattedDateTomrrow + 'T08:30:00',},{id: 11,reportId:'IN20240509435732',title: `机器安装单`,color:'rgba(63,72,204,0.8)',start: formattedDateTomrrow + 'T13:00:00',end: formattedDateTomrrow + 'T14:20:00',},{id: 12,reportId:'CIN20240604436001',title: `合同加装单`,color:'rgba(112,146,190,0.8)',start: formattedDateTomrrow + 'T15:10:00',end: formattedDateTomrrow + 'T16:10:00',},{id: 13,reportId:'PLF2023032415233400000111',title: `客户报修单`,color:'rgba(43,177,76,0.8)',start: formattedDateTomrrow + 'T16:00:00',end: formattedDateTomrrow + 'T17:10:00',},{id: 14,reportId:'CIN20240604436001',title: `合同加装单`,color:'rgba(112,146,190,0.8)',start: formattedDateTomrrow + 'T17:30:00',end: formattedDateTomrrow + 'T18:10:00',},//后天{id: 8,reportId:'SR20240527435908',title: `机器维修单`,start: formattedDateAfterTomrrow + 'T00:00:00',end: formattedDateAfterTomrrow + 'T23:59:59',context: '自定义的内容',color:'rgba(43,177,76,0.8)',textColor:'#fff', age: 18,sex: '男',zw: '董事长',// 开始时段topSt:formattedDateAfterTomrrow + 'T02:30:00',topEt:formattedDateAfterTomrrow + 'T03:00:00',//中间时段midSt:formattedDateAfterTomrrow + 'T03:30:00',midEt:formattedDateAfterTomrrow + 'T04:30:00',//结束时段bottomSt:formattedDateAfterTomrrow + 'T05:30:00',bottomEt:formattedDateAfterTomrrow + 'T06:00:00',},{id: 9,reportId:'SR20240527435999',title: `机器维修单`,start: formattedDateAfterTomrrow + 'T01:30:00',end: formattedDateAfterTomrrow + 'T06:30:00',context: '自定义的内容',color:'rgba(43,177,76,0.8)',textColor:'#fff', age: 18,sex: '男',zw: '董事长',// 开始时段topSt:formattedDateAfterTomrrow + 'T02:30:00',topEt:formattedDateAfterTomrrow + 'T03:00:00',//中间时段midSt:formattedDateAfterTomrrow + 'T03:30:00',midEt:formattedDateAfterTomrrow + 'T04:30:00',//结束时段bottomSt:formattedDateAfterTomrrow + 'T05:30:00',bottomEt:formattedDateAfterTomrrow + 'T06:00:00',},{id: 10,reportId:'IN202405094357333',title: `机器安装单`,color:'rgba(63,72,204,0.8)',start: formattedDateAfterTomrrow + 'T07:30:00',end: formattedDateAfterTomrrow + 'T08:30:00',},{id: 11,reportId:'IN20240509435732',title: `机器安装单`,color:'rgba(63,72,204,0.8)',start: formattedDateAfterTomrrow + 'T13:00:00',end: formattedDateAfterTomrrow + 'T14:20:00',},{id: 12,reportId:'CIN20240604436001',title: `合同加装单`,color:'rgba(112,146,190,0.8)',start: formattedDateAfterTomrrow + 'T15:10:00',end: formattedDateAfterTomrrow + 'T16:10:00',},{id: 13,reportId:'PLF2023032415233400000111',title: `客户报修单`,color:'rgba(43,177,76,0.8)',start: formattedDateAfterTomrrow + 'T16:00:00',end: formattedDateAfterTomrrow + 'T17:10:00',},{id: 14,reportId:'CIN20240604436001',title: `合同加装单`,color:'rgba(112,146,190,0.8)',start: formattedDateAfterTomrrow + 'T17:30:00',end: '2024-06-16' + 'T18:10:00',},//昨天{id: 15,reportId:'SR20240527435908',title: `机器维修单`,start: formattedDateYestoday + 'T00:00:00',end: formattedDateYestoday + 'T23:59:59',context: '自定义的内容',color:'rgba(43,177,76,0.8)',textColor:'#fff', age: 18,sex: '男',zw: '董事长',// 开始时段topSt:formattedDateYestoday + 'T02:30:00',topEt:formattedDateYestoday + 'T03:00:00',//中间时段midSt:formattedDateYestoday + 'T03:30:00',midEt:formattedDateYestoday + 'T04:30:00',//结束时段bottomSt:formattedDateYestoday + 'T05:30:00',bottomEt:formattedDateYestoday + 'T06:00:00',},{id: 16,reportId:'SR20240527435999',title: `机器维修单`,start: formattedDateYestoday + 'T01:30:00',end: formattedDateYestoday + 'T06:30:00',context: '自定义的内容',color:'rgba(43,177,76,0.8)',textColor:'#fff', age: 18,sex: '男',zw: '董事长',// 开始时段topSt:formattedDateYestoday + 'T02:30:00',topEt:formattedDateYestoday + 'T03:00:00',//中间时段midSt:formattedDateYestoday + 'T03:30:00',midEt:formattedDateYestoday + 'T04:30:00',//结束时段bottomSt:formattedDateYestoday + 'T05:30:00',bottomEt:formattedDateYestoday + 'T06:00:00',},{id: 17,reportId:'IN202405094357333',title: `机器安装单`,color:'rgba(63,72,204,0.8)',start: formattedDateYestoday + 'T07:30:00',end: formattedDateYestoday + 'T08:30:00',},{id: 18,reportId:'IN20240509435732',title: `机器安装单`,color:'rgba(63,72,204,0.8)',start: formattedDateYestoday + 'T13:00:00',end: formattedDateYestoday + 'T14:20:00',},{id: 19,reportId:'CIN20240604436001',title: `合同加装单`,color:'rgba(112,146,190,0.8)',start: formattedDateYestoday + 'T15:10:00',end: formattedDateYestoday + 'T16:10:00',},{id: 20,reportId:'PLF2023032415233400000111',title: `客户报修单`,color:'rgba(43,177,76,0.8)',start: formattedDateYestoday + 'T16:00:00',end: formattedDateYestoday + 'T17:10:00',},{id: 21,reportId:'CIN20240604436001',title: `合同加装单`,color:'rgba(112,146,190,0.8)',start: formattedDateYestoday + 'T17:30:00',end: formattedDateYestoday + 'T18:10:00',},//前天{id: 22,reportId:'SR20240527435908',title: `机器维修单`,start: formattedDateBeforeYestoday + 'T00:00:00',end: formattedDateBeforeYestoday + 'T23:59:59',context: '自定义的内容',color:'rgba(43,177,76,0.8)',textColor:'#fff', age: 18,sex: '男',zw: '董事长',// 开始时段topSt:formattedDateBeforeYestoday + 'T02:30:00',topEt:formattedDateBeforeYestoday + 'T03:00:00',//中间时段midSt:formattedDateBeforeYestoday + 'T03:30:00',midEt:formattedDateBeforeYestoday + 'T04:30:00',//结束时段bottomSt:formattedDateBeforeYestoday + 'T05:30:00',bottomEt:formattedDateBeforeYestoday + 'T06:00:00',},{id: 23,reportId:'SR20240527435999',title: `机器维修单`,start: formattedDateBeforeYestoday + 'T01:30:00',end: formattedDateBeforeYestoday + 'T06:30:00',context: '自定义的内容',color:'rgba(43,177,76,0.8)',textColor:'#fff', age: 18,sex: '男',zw: '董事长',// 开始时段topSt:formattedDateBeforeYestoday + 'T02:30:00',topEt:formattedDateBeforeYestoday + 'T03:00:00',//中间时段midSt:formattedDateBeforeYestoday + 'T03:30:00',midEt:formattedDateBeforeYestoday + 'T04:30:00',//结束时段bottomSt:formattedDateBeforeYestoday + 'T05:30:00',bottomEt:formattedDateBeforeYestoday + 'T06:00:00',},{id: 24,reportId:'IN202405094357333',title: `机器安装单`,color:'rgba(63,72,204,0.8)',start: formattedDateBeforeYestoday + 'T07:30:00',end: formattedDateBeforeYestoday + 'T08:30:00',},{id: 25,reportId:'IN20240509435732',title: `机器安装单`,color:'rgba(63,72,204,0.8)',start: formattedDateBeforeYestoday + 'T13:00:00',end: formattedDateBeforeYestoday + 'T14:20:00',},{id: 26,reportId:'CIN20240604436001',title: `合同加装单`,color:'rgba(112,146,190,0.8)',start: formattedDateBeforeYestoday + 'T15:10:00',end: formattedDateBeforeYestoday + 'T16:10:00',},{id: 27,reportId:'PLF2023032415233400000111',title: `客户报修单`,color:'rgba(43,177,76,0.8)',start: formattedDateBeforeYestoday + 'T16:00:00',end: formattedDateBeforeYestoday + 'T17:10:00',},{id: 28,reportId:'CIN20240604436001',title: `合同加装单`,color:'rgba(112,146,190,0.8)',start: formattedDateBeforeYestoday + 'T17:30:00',end: formattedDateBeforeYestoday + 'T18:10:00',},
]export default meetingArr;