实现思路:
1、将日历分为四个部分:
1)日历中要显示的上个月日期部分
2)当月到当天的日期部分
3)当月当前之后的部分(为了实现点击无操作)
4)日历中要显示的下个月日期部分
2、日历的操作:
1)点击上个月日期进入到上个月日历。
2)(当月)点击到当前日期之前的显示当天的报工信息、
(当月之前)点击任意七日都可显示当天的报工信息
3)当月之后不可操作。
4)节假日、休息日点击显示休息日。

**注意:不支持年切换,只允许对当前年份进行操作

<template>
  <div class="container">
    <div class="calendar-container">
      <div class="year" style="display: flex;justify-content: space-between;">
        <div> 
          每日统计
          <span>({{ nowDate.year }}年{{ nowDate.month + 1 }}月)</span>
        </div>
        <el-button
          type="text"
          style="margin-right: 15px;"
          @click="clickToIndex()"
          >返回首页</el-button
        >
      </div>
      <ul class="week">
        <li v-for="(o, index) in 7" :key="o">{{ formatWeek(index) }}</li>
      </ul>
      <ul class="date">
        <li class="none-week last" v-for="o in lastMonthDays" :key="o + 50" @click="lastClickEvent">
          {{ lastMonthStartDay + o - 1 }}
        </li>

        <li @click="handleClick(item)" 
            v-for=" item in showList" :key="item.daySn"
            :class="[item.holType !== '1' ? 'holidayActiv': item.appFlag? (item.appFlag === 'Y' || item.appFlag === 'F') ? 'normalActiv': 'unormalActiv' : ((item.daySn - 0) === nowDate.date && isNowMonth) ? 'notActiv' : 'unormalActiv', isClickDay === (item.daySn - 0) ? 'clickActiv': '']">
          {{ item.daySn }}
        </li>
        <!-- 当前日期后,不做点击处理 -->
        <li v-for="day in nowMonthDays - nowDate.date" :key="day + nowDate.date" v-if="isNowMonth">
          {{ day + nowDate.date }}
        </li>
        <li class="none-week next" @click="nextClickEvent"
          v-for="day in 42 - lastMonthDays - nowMonthDays"
          :key="day + 100">
          {{ day }}
        </li>
      </ul>
      <div class="explain">
        <div class="info"><p class="normal"></p>正常</div>
        <div class="info"><p class="unormal"></p>异常</div>
        <div class="info"><p class="holiday"></p>节假日</div>
        <div class="info"><p class="not"></p>待报工</div>
      </div>
    </div>
    <div class="body" v-if="showForm">
      <div style="margin: 0 15px;color: rgb(158, 155, 155);
            display: flex;align-items: center;
            justify-content: space-between;">
        <span>每日报工信息</span>
        <span v-show="form.appFlag === 'B' ">驳回</span>
        <span v-show="form.appFlag === 'A' ">未审核</span>
      </div>
      <el-form ref="form" :model="form" label-width="125px" :disabled="form.state !== 'Y' ">
        <el-form-item label="报工日期" required>
          <el-input v-model="form.jobDate" required readonly></el-input>
        </el-form-item>
        <el-form-item label="项目编号" required>
          <el-select v-model="projectValue" placeholder="请选择项目编号" 
                  @change="currentSel" 
                  value-key="xmIncode" :disabled="!ifShowButton">
            <el-option :label="item.xmbh" :value="item"
                  v-for="item in projectList" :key="item.xmIncode">
              <span style="float: left;display: inline-block;
                    max-width: 240px;overflow: hidden;
                    text-overflow: ellipsis;padding-left: 10px;
                    white-space: nowrap;">{{ item.xmmc }}</span>
              <span style="float: right; color: #8492a6; font-size: 13px;padding-right: 10px;">{{ item.xmbh }}</span>
            </el-option>
            <el-option :label="uchose.xmbh" 
                  :value="uchose"
                  :key="uchose.xmIncode"
                  disabled v-if="uchose.xmIncode !== 0"
                  >
              <span style="float: left;display: inline-block;
                    max-width: 240px;overflow: hidden;
                    text-overflow: ellipsis;padding-left: 10px;
                    white-space: nowrap;">{{ uchose.xmmc }}</span>
              <span style="float: right; color: #8492a6; font-size: 13px;padding-right: 10px;">{{ uchose.xmbh }}</span>
            </el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="项目部门" required>
          <el-input v-model="form.groupName" placeholder="请输入" readonly></el-input>
        </el-form-item>
        <el-form-item label="工作内容简述">
          <el-input type="textarea" 
              :rows="3"
              v-model="form.remark" 
              placeholder="请输入工作内容简述" :readonly="!ifShowButton"></el-input>
        </el-form-item>
        <el-form-item v-if="form.state === 'Y' && ifShowButton"
            style="border-radius: 0px;padding: 0px;margin: 10px;background-color:transparent;">
          <el-button type="primary" @click="onSubmit" :disabled="isSubmit">提交</el-button>
        </el-form-item>
      </el-form>
    </div>
    <div v-else class="body" 
          style="height: calc(100% - 405.5px);background-color: rgb(255, 255, 255);
          margin: 10px;color: #9e9b9b;
          display: flex;
          flex-direction: column;
          align-items: center;
          border-radius: 15px;
          justify-content: center;">
      <i class="el-icon-hot-water" style="font-size: 80px"></i>
      <span style="margin-top: 12px;letter-spacing: 2px;">今日休息</span>
    </div>
  </div>
