SpringBoot3+Vue3+UniApp 假勤配置:部门班次、WiFi/GPS 与请假方案怎么选
🌐 文档地址:https://ruoyioffice.com
📦 源码1·GitHub:https://github.com/yuqing2026/ruoyi-office
📦 源码2·GitCode:https://gitcode.com/zhouzhongyan/ruoyi-office
📦 源码3·Gitee:https://gitee.com/yqzy1688/ruoyi-office
💬 微信:17156169080(备注「RuoYi Office」)
总部 9 点,门店 8 点半;办公室要连指定 WiFi,工地只认围栏。规则若拆成「班次页 / 定位页 / 假期页」,实施对不上,手机打卡各吃各的。RuoYi Office 把假勤收成一页:按部门保存,没有本级就继承父级。UniApp 打卡不读第二套配置。
▲ 部门班次继承之后,GPS 围栏和 WiFi 白名单一起拦打卡;手机只显示解析结果
引言:假勤难在「谁用哪套规则」
打卡、请假、节假日经常被做成三个模块三个默认值。员工在手机上迟到,HR 在 PC 上说「我们配的是 9:30」。对不上的原因通常不是公式,而是 配置入口散了,继承关系没人解释。
|
|
|
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
本文只讲配置中枢:在哪一页选、本级还是继承、手机吃哪些字段。 围栏怎么画圆见天地图专文;补卡回写见补卡专文;请假额度见余额账户文。不重复那些算法。
技术栈锚点:Spring Boot 3.5 + Vue3 Vben + UniApp。PC 配,App 打。
一、一页中枢:模块表先看清
菜单:人力资源 → 假勤管理 → 假勤配置,路由 /hrm/attendance/attendance-config。左部门树,右一张大表。保存写 hrm_attendance_config,按 deptId 一行。
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
不要把「请假类型」理解成另一套部门继承。假期类型是全局字典;部门挂的是节假日方案 + 班次。配置页下半截也会提示「假期规则继承自上级」,和考勤规则同一套 inherited 黄条。


