| | |
| | | } else { |
| | | noNeedCheckIn.value = false; |
| | | } |
| | | updateInCheckRange(); |
| | | } else { |
| | | // 页面显示“无需打卡” |
| | | todayRecord.value = {}; |
| | | noNeedCheckIn.value = true; |
| | | updateInCheckRange(); |
| | | } |
| | | }); |
| | | }; |
| | |
| | | const m = String(now.getMinutes()).padStart(2, "0"); |
| | | const s = String(now.getSeconds()).padStart(2, "0"); |
| | | nowTime.value = `${Y}-${M}-${D} ${h}:${m}:${s}`; |
| | | updateInCheckRange(); |
| | | }; |
| | | |
| | | // 今日日期 |
| | | const todayStr = computed(() => nowTime.value.slice(0, 10)); |
| | | |
| | | const parseHmToMinutes = hm => { |
| | | if (!hm || typeof hm !== "string") return null; |
| | | const [hStr, mStr] = hm.split(":"); |
| | | const h = Number(hStr); |
| | | const m = Number(mStr); |
| | | if (!Number.isFinite(h) || !Number.isFinite(m)) return null; |
| | | if (h < 0 || h > 23 || m < 0 || m > 59) return null; |
| | | return h * 60 + m; |
| | | }; |
| | | |
| | | const parseYmdToDate = ymd => { |
| | | if (!ymd || typeof ymd !== "string") return null; |
| | | const [yStr, mStr, dStr] = ymd.slice(0, 10).split("-"); |
| | | const y = Number(yStr); |
| | | const m = Number(mStr); |
| | | const d = Number(dStr); |
| | | if (!Number.isFinite(y) || !Number.isFinite(m) || !Number.isFinite(d)) { |
| | | return null; |
| | | } |
| | | return new Date(y, m - 1, d, 0, 0, 0, 0); |
| | | }; |
| | | |
| | | const addMinutes = (date, minutes) => { |
| | | return new Date(date.getTime() + minutes * 60 * 1000); |
| | | }; |
| | | |
| | | const buildShiftWindow = () => { |
| | | const startAtMinutes = parseHmToMinutes(todayRecord.value?.startAt); |
| | | const endAtMinutes = parseHmToMinutes(todayRecord.value?.endAt); |
| | | if (startAtMinutes === null || endAtMinutes === null) return null; |
| | | |
| | | const baseYmd = todayRecord.value?.date |
| | | ? String(todayRecord.value.date).slice(0, 10) |
| | | : todayStr.value; |
| | | const baseDate = parseYmdToDate(baseYmd); |
| | | if (!baseDate) return null; |
| | | |
| | | const startDateTime = addMinutes(baseDate, startAtMinutes); |
| | | const crossDay = startAtMinutes > endAtMinutes; |
| | | const endBase = crossDay ? addMinutes(baseDate, 24 * 60) : baseDate; |
| | | const endDateTime = addMinutes(endBase, endAtMinutes); |
| | | |
| | | return { startDateTime, endDateTime }; |
| | | }; |
| | | |
| | | const updateInCheckRange = () => { |
| | | if (noNeedCheckIn.value) { |
| | | inCheckRange.value = true; |
| | | return; |
| | | } |
| | | const window = buildShiftWindow(); |
| | | if (!window) { |
| | | inCheckRange.value = true; |
| | | return; |
| | | } |
| | | const now = new Date(); |
| | | const checkInEarlyMinutes = 120; |
| | | const checkOutLateMinutes = 720; |
| | | const needAction = (() => { |
| | | if (todayRecord.value?.workEndAt) return "done"; |
| | | if (todayRecord.value?.workStartAt) return "checkOut"; |
| | | const distToStart = Math.abs( |
| | | now.getTime() - window.startDateTime.getTime() |
| | | ); |
| | | const distToEnd = Math.abs(now.getTime() - window.endDateTime.getTime()); |
| | | return distToEnd < distToStart ? "checkOut" : "checkIn"; |
| | | })(); |
| | | const start = addMinutes(window.startDateTime, -checkInEarlyMinutes); |
| | | const end = addMinutes( |
| | | window.endDateTime, |
| | | needAction === "checkOut" ? checkOutLateMinutes : 0 |
| | | ); |
| | | inCheckRange.value = now >= start && now <= end; |
| | | }; |
| | | |
| | | // 打卡按钮文本 |
| | | const checkInOutText = computed(() => { |
| | | if (noNeedCheckIn.value) { |
| | | return "无需打卡"; |
| | | } |
| | | if (!todayRecord.value || !todayRecord.value.workStartAt) { |
| | | return "上班打卡"; |
| | | } |
| | | if (!todayRecord.value.workEndAt) { |
| | | return "下班打卡"; |
| | | if (todayRecord.value.workStartAt) { |
| | | return "下班打卡"; |
| | | } |
| | | const window = buildShiftWindow(); |
| | | if (!window) return "上班打卡"; |
| | | const now = new Date(); |
| | | const distToStart = Math.abs( |
| | | now.getTime() - window.startDateTime.getTime() |
| | | ); |
| | | const distToEnd = Math.abs(now.getTime() - window.endDateTime.getTime()); |
| | | return distToEnd < distToStart ? "下班打卡" : "上班打卡"; |
| | | } |
| | | return "已打卡"; |
| | | }); |
| | |
| | | .attendance-records { |
| | | animation-delay: 0.2s; |
| | | } |
| | | </style> |
| | | </style> |