vue实现日历功能

父组件

<template>
  <div class="dateSet">
    <div class="tabs-list">
      <el-tabs type="card" v-model="tabPosition" :before-leave="confirmLeave">
        <el-tab-pane
          v-for="(year, index) in tabs"
          :label="year.name"
          :name="year.name"
        ></el-tab-pane>
      </el-tabs>
    </div>

    <div class="month" v-loading="!showMonth">
      <div class="tips">
        <div class="box"></div>
        <div class="title">红色块表示节假日</div>
        <el-button class="holiday" @click="selectHoliday"
          >一健选择周六日</el-button
        >
      </div>
      <div class="content" v-for="(ym, index) in yearMonth">
        <the-month
          v-if="showMonth"
          ref="month"
          :yearMonth="ym"
          :key="index"
          :holidaySetting="holidaySetting"
        >
        </the-month>
      </div>
    </div>
    <div class="btn-list">
      <el-button class="save" type="primary" @click="save">保存</el-button>
    </div>
  </div>
</template>

<script>
import { holidaySettingService_addHolidaySetting } from "apis/wtzg/business/services/HolidaySettingServiceAPI";
import { busiHolidaySetting_fetchAll } from "apis/wtzg/business/publicschema/BusiHolidaySettingAPI";

export default {
  name: "dateSet",
  data() {
    return {
      yearMonth: [],
      tabs: [],
      currYear: "",
      tabPosition: "",
      holidaySetting: [],
      showMonth: false,
      isSelect: true
    };
  },
  watch: {
    currYear(val) {
      this.setYearMonth();
    }
  },
  computed: {
    isPrimary() {
      return isActive => {
        return isActive ? "primary" : "default";
      };
    },

    isActive(item) {
      return item.active;
    }
  },
  mounted() {
    this.initYearMonth();
    this.getHolidaySetting();
  },
  methods: {
    // 获取节假日
    async getHolidaySetting() {
      this.showMonth = false;
      const { code, content } = await this.$to(busiHolidaySetting_fetchAll());
      if (code == 200) {
        this.holidaySetting = content;
        this.showMonth = true;
      }
    },

    // 保存节假日
    async save() {
      let params = this.getParams();
      if (!params.length) return this.$showMessage("请选择非工作日", "warning");
      this.showMonth = false;
      const { code } = await this.$to(
        holidaySettingService_addHolidaySetting(params)
      );
      if (code == 200) {
        this.$showMessage("保存成功");
        this.getHolidaySetting();
        this.showMonth = true;
      }
    },

    selectHoliday() {
      let month = this.$refs.month;
      let refLeg = month.length;
      for (let i = 0; i < refLeg; i++) {
        month[i].todayArr.forEach(item => {
          if (["00", "06"].includes(item.day)) {
            item.isActive = this.isSelect;
          }
        });
      }
      this.isSelect = !this.isSelect;
    },

    getParams() {
      let month = this.$refs.month;
      let refLeg = month.length;
      let arr = [],
        params = [];
      for (let i = 0; i < refLeg; i++) {
        arr.push(month[i].getNonworkdays());
      }
      arr = arr.flat();
      arr.forEach(date => {
        params.push({
          date,
          year: this.currYear.toString()
        });
      });
      return params;
    },

    initYearMonth() {
      let today = new Date();
      this.currYear = today.getFullYear();
      this.settabs();
    },

    settabs() {
      this.tabs = [];
      for (let i = 0; i < 2; i++) {
        this.tabs.push({
          name: parseInt(this.currYear) + i + "年"
        });
      }
      this.tabPosition = this.tabs[0].name;
    },

    setYearMonth() {
      this.yearMonth = [];
      for (let i = 1; i <= 12; i++) {
        this.yearMonth.push(`${this.currYear}-${i}`);
      }
    },

    async confirmLeave(active, old) {
      if (!old) return;
      await this.$confirm("请确认您已保存当前页面数据, 是否继续跳转?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
      })
        .then(() => {
          this.currYear = parseInt(active);
          return true;
        })
        .catch(() => {
          return reject();
        });
    }
  }
};
</script>

<style lang="less" scoped>
.dateSet {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  padding-bottom: 50px;
  background: white;
  .tabs-list {
    display: flex;
    justify-content: center;
    padding: 20px 0 10px 0;
  }

  .month {
    position: relative;
    display: flex;
    justify-content: space-around;
    flex-wrap: wrap;
    width: 100%;
    max-width: 1100px;
    .tips {
      display: flex;
      justify-content: flex-end;
      align-items: center;
      margin-right: 30px;
      margin-bottom: 20px;
      width: 100%;
      .box {
        width: 20px;
        height: 20px;
        background: #ed646f;
        margin-right: 10px;
      }
      .title {
        font-size: 14px;
      }
      .holiday {
        margin-left: 10px;
      }
    }
    .content {
    }
  }
  .btn-list {
    display: flex;
    justify-content: flex-end;
    position: sticky;
    bottom: 0;
    left: 0;
    right: 0;
    width: 100%;
    padding: 20px 0;
    background: rgba(255, 255, 255, 0.6);
    .save {
      margin-right: 20px;
    }
  }
}
</style>

子组件