▲ /hrm/attendance/attendance-config。选中有本级配置的部门,班次和时间规则可改。这是主效果图
二、继承怎么选:有行覆盖,没行往上走
AttendanceConfigServiceImpl.getAttendanceConfigByDeptId 先查本级。命中则 inherited=false。没有行就取部门 parentId 递归。到顶级还没有,返回 null,打卡页 hasConfig=false。
public AttendanceConfigRespVO getAttendanceConfigByDeptId(Long deptId) {AttendanceConfigDO config = attendanceConfigMapper.selectByDeptId(deptId);if (config != null) {AttendanceConfigRespVO respVO = BeanUtils.toBean(config, AttendanceConfigRespVO.class);respVO.setTimeRules(BeanUtils.toBean(config.getTimeRules(), AttendanceTimeRuleVO.class));respVO.setWifiList(BeanUtils.toBean(config.getWifiList(), AttendanceWifiItemVO.class));respVO.setInherited(false);return respVO;}DeptRespDTO dept = deptApi.getDept(deptId).getCheckedData();if (dept == null || dept.getParentId() == null || dept.getParentId() == 0) {return null;}AttendanceConfigRespVO parentConfig = getAttendanceConfigByDeptId(dept.getParentId());if (parentConfig != null) {parentConfig.setInherited(true);}return parentConfig;}
前端 loadConfig:inherited=true 时黄条「当前部门未设置,以下继承自上级。改完点保存即变成本级」。保存后 hasConfig=true,黄条消失。删除本级行,下次加载重新继承——确认框写的就是这句。
|
|
|
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
保存是整行覆盖,没有「只改 WiFi、班次继续继承」的字段级继承。需要半套不同,就复制父级后再改。这是有意做简单:实施讲得清,排障只查有没有本级行。
三、班次:timeRules 比两个字符串更靠谱
表上仍留着 workStartTime / workEndTime 当回退。真正生效的是 JSON timeRules:季节(全年/夏/冬)、精确或弹性、弹性窗、最少工时。前端保存前 ensureTimeRules,精确班次还会把当前规则写回那两个回退字段。
weekMode=1 才走大小周:bigWeekParity 奇数周或偶数周,bigWeekDays / smallWeekDays 各写一份。固定工作日只用 workDays。
打卡时不把整份 timeRules 丢给手机算。AttendancePunchController.getPunchInfo 调 attendanceRuleService.resolveDayRule(config, today),只下发 今天 的工作日、上下班、弹性窗。手机只展示和判断,迟到早退以后端 calcCheckInStatus / calcCheckOutStatus 为准,不采信前端 statusFlag。
四、打卡方式:位置、内网、外勤怎么选
punchMode:1 位置打卡,2 内网打卡。不要理解成「PC 一种、App 一种」——两端读同一字段。
位置打卡。 配经纬度和 punchRadius。UniApp 用当前距离比半径,isInRange 为假则不能普通打卡。外勤另开 allowFieldPunch,状态记 2,不走围栏。
内网打卡。wifiList 是 {ssid, bssid} 数组。SSID 给人看,匹配只认 BSSID。名单为空:兼容旧逻辑,能进系统就能打。名单非空:必须提交 BSSID,且归一化后命中任一项。PC 浏览器、H5 常常拿不到 BSSID,会被 ATTENDANCE_PUNCH_WIFI_REQUIRED 拦住——这是门禁,不是 bug。外勤打卡跳过 WiFi 校验。
private void validatePunchWifi(AttendanceConfigRespVO config, String bssid) {if (config == null || config.getPunchMode() == null || config.getPunchMode() != 2) {return;}if (CollUtil.isEmpty(config.getWifiList())) {return;}if (StrUtil.isBlank(bssid)) {throw exception(ATTENDANCE_PUNCH_WIFI_REQUIRED);}String current = normalizeBssid(bssid);boolean matched = config.getWifiList().stream().map(item -> normalizeBssid(item.getBssid())).anyMatch(white -> StrUtil.isNotBlank(white) && white.equals(current));if (!matched) {throw exception(ATTENDANCE_PUNCH_WIFI_NOT_MATCH);}}
归一化:去空格、小写、- 改 :。路由器后台抄 MAC 时格式不统一,不要让实施手工对齐冒号。
前端保存会丢掉没填 BSSID 的行。只写「办公室 WiFi」不写物理地址,等于没配白名单。
▲ 研发部门本级行:定位打卡、500 米半径、大小周、2026 法定假、08:00–17:00。演示数据是位置模式,所以露出经纬而不是 WiFi 表
选法对照:
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
五、节假日和补卡为什么挂在同一页
holidayPlanId 指向节假日方案。方案本身在弹窗里维护(调休、法定假),配置页只选「本部门用哪一套」。班次说「周一到周五要打」,方案说「十月一日不用打」。resolveDayRule 两边都看。方案配错页,手机只看见「今天不是工作日」,HR 以为班次坏了。
补卡:allowCardReplacement、每月次数、截止类型(当天/本周/本月/自定义天数)。提交补卡单时读的是 员工部门解析后的那一行,不是请假类型上的开关。关补卡却在请假里开「事假抵缺卡」,对不上账。
考核开关 needCheck:不考核的部门仍可能要打卡记出勤,但不进扣款。和「没有配置」不同——没有配置是 hasConfig=false,按钮直接不可用。
六、UniApp:只消费解析结果
移动端 pages-hrm/attendance/punch.vue。getPunchInfo 回来后:
hasConfig===false:提示无考勤规则,不能打。 punchMode===2:不比距离,看 wifiRequired和wifiList的 SSID 提示。-
否则比 punchRadius。 -
展示的上班时间来自当日 workStartTime,不是写死 9:00。
const isIntranetMode = computed(() => punchInfo.value.punchMode === 2)const wifiRequired = computed(() => punchInfo.value.wifiRequired === true)const isInRange = computed(() => {if (!punchInfo.value.hasConfig) return falseif (isIntranetMode.value) return trueif (distance.value === null) return falsereturn distance.value <= (punchInfo.value.punchRadius || 200)})
executePunch 带 punchType、加班、外勤。迟到早退以后端规则引擎为准。PC 打卡页走同一套 /info 和 /do。改配置不用发 App 版本,只要员工重新进入打卡页。


