1. 程式人生 > 程式設計 >vue實現釘釘的考勤日曆

vue實現釘釘的考勤日曆

本文例項為大家分享了vue實現釘釘的考勤日曆的具體程式碼,供大家參考,具體內容如下

直接上效果圖,需要再往下看

vue實現釘釘的考勤日曆

github地址:vue-calendar-component
由於需要對此元件的樣式及功能的擴充套件,直接複製程式碼過來修改,開始貼程式碼,很長很長 慢慢看

checkCalendar.vue(子元件)

<style lang="scss" rel="stylesheet/scss">
    @media screen and (min-width: 460px) {
        .wh_item_date:hover {
            background: #71c7a5;
            cursor: pointer;
        }
    }

    * {
        margin: 0;
        padding: 0;
    }

    .wh_container {
        max-width: 410px;
        margin: auto;
    }

    li {
        list-style-type: none;
    }

    .wh_top_title {
        display: flex;
    }

    .wh_top_title li {
        cursor: pointer;
        display: flex;
        color: #fff;
        font-size: 18px;
        flex: 1;
        justify-content: center;
        align-items: center;
        height: 47px;
    }

    .wh_top_title .wh_content_li {
        cursor: auto;
        flex: 2.5;
        color: black;
    }

    .wh_content_all {
        font-family: -apple-system,BlinkMacSystemFont,"PingFang SC","Helvetica Neue",STHeiti,"Microsoft Yahei",Tahoma,Simsun,sans-serif;
        background-color: white;
        width: 100%;
        overflow: hidden;
        padding-bottom: 8px;
    }

    .wh_content {
        display: flex;
        flex-wrap: wrap;
        padding: 0 3% 0 3%;
        width: 100%;
    }

    .wh_content:first-child .wh_content_item_tag,.wh_content:first-child .wh_content_item {
        color: #ddd;
        font-size: 16px;
    }

    .wh_content_item,wh_content_item_tag {
        font-size: 15px;
        width: 13.4%;
        text-align: center;
        color: #fff;
        position: relative;
    }

    .wh_content_item {
        height: 40px;
    }

    .wh_top_tag {
        width: 40px;
        height: 40px;
        line-height: 40px;
        margin: auto;
        display: flex;
        justify-content: center;
        align-items: center;
        color: black;
    }

    .wh_item_date {
        width: 30px;
        height: 30px;
        line-height: 30px;
        margin: auto;
        display: flex;
        justify-content: center;
        align-items: center;
        color: black;

        .smallDot {
            background-color: #f99341;
            width: 5px;
            height: 5px;
            border-radius: 50%;
            text-align: center;
            margin-left: 13px;
        }

        .smallDot1 {
            background-color: #1989fa;
            width: 5px;
            height: 5px;
            border-radius: 50%;
            text-align: center;
            margin-left: 13px;
        }
    }

    .wh_left {
        width: 12px;
        height: 12px;
        border-top: 2px solid #ffffff;
        border-left: 2px solid #ffffff;
        transform: rotate(-45deg);
        border-color: black;
    }

    .wh_left:active,.wh_right:active {
        border-color: #ddd;
    }

    .wh_right {
        width: 12px;
        height: 12px;
        border-top: 2px solid #ffffff;
        border-right: 2px solid #ffffff;
        transform: rotate(45deg);
        border-color: black;
    }

    .wh_content_item > .wh_isMark {
        margin: auto;
        border-radius: 50%;
        background: blue;
        z-index: 2;
    }

    .wh_content_item .wh_other_dayHide {
        color: #bfbfbf;
    }

    .wh_content_item .wh_want_dayHide {
        color: #bfbfbf;
    }

    .wh_content_item .wh_isToday {
        background: #77adfa;
        border-radius: 50%;
    }

    .wh_content_item .wh_chose_day {
        background: #1989fa;
        border-radius: 50%;
    }
</style>

