直接上效果图,需要再往下看
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,
default: () => []
},
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("nanny", {}, 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.markClassName] = 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 {
this.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, date, isSelectedDay);
} else {
this.getList(this.myDate);
}
},
NextMonth(date, isSelectedDay = true) {
date = timeUtil.dateFormat(date);
this.myDate = timeUtil.getOtherMonth(this.myDate, "nextMonth");
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, date, isSelectedDay);
} else {
this.getList(this.myDate);
}
},
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, oldVal) {
this.getList(this.myDate);
},
deep: true
},
agoDayHide: {
handler(val, oldVal) {
this.getList(this.myDate);
},
deep: true
},
futureDayHide: {
handler(val, oldVal) {
this.getList(this.myDate);
},
deep: true
},
sundayStart: {
handler(val, oldVal) {
this.intStart();
this.getList(this.myDate);
},
deep: true
},
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,
date: nowTime,
isToday: false,
otherMonth: 'nextMonth',
});
}
return arr;
},
// format日期
dateFormat(date) {
date = typeof date === 'string' ? new Date(date.replace(/\-/g, '/')) : 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,
date: nowTime,
isToday: toDay === nowTime,
otherMonth: 'nowMonth',
});
}
return arr;
},
// 获取某月的列表 用于渲染
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,'/'))>
<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>
签到时间
<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>
签退时间
<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: {},
loginGzhUser: {},
obj: {},
obj1: {},
list: [],
dateTemp: null
}
},
methods: {
isLate(str, str1) {//判断两个时分秒大小
return new Date((this.formatDates(new Date()) + " " + str).replace(/-/g, '/')) > new Date((this.formatDates(new Date()) + " " + str1).replace(/-/g, '/'));
},
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;
});
}
},
deep: true
},
}
}
</script>
差不多就是以上代码,直接复制了用,改一下ajax请求就行,需要扩展的就自己修改了[抱拳]