|
|
@@ -38,22 +38,22 @@ |
|
|
|
<div class="status-card"> |
|
|
|
<div class="status-time"> |
|
|
|
<!-- 上班 --> |
|
|
|
{{ $t("checkin.workStartTime") }} |
|
|
|
{{ $t('checkin.workStartTime') }} |
|
|
|
{{ attendanceGroup.workStartTime }} |
|
|
|
</div> |
|
|
|
<div class="status-label"> |
|
|
|
<span>{{ getCheckInStatusText("clockIn") }}</span> |
|
|
|
<span>{{ getCheckInStatusText('clockIn') }}</span> |
|
|
|
<span>{{ formatTime(attendanceStatus.clockInTime) }}</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="status-card"> |
|
|
|
<div class="status-time"> |
|
|
|
<!-- 下班 --> |
|
|
|
{{ $t("checkin.workEndTime") }} |
|
|
|
{{ $t('checkin.workEndTime') }} |
|
|
|
{{ attendanceGroup.workEndTime }} |
|
|
|
</div> |
|
|
|
<div class="status-label"> |
|
|
|
<span>{{ getCheckInStatusText("clockOut") }}</span> |
|
|
|
<span>{{ getCheckInStatusText('clockOut') }}</span> |
|
|
|
<span>{{ formatTime(attendanceStatus.clockOutTime) }}</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
@@ -122,35 +122,38 @@ |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
<script> |
|
|
|
import { mapGetters } from "vuex"; |
|
|
|
import { AttendanceService, PUNCH_STATUS, PUNCH_TYPE } from "./service"; |
|
|
|
import RemarkDialog from "./components/RemarkDialog.vue"; |
|
|
|
import SuccessDialog from "./components/SuccessDialog.vue"; |
|
|
|
import LocationInfo from "./components/LocationInfo.vue"; |
|
|
|
import { getGeocode } from "@/api/oa/attendance/clockIn"; |
|
|
|
import moment from "moment"; |
|
|
|
import timeService from "@/utils/timeService"; |
|
|
|
import { mapGetters } from 'vuex' |
|
|
|
import { AttendanceService, PUNCH_STATUS, PUNCH_TYPE } from './service' |
|
|
|
import RemarkDialog from './components/RemarkDialog.vue' |
|
|
|
import SuccessDialog from './components/SuccessDialog.vue' |
|
|
|
import LocationInfo from './components/LocationInfo.vue' |
|
|
|
import { getGeocode } from '@/api/oa/attendance/clockIn' |
|
|
|
import moment from 'moment' |
|
|
|
import timeService from '@/utils/timeService' |
|
|
|
import ResizeMixin from '@/layout/mixin/ResizeHandler' |
|
|
|
|
|
|
|
export default { |
|
|
|
name: "MCheckin", |
|
|
|
name: 'MCheckin', |
|
|
|
components: { |
|
|
|
RemarkDialog, |
|
|
|
SuccessDialog, |
|
|
|
LocationInfo, |
|
|
|
LocationInfo |
|
|
|
}, |
|
|
|
mixins: [ResizeMixin], |
|
|
|
data() { |
|
|
|
return { |
|
|
|
// 时间相关 |
|
|
|
currentTime: "", |
|
|
|
currentCompleteDate: "", |
|
|
|
currentTime: '', |
|
|
|
currentCompleteDate: '', |
|
|
|
removeTimeUpdateCallback: null, |
|
|
|
|
|
|
|
// 打卡成功地址 |
|
|
|
formattedAddress: "", |
|
|
|
formattedAddress: '', |
|
|
|
|
|
|
|
// 位置相关 |
|
|
|
userLocation: { |
|
|
|
latitude: null, |
|
|
|
longitude: null, |
|
|
|
longitude: null |
|
|
|
}, |
|
|
|
isInRange: false, |
|
|
|
watchId: null, |
|
|
@@ -161,43 +164,44 @@ export default { |
|
|
|
clockInTime: null, |
|
|
|
clockOutTime: null, |
|
|
|
clockInStatus: PUNCH_STATUS.NOT_CHECKED, |
|
|
|
clockOutStatus: PUNCH_STATUS.NOT_CHECKED, |
|
|
|
clockOutStatus: PUNCH_STATUS.NOT_CHECKED |
|
|
|
}, |
|
|
|
|
|
|
|
// 弹窗状态 |
|
|
|
showRemarkDialog: false, |
|
|
|
showSuccessDialog: false, |
|
|
|
remarkDialogTitle: "", |
|
|
|
remarkDialogTitle: '', |
|
|
|
remarkForm: { |
|
|
|
remark: "", |
|
|
|
type: "", |
|
|
|
remark: '', |
|
|
|
type: '' |
|
|
|
}, |
|
|
|
}; |
|
|
|
isPC: false |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
computed: { |
|
|
|
...mapGetters(["userinfo", "nickname"]), |
|
|
|
...mapGetters(['userinfo', 'nickname']), |
|
|
|
|
|
|
|
hasBirthday() { |
|
|
|
if (!this.userinfo.birthday) return false; |
|
|
|
if (!this.userinfo.birthday) return false |
|
|
|
// 使用服务器时间组件而不是系统时间 |
|
|
|
const timeComponents = timeService.getCurrentTimeComponents(); |
|
|
|
const birthday = this.userinfo.birthday.split("-"); |
|
|
|
const timeComponents = timeService.getCurrentTimeComponents() |
|
|
|
const birthday = this.userinfo.birthday.split('-') |
|
|
|
|
|
|
|
const month = birthday[1]; |
|
|
|
const day = birthday[2]; |
|
|
|
const month = birthday[1] |
|
|
|
const day = birthday[2] |
|
|
|
|
|
|
|
const todayMonth = String(timeComponents.month).padStart(2, "0"); |
|
|
|
const todayDay = String(timeComponents.day).padStart(2, "0"); |
|
|
|
const todayMonth = String(timeComponents.month).padStart(2, '0') |
|
|
|
const todayDay = String(timeComponents.day).padStart(2, '0') |
|
|
|
|
|
|
|
return month == todayMonth && day == todayDay; |
|
|
|
return month == todayMonth && day == todayDay |
|
|
|
}, |
|
|
|
birthdayMessage() { |
|
|
|
if (!this.userinfo.birthday) return ""; |
|
|
|
return this.$t("home.birthday", { |
|
|
|
if (!this.userinfo.birthday) return '' |
|
|
|
return this.$t('home.birthday', { |
|
|
|
name: this.nickname, |
|
|
|
birthday: moment(this.userinfo.birthday).format(`M/D`), |
|
|
|
}); |
|
|
|
birthday: moment(this.userinfo.birthday).format(`M/D`) |
|
|
|
}) |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
@@ -208,7 +212,7 @@ export default { |
|
|
|
return ( |
|
|
|
this.attendanceGroup.timeZone || |
|
|
|
Intl.DateTimeFormat().resolvedOptions().timeZone |
|
|
|
); |
|
|
|
) |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
@@ -216,13 +220,13 @@ export default { |
|
|
|
* @returns {string} 按钮文本 |
|
|
|
*/ |
|
|
|
punchButtonText() { |
|
|
|
const { clockInStatus, clockOutStatus } = this.attendanceStatus; |
|
|
|
const { clockInStatus, clockOutStatus } = this.attendanceStatus |
|
|
|
|
|
|
|
console.log(PUNCH_STATUS); |
|
|
|
console.log(PUNCH_STATUS) |
|
|
|
|
|
|
|
if (clockInStatus == PUNCH_STATUS.NOT_CHECKED) { |
|
|
|
// return '上班打卡' |
|
|
|
return this.$t("checkin.button.notChecked"); |
|
|
|
return this.$t('checkin.button.notChecked') |
|
|
|
} |
|
|
|
if ( |
|
|
|
clockOutStatus == PUNCH_STATUS.NOT_CHECKED || |
|
|
@@ -230,27 +234,43 @@ export default { |
|
|
|
clockOutStatus == PUNCH_STATUS.LATE_IN |
|
|
|
) { |
|
|
|
// return '下班打卡' |
|
|
|
return this.$t("checkin.button.checkedIn"); |
|
|
|
return this.$t('checkin.button.checkedIn') |
|
|
|
} |
|
|
|
// return '已打卡' |
|
|
|
return this.$t("checkin.button.checkedOut"); |
|
|
|
}, |
|
|
|
return this.$t('checkin.button.checkedOut') |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
async mounted() { |
|
|
|
try { |
|
|
|
if (this.userinfo.language) { |
|
|
|
this.$i18n.locale = this.userinfo.language; |
|
|
|
this.$store.dispatch("language/setLanguage", this.userinfo.language); |
|
|
|
this.$i18n.locale = this.userinfo.language |
|
|
|
this.$store.dispatch('language/setLanguage', this.userinfo.language) |
|
|
|
} |
|
|
|
// 判断如果是PC端 |
|
|
|
if (!this.$_isMobile()) { |
|
|
|
this.$alert(this.$t('checkin.error.pcMessage'), this.$t('checkin.error.message'), { |
|
|
|
confirmButtonText: this.$t('checkin.error.confirm'), |
|
|
|
showCancelButton: false, |
|
|
|
closeOnClickModal: false, |
|
|
|
closeOnPressEscape: false, |
|
|
|
showClose: false, |
|
|
|
center: true, |
|
|
|
callback: () => { |
|
|
|
this.$router.push('/') |
|
|
|
} |
|
|
|
}) |
|
|
|
return |
|
|
|
} else { |
|
|
|
await this.initializeApp() |
|
|
|
} |
|
|
|
await this.initializeApp(); |
|
|
|
} catch (error) { |
|
|
|
// this.handleError(this.$i18n.t("checkin.error.init"), error); |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
beforeDestroy() { |
|
|
|
this.cleanup(); |
|
|
|
this.cleanup() |
|
|
|
}, |
|
|
|
|
|
|
|
methods: { |
|
|
@@ -260,38 +280,38 @@ export default { |
|
|
|
async initializeApp() { |
|
|
|
// 初始化时间服务(获取服务器时间) |
|
|
|
try { |
|
|
|
const syncSuccess = await timeService.initialize(); |
|
|
|
const syncSuccess = await timeService.initialize() |
|
|
|
if (!syncSuccess) { |
|
|
|
console.warn("服务器时间同步失败,将使用设备本地时间"); |
|
|
|
console.warn('服务器时间同步失败,将使用设备本地时间') |
|
|
|
// 可以选择性地显示警告提示 |
|
|
|
// this.$toast.warning('时间同步失败,请确保网络连接正常'); |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
console.error("时间服务初始化失败:", error); |
|
|
|
console.error('时间服务初始化失败:', error) |
|
|
|
// 降级到本地时间,不影响正常功能 |
|
|
|
} |
|
|
|
|
|
|
|
this.startTimeUpdate(); |
|
|
|
await this.startLocationTracking(); |
|
|
|
await this.loadAttendanceData(); |
|
|
|
this.startTimeUpdate() |
|
|
|
await this.startLocationTracking() |
|
|
|
await this.loadAttendanceData() |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
|
* 开始时间更新(使用稳定的服务器时间更新机制) |
|
|
|
*/ |
|
|
|
startTimeUpdate() { |
|
|
|
this.updateCurrentTime(); |
|
|
|
this.updateCurrentTime() |
|
|
|
// 使用timeService的稳定更新回调,不受系统时间影响 |
|
|
|
this.removeTimeUpdateCallback = timeService.onTimeUpdate(() => { |
|
|
|
this.updateCurrentTime(); |
|
|
|
}); |
|
|
|
this.updateCurrentTime() |
|
|
|
}) |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
|
* 更新当前时间显示(使用服务器时间) |
|
|
|
*/ |
|
|
|
updateCurrentTime() { |
|
|
|
this.currentTime = timeService.getCurrentTimeString(); |
|
|
|
this.currentTime = timeService.getCurrentTimeString() |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
@@ -301,14 +321,14 @@ export default { |
|
|
|
const options = { |
|
|
|
enableHighAccuracy: true, |
|
|
|
timeout: 5000, |
|
|
|
maximumAge: 0, |
|
|
|
}; |
|
|
|
maximumAge: 0 |
|
|
|
} |
|
|
|
|
|
|
|
this.watchId = navigator.geolocation.watchPosition( |
|
|
|
this.handleLocationSuccess, |
|
|
|
this.handleLocationError, |
|
|
|
options |
|
|
|
); |
|
|
|
) |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
@@ -318,9 +338,9 @@ export default { |
|
|
|
handleLocationSuccess(position) { |
|
|
|
this.userLocation = { |
|
|
|
latitude: position.coords.latitude, |
|
|
|
longitude: position.coords.longitude, |
|
|
|
}; |
|
|
|
this.updateLocationRange(); |
|
|
|
longitude: position.coords.longitude |
|
|
|
} |
|
|
|
this.updateLocationRange() |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
@@ -329,13 +349,13 @@ export default { |
|
|
|
*/ |
|
|
|
handleLocationError(error) { |
|
|
|
const errorMessages = { |
|
|
|
[error.PERMISSION_DENIED]: "请允许获取位置权限", |
|
|
|
[error.POSITION_UNAVAILABLE]: "位置信息不可用", |
|
|
|
[error.TIMEOUT]: "获取位置超时", |
|
|
|
}; |
|
|
|
[error.PERMISSION_DENIED]: '请允许获取位置权限', |
|
|
|
[error.POSITION_UNAVAILABLE]: '位置信息不可用', |
|
|
|
[error.TIMEOUT]: '获取位置超时' |
|
|
|
} |
|
|
|
|
|
|
|
const message = errorMessages[error.code] || "获取位置失败"; |
|
|
|
this.$toast.error(message); |
|
|
|
const message = errorMessages[error.code] || '获取位置失败' |
|
|
|
this.$toast.error(message) |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
@@ -345,22 +365,22 @@ export default { |
|
|
|
this.isInRange = AttendanceService.isInAttendanceRange( |
|
|
|
this.userLocation, |
|
|
|
this.attendanceGroup |
|
|
|
); |
|
|
|
) |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
|
* 加载考勤数据 |
|
|
|
*/ |
|
|
|
async loadAttendanceData() { |
|
|
|
const { userId } = this.userinfo; |
|
|
|
const { userId } = this.userinfo |
|
|
|
if (!userId) { |
|
|
|
throw new Error("用户信息获取失败"); |
|
|
|
throw new Error('用户信息获取失败') |
|
|
|
} |
|
|
|
|
|
|
|
await Promise.all([ |
|
|
|
this.loadAttendanceGroup(userId), |
|
|
|
this.loadTodayAttendance(userId), |
|
|
|
]); |
|
|
|
this.loadTodayAttendance(userId) |
|
|
|
]) |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
@@ -368,8 +388,8 @@ export default { |
|
|
|
* @param {string} userId 用户ID |
|
|
|
*/ |
|
|
|
async loadAttendanceGroup(userId) { |
|
|
|
this.attendanceGroup = await AttendanceService.getAttendanceGroup(userId); |
|
|
|
this.updateLocationRange(); |
|
|
|
this.attendanceGroup = await AttendanceService.getAttendanceGroup(userId) |
|
|
|
this.updateLocationRange() |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
@@ -377,9 +397,9 @@ export default { |
|
|
|
* @param {string} userId 用户ID |
|
|
|
*/ |
|
|
|
async loadTodayAttendance(userId) { |
|
|
|
const records = await AttendanceService.getTodayAttendance(userId); |
|
|
|
const records = await AttendanceService.getTodayAttendance(userId) |
|
|
|
this.attendanceStatus = |
|
|
|
AttendanceService.processAttendanceRecords(records); |
|
|
|
AttendanceService.processAttendanceRecords(records) |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
@@ -387,14 +407,14 @@ export default { |
|
|
|
*/ |
|
|
|
async handlePunchClick() { |
|
|
|
if (!this.validatePunchConditions()) { |
|
|
|
return; |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
const punchAction = this.determinePunchAction(); |
|
|
|
await this.executePunchAction(punchAction); |
|
|
|
const punchAction = this.determinePunchAction() |
|
|
|
await this.executePunchAction(punchAction) |
|
|
|
} catch (error) { |
|
|
|
this.handleError("打卡失败", error); |
|
|
|
this.handleError('打卡失败', error) |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
@@ -405,21 +425,21 @@ export default { |
|
|
|
validatePunchConditions() { |
|
|
|
if (!this.isInRange) { |
|
|
|
// this.$toast.error("请在打卡范围内进行打卡"); |
|
|
|
this.$toast.error(this.$t("checkin.error.outOfRange")); |
|
|
|
return false; |
|
|
|
this.$toast.error(this.$t('checkin.error.outOfRange')) |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
|
const { clockInStatus, clockOutStatus } = this.attendanceStatus; |
|
|
|
const { clockInStatus, clockOutStatus } = this.attendanceStatus |
|
|
|
if ( |
|
|
|
clockInStatus !== PUNCH_STATUS.NOT_CHECKED && |
|
|
|
clockOutStatus !== PUNCH_STATUS.NOT_CHECKED |
|
|
|
) { |
|
|
|
// this.$toast.info("今日已完成打卡"); |
|
|
|
this.$toast.info(this.$t("checkin.punch.status.todayChecked")); |
|
|
|
return false; |
|
|
|
this.$toast.info(this.$t('checkin.punch.status.todayChecked')) |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
|
return true; |
|
|
|
return true |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
@@ -427,21 +447,21 @@ export default { |
|
|
|
* @returns {Object} 打卡动作信息 |
|
|
|
*/ |
|
|
|
determinePunchAction() { |
|
|
|
const { clockInStatus } = this.attendanceStatus; |
|
|
|
const { clockInStatus } = this.attendanceStatus |
|
|
|
|
|
|
|
if (clockInStatus === PUNCH_STATUS.NOT_CHECKED) { |
|
|
|
return AttendanceService.isLateForWork( |
|
|
|
this.attendanceGroup.workStartTime |
|
|
|
) |
|
|
|
? { type: "morning_late", needRemark: true } |
|
|
|
: { type: "morning", needRemark: false }; |
|
|
|
? { type: 'morning_late', needRemark: true } |
|
|
|
: { type: 'morning', needRemark: false } |
|
|
|
} |
|
|
|
|
|
|
|
return AttendanceService.isEarlyForLeaving( |
|
|
|
this.attendanceGroup.workEndTime |
|
|
|
) |
|
|
|
? { type: "evening_early", needRemark: true } |
|
|
|
: { type: "evening", needRemark: false }; |
|
|
|
? { type: 'evening_early', needRemark: true } |
|
|
|
: { type: 'evening', needRemark: false } |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
@@ -450,9 +470,9 @@ export default { |
|
|
|
*/ |
|
|
|
async executePunchAction(action) { |
|
|
|
if (action.needRemark) { |
|
|
|
this.showRemarkDialogForType(action.type); |
|
|
|
this.showRemarkDialogForType(action.type) |
|
|
|
} else { |
|
|
|
await this.submitPunch(action.type); |
|
|
|
await this.submitPunch(action.type) |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
@@ -467,14 +487,14 @@ export default { |
|
|
|
// }; |
|
|
|
|
|
|
|
const titles = { |
|
|
|
morning_late: this.$t("checkin.punch.status.lateIn"), |
|
|
|
evening_early: this.$t("checkin.punch.status.earlyOut"), |
|
|
|
}; |
|
|
|
|
|
|
|
this.remarkDialogTitle = titles[type]; |
|
|
|
this.remarkForm.type = type; |
|
|
|
this.remarkForm.remark = ""; |
|
|
|
this.showRemarkDialog = true; |
|
|
|
morning_late: this.$t('checkin.punch.status.lateIn'), |
|
|
|
evening_early: this.$t('checkin.punch.status.earlyOut') |
|
|
|
} |
|
|
|
|
|
|
|
this.remarkDialogTitle = titles[type] |
|
|
|
this.remarkForm.type = type |
|
|
|
this.remarkForm.remark = '' |
|
|
|
this.showRemarkDialog = true |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
@@ -482,11 +502,11 @@ export default { |
|
|
|
*/ |
|
|
|
async submitRemarkPunch() { |
|
|
|
try { |
|
|
|
await this.submitPunch(this.remarkForm.type); |
|
|
|
this.closeRemarkDialog(); |
|
|
|
await this.submitPunch(this.remarkForm.type) |
|
|
|
this.closeRemarkDialog() |
|
|
|
} catch (error) { |
|
|
|
// this.handleError("提交失败", error); |
|
|
|
this.handleError(this.$t("checkin.error.submitFailed"), error); |
|
|
|
this.handleError(this.$t('checkin.error.submitFailed'), error) |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
@@ -501,32 +521,32 @@ export default { |
|
|
|
userLocation: this.userLocation, |
|
|
|
attendanceGroupId: this.attendanceGroup.attendanceGroupId, |
|
|
|
attendanceGroupName: this.attendanceGroup.attendanceGroupName, |
|
|
|
remark: this.remarkForm.remark, |
|
|
|
}); |
|
|
|
remark: this.remarkForm.remark |
|
|
|
}) |
|
|
|
|
|
|
|
await AttendanceService.submitPunch(punchData); |
|
|
|
await AttendanceService.submitPunch(punchData) |
|
|
|
|
|
|
|
this.currentCompleteDate = AttendanceService.formatDateTime(); |
|
|
|
this.showSuccessDialog = true; |
|
|
|
this.formattedAddress = "Loading..."; |
|
|
|
this.currentCompleteDate = AttendanceService.formatDateTime() |
|
|
|
this.showSuccessDialog = true |
|
|
|
this.formattedAddress = 'Loading...' |
|
|
|
|
|
|
|
try { |
|
|
|
const res = await getGeocode( |
|
|
|
this.userLocation.longitude, |
|
|
|
this.userLocation.latitude |
|
|
|
); |
|
|
|
console.log(res); |
|
|
|
const { status, results } = res; |
|
|
|
) |
|
|
|
console.log(res) |
|
|
|
const { status, results } = res |
|
|
|
if (status.code === 200 && results.length > 0) { |
|
|
|
const { formatted } = results[0]; |
|
|
|
this.formattedAddress = formatted; |
|
|
|
const { formatted } = results[0] |
|
|
|
this.formattedAddress = formatted |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
this.formattedAddress = this.attendanceGroup.areaName; |
|
|
|
console.error(error); |
|
|
|
this.formattedAddress = this.attendanceGroup.areaName |
|
|
|
console.error(error) |
|
|
|
} |
|
|
|
|
|
|
|
await this.loadTodayAttendance(this.userinfo.userId); |
|
|
|
await this.loadTodayAttendance(this.userinfo.userId) |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
@@ -538,9 +558,9 @@ export default { |
|
|
|
const status = |
|
|
|
type === PUNCH_TYPE.CLOCK_IN |
|
|
|
? this.attendanceStatus.clockInStatus |
|
|
|
: this.attendanceStatus.clockOutStatus; |
|
|
|
: this.attendanceStatus.clockOutStatus |
|
|
|
|
|
|
|
return AttendanceService.getStatusText(status); |
|
|
|
return AttendanceService.getStatusText(status) |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
@@ -549,22 +569,22 @@ export default { |
|
|
|
* @returns {string} 格式化后的时间 |
|
|
|
*/ |
|
|
|
formatTime(time) { |
|
|
|
return AttendanceService.formatTime(time); |
|
|
|
return AttendanceService.formatTime(time) |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
|
* 关闭备注对话框 |
|
|
|
*/ |
|
|
|
closeRemarkDialog() { |
|
|
|
this.showRemarkDialog = false; |
|
|
|
this.remarkForm.remark = ""; |
|
|
|
this.showRemarkDialog = false |
|
|
|
this.remarkForm.remark = '' |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
|
* 关闭成功对话框 |
|
|
|
*/ |
|
|
|
closeSuccessDialog() { |
|
|
|
this.showSuccessDialog = false; |
|
|
|
this.showSuccessDialog = false |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
@@ -573,8 +593,8 @@ export default { |
|
|
|
* @param {Error} error 错误对象 |
|
|
|
*/ |
|
|
|
handleError(message, error) { |
|
|
|
console.error(message, error); |
|
|
|
this.$toast.error(error.message || message); |
|
|
|
console.error(message, error) |
|
|
|
this.$toast.error(error.message || message) |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
@@ -582,18 +602,18 @@ export default { |
|
|
|
*/ |
|
|
|
cleanup() { |
|
|
|
if (this.watchId !== null) { |
|
|
|
navigator.geolocation.clearWatch(this.watchId); |
|
|
|
navigator.geolocation.clearWatch(this.watchId) |
|
|
|
} |
|
|
|
if (this.removeTimeUpdateCallback) { |
|
|
|
this.removeTimeUpdateCallback(); |
|
|
|
this.removeTimeUpdateCallback() |
|
|
|
} |
|
|
|
}, |
|
|
|
}, |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
</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; |
|
|
|
min-height: 100vh; |
|
|
|
color: #333; |
|
|
|
@media (min-width: 480px) { |