oa_app仓库初始化
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<fy-header title="打卡" />
|
||||
<view v-if="!canPunch" class="deny">当前账号没有打卡权限</view>
|
||||
<view v-else class="body">
|
||||
<view class="clock-box">
|
||||
<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>
|
||||
</view>
|
||||
</view>
|
||||
<view class="btn-primary" @click="doPunch">{{ punching ? '定位中…' : (outRec ? '更新打卡' : '打卡') }}</view>
|
||||
<text class="geo">将使用手机定位校验打卡范围</text>
|
||||
<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>
|
||||
<view class="sec">
|
||||
<text class="st">今日及近期记录</text>
|
||||
</view>
|
||||
<view class="card">
|
||||
<view v-if="!records.length" class="empty">暂无记录</view>
|
||||
<view v-for="r in records" :key="r.id || r.time" class="rec">
|
||||
<view>
|
||||
<text class="rt">{{ r.title || r.kind || '打卡' }} {{ r.time || r.punchTime || '' }}</text>
|
||||
<text class="rl">{{ r.location || r.address || '' }}</text>
|
||||
</view>
|
||||
<text class="ok">{{ r.status || '正常' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FyHeader from '../../components/fy-header.vue'
|
||||
import { store } from '../../utils/store.js'
|
||||
import { clockText, toast } from '../../utils/format.js'
|
||||
|
||||
export default {
|
||||
components: { FyHeader },
|
||||
data() {
|
||||
return { now: clockText(), timer: 0, punching: false, off: null }
|
||||
},
|
||||
computed: {
|
||||
canPunch() { return store.can('personal', 'punch') },
|
||||
rules() { return store.attendRules },
|
||||
records() { return store.attendance || [] },
|
||||
locName() {
|
||||
const locs = this.rules.locations || []
|
||||
return locs[0] ? (locs[0].name || locs[0].title || '') : ''
|
||||
},
|
||||
inRec() {
|
||||
return this.records.find((r) => /上班|in|on/i.test(String(r.title || r.kind || r.type || '')))
|
||||
},
|
||||
outRec() {
|
||||
return this.records.find((r) => /下班|out/i.test(String(r.title || r.kind || r.type || '')))
|
||||
}
|
||||
},
|
||||
onShow() {
|
||||
if (store.phase !== 'app') uni.reLaunch({ url: '/pages/login/login' })
|
||||
store.refreshAttendance()
|
||||
this.timer = setInterval(() => { this.now = clockText() }, 1000)
|
||||
this.off = store.on(() => this.$forceUpdate())
|
||||
},
|
||||
onHide() {
|
||||
if (this.timer) clearInterval(this.timer)
|
||||
if (this.off) this.off()
|
||||
},
|
||||
methods: {
|
||||
async doPunch() {
|
||||
if (this.punching) return
|
||||
this.punching = true
|
||||
try {
|
||||
const msg = await store.punch()
|
||||
toast(msg, 'success')
|
||||
} catch (e) {
|
||||
toast(e.message || '打卡失败')
|
||||
} finally {
|
||||
this.punching = false
|
||||
}
|
||||
},
|
||||
goKind(kind) {
|
||||
if (!store.can('personal', 'apply')) return toast('没有发起申请权限')
|
||||
uni.navigateTo({ url: '/pages/apply/form?kind=' + kind })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.body { padding: 16rpx 24rpx 40rpx; }
|
||||
.clock-box { background: #f2f3ff; border-radius: 16rpx; padding: 36rpx 0; text-align: center; }
|
||||
.now { display: block; font-size: 68rpx; font-weight: 700; letter-spacing: 2rpx; }
|
||||
.shift { font-size: 22rpx; color: #434655; }
|
||||
.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: #434655; display: block; margin-top: 12rpx; }
|
||||
.val.ok { color: #006c49; font-weight: 700; }
|
||||
.tiny { font-size: 20rpx; color: #737686; }
|
||||
.geo { display: block; text-align: center; font-size: 22rpx; color: #434655; margin: 16rpx 0 24rpx; }
|
||||
.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 #eaedff; }
|
||||
.rt { display: block; font-size: 28rpx; font-weight: 600; }
|
||||
.rl { display: block; font-size: 22rpx; color: #737686; }
|
||||
.ok { color: #006c49; font-size: 24rpx; }
|
||||
.empty { padding: 40rpx; text-align: center; color: #737686; }
|
||||
.deny { padding: 120rpx 40rpx; text-align: center; color: #737686; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user