|
|
@@ -62,7 +62,11 @@ |
|
|
|
<div class="status-time"> |
|
|
|
上班{{ attendanceGroup.workStartTime }} |
|
|
|
</div> |
|
|
|
<div class="status-label">未打卡</div> |
|
|
|
<div class="status-label"> |
|
|
|
<span v-if="checkInStatus === 0">未打卡</span> |
|
|
|
<span v-else-if="checkInStatus === 1">已打卡</span> |
|
|
|
<span v-else-if="checkInStatus === 3">迟到打卡</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="status-card"> |
|
|
|
<div class="status-time">下班{{ attendanceGroup.workEndTime }}</div> |
|
|
@@ -121,6 +125,7 @@ |
|
|
|
<transition name="fade"> |
|
|
|
<div v-if="showSuccess" class="success-overlay"> |
|
|
|
<div class="success-content"> |
|
|
|
<div class="success-close" @click="closeSuccessDialog">×</div> |
|
|
|
<div class="success-icon"> |
|
|
|
<svg viewBox="0 0 24 24" class="checkmark"> |
|
|
|
<path |
|
|
@@ -132,11 +137,11 @@ |
|
|
|
<div class="success-info"> |
|
|
|
<div class="info-item"> |
|
|
|
<span class="label">打卡时间</span> |
|
|
|
<span class="value">{{ currentTime }}</span> |
|
|
|
<span class="value">{{ currentCompleteDate }}</span> |
|
|
|
</div> |
|
|
|
<div class="info-item"> |
|
|
|
<span class="label">打卡地点</span> |
|
|
|
<span class="value">{{ locationStatus }}</span> |
|
|
|
<span class="value">{{ attendanceGroup.areaName }}</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
@@ -146,18 +151,20 @@ |
|
|
|
<!-- 范围,地点提示 --> |
|
|
|
<div class="location-info"> |
|
|
|
<div class="location-text"> |
|
|
|
<em v-if="isInRange" class="text-success" |
|
|
|
><i class="el-icon-success" />已进入打卡范围</em |
|
|
|
> |
|
|
|
<em v-else class="text-error" |
|
|
|
><i class="el-icon-error" />未进入打卡范围</em |
|
|
|
> |
|
|
|
<span>{{ locationStatus }}</span> |
|
|
|
<em |
|
|
|
v-if="isInRange" |
|
|
|
class="text-success" |
|
|
|
><i class="el-icon-success" />已进入打卡范围</em> |
|
|
|
<em |
|
|
|
v-else |
|
|
|
class="text-error" |
|
|
|
><i class="el-icon-error" />未进入打卡范围</em> |
|
|
|
<span>{{ attendanceGroup.areaName }}</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<p style="text-align: center"> |
|
|
|
经度:{{ userLocation.longitude }} <br /> |
|
|
|
经度:{{ userLocation.longitude }} <br> |
|
|
|
纬度:{{ userLocation.latitude }} |
|
|
|
</p> |
|
|
|
|
|
|
@@ -184,97 +191,113 @@ |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
<script> |
|
|
|
import { mapGetters } from "vuex"; |
|
|
|
import { mapGetters } from 'vuex' |
|
|
|
import { |
|
|
|
queryAttendanceGroupByUserId, |
|
|
|
checkIn, |
|
|
|
checkOut, |
|
|
|
getCurrentDayRecord, |
|
|
|
} from "@/api/checkin/punch-card"; |
|
|
|
getCurrentDayRecord |
|
|
|
} from '@/api/checkin/punch-card' |
|
|
|
export default { |
|
|
|
name: "MCheckin", |
|
|
|
name: 'MCheckin', |
|
|
|
data() { |
|
|
|
return { |
|
|
|
// 当前时间 |
|
|
|
currentTime: new Date().toLocaleTimeString("zh-CN", { hour12: false }), |
|
|
|
currentTime: new Date().toLocaleTimeString('zh-CN', { hour12: false }), |
|
|
|
// 打卡完成时间 |
|
|
|
currentCompleteDate: '', |
|
|
|
// 用户位置 |
|
|
|
userLocation: { |
|
|
|
latitude: null, // 纬度 |
|
|
|
longitude: null, // 经度 |
|
|
|
longitude: null // 经度 |
|
|
|
}, |
|
|
|
// 位置状态 |
|
|
|
locationStatus: "正在获取位置信息...", |
|
|
|
locationStatus: '正在获取位置信息...', |
|
|
|
// 打卡成功提示 |
|
|
|
showSuccess: false, |
|
|
|
// 位置监听ID |
|
|
|
watchId: null, |
|
|
|
// 打卡状态 |
|
|
|
punchStatus: { |
|
|
|
morning: "未打卡", // 上班打卡状态:未打卡、已打卡、迟到 |
|
|
|
evening: "未打卡", // 下班打卡状态:未打卡、已打卡、早退 |
|
|
|
morning: '未打卡', // 上班打卡状态:未打卡、已打卡、迟到 |
|
|
|
evening: '未打卡' // 下班打卡状态:未打卡、已打卡、早退 |
|
|
|
}, |
|
|
|
// 备注对话框 |
|
|
|
showRemarkDialog: false, |
|
|
|
// 备注对话框标题 |
|
|
|
remarkDialogTitle: "", |
|
|
|
remarkDialogTitle: '', |
|
|
|
// 备注表单 |
|
|
|
remarkForm: { |
|
|
|
remark: "", // 备注 |
|
|
|
type: "", // 打卡类型:morning_late 或 evening_early |
|
|
|
remark: '', // 备注 |
|
|
|
type: '' // 打卡类型:morning_late 或 evening_early |
|
|
|
}, |
|
|
|
// 是否在打卡范围内 |
|
|
|
isInRange: false, |
|
|
|
// 考勤组信息 |
|
|
|
attendanceGroup: {}, |
|
|
|
// 当前考勤状态 |
|
|
|
currentAttendance: {}, |
|
|
|
}; |
|
|
|
currentAttendance: null |
|
|
|
} |
|
|
|
}, |
|
|
|
computed: { |
|
|
|
...mapGetters(["userinfo", "avatar"]), |
|
|
|
...mapGetters(['userinfo', 'avatar']), |
|
|
|
// 获取时区 |
|
|
|
timeZone() { |
|
|
|
return Intl.DateTimeFormat().resolvedOptions().timeZone; |
|
|
|
return Intl.DateTimeFormat().resolvedOptions().timeZone |
|
|
|
}, |
|
|
|
// 打卡按钮文本 |
|
|
|
punchButtonText() { |
|
|
|
// 优先根据打卡状态判断,而不是时间 |
|
|
|
if (this.punchStatus.morning === "未打卡") { |
|
|
|
if (this.punchStatus.morning === '未打卡') { |
|
|
|
// 如果上班还没打卡,判断是否迟到 |
|
|
|
if (this.isLate()) { |
|
|
|
return "上班打卡"; |
|
|
|
return '上班打卡' |
|
|
|
} |
|
|
|
return "上班打卡"; |
|
|
|
} else if (this.punchStatus.evening === "未打卡") { |
|
|
|
return '上班打卡' |
|
|
|
} else if (this.punchStatus.evening === '未打卡') { |
|
|
|
// 上班已打卡,下班未打卡,判断是否早退 |
|
|
|
if (this.isEarly()) { |
|
|
|
return "下班打卡"; |
|
|
|
return '下班打卡' |
|
|
|
} |
|
|
|
return "下班打卡"; |
|
|
|
return '下班打卡' |
|
|
|
} else { |
|
|
|
// 都已经打卡了 |
|
|
|
return "已打卡"; |
|
|
|
return '已打卡' |
|
|
|
} |
|
|
|
}, |
|
|
|
/** |
|
|
|
* 获取当前考勤状态 |
|
|
|
* @returns {number} 考勤状态码 |
|
|
|
*/ |
|
|
|
checkInStatus() { |
|
|
|
if ( |
|
|
|
this.currentAttendance == null || |
|
|
|
this.currentAttendance.checkInStatus == 0 |
|
|
|
) { |
|
|
|
return 0 |
|
|
|
} else { |
|
|
|
return Number(this.currentAttendance.checkInStatus) |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
mounted() { |
|
|
|
// 更新时间 |
|
|
|
setInterval(() => { |
|
|
|
this.currentTime = new Date().toLocaleTimeString("zh-CN", { |
|
|
|
hour12: false, |
|
|
|
}); |
|
|
|
}, 1000); |
|
|
|
this.currentTime = new Date().toLocaleTimeString('zh-CN', { |
|
|
|
hour12: false |
|
|
|
}) |
|
|
|
}, 1000) |
|
|
|
|
|
|
|
// 开始监听位置变化 |
|
|
|
this.startLocationUpdates(); |
|
|
|
this.startLocationUpdates() |
|
|
|
|
|
|
|
// 初始化 |
|
|
|
this.init(); |
|
|
|
this.init() |
|
|
|
}, |
|
|
|
beforeDestroy() { |
|
|
|
// 组件销毁前清除位置监听 |
|
|
|
if (this.watchId !== null) { |
|
|
|
navigator.geolocation.clearWatch(this.watchId); |
|
|
|
navigator.geolocation.clearWatch(this.watchId) |
|
|
|
} |
|
|
|
}, |
|
|
|
methods: { |
|
|
@@ -282,39 +305,70 @@ export default { |
|
|
|
* 初始化 |
|
|
|
*/ |
|
|
|
async init() { |
|
|
|
const { userId } = this.userinfo; |
|
|
|
const { userId } = this.userinfo |
|
|
|
if (!userId) { |
|
|
|
this.$message.error("用户信息获取失败"); |
|
|
|
return; |
|
|
|
this.$message.error('用户信息获取失败') |
|
|
|
return |
|
|
|
} |
|
|
|
// 获取考勤组信息 |
|
|
|
const res = await queryAttendanceGroupByUserId({ userId }); |
|
|
|
const res = await queryAttendanceGroupByUserId({ userId }) |
|
|
|
if (res.code === 200) { |
|
|
|
if (res.data === null) { |
|
|
|
this.$message.error("未配置考勤组,请联系管理员"); |
|
|
|
return; |
|
|
|
this.$message.error('未配置考勤组,请联系管理员') |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
// 获取当前考勤状态 |
|
|
|
const currentAttendance = await getCurrentDayRecord({ userId }) |
|
|
|
if (currentAttendance.code === 200) { |
|
|
|
this.currentAttendance = currentAttendance.data |
|
|
|
if (currentAttendance.data.length > 0) { |
|
|
|
this.currentAttendance = |
|
|
|
currentAttendance.data[currentAttendance.data.length - 1] |
|
|
|
} else { |
|
|
|
this.currentAttendance = null |
|
|
|
} |
|
|
|
} else { |
|
|
|
this.currentAttendance = null |
|
|
|
this.$message.error('获取考勤状态失败,请联系管理员') |
|
|
|
} |
|
|
|
|
|
|
|
// 考勤组信息 |
|
|
|
this.attendanceGroup = res.data; |
|
|
|
this.attendanceGroup = res.data |
|
|
|
|
|
|
|
// 获取考勤范围 |
|
|
|
const { latitude, longitude } = this.userLocation; |
|
|
|
const { lat, lng, radius } = this.attendanceGroup; |
|
|
|
const distance = this.getDistance(latitude, longitude, lat, lng); |
|
|
|
console.log(distance); |
|
|
|
const { latitude, longitude } = this.userLocation |
|
|
|
const { lat, lng, radius } = this.attendanceGroup |
|
|
|
const distance = this.getDistance(latitude, longitude, lat, lng) |
|
|
|
console.log(distance) |
|
|
|
|
|
|
|
// 判断是否在打卡范围内 |
|
|
|
if (distance > radius) { |
|
|
|
this.isInRange = false; |
|
|
|
this.isInRange = false |
|
|
|
} else { |
|
|
|
this.isInRange = true; |
|
|
|
this.isInRange = true |
|
|
|
} |
|
|
|
} else { |
|
|
|
this.$message.error(res.msg); |
|
|
|
this.$message.error(res.msg) |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
|
* 格式化日期时间为 YYYY-MM-DD HH:mm:ss 格式 |
|
|
|
* @param {Date} date 日期对象 |
|
|
|
* @returns {string} 格式化后的日期时间字符串 |
|
|
|
*/ |
|
|
|
formatDateTime(date) { |
|
|
|
const year = date.getFullYear() |
|
|
|
const month = String(date.getMonth() + 1).padStart(2, '0') |
|
|
|
const day = String(date.getDate()).padStart(2, '0') |
|
|
|
const hours = String(date.getHours()).padStart(2, '0') |
|
|
|
const minutes = String(date.getMinutes()).padStart(2, '0') |
|
|
|
const seconds = String(date.getSeconds()).padStart(2, '0') |
|
|
|
|
|
|
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}` |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
|
* 计算两个经纬度之间的距离 |
|
|
|
* @param {number} lat1 纬度1 |
|
|
@@ -324,21 +378,21 @@ export default { |
|
|
|
* @returns {number} 距离,单位为公里 |
|
|
|
*/ |
|
|
|
getDistance(lat1, lng1, lat2, lng2) { |
|
|
|
const R = 6371; // 地球半径,单位为公里 |
|
|
|
const R = 6371 // 地球半径,单位为公里 |
|
|
|
// 计算纬度差 |
|
|
|
const dLat = (lat2 - lat1) * (Math.PI / 180); |
|
|
|
const dLat = (lat2 - lat1) * (Math.PI / 180) |
|
|
|
// 计算经度差 |
|
|
|
const dLng = (lng2 - lng1) * (Math.PI / 180); |
|
|
|
const dLng = (lng2 - lng1) * (Math.PI / 180) |
|
|
|
// 计算距离 |
|
|
|
const a = |
|
|
|
Math.sin(dLat / 2) * Math.sin(dLat / 2) + |
|
|
|
Math.cos(lat1 * (Math.PI / 180)) * |
|
|
|
Math.cos(lat2 * (Math.PI / 180)) * |
|
|
|
Math.sin(dLng / 2) * |
|
|
|
Math.sin(dLng / 2); |
|
|
|
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); |
|
|
|
const distance = R * c; // 距离,单位为公里 |
|
|
|
return distance; |
|
|
|
Math.sin(dLng / 2) |
|
|
|
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)) |
|
|
|
const distance = R * c // 距离,单位为公里 |
|
|
|
return distance |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
@@ -350,15 +404,15 @@ export default { |
|
|
|
const options = { |
|
|
|
enableHighAccuracy: true, // 使用高精度定位 |
|
|
|
timeout: 5000, // 超时时间 |
|
|
|
maximumAge: 0, // 不使用缓存的位置信息 |
|
|
|
}; |
|
|
|
maximumAge: 0 // 不使用缓存的位置信息 |
|
|
|
} |
|
|
|
|
|
|
|
// 开始监听位置变化 |
|
|
|
this.watchId = navigator.geolocation.watchPosition( |
|
|
|
this.handleLocationSuccess, |
|
|
|
this.handleLocationError, |
|
|
|
options |
|
|
|
); |
|
|
|
) |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
@@ -368,11 +422,11 @@ export default { |
|
|
|
handleLocationSuccess(position) { |
|
|
|
this.userLocation = { |
|
|
|
latitude: position.coords.latitude, |
|
|
|
longitude: position.coords.longitude, |
|
|
|
}; |
|
|
|
longitude: position.coords.longitude |
|
|
|
} |
|
|
|
|
|
|
|
// 调用后端API获取具体地址 |
|
|
|
this.locationStatus = ``; |
|
|
|
this.locationStatus = this.attendanceGroup.areaName |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
@@ -380,19 +434,19 @@ export default { |
|
|
|
* @param {GeolocationPositionError} error 错误信息 |
|
|
|
*/ |
|
|
|
handleLocationError(error) { |
|
|
|
console.error("获取位置失败:", error); |
|
|
|
console.error('获取位置失败:', error) |
|
|
|
switch (error.code) { |
|
|
|
case error.PERMISSION_DENIED: |
|
|
|
this.locationStatus = "请允许获取位置权限"; |
|
|
|
break; |
|
|
|
this.locationStatus = '请允许获取位置权限' |
|
|
|
break |
|
|
|
case error.POSITION_UNAVAILABLE: |
|
|
|
this.locationStatus = "位置信息不可用"; |
|
|
|
break; |
|
|
|
this.locationStatus = '位置信息不可用' |
|
|
|
break |
|
|
|
case error.TIMEOUT: |
|
|
|
this.locationStatus = "获取位置超时"; |
|
|
|
break; |
|
|
|
this.locationStatus = '获取位置超时' |
|
|
|
break |
|
|
|
default: |
|
|
|
this.locationStatus = "获取位置失败,请检查定位权限"; |
|
|
|
this.locationStatus = '获取位置失败,请检查定位权限' |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
@@ -406,15 +460,15 @@ export default { |
|
|
|
navigator.geolocation.getCurrentPosition(resolve, reject, { |
|
|
|
enableHighAccuracy: true, |
|
|
|
timeout: 5000, |
|
|
|
maximumAge: 0, |
|
|
|
}); |
|
|
|
}); |
|
|
|
maximumAge: 0 |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
this.handleLocationSuccess(position); |
|
|
|
return this.userLocation; |
|
|
|
this.handleLocationSuccess(position) |
|
|
|
return this.userLocation |
|
|
|
} catch (error) { |
|
|
|
this.handleLocationError(error); |
|
|
|
throw error; |
|
|
|
this.handleLocationError(error) |
|
|
|
throw error |
|
|
|
} |
|
|
|
}, |
|
|
|
/** |
|
|
@@ -422,41 +476,41 @@ export default { |
|
|
|
*/ |
|
|
|
async handlePunch() { |
|
|
|
if (!this.isInRange) { |
|
|
|
this.$message.error("请在打卡范围内进行打卡"); |
|
|
|
return; |
|
|
|
this.$message.error('请在打卡范围内进行打卡') |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
// 根据打卡状态判断,而不是时间 |
|
|
|
if (this.punchStatus.morning === "未打卡") { |
|
|
|
if (this.punchStatus.morning === '未打卡') { |
|
|
|
// 上班打卡 |
|
|
|
if (this.isLate()) { |
|
|
|
// 迟到打卡,需要填写备注 |
|
|
|
this.showRemarkDialog = true; |
|
|
|
this.remarkDialogTitle = "迟到打卡"; |
|
|
|
this.remarkForm.type = "morning_late"; |
|
|
|
this.showRemarkDialog = true |
|
|
|
this.remarkDialogTitle = '迟到打卡' |
|
|
|
this.remarkForm.type = 'morning_late' |
|
|
|
} else { |
|
|
|
// 正常打卡 |
|
|
|
await this.submitPunch("morning"); |
|
|
|
await this.submitPunch('morning') |
|
|
|
} |
|
|
|
} else if (this.punchStatus.evening === "未打卡") { |
|
|
|
} else if (this.punchStatus.evening === '未打卡') { |
|
|
|
// 下班打卡 |
|
|
|
if (this.isEarly()) { |
|
|
|
// 早退打卡,需要填写备注 |
|
|
|
this.showRemarkDialog = true; |
|
|
|
this.remarkDialogTitle = "早退打卡"; |
|
|
|
this.remarkForm.type = "evening_early"; |
|
|
|
this.showRemarkDialog = true |
|
|
|
this.remarkDialogTitle = '早退打卡' |
|
|
|
this.remarkForm.type = 'evening_early' |
|
|
|
} else { |
|
|
|
// 正常打卡 |
|
|
|
await this.submitPunch("evening"); |
|
|
|
await this.submitPunch('evening') |
|
|
|
} |
|
|
|
} else { |
|
|
|
// 都已经打卡了 |
|
|
|
this.$message.info("今日已完成打卡"); |
|
|
|
this.$message.info('今日已完成打卡') |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
console.error("打卡失败:", error); |
|
|
|
this.$message.error("打卡失败,请重试"); |
|
|
|
console.error('打卡失败:', error) |
|
|
|
this.$message.error('打卡失败,请重试') |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
@@ -464,24 +518,24 @@ export default { |
|
|
|
* 判断是否迟到 |
|
|
|
*/ |
|
|
|
isLate() { |
|
|
|
const now = new Date(); |
|
|
|
const hour = now.getHours(); |
|
|
|
const minute = now.getMinutes(); |
|
|
|
const { workStartTime } = this.attendanceGroup; |
|
|
|
const [hour2, minute2] = workStartTime.split(":"); |
|
|
|
return hour > hour2 || (hour === hour2 && minute > minute2); |
|
|
|
const now = new Date() |
|
|
|
const hour = now.getHours() |
|
|
|
const minute = now.getMinutes() |
|
|
|
const { workStartTime } = this.attendanceGroup |
|
|
|
const [hour2, minute2] = workStartTime.split(':') |
|
|
|
return hour > hour2 || (hour === hour2 && minute > minute2) |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
|
* 判断是否早退 |
|
|
|
*/ |
|
|
|
isEarly() { |
|
|
|
const now = new Date(); |
|
|
|
const hour = now.getHours(); |
|
|
|
const minute = now.getMinutes(); |
|
|
|
const { workEndTime } = this.attendanceGroup; |
|
|
|
const [hour2, minute2] = workEndTime.split(":"); |
|
|
|
return hour < hour2 || (hour === hour2 && minute < minute2); |
|
|
|
const now = new Date() |
|
|
|
const hour = now.getHours() |
|
|
|
const minute = now.getMinutes() |
|
|
|
const { workEndTime } = this.attendanceGroup |
|
|
|
const [hour2, minute2] = workEndTime.split(':') |
|
|
|
return hour < hour2 || (hour === hour2 && minute < minute2) |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
@@ -489,81 +543,92 @@ export default { |
|
|
|
*/ |
|
|
|
async submitRemark() { |
|
|
|
try { |
|
|
|
await this.submitPunch(this.remarkForm.type); |
|
|
|
this.showRemarkDialog = false; |
|
|
|
this.remarkForm.remark = ""; |
|
|
|
await this.submitPunch(this.remarkForm.type) |
|
|
|
this.showRemarkDialog = false |
|
|
|
this.remarkForm.remark = '' |
|
|
|
} catch (error) { |
|
|
|
console.error("提交备注失败:", error); |
|
|
|
this.$message.error("提交失败,请重试"); |
|
|
|
console.error('提交备注失败:', error) |
|
|
|
this.$message.error('提交失败,请重试') |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
|
* 关闭打卡成功弹窗 |
|
|
|
*/ |
|
|
|
closeSuccessDialog() { |
|
|
|
this.showSuccess = false |
|
|
|
this.init() |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
|
* 提交打卡 |
|
|
|
* @param {string} type 打卡类型:morning/evening/morning_late/evening_early |
|
|
|
*/ |
|
|
|
async submitPunch(type) { |
|
|
|
// TODO: 调用打卡API |
|
|
|
console.log("打卡类型:", type); |
|
|
|
console.log("备注:", this.remarkForm.remark); |
|
|
|
let checkInStatus = -1; |
|
|
|
let checkInType = "clockIn"; |
|
|
|
console.log('打卡类型:', type) |
|
|
|
console.log('备注:', this.remarkForm.remark) |
|
|
|
let checkInStatus = -1 |
|
|
|
let checkInType = 'clockIn' |
|
|
|
switch (type) { |
|
|
|
case "morning": |
|
|
|
case 'morning': |
|
|
|
// 正常上班打卡 |
|
|
|
checkInStatus = 0; |
|
|
|
checkInType = "clockIn"; |
|
|
|
break; |
|
|
|
case "evening": |
|
|
|
checkInStatus = 0 |
|
|
|
checkInType = 'clockIn' |
|
|
|
break |
|
|
|
case 'evening': |
|
|
|
// 正常下班打卡 |
|
|
|
checkInStatus = 0; |
|
|
|
checkInType = "下班打卡"; |
|
|
|
break; |
|
|
|
case "morning_late": |
|
|
|
checkInStatus = 0 |
|
|
|
checkInType = '下班打卡' |
|
|
|
break |
|
|
|
case 'morning_late': |
|
|
|
// 迟到打卡 |
|
|
|
checkInStatus = 1; |
|
|
|
checkInType = "clockIn"; |
|
|
|
break; |
|
|
|
case "evening_early": |
|
|
|
checkInStatus = 1 |
|
|
|
checkInType = 'clockIn' |
|
|
|
break |
|
|
|
case 'evening_early': |
|
|
|
// 早退打卡 |
|
|
|
checkInStatus = 1; |
|
|
|
checkInType = "早退打卡"; |
|
|
|
break; |
|
|
|
checkInStatus = 1 |
|
|
|
checkInType = '早退打卡' |
|
|
|
break |
|
|
|
default: |
|
|
|
this.$message.error("打卡类型错误"); |
|
|
|
break; |
|
|
|
this.$message.error('打卡类型错误') |
|
|
|
break |
|
|
|
} |
|
|
|
|
|
|
|
// 更新打卡状态 |
|
|
|
if (type === "morning" || type === "morning_late") { |
|
|
|
if (type === 'morning' || type === 'morning_late') { |
|
|
|
this.currentCompleteDate = this.formatDateTime(new Date()) |
|
|
|
const params = { |
|
|
|
userId: this.userinfo.userId, |
|
|
|
userName: this.userinfo.nickName, |
|
|
|
lng: this.userLocation.longitude, |
|
|
|
lat: this.userLocation.latitude, |
|
|
|
checkInStatus, |
|
|
|
clockIn: new Date().toISOString(), |
|
|
|
clockIn: this.currentCompleteDate, |
|
|
|
checkInType, |
|
|
|
description: this.remarkForm.remark, |
|
|
|
}; |
|
|
|
const res = await checkIn(params); |
|
|
|
description: this.remarkForm.remark |
|
|
|
} |
|
|
|
const res = await checkIn(params) |
|
|
|
|
|
|
|
if (res.code === 200) { |
|
|
|
this.punchStatus.morning = type === "morning" ? "已打卡" : "迟到"; |
|
|
|
//打卡成功 |
|
|
|
this.showSuccess = true; |
|
|
|
this.init(); |
|
|
|
this.punchStatus.morning = type === 'morning' ? '已打卡' : '迟到' |
|
|
|
// 打卡成功 |
|
|
|
this.showSuccess = true |
|
|
|
this.init() |
|
|
|
} else { |
|
|
|
this.$message.error(res.msg); |
|
|
|
this.$message.error(res.msg) |
|
|
|
} |
|
|
|
} else { |
|
|
|
this.punchStatus.evening = type === "evening" ? "已打卡" : "早退"; |
|
|
|
this.punchStatus.evening = type === 'evening' ? '已打卡' : '早退' |
|
|
|
} |
|
|
|
}, |
|
|
|
}, |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
</script> |
|
|
|
<style lang="scss" scoped> |
|
|
|
.page { |
|
|
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; |
|
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; |
|
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
|
|
|
min-height: 100vh; |
|
|
|
color: #333; |
|
|
@@ -736,6 +801,7 @@ export default { |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
gap: 6px; |
|
|
|
align-items: center; |
|
|
|
em { |
|
|
|
font-style: normal; |
|
|
|
display: flex; |
|
|
@@ -836,6 +902,28 @@ export default { |
|
|
|
text-align: center; |
|
|
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2); |
|
|
|
animation: popIn 0.3s ease-out; |
|
|
|
position: relative; |
|
|
|
} |
|
|
|
|
|
|
|
.success-close { |
|
|
|
position: absolute; |
|
|
|
top: 15px; |
|
|
|
right: 20px; |
|
|
|
font-size: 24px; |
|
|
|
color: #999; |
|
|
|
cursor: pointer; |
|
|
|
padding: 4px; |
|
|
|
border-radius: 50%; |
|
|
|
transition: all 0.2s ease; |
|
|
|
|
|
|
|
&:hover { |
|
|
|
background: #f5f5f5; |
|
|
|
color: #666; |
|
|
|
} |
|
|
|
|
|
|
|
&:active { |
|
|
|
transform: scale(0.95); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.success-icon { |