打卡
This commit is contained in:
+101
-42
@@ -4,39 +4,69 @@
|
||||
<fy-scroll class="edge-scroll" dock @refresh="reload">
|
||||
<view v-if="!canPunch" class="deny">当前账号没有打卡权限</view>
|
||||
<view v-else class="body">
|
||||
<view class="clock-box">
|
||||
<view class="day">
|
||||
<text class="date">{{ dateLabel }}</text>
|
||||
<text class="shift">班次 {{ rules.workStart }}–{{ rules.workEnd }}</text>
|
||||
</view>
|
||||
|
||||
<view class="slots">
|
||||
<view class="slot">
|
||||
<view class="dot" :class="{ on: inRec }" />
|
||||
<view class="slot-m">
|
||||
<text class="lab">上班 {{ rules.workStart }}</text>
|
||||
<text class="val" :class="{ ok: inRec }">{{ inRec ? (inRec.time || '') + ' 已打卡' : '未打卡' }}</text>
|
||||
</view>
|
||||
<text class="tiny">{{ inRec ? (inRec.status || '正常') : '' }}</text>
|
||||
</view>
|
||||
<view class="slot">
|
||||
<view class="dot" :class="{ on: outRec }" />
|
||||
<view class="slot-m">
|
||||
<text class="lab">下班 {{ rules.workEnd }}</text>
|
||||
<text class="val" :class="{ ok: outRec }">{{ outRec ? (outRec.time || '') + ' 已打卡' : '未打卡' }}</text>
|
||||
</view>
|
||||
<text class="tiny">{{ outRec ? (outRec.status || '正常') : '' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="ring-wrap">
|
||||
<view class="ring" :class="{ busy: punching }" @click="doPunch">
|
||||
<text class="now">{{ now }}</text>
|
||||
<text class="shift">班次 {{ rules.workStart }}–{{ rules.workEnd }}{{ locName ? ' · ' + locName : '' }}</text>
|
||||
</view>
|
||||
<view class="grid">
|
||||
<view class="stat card">
|
||||
<text class="lab">上班</text>
|
||||
<text class="val" :class="{ ok: inRec }">{{ inRec ? inRec.time + ' 已打卡' : '未打卡' }}</text>
|
||||
<text class="tiny">{{ inRec ? (inRec.status || '正常') : '待打卡' }}</text>
|
||||
</view>
|
||||
<view class="stat card">
|
||||
<text class="lab">下班</text>
|
||||
<text class="val" :class="{ ok: outRec }">{{ outRec ? outRec.time + ' 已打卡' : '未打卡' }}</text>
|
||||
<text class="tiny">{{ outRec ? (outRec.status || '正常') : '待打卡' }}</text>
|
||||
<text class="act">{{ punchLabel }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<wd-button type="primary" block size="large" :loading="punching" @click="doPunch">{{ outRec ? '更新打卡' : '打卡' }}</wd-button>
|
||||
<text class="geo">将使用手机定位校验打卡范围</text>
|
||||
|
||||
<view class="geo">
|
||||
<wd-icon name="location" size="28rpx" color="#1677FF" />
|
||||
<text>{{ locName || '将使用手机定位校验打卡范围' }}</text>
|
||||
</view>
|
||||
|
||||
<view class="quick">
|
||||
<text class="q" @click="goKind('card')">补卡</text>
|
||||
<text class="q" @click="goKind('leave')">请假</text>
|
||||
<text class="q" @click="goKind('overtime')">加班</text>
|
||||
<text class="q" @click="goKind('outing')">外出</text>
|
||||
<view class="q" @click="goKind('card')">
|
||||
<wd-icon name="edit-1" size="40rpx" color="#1677FF" />
|
||||
<text>补卡</text>
|
||||
</view>
|
||||
<view class="sec">
|
||||
<text class="st">今日及近期记录</text>
|
||||
<view class="q" @click="goKind('leave')">
|
||||
<wd-icon name="calendar" size="40rpx" color="#1677FF" />
|
||||
<text>请假</text>
|
||||
</view>
|
||||
<view class="card">
|
||||
<view class="q" @click="goKind('overtime')">
|
||||
<wd-icon name="time" size="40rpx" color="#1677FF" />
|
||||
<text>加班</text>
|
||||
</view>
|
||||
<view class="q" @click="goKind('outing')">
|
||||
<wd-icon name="location" size="40rpx" color="#1677FF" />
|
||||
<text>外出</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="sec">打卡记录</view>
|
||||
<view class="card log">
|
||||
<view v-if="!records.length" class="empty">暂无记录</view>
|
||||
<view v-for="r in records" :key="r.id || r.time" class="rec">
|
||||
<view>
|
||||
<view class="rail" />
|
||||
<view class="rec-m">
|
||||
<text class="rt">{{ r.title || r.kind || '打卡' }} {{ r.time || r.punchTime || '' }}</text>
|
||||
<text class="rl">{{ r.location || r.address || '' }}</text>
|
||||
<text class="rl">{{ r.location || r.address || locName || '' }}</text>
|
||||
</view>
|
||||
<text class="ok">{{ r.status || '正常' }}</text>
|
||||
</view>
|
||||
@@ -61,6 +91,17 @@ export default {
|
||||
canPunch() { return store.can('personal', 'punch') },
|
||||
rules() { return store.attendRules },
|
||||
records() { return store.attendance || [] },
|
||||
dateLabel() {
|
||||
const d = new Date()
|
||||
const w = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
|
||||
return (d.getMonth() + 1) + '月' + d.getDate() + '日 ' + w[d.getDay()]
|
||||
},
|
||||
punchLabel() {
|
||||
if (this.punching) return '打卡中'
|
||||
if (!this.inRec) return '上班打卡'
|
||||
if (!this.outRec) return '下班打卡'
|
||||
return '更新打卡'
|
||||
},
|
||||
locName() {
|
||||
const locs = this.rules.locations || []
|
||||
return locs[0] ? (locs[0].name || locs[0].title || '') : ''
|
||||
@@ -105,24 +146,42 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.body { padding: 16rpx 24rpx 40rpx; }
|
||||
.clock-box { background: #fff; border-radius: 24rpx; padding: 48rpx 0 40rpx; text-align: center; border: 1rpx solid rgba(17,24,39,0.06); }
|
||||
.now { display: block; font-size: 72rpx; font-weight: 650; letter-spacing: 2rpx; color: #111827; }
|
||||
.shift { font-size: 22rpx; color: #4B5563; }
|
||||
.grid { display: flex; gap: 16rpx; margin: 20rpx 0; }
|
||||
.stat { flex: 1; padding: 24rpx; }
|
||||
.lab { font-size: 26rpx; font-weight: 600; display: block; }
|
||||
.val { font-size: 24rpx; color: #4B5563; display: block; margin-top: 12rpx; }
|
||||
.val.ok { color: #16A34A; font-weight: 650; }
|
||||
.tiny { font-size: 20rpx; color: #6B7280; }
|
||||
.geo { display: block; text-align: center; font-size: 22rpx; color: #4B5563; margin: 16rpx 0 24rpx; }
|
||||
.body :deep(.wd-button) { margin-top: 8rpx; }
|
||||
.quick { display: flex; gap: 12rpx; }
|
||||
.q { flex: 1; height: 72rpx; background: #fff; border-radius: 12rpx; text-align: center; line-height: 72rpx; font-size: 24rpx; }
|
||||
.sec { margin: 32rpx 0 12rpx; font-size: 28rpx; font-weight: 600; }
|
||||
.rec { display: flex; justify-content: space-between; align-items: center; padding: 24rpx 28rpx; border-bottom: 1rpx solid #E8ECF2; }
|
||||
.rt { display: block; font-size: 28rpx; font-weight: 600; }
|
||||
.rl { display: block; font-size: 22rpx; color: #6B7280; }
|
||||
.body { padding: 8rpx 28rpx 48rpx; }
|
||||
.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; }
|
||||
.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; }
|
||||
.dot { width: 16rpx; height: 16rpx; border-radius: 50%; background: #D1D5DB; margin-right: 16rpx; flex-shrink: 0; }
|
||||
.dot.on { background: #1677FF; }
|
||||
.slot-m { flex: 1; min-width: 0; }
|
||||
.lab { display: block; font-size: 28rpx; font-weight: 600; color: #111827; }
|
||||
.val { display: block; font-size: 24rpx; color: #9CA3AF; margin-top: 6rpx; }
|
||||
.val.ok { color: #16A34A; }
|
||||
.tiny { font-size: 22rpx; color: #16A34A; }
|
||||
.ring-wrap { display: flex; justify-content: center; padding: 56rpx 0 28rpx; }
|
||||
.ring {
|
||||
width: 320rpx; height: 320rpx; border-radius: 50%;
|
||||
background: linear-gradient(180deg, #3D8BFF 0%, #1677FF 100%);
|
||||
box-shadow: 0 16rpx 40rpx rgba(22, 119, 255, 0.35);
|
||||
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
||||
color: #fff;
|
||||
}
|
||||
.ring.busy { opacity: 0.72; }
|
||||
.now { font-size: 44rpx; font-weight: 650; letter-spacing: 1rpx; font-variant-numeric: tabular-nums; }
|
||||
.act { margin-top: 10rpx; font-size: 30rpx; }
|
||||
.geo { display: flex; align-items: center; justify-content: center; gap: 8rpx; font-size: 24rpx; color: #6B7280; }
|
||||
.quick { display: flex; margin-top: 36rpx; background: #fff; border-radius: 20rpx; border: 1rpx solid rgba(17,24,39,0.06); }
|
||||
.q { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 10rpx; padding: 28rpx 0; font-size: 24rpx; color: #374151; }
|
||||
.sec { margin: 36rpx 8rpx 14rpx; font-size: 28rpx; font-weight: 650; color: #111827; }
|
||||
.log { padding: 8rpx 0; }
|
||||
.rec { display: flex; align-items: center; padding: 22rpx 24rpx; position: relative; }
|
||||
.rec + .rec { border-top: 1rpx solid #F0F2F5; }
|
||||
.rail { width: 12rpx; height: 12rpx; border-radius: 50%; background: #1677FF; margin-right: 16rpx; flex-shrink: 0; }
|
||||
.rec-m { flex: 1; min-width: 0; }
|
||||
.rt { display: block; font-size: 28rpx; font-weight: 600; color: #111827; }
|
||||
.rl { display: block; font-size: 22rpx; color: #6B7280; margin-top: 4rpx; }
|
||||
.ok { color: #16A34A; font-size: 24rpx; }
|
||||
.empty { padding: 40rpx; text-align: center; color: #6B7280; }
|
||||
.deny { padding: 120rpx 40rpx; text-align: center; color: #6B7280; }
|
||||
|
||||
Reference in New Issue
Block a user