diff --git a/pages/tabs/clock.vue b/pages/tabs/clock.vue index 839ed65..9e05c94 100644 --- a/pages/tabs/clock.vue +++ b/pages/tabs/clock.vue @@ -6,14 +6,15 @@ {{ dateLabel }} - 班次 {{ rules.workStart }}–{{ rules.workEnd }} + 弹性 09:00–09:30 / 18:00–18:30 + 多出工时记调休 {{ lieuText }} - 上班 {{ rules.workStart }} + 上班 09:00–09:30 {{ inRec ? (inRec.time || '') + ' 已打卡' : '未打卡' }} {{ inRec ? (inRec.status || '正常') : '' }} @@ -21,7 +22,7 @@ - 下班 {{ rules.workEnd }} + 下班 18:00–18:30 {{ outRec ? (outRec.time || '') + ' 已打卡' : '未打卡' }} {{ outRec ? (outRec.status || '正常') : '' }} @@ -80,7 +81,7 @@ import FyHeader from '../../components/fy-header.vue' import FyScroll from '../../components/fy-scroll.vue' import { store } from '../../utils/store.js' -import { clockText, toast } from '../../utils/format.js' +import { clockText, flexCreditMinutes, flexCreditText, toast } from '../../utils/format.js' export default { components: { FyHeader, FyScroll }, @@ -111,6 +112,11 @@ export default { }, outRec() { return this.records.find((r) => /下班|out/i.test(String(r.title || r.kind || r.type || ''))) + }, + lieuText() { + const inn = this.inRec && (this.inRec.time || this.inRec.punchTime) + const out = this.outRec && (this.outRec.time || this.outRec.punchTime) + return flexCreditText(flexCreditMinutes(inn, out)) } }, onShow() { @@ -150,6 +156,7 @@ export default { .day { display: flex; justify-content: space-between; align-items: baseline; padding: 8rpx 8rpx 20rpx; } .date { font-size: 32rpx; font-weight: 650; color: #111827; } .shift { font-size: 24rpx; color: #6B7280; } +.lieu { margin: 0 8rpx 16rpx; font-size: 24rpx; color: #1677FF; } .slots { background: #fff; border-radius: 20rpx; padding: 8rpx 8rpx; border: 1rpx solid rgba(17,24,39,0.06); } .slot { display: flex; align-items: center; padding: 22rpx 20rpx; } .slot + .slot { border-top: 1rpx solid #F0F2F5; } diff --git a/utils/format.js b/utils/format.js index 2409968..9dccdf9 100644 --- a/utils/format.js +++ b/utils/format.js @@ -92,6 +92,35 @@ export function pad2(n) { return String(n).padStart(2, '0') } +/** 弹性:9:00–9:30 上班,18:00–18:30 下班。早于 9:00、晚于 18:30 的分钟计入调休。 */ +export function flexCreditMinutes(inTime, outTime) { + const inn = hmMinutes(inTime) + const out = hmMinutes(outTime) + let extra = 0 + if (inn != null && inn < 9 * 60) extra += 9 * 60 - inn + if (out != null && out > 18 * 60 + 30) extra += out - (18 * 60 + 30) + return extra +} + +export function flexCreditText(minutes) { + const n = Math.max(0, Math.round(Number(minutes) || 0)) + if (!n) return '0 分钟' + const h = Math.floor(n / 60) + const m = n % 60 + if (h && m) return h + ' 小时 ' + m + ' 分钟' + if (h) return h + ' 小时' + return m + ' 分钟' +} + +function hmMinutes(value) { + const m = String(value || '').match(/(\d{1,2}):(\d{2})/) + if (!m) return null + const h = Number(m[1]) + const min = Number(m[2]) + if (h > 23 || min > 59) return null + return h * 60 + min +} + export function clockText(date) { const d = date || new Date() return `${pad2(d.getHours())}:${pad2(d.getMinutes())}:${pad2(d.getSeconds())}` diff --git a/utils/store.js b/utils/store.js index b4ffe27..636e000 100644 --- a/utils/store.js +++ b/utils/store.js @@ -867,32 +867,37 @@ export const store = { this.emit() }, - punch() { + _locate() { + let type = 'gcj02' + // #ifdef H5 + type = 'wgs84' + // #endif return new Promise((resolve, reject) => { uni.getLocation({ - type: 'gcj02', - isHighAccuracy: true, - success: async (pos) => { - try { - const rec = await api.oaPost('/profile/attendance/punch', { - source: 'mobile', - latitude: pos.latitude, - longitude: pos.longitude, - accuracyM: pos.accuracy - }, this.token) - await this.refreshAttendance() - resolve((rec && rec.title) || '打卡成功') - } catch (e) { - reject(e) - } - }, - fail() { - reject(new Error('需要定位权限才能打卡')) - } + type, + isHighAccuracy: false, + timeout: 8000, + success: resolve, + fail: reject }) }) }, + async punch() { + const body = { source: 'mobile' } + try { + const pos = await this._locate() + body.latitude = pos.latitude + body.longitude = pos.longitude + body.accuracyM = pos.accuracy + } catch (_) { + // 桌面浏览器经常没有定位;坐标缺省时仍提交,由服务端决定是否允许 + } + const rec = await api.oaPost('/profile/attendance/punch', body, this.token) + await this.refreshAttendance() + return (rec && rec.title) || '打卡成功' + }, + async audit(no, action, comment) { await api.oaPost(`/workflow/requests/${no}/audit`, { action, comment }, this.token) await this.refreshWorkbench()