▲ 390 宽竖屏。顶栏是班次时间,中部是范围或 WiFi 提示。规则来自 PC 假勤配置,不是小程序本地缓存
七、和相邻页怎么分工
|
|
|
|
|---|---|---|
|
|
/hrm/attendance/attendance-config |
|
|
|
/hrm/attendance/punch-record |
|
|
|
/hrm/attendance/leave-type |
|
|
|
|
|
|
|
/pages-hrm/attendance/punch |
|
打卡记录用来印证「配完能打」,不要再截第二张表。围栏画圆去天地图文;本页只要半径和经纬字段看得到。
八、保存时的两个实施坑
1. 逻辑删除后主键冲突。 本级曾经配过又删掉,再保存必须 config.setId(null) 再 insert。代码已经清 id。二次开发不要把前端带回的旧 id 硬塞回去。
2. 继承黄条下直接保存。 黄条数据是父级内容。点保存等于 复制一份到本级。门店只想改半径、班次仍跟总部,当前模型做不到字段级继承——保存后班次也固定在门店行,总部再改班次门店不会跟。这是最常见的误配。解决:门店不要保存整页;或接受「门店从此独立」。
统计出勤时 PunchStatisticsServiceImpl 同样按员工部门 getAttendanceConfigByDeptId。报表和打卡页必须是同一套继承,禁止统计服务自己写一份默认 9 点。
九、技术亮点
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
十、快速体验
在线演示:https://ruoyioffice.com/web/(账号 admin / admin123)
-
打开 人力资源 → 假勤管理 → 假勤配置。 -
点公司节点,看是否已有本级行;再点子部门,看黄条是否出现。 -
看打卡模式:1 则认半径,2 则认 WiFi 表是否有 BSSID。 -
打开节假日方案,确认 holidayPlanId有值。 -
手机或 H5: pages-hrm/attendance/punch,核对上班时间和 PC 当日规则一致。 -
演示站不要随便给公共部门删配置。
源码仓库:GitHub:https://github.com/yuqing2026/ruoyi-office | GitCode:https://gitcode.com/zhouzhongyan/ruoyi-office | Gitee:https://gitee.com/yqzy1688/ruoyi-office
本地:后端 48080,PC pnpm dev:antd,UniApp pnpm dev 后用 390 宽。两端验证码关闭后才能自动登录截图。
常见问题(FAQ)
子部门改了半径,总部改班次为什么带不动?
子部门一旦保存,就是完整本级行。班次也被固定。要跟总部,删掉子部门配置。
内网打卡在电脑浏览器失败?
白名单非空时必须有 BSSID。浏览器拿不到就失败。改用 App,或该部门改回位置打卡,或清空白名单(只保留内网模式、不校验 WiFi)。
没有配置为什么不能打卡?
hasConfig=false。给员工部门或任一祖先保存一行。不要在 UniApp 写本地默认班次。
节假日和班次哪个优先?
resolveDayRule 先看今天是不是工作日(含方案里的假/调休),再套 timeRules。方案说放假,弹性窗不会让你变成上班。
和请假规则配置那篇文章什么关系?
那篇讲假种额度、单位、限制。本篇讲部门用哪套班次和哪套日历。请假扣的是余额,打卡看的是当日规则,不要把假种开关当成班次。
结语
假勤配置要选的是「本级覆盖还是继承」,以及「位置、内网、外勤」怎么组合。班次、WiFi、围栏、节假日、补卡写在同一页,手机只吃解析后的当日字段。字段级继承故意不做,免得实施讲不清。
读者能带走的三句:只在需要例外的部门保存;WiFi 认 BSSID;App 不写第二套班次。你们现在门店迟到,是班次真的 9 点,还是继承断了?评论区贴一下有没有黄条。
相关阅读:天地图文讲围栏怎么画;补卡文讲审批回写打卡记录;假期规则文讲假种。那些文章不替代本页的部门继承。
💡 想要体验 RuoYi Office 的强大功能?
🌐 在线演示:https://ruoyioffice.com/web/(账号 admin / admin123)
📦 源码仓库:GitHub:https://github.com/yuqing2026/ruoyi-office | GitCode:https://gitcode.com/zhouzhongyan/ruoyi-office | Gitee:https://gitee.com/yqzy1688/ruoyi-office
💬 技术咨询:添加微信 17156169080,备注「RuoYi Office」
⭐ 如果觉得不错,请给个 Star 支持一下!