<template>
    <section class="wh_container">
        <div class="wh_content_all">
            <div class="wh_top_title">
                <li @click="PreMonth(myDate,false)">
                    <div class="wh_left"></div>
                </li>
                <li class="wh_content_li">{{dateTop}}</li>
                <li @click="NextMonth(myDate,false)">
                    <div class="wh_right"></div>
                </li>
            </div>
            <div class="wh_content">
                <div class="wh_content_item" v-for="tag in textTop">
                    <div class="wh_top_tag">{{tag}}</div>
                </div>
            </div>
            <div class="wh_content">
                <div class="wh_content_item" v-for="(item,index) in list" @click="clickDay(item,index)">
                    <div class="wh_item_date" style="display: block"
                         v-bind:class="[{ wh_isMark: item.isMark},{wh_other_dayHide:item.otherMonth!=='nowMonth'},{wh_want_dayHide:item.dayHide},{wh_isToday:item.isToday},{wh_chose_day:item.chooseDay},setClass(item)]">
                        {{item.id}}
                        <!--這裡是控制異常、正常的那個小圓點-->
                        <span v-for="(date,index) in dateList" :key="index">
                            <span v-if="date.offDutyTime&&date.onDutyTime&&formatDate(date.recordDate)==item.date&&(isLate(date.serverEndTime,date.offDutyTime)||isLate(date.onDutyTime,date.serverStartTime))">
                                    <div class="smallDot"></div>
                            </span>
                            <span v-if="date.offDutyTime&&date.onDutyTime&&formatDate(date.recordDate)==item.date&&!isLate(date.serverEndTime,date.offDutyTime)&&!isLate(date.onDutyTime,date.serverStartTime)">
                                <div class="smallDot1"></div>
                            </span>
                        </span>
                    </div>
                </div>
            </div>
        </div>
    </section>
</template>

