<template>
<div class="M_container">
<div class="top-title">
<i class="el-icon-arrow-left" @click="getPrev"></i>
第{{week}}周({{title}})
<i class="el-icon-arrow-right" @click="getNext"></i>
</div>
<FullCalendar
ref="fullCalendar"
class="fullcalendar week"
:options="calendarOptions"
id="calendar1"
>
<!-- <template v-slot:dayHeaderContent='arg'>
<div class="top" @click="changeToDay(arg.date)">
{{arg|formateHeaderContent}}
<span v-if="weekEventNumObj[arg.dow]>1" class="moreTips">更多日程</span>
</div>
</template> -->
</FullCalendar>
</div>
</template>
<script>
import { GetWeekList } from "@/api/schedule/index";
import FullCalendar from "@fullcalendar/vue";
import dayGridPlugin from "@fullcalendar/daygrid";
import timeGridPlugin from "@fullcalendar/timegrid";
import interactionPlugin from "@fullcalendar/interaction";
import { getWeek, y2k } from "@/utils/schedule/formate";
import {slotLabelContent,eventContetFun,changeStartEnd,eventMouseEnter} from "@/utils/schedule/fullcalendarHandler" ;
import elementResizeDetectorMaker from "element-resize-detector";
export default {
name: "byWeek",
components: {
FullCalendar,
},
filters: {
formateHeaderContent: (arg) => {
let weekDay = arg.dow;
let weekObj = {0: "星期天",1: "星期一",2: "星期二",3: "星期三",4: "星期四", 5: "星期五", 6: "星期六",};
let weekName = weekObj[weekDay];
weekName += "( " + arg.text.replace("/", "-") + " )";
return weekName;
},
},
props: ["type"],
data() {
return {
title: "",
startDate: "",
endDate: "",
week: "",
weekEventNumObj: { 0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0 },
calendarOptions: {
// 引入的插件,比如fullcalendar/daygrid,fullcalendar/timegrid引入后才可显示月,周,日
plugins: [dayGridPlugin, interactionPlugin, timeGridPlugin],
initialView: "timeGridWeek", // 默认为那个视图(月:dayGridMonth,周:timeGridWeek,日:timeGridDay)
events: [],
/* eventOrder:'duration,start,allDay,title', */
firstDay: 1, // 设置一周中显示的第一天是哪天,周日是0,周一是1,类推
locale: "zh-cn",
eventColor: "#fff",
themeSystem: "bootstrap", // 主题色(本地测试未能生效)
expandRows: true,
contentHeight: 910,
timeGridEventMinHeight: " 30", // 设置事件的最小高度
/* weekNumbers:true,
weekText: "周", */
// displayEventTime: false, // 是否显示时间
eventLimit: true, // 设置月日程,与all-day slot的最大显示数量,超过的通过弹窗显示
allDaySlot: true,
allDayText: "全天",
scrollTimeReset: true,
scrollTime: "12:00:00",
slotMinTime: "07:00:00",
slotMaxTime: "20:00:00",
slotDuration: "01:00",
slotLabelInterval:"01:00",
showNonCurrentDates: false,
/* slotEventOverlap: false, */
eventMouseEnter:eventMouseEnter,
dayHeaderContent:this.dayHeaderContent,
slotLabelContent:slotLabelContent,
eventContent:eventContetFun,
moreLinkDidMount:this.moreLinkDidMount,
moreLinkWillUnmount:this.moreLinkWillUnmount,
allowContextMenu: false,
views: {
timeGridWeek: {
eventMaxStack: 4,
eventLimit: 5,
dayMaxEventRows: 4,
moreLinkContent: "更多",
moreLinkClick: "popover",
dayHeaderFormat: {
month: "2-digit",
day: "2-digit",
omitCommas: true,
},
titleFormat: { year: "numeric", month: "2-digit", day: "2-digit" },
},
},
headerToolbar: false,
slotLabelFormat: {
hour: "2-digit",
minute: "2-digit",
meridiem: false,
hour12: false, // 设置时间为24小时
},
eventLimitNum: {
// 事件显示数量限制(本地测试未能生效)
dayGrid: {
eventLimit: 3,
},
timeGrid: {
eventLimit: 2, // adjust to 6 only for timeGridWeek/timeGridDay
},
},
eventClick: this.handleEventClick,
/* dayClick: function(event, jsEvent, view) {
console.log("222222");
}, */
},
};
},
mounted() {
if (!this.type || this.type == "init") {
this.getDateFun();
}
this.resizeCalendarBox();
},
methods: {
resizeCalendarBox(){
const _this=this;
const erd=elementResizeDetectorMaker();
erd.listenTo(document.getElementById("calendar1"),(element)=>{
_this.$nextTick(()=>{
let calendarApi = this.$refs.fullCalendar.getApi();
calendarApi.gotoDate(_this.startDate )
})
})
},
changeToDay(date) {
this.$emit("turnToDaySchedule", date);
},
//获取当前日期范围
getDateFun() {
let calendarApi = this.$refs.fullCalendar.getApi();
let title = calendarApi.view.title;
let dateArr = title.split("–");
let start = this.$refs.fullCalendar.getApi().view.activeStart;
let now = new Date(start);
this.week = getWeek(y2k(now.getYear()), now.getMonth(), now.getDate());
if (dateArr.length > 0) {
this.startDate = dateArr[0].replace(/\//g, "-").replace(/\s*/g, "");
this.endDate = dateArr[1].replace(/\//g, "-").replace(/\s*/g, "");
this.title = title;
this.$nextTick(() => {
this.$emit("changeWeekDate", title);
});
this.getWeekData();
}
},
//日视图数据请求
getWeekData() {
const _this = this;
GetWeekList({
startDate: this.startDate,
endDate: this.endDate,
}).then((res) => {
let resData = res.data,
result = resData.flat(Infinity);
const handleData = result.map((item) => {
let start = item.startTime ? item.startTime : item.allDayStartTime;
let day = start.split(" ")[0];
let timeObj = changeStartEnd(day, item);
return {
start: timeObj.itemStart,
end: timeObj.itemEnd,
startTimes: new Date(item.startTime ? item.startTime : item.allDayStartTime),
endTimes: new Date(item.endTime ? item.endTime : item.allDayEndTime),
title: item.sysScheduleContent,
classNames: item.actualCompleteTime ? "blue" : "orange",
sysScheduleArrangeAllRecordId: item.sysScheduleArrangeAllRecordId,
sysScheduleArrangeId: item.sysScheduleArrangeId,
status: item.status,
actualCompleteTime: item.actualCompleteTime,
important: item.important,
};
});
_this.calendarOptions.events = handleData;
});
},
//根据日期更新视图
gotoDate(arg) {
let calendarApi = this.$refs.fullCalendar.getApi();
calendarApi.gotoDate(new Date(arg[0]));
this.getDateFun();
},
getPrev() {
let calendarApi = this.$refs.fullCalendar.getApi();
calendarApi.prev();
this.getDateFun();
},
getNext() {
let calendarApi = this.$refs.fullCalendar.getApi();
calendarApi.next();
this.getDateFun();
},
dayHeaderContent(arg) {
const _this=this;
let weekDay = arg.dow;
let weekObj={0:'星期天',1:'星期一',2:'星期二',3:'星期三',4:'星期四',5:'星期五',6:'星期六'}
let weekName=weekObj[weekDay];
weekName+= "( "+arg.text.replace('/', '-')+" )"
let italicEle= document.createElement('div');
italicEle.className="top";
italicEle.addEventListener('click',function(){
_this.$emit("turnToDaySchedule", arg.date);
});
if(this.weekEventNumObj[arg.dow]>0){
italicEle.innerHTML=weekName+"<span class='moreTips'>更多日程</span>"
}else{
italicEle.innerHTML=weekName;
}
return {domNodes:[italicEle]}
},
moreLinkWillUnmount(){
this.weekEventNumObj={ 0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0 }
},
moreLinkDidMount(arg){
let date= arg.el.closest('.fc-day').dataset.date;
let weekday=new Date(date).getDay();
let weekEventNumObj = this.weekEventNumObj;
if(weekEventNumObj[weekday]<arg.num){
weekEventNumObj[weekday]=arg.num;
this.weekEventNumObj = weekEventNumObj;
let calendarApi = this.$refs.fullCalendar.getApi();
calendarApi.gotoDate(new Date(date));
}
},
/**
* 点击日历日程事件
*
* info: 事件信息
* event是日程(事件)对象
* jsEvent是个javascript事件
* view是当前视图对象。
*/
handleEventClick(info) {
if(info.el.closest('.fc-more-popover')){
let removeObj=info.el.closest('.fc-more-popover');
removeObj.parentNode.removeChild(removeObj)
}
const data = info.event._def.extendedProps;
const scheduleID = {
sysScheduleArrangeAllRecordId: data.sysScheduleArrangeAllRecordId,
sysScheduleArrangeId: data.sysScheduleArrangeId,
status: data.status,
};
this.$emit("getScheduleID", scheduleID);
},
},
};
</script>
<style lang="scss" scoped>
.top-title {
height: 70px;
line-height: 70px;
font-size: 18px;
color: #1890ff;
text-align: right;
margin-top: -70px;
i {
cursor: pointer;
}
}
::v-deep {
/* .fc-timegrid-slot {
height: 3em; // 1.5em by default
} */
.fc-scrollgrid-sync-inner {
position: relative;
}
.moreTips {
font-size: 12px;
color: #1890ff;
width: 30px;
display: inline-block;
white-space: break-spaces;
line-height: 1.2em;
padding-top: 5px;
position: absolute;
z-index: 99;
right: 8px;
top: 6px;
}
.time {
white-space: nowrap;
}
.tit {
font-size: 14px;
position: relative;
font-weight: 700;
width: 100%;
overflow: hidden;
height: 1.2em;
line-height: 1.2em;
margin-top: 5px;
.red {
color: #ff2323;
}
}
.finish {
color: #1890ff;
position: absolute;
top: 0px;
z-index: 1009;
background: #e8f4ff;
}
.unfinish {
color: #ff7c3d;
position: absolute;
background: #e8f4ff;
top: 0px;
z-index: 1009;
}
.fc-direction-ltr .fc-timegrid-more-link {
display: none;
}
.fc .fc-timegrid-col.fc-day-today {
background: none;
}
.fc-v-event .fc-event-main {
color: #333333ff;
overflow: hidden;
}
.fc-direction-ltr .fc-daygrid-event {
background: #e8f4ffff;
border: none;
border-left: 5px solid #63b4ffff;
margin-left: 0;
display: block;
margin-top: 0;
/* border-bottom: 1px solid #fff; */
margin-bottom: 1px;
padding-left: 3px;
height: 42px;
overflow: hidden;
}
.fc-timegrid-event{
margin-bottom: 0;
}
.fc-timegrid-event-harness-inset .fc-timegrid-event.orange,
.orange.fc-daygrid-event.fc-event-end {
border-left: 5px solid #ffb18dff !important;
background: rgba(255, 224, 209, 0.9) !important;
}
.fc-timegrid-event-harness-inset .fc-timegrid-event.blue,
.blue.fc-daygrid-event.fc-event-end {
border-left: 5px solid #63b4ffff !important;
background: rgba(232, 244, 255, 0.9) !important;
}
.fc-timegrid-event-harness-inset .fc-timegrid-event.red,
.red.fc-daygrid-event.fc-event-end {
border-left: 5px solid #ff2323 !important;
}
.fc-daygrid-event.fc-event-end {
margin-right: 0;
}
.fc-direction-ltr .fc-daygrid-event.fc-event-start {
margin-left: 0;
}
.fc-direction-ltr .fc-timegrid-col-events {
margin: 0;
}
.fc-theme-standard th {
height: 50px;
line-height: 50px;
background: #ececec;
font-size: 18px;
color: #333;
font-weight: 400;
}
.week.fc .fc-toolbar-title {
display: inline-block;
font-weight: 400;
font-size: 18px;
color: #1890ff;
}
.week.fc .fc-button-primary {
background: #fff;
border: none;
color: #1890ff;
display: inline-block;
}
.week.fc .fc-toolbar.fc-header-toolbar {
margin-bottom: 1.5em;
position: absolute;
z-index: 1000;
top: 110px;
right: 30px;
}
.fc-h-event .fc-event-main {
color: #333;
}
.fc .fc-daygrid-body-natural .fc-daygrid-day-events {
margin-bottom: 0;
}
.fc .fc-timegrid-divider {
padding: 0;
display: none;
}
.fc .fc-timegrid-slot-minor {
display: none;
}
.fc .fc-daygrid-day.fc-day-today {
background: none;
}
.fc .fc-daygrid-day-bottom {
position: absolute;
z-index: 99;
bottom: 3px;
right: 0;
font-size: 14px;
}
.fc .fc-daygrid-day-frame .fc-daygrid-day-events{
max-height: 173px;
overflow: hidden;
}
.fc .fc-daygrid-event-harness-abs{
position:relative !important;
visibility: visible !important;
}
.text {
width: calc(100% - 10px);
overflow: hidden;
text-overflow: ellipsis;
height: 1em;
line-height: 1em;
display: inline-block;
white-space: nowrap;
}
.slim {
font-size: 12px;
padding-top: 0px;
height: 1.1em;
line-height: 1.1em;
/* font-weight: 400; */
margin-top: 0;
}
}
</style>
功能点 :
1.点击相应日期调跳转到日视图界面,周头部格式改成星期几格式
dayHeaderContent(arg) {
const _this=this;
let weekDay = arg.dow;
let weekObj={0:'星期天',1:'星期一',2:'星期二',3:'星期三',4:'星期四',5:'星期五',6:'星期六'}
let weekName=weekObj[weekDay];
weekName+= "( "+arg.text.replace('/', '-')+" )"
let italicEle= document.createElement('div');
italicEle.className="top";
italicEle.addEventListener('click',function(){
_this.$emit("turnToDaySchedule", arg.date);
});
if(this.weekEventNumObj[arg.dow]>0){
italicEle.innerHTML=weekName+"<span class='moreTips'>更多日程</span>"
}else{
italicEle.innerHTML=weekName;
}
return {domNodes:[italicEle]}
},
2.修复页面伸缩出现空白问题
mounted() {
this.resizeCalendarBox();
},
resizeCalendarBox(){
const _this=this;
const erd=elementResizeDetectorMaker();
erd.listenTo(document.getElementById("calendar1"),(element)=>{
_this.$nextTick(()=>{
let calendarApi = this.$refs.fullCalendar.getApi();
calendarApi.gotoDate(_this.startDate )
})
})
},
3.鼠标悬停文字显示
export function eventMouseEnter(info){
let startTime = info.event._def.extendedProps.startTimes;
let endTime = info.event._def.extendedProps.endTimes;
const showTimeStart = (startTime.getHours() < 10 ? "0" + startTime.getHours() : startTime.getHours()) + ":" + (startTime.getMinutes() < 10 ? "0" + startTime.getMinutes() : startTime.getMinutes());
const showTimeEnd = (endTime.getHours() < 10 ? "0" + endTime.getHours() : endTime.getHours()) + ":" + (endTime.getMinutes() < 10 ? "0" + endTime.getMinutes() : endTime.getMinutes());
let Time=showTimeStart+"-"+showTimeEnd;
const title=info.event.title;
let allDay = info.event.allDay;
if(allDay){
Time="全天"
}
tippy(info.el, {
content:title+"<div>"+"("+Time+")"+"</div>",
arrow:false,
placement: "top-start",
allowHTML:true,
});
}
4.左侧 时间轴
export function slotLabelContent(arg){
if (Number(arg.time.milliseconds) < 28800000) {
return "08:00前";
}
if (
Number(arg.time.milliseconds) >= 28800000 &&
Number(arg.time.milliseconds) <= 64800000
) {
return arg.text;
}
if (Number(arg.time.milliseconds) > 64800000) {
return "19:00后";
}
}