<template>
  <div class="theMonth">
    <div class="month">{{ month }}</div>
    <div class="week">
      <div
        class="week-item"
        v-for="(week, index) in weekArr"
        :key="index"
        :class="{ redColor: isRed(week) }"
      >
        {{ week }}
      </div>
    </div>
    <div class="day">
      <div
        class="day-item"
        v-for="(today, index) in todayArr"
        :title="getYMD(today)"
        :class="[
          {
            redColor: isRed(today.day),
            active: today.isActive,
            text: hasText(today.date)
          }
        ]"
        :key="index"
        @click="selectToday(today.date)"
      >
        {{ today.date }}
      </div>
    </div>
  </div>
</template>

<script>
import { month } from "@/common/localDict";
export default {
  name: "theMonth",
  props: {
    yearMonth: {
      type: String,
      default: ""
    },
    holidaySetting: {
      type: Array,
      default: () => {
        return [];
      }
    }
  },
  data() {
    return {
      todayArr: [],
      newTodayArr: [],
      weekArr: ["一", "二", "三", "四", "五", "六", "日"],
      nonworkdays: []
    };
  },
  watch: {
    yearMonth() {
      this.initDate();
    },
    holidaySetting() {
      this.initDate();
    }
  },
  computed: {
    month() {
      let m = this.yearMonth.split("-")[1].padStart(2, "0");
      return month[m];
    },

    isRed() {
      return week => {
        return ["六", "日", "6", "0"].includes(week.toString());
      };
    },

    getYMD() {
      return today => {
        return `${today.year}${today.month}${today.date}`;
      };
    },

    hasText() {
      return day => {
        return day != "";
      };
    }
  },
  mounted() {
    this.initDate();
  },
  methods: {
    // 选择非工作日
    selectToday(date) {
      if (!date) return;
      this.nonworkdays = [];
      this.todayArr.forEach(item => {
        if (item.date === date) item.isActive = !item.isActive;
      });
    },

    initDate() {
      // 获取当月的日期数量
      let currMonthMax = this.getCountDays();
      // 将当前年、月、日、周 存储于数据
      this.getTodayArr(currMonthMax);
      // 计算需要补充的空格(即第几天开始)
      this.unshiftEmpty();
      // 回显选择数据
      this.recoverSelectData();
    },

    getTodayArr(currMonthMax) {
      this.todayArr = [];
      for (let i = 1; i < currMonthMax + 1; i++) {
        let today = new Date(`${this.yearMonth}-${i}`),
          isActive = ["0", "6"].includes(today.getDay().toString()),
          date = this.setPadStart(today.getDate()),
          day = this.setPadStart(today.getDay()),
          month = this.setPadStart(today.getMonth() + 1),
          year = today.getFullYear(),
          ymdd = {
            year,
            month,
            date,
            day,
            ymd: `${year}-${month}-${date}`,
            isActive
          };
        this.todayArr.push(ymdd);
      }
    },

    setPadStart(today) {
      return today.toString().padStart(2, "0");
    },

    unshiftEmpty() {
      let day = this.todayArr[0].day == 0 ? 7 : this.todayArr[0].day;
      let emptyLength = 7 - (7 - parseInt(day) + 1);
      for (let i = 0; i < emptyLength; i++) {
        this.todayArr.unshift({ year: "", month: "", date: "", day: "" });
      }
    },

    recoverSelectData() {
      if (!this.holidaySetting.length) return;
      let holidayArr = this.holidaySetting.map(item => {
        return item.date.split(" ")[0];
      });
      this.todayArr.forEach(item => (item.isActive = false));
      this.todayArr.forEach(item => {
        if (holidayArr.includes(item.ymd)) {
          item.isActive = true;
        }
      });
    },

    getNonworkdays() {
      this.todayArr.forEach(item => {
        item.isActive
          ? this.nonworkdays.push(
              `${item.year}-${item.month}-${item.date} 00:00:00`
            )
          : "";
      });
      return this.nonworkdays;
    },

    getCountDays() {
      var curDate = new Date(this.yearMonth);
      var curMonth = curDate.getMonth();
      curDate.setMonth(curMonth + 1);
      curDate.setDate(0);
      return curDate.getDate();
    }
  }
};
</script>

<style lang="less" scoped>
@redColor: #ed646f;
.theMonth {
  width: 218px !important;
  height: 260px;
  display: flex;
  flex-direction: column;
  color: #333;
  font-size: 13px;
  padding: 0 10px;
  .month {
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 20px;
    font-weight: bold;
    padding: 8px 0;
  }
  .week {
    .week-item {
      float: left;
      width: 15px;
      text-align: center;
      padding: 5px 6px;
      margin-right: 4px;
      background: #dbdbdc;
    }
  }
  .day {
    .day-item {
      float: left;
      width: 15px;
      padding: 5px 6px;
      text-align: center;
      margin-right: 4px;
      margin-top: 4px;
      cursor: pointer;
      user-select: none;
    }
    .text:hover {
      color: #fff;
      background: #999;
    }
    .text:active {
      color: #666;
    }
    .active {
      color: #fff;
      background: @redColor !important;
    }
  }
  .redColor {
    color: @redColor;
  }
}
</style>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值