index--切换打卡和统计页面的tab
<template>
<div>
<van-tabbar v-model="active">
<van-tabbar-item :active="0">打卡</van-tabbar-item>
<van-tabbar-item :active="1">统计</van-tabbar-item>
</van-tabbar>
<check v-if="active == 0"></check>
<record v-if="active == 1"></record>
</div>
</template>
<script>
import { Tabbar, TabbarItem } from 'vant';
import check from './check.vue';
import record from './record.vue';
export default {
name: 'clock',
components: {
[Tabbar.name]: Tabbar,
[TabbarItem.name]: TabbarItem,
check,
record
},
data() {
return {
active: 0
};
},
mounted() {},
methods: {}
};
</script>
<style></style>
check--打卡页面,打卡页面设有更新打卡功能,只在下班打卡时才有,上班打卡取最早一次打卡所以不用更新打卡,下班打卡取最晚一次打卡
<template>
<div class="main">
<div class="maintop">
<div class="user">
<img class="user-icon" :src="loginInfo.userIcon" alt="" />
<div>{{ loginInfo.userNickName }}</div>
</div>
<div>{{ today }}</div>
</div>
<div class="tip">打卡记录时间和位置</div>
<!-- 打卡时间 -->
<div class="checktime">
<van-steps direction="vertical" :active="active" active-color="#3791F9">
<van-step class="clock-in" :active="0">
<div v-if="clockInfo.startTime">
<h3>上班时间{{ clockInfo.startTime | fmtTime }}</h3>
<p><van-icon name="location" color="#999" />{{ clockInfo.startPlace }}</p>
</div>
<div v-else>
<h3>上班打卡{{ clockTime }}</h3>
<p v-if="list[0].place"><van-icon name="location" color="#999" />{{ list[0].place }}</p>
</div>
</van-step>
<van-step class="clock-out" :active="1" v-if="active == 1">
<div v-if="clockInfo.endTime">
<h3>下班时间{{ clockInfo.endTime | fmtTime }}</h3>
<p><van-icon name="location" color="#999" />{{ clockInfo.endPlace }}</p>
<div @click="updateclock">更新打卡></div>
</div>
<div v-else>
<h3>下班打卡{{ clockTime }}</h3>
<p v-if="list[1].place"><van-icon name="location" color="#999" />{{ list[1].place }}</p>
</div>
</van-step>
</van-steps>
</div>
<!-- 打卡按钮 -->
<div v-show="this.btnshow">
<div class="check-container">
<div class="checkbtn">
<div class="btn-content" @click="daka">
<div>{{ active == 0 ? '上班打卡' : '下班打卡' }}</div>
<div>{{ showTime }}</div>
</div>
</div>
</div>
</div>
<!-- 打卡成功弹窗 -->
<van-dialog v-model="show" @confirm="handlesure">
<div class="success">
<img src="../../../../assets/img/img_daka@2x.png" style="width: 160px;height: 105px;" />
<div class="successTime">{{ clockTime }}</div>
<div class="successType">{{ active == 0 ? '上班' : '下班' }}打卡成功</div>
</div>
</van-dialog>
</div>
</template>
<script>
import { Step, Steps, Icon, Dialog } from 'vant';
import AMapLoader from '@amap/amap-jsapi-loader';
export default {
components: {
[Step.name]: Step,
[Steps.name]: Steps,
[Icon.name]: Icon,
[Dialog.name]: Dialog
},
data() {
return {
loginInfo: {
userIcon: '', // 用户头像路径
userNickName: '' // 用户昵称
},
today: '',
t: null,
showTime: '',
active: 0,
clockin: {},
clockout: {},
btnshow: true,
date: '',
clockInfo: {},
list: [
{
place: ''
},
{
place: ''
}
],
clockType: '',
show: false,
clockTime: ''
};
},
methods: {
getCurrentDate() {
let now = new Date();
let year = now.getFullYear();
let month = now.getMonth() + 1;
let day = now.getDate();
let h = now.getHours();
let m = now.getMinutes();
let s = now.getSeconds();
this.date = Date.parse(year + '-' + month + '-' + day + ' ' + h + ':' + m + ':' + s);
this.today = year + '-' + month + '-' + day;
},
time() {
clearTimeout(this.t); //清除定时器
var dt = new Date();
var h = this.addZero(dt.getHours()); //获取时,并补全零
var m = this.addZero(dt.getMinutes()); //获取分,并补全零
var s = this.addZero(dt.getSeconds()); //获取秒,并补全零
this.showTime = h + ':' + m + ':' + s;
this.t = setTimeout(() => this.time(), 1000); //设定定时器,循环运行
},
// 时分秒补全零
addZero(i) {
if (i < 10) {
i = '0' + i;
}
return i;
},
// 初始化获取数据
getclockInfo() {
this.$loading();
this.request('queryInfo', { startTime: this.date }).then(res => {
this.clockInfo = res;
if (this.clockInfo.startTime && this.clockInfo.endTime) {
this.btnshow = false;
this.active = 1;
} else {
this.btnshow = true;
if (this.clockInfo.startTime) {
this.active = 1;
}
}
}).finally(()=>{
this.$loading().close();
});
},
daka() {
AMapLoader.reset();
AMapLoader.load({
key: process.env.VUE_APP_AMPKEY,
version: '2.0',
plugins: ['AMap.AutoComplete', 'AMap.CitySearch', 'AMap.Geolocation', 'AMap.Geocoder']
}).then(AMap => {
const geocoder = new AMap.Geocoder();
const geolocation = new AMap.Geolocation({
enableHighAccuracy: true,
timeout: 10000
});
this.$loading();
geolocation.getCurrentPosition((status, res) => {
if (status === 'complete') {
const dt = new Date();
this.clockTime =
this.addZero(dt.getHours()) + ':' + this.addZero(dt.getMinutes()) + ':' + this.addZero(dt.getSeconds());
const position = res.position;
const lnglat = [position.lng, position.lat];
geocoder.getAddress(lnglat, (geoStatus, result) => {
if (geoStatus === 'complete' && result.info === 'OK') {
this.$loading().close();
if (this.clockType == 1) {
this.list[0].place = result.regeocode.formattedAddress;
this.show = true;
} else {
this.list[1].place = result.regeocode.formattedAddress;
}
}
});
} else {
this.$loading().close();
this.$toast.fail('获取位置失败,请打开手机定位功能');
}
});
});
},
handlesure() {
this.show = false;
this.clockIn();
},
clockIn() {
// 将打卡信息提交到接口
const params = {
clockType: this.clockInfo.startTime ? 2 : 1,
place: this.clockType == 1 ? this.list[0].place : this.list[1].place,
dateTime: this.date,
userId: this.loginInfo.userId
};
this.request('insert', params).then(() => {
this.getclockInfo();
});
},
// 更新打卡
updateclock() {
Dialog.confirm({
message: '确定更新此次打卡记录吗?'
})
.then(() => {
// on confirm
this.clockType = 2;
this.daka();
this.clockIn();
this.getclockInfo();
})
.catch(() => {
// on cancel
});
}
},
mounted() {
this.loginInfo = this.getLoginInfo();
this.getCurrentDate();
this.getclockInfo();
if (this.list[0].place == '') {
this.clockType = 1;
this.active = 0;
} else {
this.clockType = 2;
this.active = 1;
}
},
created() {
this.t = setTimeout(this.time, 1000);
}
};
</script>
<style lang="scss" scoped>
.main {
background-color: #f3f4f6;
height: 100vh;
}
.user-icon {
width: 35px;
height: 35px;
border-radius: 35px;
}
.maintop {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
font-size: 16px;
color: #333;
background-color: #fff;
.user {
display: flex;
justify-content: space-between;
align-items: center;
}
}
.tip {
color: #999;
text-align: center;
margin-top: 10px;
}
.check-container {
display: flex;
justify-content: center;
align-items: center;
margin-top: 20px; /* Adjust margin as needed */
}
.checkbtn {
width: 100px;
height: 100px;
border-radius: 50%; /* Use 50% to make a perfect circle */
color: #fff;
text-align: center;
background: linear-gradient(135deg, #97c6fd, #73b2fb, #54a1fa, #4297fa);
}
.btn-content {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100%;
}
.checktime {
padding: 20px;
}
.van-steps {
background-color: #f3f4f6;
}
/* 隐藏活动状态的图标 */
.van-step__icon--active {
display: none;
}
.success {
padding: 50px 75px;
text-align: center;
.successTime {
font-size: 45px;
font-weight: bold;
color: #3791f9;
}
.successType {
margin-top: 15px;
font-size: 16px;
color: #3791f9;
}
}
</style>
record--打卡记录页面,当月数据有上下班打卡的日期下加蓝点,只有一次打卡记录的为黄点,没有打卡就不管,可以切换上一个月下一个月,切换上一个月就默认default日期为当月最后一天,切换下一个月就默认日期default为当月第一天,如果切换回当月,就查当月当天的数据。
<template>
<div>
<div v-if="cloading" class="loading">
<van-loading size="24px" vertical>加载中...</van-loading>
</div>
<div class="main" v-else>
<div class="maintop">
<div class="user">
<img class="user-icon" :src="loginInfo.userIcon" alt="" />
<div>{{ loginInfo.userNickName }}</div>
</div>
<div>
<van-icon name="arrow-left" @click="lastMonth" />
<span style="color: #3791F9;">{{ year }}-{{ month + 1 }}</span>
<van-icon name="arrow" @click="nextMonth" />
</div>
</div>
<!-- 日历 -->
<div>
<van-calendar
:poppable="false"
:show-confirm="false"
:show-mark="false"
:show-title="false"
:show-subtitle="false"
:min-date="minDate"
:max-date="maxDate"
:first-day-of-week="1"
:style="{ height: '400px' }"
@select="onselect"
:formatter="formatter"
:default-date="defaultDate"
/>
<div class="checktime" v-if="records && (records.startTime || records.endTime)">
<van-steps direction="vertical" active-color="#999" inactive-color="#999" active-icon="stop">
<van-step>
<h3>{{ records.startTime ? `上班时间${formatTimestamp(records.startTime)}` : '上班未打卡' }}</h3>
<p v-if="records.startPlace"><van-icon name="location" color="#999" />{{ records.startPlace }}</p>
</van-step>
<van-step>
<h3>{{ records.endTime ? `下班时间${formatTimestamp(records.endTime)}` : '下班未打卡' }}</h3>
<p v-if="records.endPlace"><van-icon name="location" color="#999" />{{ records.endPlace }}</p>
</van-step>
</van-steps>
</div>
<div class="unavailable" v-else>暂无打卡信息</div>
</div>
</div>
</div>
</template>
<script>
import { Icon, Calendar, Step, Steps, Loading } from 'vant';
export default {
components: {
[Icon.name]: Icon,
[Calendar.name]: Calendar,
[Step.name]: Step,
[Steps.name]: Steps,
[Loading.name]: Loading
},
data() {
return {
loginInfo: '',
date: '',
records: '',
cloading: false,
selecttimestamp: '',
dayDatas: { days: [] },
// 月份
minDate: new Date(),
maxDate: new Date(),
year: new Date().getFullYear(),
month: new Date().getMonth(),
nowDay: new Date().getDate(),
defaultDate: new Date(),
cont: 0
};
},
methods: {
// 将时间戳转为时间展示
formatTimestamp(timestamp) {
const date = new Date(timestamp);
const year = date.getFullYear();
const month = date.getMonth() + 1; // 月份从 0 开始,所以需要加 1
const day = date.getDate();
const hours = this.addZero(date.getHours());
const minutes = this.addZero(date.getMinutes());
const seconds = this.addZero(date.getSeconds());
// 拼接成展示的时间字符串
const timeString = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
return timeString;
},
// 时分秒补全零
addZero(i) {
if (i < 10) {
i = '0' + i;
}
return i;
},
// 查询打卡信息
getclockInfo() {
let now = new Date();
let year = now.getFullYear();
let month = now.getMonth() + 1;
let day = now.getDate();
let h = now.getHours();
let m = '0' + now.getMinutes();
let s = '0' + now.getSeconds();
// 判断使用哪个时间参数
let selectedTime = this.selectTime
? this.selectTime
: this.defaultDate
? this.defaultDate.getTime()
: Date.parse(year + '-' + month + '-' + day + ' ' + h + ':' + m + ':' + s);
// 检查选择的日期是否在本月内,如果是则使用选择日期的时间戳
if (new Date(selectedTime).getMonth() + 1 === this.defaultDate.getMonth() + 1) {
selectedTime = this.selectTime ? this.selectTime : this.defaultDate.getTime();
} else {
selectedTime = this.selectTime
? this.selectTime
: Date.parse(year + '-' + month + '-' + day + ' ' + h + ':' + m + ':' + s);
}
this.request('queryInfo', { startTime: selectedTime }).then(res => {
this.records = res;
});
},
// 查询打卡数据
getclockListInfo() {
var y = this.defaultDate.getFullYear();
var m = this.defaultDate.getMonth() + 1;
m = m < 10 ? '0' + m : m;
const monthtime = new Date(y + '-' + m).getTime();
this.cloading = true;
this.request('queryList', { startTime: monthtime })
.then(res => {
this.dayDatas.days = res;
})
.finally(() => {
this.cloading = false;
});
},
formatter(day) {
let dayTimestamp = new Date(day.date).getTime();
//判断日期是否有数据用map
this.dayDatas.days.map(item => {
let itemDate = new Date(item['dayDate'].replace(/-/g, '/')).getTime();
if (dayTimestamp == itemDate && item.startTime && item.endTime) {
day.className = 'addDot';
}
if (dayTimestamp == itemDate && (!item.startTime || !item.endTime)) {
day.className = 'incomplete';
}
// return day; // 返回更新后的day对象
});
return day;
},
onselect(value) {
this.selecttimestamp = value;
this.selectTime = Date.parse(value);
this.getclockInfo();
},
// 切换上个月
lastMonth() {
this.month--;
if (this.month < 0) {
this.month = 11;
this.year--;
}
this.selectTime = undefined;
let lastDayOfLastMonth = new Date(this.year, this.month + 1, 0);
let today = new Date();
if (
lastDayOfLastMonth.getMonth() === today.getMonth() &&
lastDayOfLastMonth.getFullYear() === today.getFullYear()
) {
this.defaultDate = today;
} else {
this.defaultDate = new Date(this.year, this.month, lastDayOfLastMonth.getDate());
}
this.setMinMaxDay();
this.getclockInfo();
this.getclockListInfo();
},
// 切换下个月
nextMonth() {
this.month++;
if (this.month > 11) {
this.month = 0;
this.year++;
}
this.selectTime = undefined;
// 获取下一个月的第一天
let firstDayOfNextMonth = new Date(this.year, this.month, 1); // 下一个月的第一天
let today = new Date();
if (
firstDayOfNextMonth.getMonth() === today.getMonth() &&
firstDayOfNextMonth.getFullYear() === today.getFullYear()
) {
this.defaultDate = today;
} else {
this.defaultDate = firstDayOfNextMonth;
}
// 更新defaultDate为当前选择的年份和月份信息
this.setMinMaxDay();
this.getclockInfo();
this.getclockListInfo(); // 重新获取当月打卡信息数据
},
setMinMaxDay() {
var firstDay = new Date(this.year, this.month, 1);
this.minDate = firstDay;
var endDate = new Date(this.year, this.month + 1, 0);
this.maxDate = endDate;
}
},
mounted() {
this.loginInfo = this.getLoginInfo();
this.getclockInfo();
this.$nextTick(() => {
this.setMinMaxDay();
this.getclockListInfo();
});
}
};
</script>
<style lang="scss" scoped>
.loading {
height: calc(100vh - 44px);
display: flex;
justify-content: center;
align-items: center;
}
.main {
background-color: #f3f4f6;
height: 100vh;
}
.maintop {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
font-size: 16px;
color: #333;
background-color: #fff;
.user-icon {
width: 35px;
height: 35px;
border-radius: 35px;
}
.user {
display: flex;
justify-content: space-between;
align-items: center;
}
}
::v-deep .van-calendar__selected-day {
background-color: #4297fa !important;
border-radius: 50% !important;
width: 40px;
height: 40px;
}
.checktime {
padding: 20px;
.van-steps {
background-color: #f3f4f6;
}
}
.unavailable {
margin-top: 20px;
color: #999;
text-align: center;
}
//有数据日期加点
::v-deep(.addDot) {
position: relative;
}
::v-deep(.addDot::after) {
position: absolute;
content: '';
width: 6px;
height: 6px;
top: 55px;
left: 25px;
border-radius: 50%;
background-color: #0084ff;
}
::v-deep(.incomplete) {
position: relative;
}
::v-deep(.incomplete::after) {
position: absolute;
content: '';
width: 6px;
height: 6px;
top: 55px;
left: 25px;
border-radius: 50%;
background-color: #ffae34;
}
</style>