<script>
    import timeUtil from "./calendar";

    export default {
        data() {
            return {
                myDate: [],list: [],historyChose: [],dateTop: "",loginNannyUser: {},loginGzhUser: {},dateList: []
            };
        },props: {
            markDate: {
                type: Array,default: () => []
            },markDateMore: {
                type: Array,textTop: {
                type: Array,default: () => ["一","二","三","四","五","六","日"]
            },sundayStart: {
                type: Boolean,default: () => false
            },agoDayHide: {
                type: String,default: `0`
            },futureDayHide: {
                type: String,default: `2554387200`
            },joinWishId: {
                default: null
            }
        },created() {
            let $this = this;
            this.getLoginAllUser("nannyhttp://www.cppcns.com
",{},function () {//這裡只是我這邊的業務,刪除就行 }); this.intStart();//初始化資料 this.myDate = new Date(); },methods: { isLate(str,str1) {//判斷兩個時分秒大小 return new Date((this.formatDates(new Date()) + " " + str).replace(/-/g,'/')) > new Date((this.formatDates(new Date()) + " " + str1).replace(/-/g,'/')); },formatDate(date) { date = typeof date === 'string' ? new Date(date.replace(/\-/g,'/')) : date; return date.getFullYear() + '/' + (date.getMonth() + 1) + '/' + date.getDate(); },intStart() { timeUtil.sundayStart = this.sundayStart; },setClass(data) { let obj = {}; obj[data.markClassN
程式設計客棧
ame] = data.markClassName; return obj; },clickDay(item,index) { if (item.otherMonth === "nowMonth" && !item.dayHide) { this.getList(this.myDate,item.date); } if (item.otherMonth !== "nowMonth") { item.otherMonth === "preMonth" ? this.PreMonth(item.date) : this.NextMonth(item.date); } },ChoseMonth(date,isSelectedDay = true) { date = timeUtil.dateFormat(date); this.myDate = new Date(date); this.$emit("changeMonth",timeUtil.dateFormat(this.myDate)); if (isSelectedDay) { this.getList(this.myDate,date,isSelectedDay); } else { th
程式設計客棧
is.getList(this.myDate); } },PreMonth(date,isSelectedDay = true) { date = timeUtil.dateFormat(date); this.myDate = timeUtil.getOtherMonth(this.myDate,"preMonth"); this.$emit("changeMonth",timeUtil.dateFormat(this.myDate)); this.axiosPost("/nannyCheckIn/findMonthList.n",{date: this.myDate,joinWishListId: this.joinWishId,},function (resData) { this.dateList = resData.list; }); if (isSelectedDay) { this.getList(this.myDate,isSelectedDay); } else { this.getList(this.myDate); } },NextMonth(date,"nextMonth"); this.$emit("changeMonth",forMatArgs() { let markDate = this.markDate; let markDateMore = this.markDateMore; markDate = markDate.map(k => { return timeUtil.dateFormat(k); }); markDateMore = markDateMore.map(k => { k.date = timeUtil.dateFormat(k.date); return k; }); return [markDate,markDateMore]; },getList(date,chooseDay,isSelectedDay = true) { const [markDate,markDateMore] = this.forMatArgs(); this.dateTop = `${date.getFullYear()}年${date.getMonth() + 1}月`; let arr = timeUtil.getMonthList(this.myDate); for (let i = 0; i < arr.length; i++) { let markClassName = ""; let k = arr[i]; k.chooseDay = false; const nowTime = k.date; const t = new Date(nowTime).getTime() / 1000; //看每一天的class for (const c of markDateMore) { if (c.date === nowTime) { markClassName = c.className || ""; } } //標記選中某些天 設定class k.markClassName = markClassName; k.isMark = markDate.indexOf(nowTime) > -1; //無法選中某天 k.dayHide = t < this.agoDayHide || t > this.futureDayHide; if (k.isToday) { this.$emit("isToday",nowTime); } let flag = !k.dayHide && k.otherMonth === "nowMonth"; if (chooseDay && chooseDay === nowTime && flag) { this.$emit("choseDay",nowTime); this.historyChose.push(nowTime); k.chooseDay = true; } else if ( this.historyChose[this.historyChose.length - 1] === nowTime && !chooseDay && flag ) { k.chooseDay = true; } } this.list = arr; } },mounted() { this.getList(this.myDate); this.axiosPost("/nannyCheckIn/findMonthList.n",{//業務,根據自己需要修改 joinWishListId: this.joinWishId,function (resData) { this.dateList = resData.list; }); },watch: { markDate: { handler(val,oldVal) { this.getList(this.myDate); },deep: true },markDateMore: { handler(val,agoDayHide: { handler(val,futureDayHide: { handler(val,oldVal) { http://www.cppcns.com this.getList(this.myDate); },sundayStart: { handler(val,oldVal) { this.intStart(); this.getList(this.myDate); },joinWishId: {//監聽這個是因為要切換工單,換資料 handler(val,oldVal) { this.axiosPost("/nannyCheckIn/findMonthList.n",{ joinWishListId: val,function (resData) { this.dateList = resData.list; }); },deep: true } } }; </script>

calendar.js(日期工具類)

export default {
  // 當某月的天數
  getDaysInOneMonth(date) {
    const year = date.getFullYear();
    const month = date.getMonth() + 1;
    const d = new Date(year,month,0);
    return d.getDate();
  },// 向前空幾個
  getMonthweek(date) {
    const year = date.getFullYear();
    const month = date.getMonth() + 1;
    const dateFirstOne = new Date(year + '/' + month + '/1');
    return this.sundayStart ?
      dateFirstOne.getDay() == 0 ? 7 : dateFirstOne.getDay() :
      dateFirstOne.getDay() == 0 ? 6 : dateFirstOne.getDay() - 1;
  },/**
   * 獲取當前日期上個月或者下個月
   */
  getOtherMonth(date,str = 'nextMonth') {
    const timeArray = this.dateFormat(date).split('/');
    const year = timeArray[0];
    const month = timeArray[1];
    const day = timeArray[2];
    let year2 = year;
    let month2;
    if (str === 'nextMonth') {
      month2 = parseInt(month) + 1;
      if (month2 == 13) {
        year2 = parseInt(year2) + 1;
        month2 = 1;
      }
    } else {
      month2 = parseInt(month) - 1;
      if (month2 == 0) {
        year2 = parseInt(year2) - 1;
        month2 = 12;
      }
    }
    let day2 = day;
    const days2 = new Date(year2,month2,0).getDate();
    if (day2 > days2) {
      day2 = days2;
    }
    if (month2 < 10) {
      month2 = '0' + month2;
    }
    if (day2 < 10) {
      day2 = '0' + day2;
    }
    const t2 = year2 + '/' + month2 + '/' + day2;
    return new Date(t2);
  },// 上個月末尾的一些日期
  getLeftArr(date) {
    const arr = [];
    const leftNum = this.getMonthweek(date);
    const num = this.getDaysInOneMonth(this.getOtherMonth(date,'preMonth')) - leftNum + 1;
    const preDate = this.getOtherMonth(date,'preMonth');
    // 上個月多少開始
    for (let i = 0; i < leftNum; i++) {
      const nowTime = preDate.getFullYear() + '/' + (preDate.getMonth() + 1) + '/' + (num + i);
      arr.push({
        id: num + i,date: nowTime,isToday: false,otherMonth: 'preMonth',});
    }
    return arr;
  },// 下個月末尾的一些日期
  getRightArr(date) {
    const arr = [];
    const nextDate = this.getOtherMonth(date,'nextMonth');
    const leftLength = this.getDaysInOneMonth(date) + this.getMonthweek(date);
    const _length = 7 - leftLength % 7;
    for (let i = 0; i < _length; i++) {
      const nowTime = nextDate.getFullYear() + '/' + (nextDate.getMonth() + 1) + '/' + (i + 1);
      arr.push({
        id: i + 1,otherMonth: 'nextMonth',// format日期
  dateFormat(date) {
    date = typeof date === 'string' ? new Date(date.replace(/\-/g,'www.cppcns.com/')) : date;
    return date.getFullYear() + '/' + (date.getMonth() + 1) + '/'
      + date.getDate();
  },// 獲取某月的列表不包括上月和下月
  getMonthListNoOther(date) {
    const arr = [];
    const num = this.getDaysInOneMonth(date);
    const year = date.getFullYear();
    const month = date.getMonth() + 1;
    const toDay = this.dateFormat(new Date());

    for (let i = 0; i < num; i++) {
      const nowTime = year + '/' + month + '/' + (i + 1);
      arr.push({
        id: i + 1,isToday: toDay === nowTime,otherMonth: 'nowMonth',// 獲取某月的列表 用於渲染
  getMonthList(date) {
    return [ ...this.getLeftArr(date),...this.getMonthListNoOther(date),...this.getRightArr(date) ];
  },// 預設是週一開始
  sundayStart: false,};

然後引入到元件中

import nCalendar from './checkCalendar'

export default (Vue) => {
    Vue.component("nCalendar",nCalendar);
}

然後應用在頁面中

<style lang="scss" rel="stylesheet/scss">
    .nCalender {

        .detailDiv {
            margin: 20px 0;

            .imgDiv {
                img {
                    width: 60px;
                    height: 60px;
                }
            }

            .hourDiv {
                background-color: white;
                padding-top: 10px;

                .clockStyle {
                    font-size: 16px;
                    color: #4b90ed;
                }

                .hourText {
                    font-size: 14px;
                    margin-left: 5px;
                }
            }

            .stepDiv {
                .tagDiv {
                    margin-top: 10px;
                }
            }
        }
    }
</style>
<template>
    <div class="nCalender">
        <navBar
                :showLeft="true"
                :borderLine=true
                background="#f2f2f2"
                title="考勤日曆">
            <div @click="$router.push('/h5nAddCard')" slot="right">補卡</div>
        </navBar>
        <van-field label="選擇工單" v-if="list.length>1"
                   :value="obj1!=null&&obj1.joinWishId!=null?obj1.joinWishId:null">
            <selectJoinTemp slot="input" name="joinWishId" name1="auditUserId"
                            v-model="obj1" :isDefault="true"/>
        </van-field>
        <!--日曆-->
        <div class="CalendarDiv" v-if="obj1&&obj1.joinWishId&&obj1.joinWishId>0">
            <nCalendar
                    :joinWishId="obj1.joinWishId"
                    v-on:choseDay="clickDay"
                    v-on:changeMonth="changeDate"/>
        </div>

        <div v-if="list.length==0" class="detailDiv" style="text-align: center;color: #bfbfbf">
            <div class="imgDiv">
                <img src="../img/rest.png"/>
            </div>
            <div style="margin-top: 2%">
                無合同
            </div>
        </div>
        <!--當日詳情-->
        <span></span>
        <div class="detailDiv"
             v-if="obj!=null&&obj.id>0&&obj.recordDate&&new Date(obj.recordDate.replace(/-/g,'/'))<new Date()">
            <div class="hourDiv">
                <van-row>
                    <van-col offset="1">
                        <van-icon name="clock" class="clockStyle"/>
                    </van-col>
                    <van-col class="hourText">工時共計:<span v-if="obj.totalHour!=null">{{obj.totalHour}}小時</span>
                        <span v-else>暫無</span></van-col>
                </van-row>
            </div>
            <div class="stepDiv">
                <van-steps direction="vertical" :active="-1">
                    <van-step>
                        <div>
                            簽到時間&nbsp;
                            <span v-if="obj.onDutyTime">{{formatMinutes(obj.onDutyTime)}}</span>
                            <span v-else>暫無</span>(上班時間:{{formatMinutes(obj.serverStartTime)}})
                        </div>
                        <div class="tagDiv">
                            <van-tag v-if="obj.onDutyTime&&!isLate(obj.onDutyTime,obj.serverStartTime)" round
                                     type="primary">正常
                            </van-tag>
                            <van-tag v-else round
                                     type="warning">遲到
                            </van-tag>
                        </div>
                    </van-step>
                    <van-step>
                        <div>
                            簽退時間&nbsp;
                            <span v-if="obj.offDutyTime">{{formatMinutes(obj.offDutyTime)}}</span>
                            <span v-else>暫無</span>(下班時間:{{formatMinutes(obj.serverEndTime)}})
                        </div>
                        <div class="tagDiv">
                            <van-tag v-if="obj.offDutyTime&&isLate(obj.serverEndTime,obj.offDutyTime)" round
                                     type="warning">早退
                            </van-tag>
                            <van-tag v-if="obj.offDutyTime&&!isLate(obj.serverEndTime,obj.offDutyTime)" round
                                     type="primary">正常
                            </van-tag>
                        </div>
                    </van-step>
                </van-steps>
            </div>

        </div>
        <div v-if="obj!=null&&obj.id>0&&!obj.offDutyTime&&!obj.onDutyTime" class="detailDiv"
             style="text-align: center;color: #bfbfbf">
            <div class="imgDiv">
                <img src="../img/rest.png"/>
            </div>
            <div style="margin-top: 2%">
                當天無打卡記錄
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        name: "nCalender",data() {
            return {
                loginNannyUser: {},obj: {},obj1: {},dateTemp: null
            }
        },clickDay(data) {//選中某天
                this.dateTemp = data
                this.axiosPost("/nannyCheckIn/findNowRecord.n",{
                    queryDate: data,id: this.obj1.joinWishId
                },function (resData) {
                    this.obj = resData.obj;
                });
            },changeDate(data) {//左右點選切換月份
                console.log(data);
            },mounted() {

        },created() {
            let $this = this;
            this.getLoginAllUser("nanny",function () {
                $this.axiosPost("/joinWishList/findNannyCon.n",function (resData) {
                    $this.list = resData.list;
                    if (resData.list != null && resData.list.length != 0) {
                        $this.$set($this.obj1,"joinWishId",resData.list[0].id);
                    }
                    $this.axiosPost("/nannyCheckIn/findNowRecord.n",{id: $this.obj1.joinWishId},function (resData) {
                        $this.obj = resData.obj;
                    });
                });
            });
        },watch: {
            "obj1.joinWishId": {
                handler(newObj,oldObj) {
                    if (newObj != oldObj && newObj && newObj != null) {
                        this.axiosPost("/nannyCheckIn/findNowRecord.n",{
                            queryDate: this.dateTemp,id: newObj
                        },function (resData) {
                            this.obj = resData.obj;
                        });
                    }
                },}

    }
</script>

差不多就是以上程式碼,直接複製了用,改一下ajax請求就行,需要擴充套件的就自己修改了。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。