ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

基于微信小程序的中小企业考勤请假工资系统开发实战

基于微信小程序的中小企业考勤请假工资系统开发实战 刚接手一个小型企业的HR系统需求时我理解的第一件事是老板要的并不是一个大而全的HR SaaS而是能解决考勤、请假、工资这三件最痛的事并且员工愿意用、用得顺手的工具。最终我把方案锁定在微信小程序上做了一套“微信小程序的小型企业人事人力资源考勤请假工资app”从需求确认到上线前后花了近两个月这里把完整思路、关键实现和踩坑记录整理出来给同样想给中小企业做轻量HR系统的朋友一个参考。这个项目解决的核心问题是小企业没有专职IT人事系统管理员员工流动性不小打卡靠微信群里喊一声、请假靠口头说一句、算工资靠Excel手工统计月底一到人事和财务的状态基本是“一团乱麻”。而一套基于微信小程序实现的轻量HR系统能让员工在微信里完成上下班打卡、请假申请、查看工资条让管理者在后台一键审批、结算考勤数据整个流程不依赖额外安装App也不要求员工学习复杂的系统操作。适合的人群主要是两类一类是给创业公司、工作室、连锁门店做内部管理系统的开发者或产品经理另一类是正在选型或准备自建系统的企业管理者。1. 整体方案设计与选型思考1.1 为什么选微信小程序而不是原生App或H5不少人在做企业工具类产品时第一反应就是“做个App”但中小企业场景下App的下载安装成本非常高。我见过太多公司花几万块做了个App结果员工根本不愿意装最后沦为摆设。微信小程序就不同了它在微信里搜索或扫码就能打开用完即走下次要用再调出来完全没有安装门槛。那有人会问H5不是也可以吗H5在微信里打开确实方便但存在几个问题一是微信内置浏览器的定位能力和接口权限有限打卡场景需要稳定的地理位置信息二是H5无法直接复用微信的订阅消息能力打卡异常、审批提醒这些通知要靠短信或者邮件成本高、触达率还差三是H5在Android和iOS上的兼容性风险较多真机测试时很容易出现样式错乱。而微信小程序天然具备定位、订阅消息、蓝牙如果需要对接考勤机、WebSocket等原生接口开发体验和稳定性都更好。注意如果你的业务比较复杂比如包含大量报表分析、招聘管理、绩效考核等高交互场景小程序会受限于包体积和渲染能力这时候可以考虑小程序管理后台Web端的组合。本次项目就是把员工自助端放在小程序里管理端做成了H5后台两者共用同一套API。1.2 功能模块划分与页面结构设计产品上线前我把功能收敛成三个核心模块考勤、请假、工资再加一个基础的人员与角色管理。功能不是越多越好中小企业最怕的就是复杂的规则和选项减到不能再减员工才会愿意用。具体页面结构如下员工端小程序首页今日打卡状态、日历视图、打卡页上班/下班按钮、打卡记录、请假页申请、我的申请列表、工资条页按月查看、我的个人信息、企业信息管理端H5数据看板今日出勤概览、员工管理通讯录、部门、岗位、考勤管理打卡记录、异常处理、补卡审批、请假管理审批列表、请假类型配置、工资管理工资项配置、月度工资核算、工资条发布这两个端共用一套后端接口员工端只暴露与自己相关的数据管理端则有完整的员工视角和管理权限通过登录时返回的角色字段做权限控制。1.3 后端技术选型与数据库设计要点后端我用的是Node.jsExpress MySQL原因是小企业项目用不到高并发但要快速开发、好维护。如果团队更熟Python也可以用Django或者FastAPI只要能支撑后续扩展选型不是重点。数据库表设计比较关键我按业务域拆成了几张核心表员工表user_id、姓名、手机号、部门、岗位、入职时间、角色employee/admin、基本工资考勤规则表公司ID、上班时间、下班时间、打卡范围经纬度半径、迟到/早退判定分钟数打卡记录表记录ID、用户ID、打卡类型上班/下班、打卡时间、经纬度、打卡状态正常/迟到/早退/外勤请假申请表申请ID、用户ID、请假类型事假/病假/年假/调休、开始时间、结束时间、时长、原因、审批状态待审批/通过/驳回工资表工资ID、用户ID、计薪月份、应发工资、缺勤扣款、加班补贴、实发工资、工资明细JSON这张工资明细JSON字段是我个人比较推荐的做法不同公司的薪资结构差异很大如果每个工资项都建一个字段后续改配置要改表结构。直接用JSON存储工资项的键值对灵活度会高很多取出来之后在前端按顺序渲染就行。2. 考勤打卡模块从定位到统计的完整链路2.1 打卡核心逻辑与防重复处理考勤模块是整个系统里最琐碎的部分但也是最影响员工体验的。打卡流程本身很简单员工进入小程序点击打卡按钮前端调用定位接口获取当前经纬度连同用户ID、打卡类型一起提交到后端后端校验是否在考勤范围内、是否已经打过卡然后写入记录。这里有一个特别容易踩坑的点同一员工同一天只能打一次上班卡、一次下班卡但不同的中小企业对“弹性打卡”的需求不一样。有的公司允许9点前后10分钟弹性打卡有的公司规定每天只能打一次卡外勤人员。所以我在设计打卡接口时把“是否已经打卡”这个判断放到了服务端同时允许考勤规则里配置“是否启用下班打卡”这样在门店场景下员工只需要打上班卡下班时间由系统自动生成减少操作负担。防重复打卡的代码逻辑大概是这样的// 考勤打卡接口简化版 async function handleClockIn(userId, clockType, lat, lng) { const today getTodayDate(); // 查询今日是否已有同类型打卡记录 const exists await db.query( SELECT id FROM attendance_records WHERE user_id ? AND date ? AND clock_type ?, [userId, today, clockType] ); if (exists.length 0) { return { code: 400, msg: clockType on ? 今日已打过上班卡 : 今日已打过下班卡 }; } // 校验考勤地理位置是否在范围内 const rule await getCompanyRule(userId); const distance calcDistance(lat, lng, rule.lat, rule.lng); if (distance rule.radius) { return { code: 400, msg: 不在考勤范围内 }; } // 判定状态迟到、早退、正常 const status judgeStatus(clockType, rule); await db.query( INSERT INTO attendance_records (user_id, date, clock_type, clock_time, lat, lng, status) VALUES (?, ?, ?, ?, ?, ?, ?), [userId, today, clockType, getNow(), lat, lng, status] ); return { code: 0, msg: 打卡成功 }; }2.2 基于微信小程序的定位实现及误差规避微信小程序获取定位用的是wx.getLocation这个接口返回的是经纬度、精准度等数据。在开发工具里测试通常会直接返回你电脑的IP定位和手机真机返回的GPS定位差异非常大所以定位功能一定要在真机上调试。在调用定位之前还需要在小程序后台申请权限并且在前端的app.json里声明permission字段说明用途否则调用时会弹窗遮住页面。我实际使用中发现wx.getLocation在室内或者信号差的地方精确度可能偏差几十米这对考勤范围小的公司是个问题。一个可行的补充方案是在提交打卡时不只是传当前经纬度同时把微信返回的accuracy精确度字段也传到后端如果精确度大于百米则提示“当前定位不精确请到开阔区域重试”避免员工明明在办公室却打卡失败的尴尬。注意微信的wx.getLocation是需要用户点击授权后才能使用的如果用户之前点了拒绝小程序端需要在设置页引导用户打开定位权限。实测方案是如果打开时发现authSetting[scope.userLocation]为 false直接跳转wx.openSetting让用户手动开启。2.3 考勤统计与异常记录处理打卡数据每天都在累积月底统计最头疼。我的做法不是直接在页面上做复杂汇总而是在后端定时生成每日的考勤汇总表这样月底直接查汇总就行不会因为数据量大拖慢接口响应。每天凌晨两点定时任务会扫描前一天的打卡记录做以下处理对于有上班卡但没有下班卡的员工标记为“缺下班卡”对于全天没有任何打卡记录的员工标记为“未打卡”对于迟到超过30分钟但没有请假的员工标记为“迟到”所有异常数据推送到管理端待办列表由人事确认是补卡、扣款还是人工修正这个“异常待办”机制帮了大忙因为小企业很多员工会忘记打卡如果系统直接按缺勤扣工资必然招来大量抱怨。现在人事只需要在后台看到异常列表和员工确认后选择“补卡”或“记为旷工”工资计算就会自动按修正后的数据走。3. 请假审批状态流转与通知消息的配合3.1 请假类型和额度管理请假模块看起来就是“填表单、等审批”但里面有一个隐藏难点请假额度管理。年假有多少天、调休有多少小时、病假需要什么证明这些规则如果不做好月底核算工资时会发现扣款对不上。我的做法是在员工表里增加了一个leave_balance字段用JSON格式记录各类假期的剩余额度{ annual_leave: 5.5, sick_leave: 3, personal_leave: 10, compensatory_leave: 2.5 }员工提交请假申请时后端先校验申请的时长是否小于等于剩余额度如果超了直接拒绝。审批通过之后再从余额里扣除。如果审批被驳回则不需要扣额度直接返回到员工端。这里最容易犯的错误是员工提交申请时先扣了额度结果审批被驳回后没有马上返还导致员工额度莫名其妙变少。所以我最终把“扣款”动作放在了审批通过之后而不是提交时。3.2 审批流程设计扁平化审批就够了小企业的审批流程不需要像大公司那样多层流转最多到部门主管和老板两级就顶天了。我在设计时用的是可配置路径请假类型为“年假”时默认审批人是直属上级为“事假”时默认审批人是老板也可以手动选择审批人。后台提供“审批人设置”页面让管理员随时调整。审批状态用一个字段流转pending→approved/rejected。员工提交后审批人会在管理后台看到待审批列表点击通过或驳回同时填写审批意见。这个审批意见会存入历史记录表方便后续查看。3.3 订阅消息通知与“一次性订阅”的应对方式微信小程序的通知能力经历了多次调整目前稳定可用的方式是“订阅消息”。但订阅消息有个限制用户需要主动点击“允许”后才能发送一次消息之后需要再次订阅才能再发。这对“审批提醒”这种需要多轮推送给员工的场景是致命的。我的解法是在员工提交请假申请后前端弹出一个“订阅审批结果通知”的授权框让员工允许发送一次消息。审批人点击通过后系统向员工发送“审批通过”通知。但如果员工下次再请假又需要再次订阅。这个体验虽然不够优雅但在微信目前的规则下是合规且稳定的方案。对于管理者端审批提醒则直接发到管理员的客服消息或企业微信群机器人不依赖订阅消息的授权。这个混合方案用下来反馈很好员工不会漏看审批结果管理者也不会忘记审批。注意微信小程序订阅消息的模板需要在微信公众平台申请每个模板都有固定的标题和字段。建议在开发前先把模板申请好否则联调时才发现模板ID不对会很浪费时间。4. 工资计算模块让Excel退居二线4.1 工资项的灵活配置每个公司的工资结构都不一样有的有绩效、有餐补、有交通补贴有的只有底薪加提成。如果写死工资项换一家公司就得改代码这是不可接受的。我设计了一个“工资项配置表”管理员可以在后台配置工资项的代码、名称、类型固定项/考勤联动项/变更项、计算方式加法/减法/乘法项。例如基本工资是固定加项缺勤扣款是考勤联动减项则系统在月度核算时自动读取考勤统计结果用“缺勤天数×日薪”得出扣款金额。绩效工资通常是手动输入的变更项由人事每个月录入评分或金额再合入工资。4.2 自动核算逻辑与试算流程工资核算不能直接生成最终数据必须先走“试算”流程。我的做法是人事在后台点击“锁定计薪月份”系统会把该月份所有员工的考勤数据、请假数据进行归档冻结防止后续有人补卡影响工资系统自动计算每个员工的应发工资、扣款、补贴生成工资草稿人事可以在工资草稿上手动调整比如某员工有额外的奖励调整后会记录操作日志点击“确认发布”后工资数据才会推送给员工员工在小程序端看到工资条这里最贴心的一个功能是人事在核对工资时可以点击员工姓名查看这个月的考勤明细逐条核对迟到、请假记录而不是只看到一个扣款总数。这样做让工资纠纷减少了不少因为一旦有员工问“为什么扣这么多”人事可以立刻找到原始记录。4.3 工资条的隐私保护与展示工资条本身是敏感数据绝对不能所有人可见。小程序端的工资条页面只展示当前登录用户的月工资数据并且需要在登录后设置支付密码或验证手机验证码才能查看。这个额外的验证步骤看起来有点繁琐但实际推广时员工都很理解毕竟谁也不希望自己的工资被旁边的同事偶然看到。工资条的数据结构是JSON渲染时按照工资项配置的顺序展示例如工资项金额基本工资8000.00餐补300.00迟到扣款-150.00社保公积金-800.00实发工资7350.00我会额外生成一个“实发工资”字段方便员工一眼看到重点。部分员工不习惯看明细只关心实发工资所以在首页醒目位置先展示实发工资再展开明细。5. 实操过程从零搭建项目的关键环节5.1 小程序初始化与基础框架搭建项目初始化其实没什么特别的用微信开发者工具新建一个小程序项目选择JavaScript基础模板然后按照需求安装第三方库。我建议在项目里使用WeUI组件库它针对微信生态优化过样式按钮、表单、弹窗都比自己写的要规范和整齐。目录结构大致是这样的├── miniprogram/ │ ├── pages/ │ │ ├── index/ # 首页今日状态 │ │ ├── clock/ # 打卡页 │ │ ├── leave/ # 请假页 │ │ ├── salary/ # 工资条页 │ │ └── mine/ # 我的 │ ├── utils/ │ │ ├── request.js # 封装请求 │ │ └── auth.js # 登录鉴权 │ └── app.js ├── cloudfunctions/ # 如果使用云开发则放云函数 └── project.config.json我没有使用云开发而是用了自建服务器因为薪资数据和考勤数据都涉及企业敏感信息放在自己的服务器上客户更放心。但如果你没有后端运维经验微信云开发也能快速跑通整个系统它的云函数和云数据库可以省去大量服务器搭建工作适合原型验证和小规模试用。5.2 登录鉴权与角色权限控制小程序登录流程在2022年之后发生了变化现在推荐使用wx.login获取 code然后后端用 code 换取 openid再自定义 session 返回给前端。注意不能直接用 openid 作为用户标识返回给前端因为 openid 只是用户的唯一标识不能包含业务数据。我的登录逻辑是// 后端 login 接口 async function login(code) { const wxRes await axios.get(https://api.weixin.qq.com/sns/jscode2session, { params: { appid: APPID, secret: APPSECRET, js_code: code, grant_type: authorization_code } }); const openid wxRes.data.openid; // 在用户表中查找这个 openid找不到则自动创建一个未激活员工账号 let user await db.query(SELECT * FROM employees WHERE openid ?, [openid]); if (!user) { user await createPendingUser(openid); } const token jwt.sign({ userId: user.id, role: user.role }, SECRET_KEY, { expiresIn: 7d }); return { token, user }; }前端的request.js会在每次请求时自动带上Authorization请求头后端通过中间件校验 token 的合法性。管理端的接口还会额外校验role admin确保员工不能调用管理接口。5.3 后端API设计与数据交互约定前后端约定使用RESTful风格接口统一返回{ code, data, msg }结构。举个例子POST /api/attendance/clockIn上班打卡POST /api/attendance/clockOut下班打卡GET /api/attendance/today获取今日打卡状态GET /api/attendance/month?month2025-06获取月度考勤汇总POST /api/leave/apply提交请假申请GET /api/leave/list?statuspending查询待审批列表POST /api/leave/approve审批处理GET /api/salary/detail?month2025-06获取本月工资条设计接口的时候我特别注意“敏感字段过滤”。比如员工列表接口如果返回了所有人的银行卡号或身份证号那后果不堪设想。所以后端查询后会用select或map方法把敏感字段剔除只返回前端真正需要的字段。5.4 考勤数据的定时任务与缓存优化考勤和工资都依赖定时任务我在后端用Node.js的node-cron库写了几个定时任务每天凌晨2点生成昨日考勤汇总标记异常记录每月1日凌晨3点试算上月工资推送到管理端待确认每月1日凌晨4点生成上月考勤月报这些定时任务在开发时可能看不到效果但上线后很有用。需要注意的是定时任务的执行时间要避开使用高峰期同时日志要记录每次执行的数量和错误方便排查。查询考勤记录时如果数据量变大可以用Redis做一层缓存把最近7天的当日考勤状态缓存起来员工打开首页时直接读缓存速度快很多。不过小企业几百人规模其实用不上这个优化我加上Redis纯粹是为了练手实际压力测试下来数据库直接查询也就几十毫秒。6. 常见问题与排查技巧实录6.1 真机定位失败与 errMsg 处理在开发工具里用wx.getLocation一切正常但真机测试时却出现getLocation:fail的报错。这个问题的排查优先级是确认在小程序管理后台配置了隐私保护指引并填写了位置信息的收集和使用目的确认app.json中声明了permission字段真机调试时确认系统定位服务已经打开如果用户拒绝了授权使用wx.getSetting检测授权状态再引导去设置页另外微信在2023年后对位置接口新增了“精确地理位置”的权限申请需要在后台「开发管理-接口设置」中申请开通wx.getLocation的精度权限否则即使代码正确真机也只能获取到模糊位置精度在几百米甚至几公里级别直接导致打卡范围失效。6.2 订阅消息发送失败模板ID和页面路径问题订阅消息发送失败的案例中七八成都是模板ID填错或者模板字段不匹配。开发时最好在后台申请模板后先用官方测试工具发送一次确认模板内容符合预期。另外注意订阅消息的跳转page字段必须是小程序内已存在的页面路径不能是外部链接否则用户点击消息后会进入无效页面。6.3 工资计算对不上排查思路分享工资计算偶尔会出现0.01元级别的差异这种问题通常不是代码 bug而是浮点运算精度导致的。JavaScript 的浮点运算在涉及小数点时会失真比如0.1 0.2会得到0.30000000000000004。处理方式是在后端统一使用整数分元乘以100来计算只在最后展示时转成元。6.4 微信审核被拒类目与素材准备小程序提交审核时分类选择“办公-人力管理”或“工具-效率”比较容易过审。但如果是给特定企业使用的内部系统建议在审核备注中写清楚用途和使用场景并附上测试账号。审核期间需要保证小程序可以正常登录最好准备一个游客账号给审核人员试用否则因为无法体验核心功能被拒是家常便饭。以下是我整理的一个问题速查表方便遇到问题时快速定位现象可能原因解决方案真机无法获取定位未配置隐私协议或未开通精确位置权限在微信公众平台后台配置隐私指引申请位置接口权限打卡提示不在范围内考勤范围设置太小或定位误差大将半径扩大到200-300米保存打卡原始坐标备查订阅消息收不到用户未授权、模板ID错误、发送参数不匹配检查订阅授权状态后台上传模板并核对字段审批通过后员工看不到结果状态同步或缓存延迟检查审批接口是否写库成功前端是否刷新状态工资条金额不对浮点运算或扣款项取数错误后端统一用分存储核对考勤异常数据小程序审核被拒类目不符、无法体验、隐私协议缺失修改类目补充测试账号和审核说明7. 项目上线后的几点实操体会系统上线之后我最大的感触是工具真正的价值不是替代人工而是让管理者第一次能准确看到“人”的数据。以前老板只知道员工有没有到岗但不知道有哪些人经常迟到、哪些人年假快过期了、这个月的人力成本具体是多少。现在这些数据每天自动更新老板在后台看一眼就心里有数。另外想提醒的一点是给企业做系统售后的培训也很重要。即使是微信小程序这种轻量产品也总有人不知道怎么打卡、怎么请假我的做法是在系统里内置了一个“使用说明”页面用图文步骤引导员工操作并在第一次打开时弹窗展示操作视频链接。这个不起眼的功能反而成了用户满意度最高的功能之一。最后再分享一个小细节工资发布前我建议加一个“确认并发送”的二次弹窗提示“工资一旦发布员工将立即看到”字样防止人事误操作。这个功能上线后帮我避免了一次差点提前发布工资的尴尬。做这类系统稳定性和信任感永远比功能数量重要跑得久、不出错才是小企业真正需要的。
返回列表