</template>

默认进入当前页面,选中当天进行报工,也可传入指定日期。

export default {
  name: "AddBooking",
  data() {
    return {
      showList: [],//展示日历信息
      projectList:[],//项目列表
      selectDate: [], //选择日期列表
      nowDate: this.getDate(new Date()), //当前设置时间 默认为当前系统时间
      form:{
        incode: 0,
        xmIncode: 0,
        groupName: "",
        remark: "",
        xmbh: "",
        xmmc: "",
        state: "Y",
        appFlag: null
      },
      showForm: false,
      isNowMonth: true,
      projectValue: {
        xmIncode: 0,
        xmbh: "",
        xmmc: "",
        groupName: ""
      },// 选中的项目信息
      uchose: {
        xmIncode: 0,
        xmbh: "",
        xmmc: "",
        groupName: ""
      },
      isDisabled: false,
      isClickDay: new Date().getDate(),
      isSubmit: false,//是否提交
      ifAllowSubmit:true,//是否允许上个月报工
      ifShowButton: true,//是否显示提交按钮
      listColumn: 30,//允许报工天数
    };
  },
  computed: {
    lastMonthDays() {//日历中上个月需显示的天数
      return this.startWeek();
    },
    lastMonthStartDay() {//计算日历中需要显示的上个月的开始日期
      //上个月天数
      let lastMonthMonthDays = this.calcLastMonthDays(this.nowDate.year, this.nowDate.month);
      // 需要显示的天数
      let days = this.startWeek() - 1;
      return lastMonthMonthDays - days;
    },
    nowMonthDays() {//当月天数
      return this.calcDays(this.nowDate.year, this.nowDate.month);
    }
  },
  created() {
    let that = this;
    let jobDate = that.$route.params.jobDate;
    let day = that.$route.params.day;
    if(!jobDate){//如果没有传递日期
      let date = new Date();
      let month = date.getMonth();
       month = month + 1;
      if(month < 10){
        month = "0" + month;
      }
      jobDate = date.getFullYear() + month;
      day = date.getDate();
    }
    let nowMonth = that.nowDate.month + 1;
    let jobMonth = jobDate.substring(jobDate.length-2);
    if (jobMonth[0] == '0') {
      jobMonth = jobMonth.slice(1) - 0;
    }
    if(nowMonth !== jobMonth){
      let jobyear = jobDate.substring(0,4);
      that.nowDate = that.getDate(new Date(jobyear,jobMonth - 1))
    }

    // 获取当前月份日历
    that.getList(jobDate, day);
  },
  methods: {
    getList(jobDate, day){//获取当前月报工日期
      let that = this;
      that.showList = [];
      var p1 = new Promise((resolve, reject) => {
        let data = {  
          "jobDate": jobDate,
          "day": day
        };
        postAction('/project/getJobCalendar', data).then(res => {
          if (res.status === 200) { 
            resolve(res.data.rtnData.list)
          }else{
            reject(res.data.rtnMsg)
          }
        })
      })
      var p2 = new Promise((resolve,reject)=>{
        postAction('/project/getCollection', null).then(res=>{
          if (res.status === 200) { 
            resolve(res.data.rtnData.list)
          }else{
            reject(res.data.rtnMsg)
          }
        })
      })
      Promise.all([p1,p2]).then(res=>{
        let jobClenderList = res[0];
        that.listColumn = jobClenderList[0].listColumn;
        if(that.listColumn > 30){
          that.ifAllowSubmit = true;
        }else{
          that.ifAllowSubmit = false;
        }
        let collectionProjectList = res[1];
        let jobMonth = jobDate.substring(jobDate.length-2);
        let month = new Date().getMonth() + 1;
        let today = new Date().getDate();
        if(month < 10){
            month = "0" + month;
        }
        // 处理展示的列表
        if(jobMonth === month){//当月截取当天之前日历数据
          that.isNowMonth = true;
          let nowDay = new Date().getDate();
          jobClenderList = jobClenderList.slice(0,nowDay)
          // 处理是否是当天
          if(that.listColumn > 30){
            that.ifShowButton = true;
          }else{
            if(day !== today && (day - today) > that.listColumn){
              that.ifShowButton = false;
            }else{ 
              that.ifShowButton = true;
            }
          }
        }else{//非本月处理逻辑
          that.isNowMonth = false;
          if(that.listColumn > 30){
            that.ifShowButton = true
          }else{
            that.ifShowButton = false
          }
        }
        that.showList = jobClenderList;
        that.projectList = collectionProjectList;
        // 处理form表单显示
        that.isShowForm(day);
      }).catch(err => {
        that.$message({
          message: err,
          type: 'warning'
        });
      })
    },
    isShowForm(day){
      let that = this;
      that.isClickDay  = day;
      let today = new Date().getDate();
      if(that.isNowMonth && day > today){//当月
        day = today;
      }
      let item = that.showList[day - 1];
      if(item.holType && item.holType === "1"){//工作日
        that.showForm = true;
        that.form = {
          incode: item.incode,
          appFlag: item.appFlag,
          jobDate: that.nowDateFormat(that.nowDate.year, that.nowDate.month, day),
          groupName: item.groupName,
          xmIncode: item.xmIncode,
          xmbh: item.xmbh,
          xmmc: item.xmmc,
          remark: item.remark,
          state: item.appFlag? ((item.appFlag === 'Y' || item.appFlag === 'F')? 'N': 'Y') : 'Y'
        };
        if(item.appFlag){
          that.projectValue = {
            xmIncode: item.xmIncode,
            xmbh: item.xmbh,
            xmmc: item.xmmc,
            groupName: item.groupName
          }
          that.uchose = {
              xmIncode: item.xmIncode,
              xmbh: item.xmbh,
              xmmc: item.xmmc,
              groupName: item.groupName
         };
        }
      }else{
        this.showForm = false;
      }
    },
    nowDateFormat(year, month, day) {//当天日期YYYY-MM-DD
      let date = new Date(year, month, day);
      month = month + 1;
      if(month < 10){
        month = "0" + month;
      }
      if(day < 10){
        day = "0" + day;
      }
      return date.getFullYear() + "-" + month + "-" + day;
    },
    getDate(date) {
      return {
        year: date.getFullYear(),
        month: date.getMonth(),
        day: date.getDay(),
        date: date.getDate(),
      };
    },
    formatWeek(day) {//排序星期
      switch (day) {
        case 0:
          return "日";
        case 1:
          return "一";
        case 2:
          return "二";
        case 3:
          return "三";
        case 4:
          return "四";
        case 5:
          return "五";
        case 6:
          return "六";
      }
    },
    isLeapYear(year) {//判断闰年
      return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
    },
    calcWeekend(year, month, day) {//根据日子计算星期
      return new Date(year, month, day).getDay();
    },
    calcDays(year, month) {//计算某年某月的天数
      const monthDay = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
      // 是闰年2月返回29天
      if (this.isLeapYear(year) && month === 1) return 29;
      else return monthDay[month];
    },
    //计算上个月天数
    calcLastMonthDays(year, month) {
      if (month === 0) {//1月返回去年12月天数
        return this.calcDays(year - 1, 11);
      } else {
        return this.calcDays(year, month - 1);
      }
    },
    //计算当月开始星期
    startWeek() {
      return this.calcWeekend(this.nowDate.year, this.nowDate.month, 1);
    },
    //点击事件
    handleClick(item) {
      this.isClickDay = item.daySn - 0;
      if(item.holType !== "1"){//非工作日
        this.showForm = false;
        return
      }
      if(this.isNowMonth && !this.ifAllowSubmit){//不允许上个月提交
        let nowDay = new Date().getDate();
        let clickDay = item.daySn - 0;
        if((nowDay - clickDay) < this.listColumn){
          this.ifShowButton = true
        }else{
          this.ifShowButton = false
        }
      }
      this.showForm = true;
      if(item.appFlag){//有报工信息
        this.form.incode = item.incode;
        this.form.groupName = item.groupName;
        this.form.remark = item.remark;
        this.form.xmbh = item.xmbh;
        this.form.xmmc = item.xmmc;
        this.form.xmIncode = item.xmIncode;
        this.form.appFlag = item.appFlag;
        this.form.state = (item.appFlag === 'Y' || item.appFlag === 'F')? 'N': 'Y'
        this.projectValue = {
          xmIncode: item.xmIncode,
          xmbh: item.xmbh,
          xmmc: item.xmmc,
          groupName: item.groupName
        }
        let list = this.projectList;
        let xmIncode = item.xmIncode;
        list.forEach(e => {
          if(e.xmIncode === xmIncode){
            return;
          }
        })
        this.uchose = {
            xmIncode: item.xmIncode,
            xmbh: item.xmbh,
            xmmc: item.xmmc,
            groupName: item.groupName
        };
      }else{
        this.form.appFlag = null;
        this.form.incode = 0;
        this.form.xmIncode = 0,
        this.form.groupName = "";
        this.form.remark = "";
        this.form.xmbh = "";
        this.form.xmmc = "";
        this.form.state = "Y";
        // 清空
        this.projectValue = {
          xmIncode: 0,
          xmbh: "",
          xmmc: "",
          groupName: ""
        }
        this.uchose = {
          xmIncode: 0,
          xmbh: "",
          xmmc: "",
          groupName: ""
        };
      }
      // let date = this.getDate(new Date());
      let month = this.nowDate.month + 1;
      let day = item.daySn;
      if(month < 10){
         month = "0" + month;
      }
      if(day < 10){
        day = "0" + day;
      }
      this.form.jobDate = this.nowDate.year + "-" +month + "-" + day;
    },
    onSubmit(){//提交或修改报工
      let that = this;
      if(that.form.xmIncode === 0){
        that.$message({
          message: "请选择项目编号",
          type: 'warning'
        })
        return
      }
      if(that.form.remark !== null && that.form.remark.length > 100){
        that.$message({
          message: "工作内容简述长度不得超过100",
          type: 'warning'
        })
        return
      }
      const loading = that.$loading({
        lock: true,
        text: '正在提交报工'
      });
      that.isSubmit = true;
      new Promise((resolve, reject) => {
        let data = {
          partyId: 10012,
          incode: that.form.incode,
          xmsbDate: that.form.jobDate,
          groupName: that.form.groupName,
          xmIncode: that.form.xmIncode,
          xmbh: that.form.xmbh,
          xmmc: that.form.xmmc,
          remark: that.form.remark,
        };
        let url = "/project/createJob";
        if(data.incode !== 0){
          url = "/project/alterJob"
        }
        postAction(url, data).then(result => {
          loading.close();
          if (result.status === 200) {
            let type = 'success';
            if(result.data.rtnCode === -1){
              type = 'warning'
            }
            that.$message({
              message: result.data.rtnMsg,
              type: type,
              onClose:()=>{//此处写提示关闭后需要执行的函数
                that.isSubmit = false;
              }
            })
            if(result.data.rtnCode !== -1){
              that.$router.push({name:'Index'})
            }
          } else { 
            that.$message({
              message: result.data.rtnMsg,
              type: 'warning'
            })
          }
        })
      })
    },
    lastClickEvent(e){//上个月
      let nowMonth = new Date().getMonth();
      // let nowDay = new Date().getDate();
      if (this.nowDate.month === 0) {
        return 
      } 
      this.nowDate.month--;
      if(nowMonth === this.nowDate.month){//当前月
        this.isNowMonth = true;
      }else{
        this.isNowMonth = false;
        if(this.ifAllowSubmit){//允许上个月提交
          this.ifShowButton = true
        }else{
          this.ifShowButton = false
        }
      }
      let month = this.nowDate.month;
      month = month + 1;
      if(month < 10){
        month = "0" + month;
      }
      let jobDate = this.nowDate.year + "" + month
      let day = Number(e.target.innerText)
      this.getList(jobDate, day);
    },
    nextClickEvent(e){//下个月
      let nowMonth = new Date().getMonth();
      let day = Number(e.target.innerText);
      if(nowMonth === this.nowDate.month){
        return
      }
      if (this.nowDate.month === 11) {
        this.nowDate.month = 0;
        this.nowDate.year++;
      } else {
        this.nowDate.month++;
      }
      if(nowMonth === this.nowDate.month){
        this.isNowMonth = true;
        this.ifShowButton = true;
        let today = new Date().getDate();
        if(day >= today){
          day = today;
        }
      }else{
        this.isNowMonth = false;
        if(this.ifAllowSubmit){//允许上个月提交
          this.ifShowButton = true
        }else{
          this.ifShowButton = false
        }
      }
      let month = this.nowDate.month;
      month = month + 1;
      if(month < 10){
        month = "0" + month;
      }
      let jobDate = this.nowDate.year + "" + month
      

      this.getList(jobDate, day);
    },
    currentSel(selVal) {
      this.form.xmbh = selVal.xmbh;
      this.form.xmmc = selVal.xmmc;
      this.form.xmIncode = selVal.xmIncode;
      this.form.groupName = selVal.groupName;
    },
    clickToIndex(){//返回首页
      this.$router.push({
        path: '/Index',
        query:{}
      })
    }

效果图

element 日历 周末颜色 elementui节假日日历_List