SpringBoot+Vue+MyBatis+MySQL前后端分离考勤系统源码部署教程
项目标题: 前后端分离公司日常考勤系统SpringBootVueMyBatisMySQL完整源码部署教程项目正文: 一个基于SpringBoot、Vue、MyBatis、MySQL搭建的前后端分离考勤系统包含员工打卡、请假审批、考勤统计等模块提供完整源码和万字部署教程。关键词: SpringBoot, Vue, MyBatis, MySQL, 前后端分离, 考勤系统, 部署教程摘要描述: 从技术选型到代码实现再到部署上线的完整考勤系统实操记录拆解核心模块设计思路与避坑经验。1. 项目概述与需求分析考勤这事说起来简单做起来全是坑。真要把一套考勤系统从零到一搭起来最麻烦的不是打卡那个动作而是围绕打卡衍生出来的一堆业务规则——迟到早退怎么算、请假和打卡记录怎么联动、每个月的数据怎么汇总成报表、管理员和员工和审批人三个角色看的东西完全不一样……要是没有一套清晰的架构代码写到最后基本是东补一块西补一块。这个项目的初衷是给中小型公司做一套内部日常考勤工具。之所以强调“中小型”是因为大厂一般有成熟的OA或HR系统而很多几十人到几百人的公司买商业考勤系统觉得贵用Excel又太原始正好卡在中间。自己做一套前后端分离SpringBoot做主后端Vue做前端页面MyBatis操作MySQL数据权限区分管理员和普通员工打卡、请假、审批、统计报表这些模块一个不落。按这个标题来拆可以提炼出几个关键点前后端分离决定你整个项目结构怎么摆前后端怎么联调部署时怎么处理。SpringBoot MyBatis MySQL后端基础框架和持久层方案。Vue前端框架负责页面渲染和交互。完整源码 部署教程具备很强的工程属性不是玩具项目。所以这篇内容我打算按一条完整的主线来写先从需求盘点和技术选型说起然后拆数据库设计和后端核心接口再讲前端页面怎么对接REST API接着给出完整的部署流程最后把我实际开发中踩过的坑列一份清单出来。无论你是刚学完SpringBoot想找个练手项目还是真需要在公司内部跑这样一套系统应该都能从里面找到可以直接拿走用的东西。1.1 核心需求盘点动工之前先把需求捋清楚下面这些是我跟需求方反复对齐过的清单员工端上下班打卡每日二次、查看个人当日考勤状态、提交请假申请、查看自己的考勤月报和请假记录。管理员端管理员工账号增删改查、启用禁用、查看全员每日考勤明细、处理请假审批、按月统计出勤/迟到/早退/请假数据。假期规则需要支持事假、病假、年假三类类型审批状态分为待审批、通过、驳回。考勤规则固定工作时间比如上午9点到12点下午13点半到18点迟到和早退都需要有明确判断逻辑。报表导出管理员需要按月份导出考勤统计表方便人事部门使用。实际做过项目的同学看到这份需求应该能感觉到真正的复杂度不在CRUD本身而在状态流转和数据聚合。比如员工“请假”这个动作完成后会自动联动当月统计比如“打卡时间”要和设定好的上下班时间做比对才能得出迟到早退结果。这些都是需要提前设计清楚、否则后面一定会返工的点。1.2 技术选型与架构拆解前后端分离已经不算新鲜事但对一个考勤系统来说这个选择背后有几层实在的考量。第一业务形态适合。考勤系统的用户分管理员和普通员工页面逻辑有表单类操作、有表格展示、有统计图表前端交互复杂度中等偏高。用Vue这类前端框架页面路由、状态管理、组件复用都有成熟方案比后端模板引擎渲染页面的开发效率高出一截。第二并行开发效率高。前后端分离后后端只需要把REST API定义清楚前端就可以先拿Mock数据并行推进不用像传统JSP项目那样等后端把页面渲染好才能联调。第三部署灵活。后端用SpringBoot打成Jar包独立运行前端构建成静态文件扔到Nginx里两台机器分开部署也完全没问题。小公司一台服务器也可以搞定——Nginx负责静态资源访问和反向代理后端进程独立跑在8080端口。技术栈的选择我也顺带说明一下。MyBatis看起来比JPA繁琐但胜在SQL可控性强。考勤统计这种需求经常要写多表联查和分组聚合MyBatis能直接写原生SQL排查慢查询、调整索引都比Hibernate更直观而且国内大部分公司的Java项目都是MyBatis体系接手成本低。MySQL这套组合的生态成熟、资料多中小型考勤系统的并发量用它绰绰有余。整体架构分三层前端层Vue 2 Element UI Axios构建后生成静态文件。后端层SpringBoot 2.x MyBatis Spring Security或JWT提供RESTful接口。数据层MySQL 8.0存放用户、考勤、请假等数据。前后端之间走JSON格式的HTTP接口鉴权使用JWT Token。整体结构清爽也方便后续扩展比如再接入企业微信提醒、把仪表盘数据做成图表等。2. 数据库设计与后端核心实现一套考勤系统能否扛住真实业务需求数据库设计占一半功劳。表结构没设计好后面写SQL的时候就会发现自己天天在跟数据冗余和查询混乱作斗争。我当时设计表时主要从“人”、“行为”、“结果”三个维度来规划。2.1 表结构与关系梳理核心表一共四张用户表、考勤记录表、请假申请表、考勤统计汇总表。用户表主要字段包括id、用户名、密码BCrypt加密存储、姓名、部门、角色admin/employee、状态启用/禁用、创建时间。这里的角色字段非常关键所有接口的权限控制都建立在它之上。密码是敏感数据存储格式选的是BCrypt加盐哈希就算数据库泄露也不会直接暴露明文密码。考勤记录表设计时需要注意除了常规的id、用户id、打卡日期之外还要分出上班打卡时间和下班打卡时间两个字段而不是一条记录只存一个时间点。这样每天每个员工只产生一条考勤记录上班打了卡就更新上班时间下班打了卡再更新下班时间方便后续统计和展示。另外还需要冗余存状态字段比如正常、迟到、早退、缺卡省得每次统计都要临时计算。请假申请表字段包括id、用户id、请假类型、开始日期、结束日期、请假天数、请假原因、审批状态、审批人id、审批备注、申请时间和审批时间。请假天数这里看似冗余实际上是为了防止后续修改起止日期导致统计口径混乱申请时就固化下来更稳妥。统计汇总表按“用户id 统计月份”做唯一维度存储出勤天数、迟到次数、早退次数、请假天数、缺卡次数、加班时长这个看需求可加可不加。这张表是数据报表的直接来源好处是查询报表时只要查一张表不用临时去聚合考勤记录。代价是每次打卡和审批通过后需要触发一次汇总更新。这个设计思路本质上是空间换时间小规模系统完全够用。四张表之间的关系其实并不复杂用户 1 — N 考勤记录用户 1 — N 请假申请用户汇总表1 — 1 月度统计2.2 打卡逻辑与状态判定打卡是考勤系统的核心动作但后端处理打卡请求的代码并不复杂复杂的是判定逻辑。我设计打卡接口时遵循的规则是每个工作日允许打两次卡只记录上下班时间不做两次以上的限制防止用户早到后重复打卡刷新时间但会校验时间合法性。简单说就是上班时间点之前打上班卡自动标记为正常超过规定上班时间打上班卡自动标记迟到下班时间点之后打下班卡为正常提前打则标记早退。这里有个需要注意的细节打卡时间不能只做本地时间判断。我踩过最典型的一个坑就是服务器时区没有设置好导致用户早上9点打卡数据库里存的时间却是凌晨1点。后来统一规定前端传时间戳后端统一转成北京时间的字符串再入库彻底解决时区问题。这一点不只是考勤系统任何有时间业务逻辑的系统都必须注意。打卡接口的完整逻辑简单描述一下前端请求/api/attendance/check带上token识别用户id。后端根据当前日期查询当天考勤记录如果没有则新建一条把当前时间写入上班时间。判断当前时间是否晚于规定上班时间写入状态字段。如果已存在记录则判断当前时间是否早于规定下班时间写入早退状态或更新下班时间。返回当天的考勤状态给前端展示。判断迟到早退不能直接在代码里写死两个时间常量正确的做法是把上下班时间配置到系统表里这样以后想要调整作息时间或支持不同班次直接在页面上改配置而不用改代码重新部署。毕业设计或小型系统可能不需要这么复杂的班次管理但至少预留一张配置表会比写死在常量里好太多。2.3 请假审批的流程实现请假审批是一个典型的“状态流转”场景。员工提交请假申请初始状态为“待审批”管理员查看列表后选择通过或驳回流程就结束了。还有一类可选需求是“撤销申请”即待审批状态下申请人可以自行撤回。后端我设计了两个接口POST/api/leave/add提交请假申请。需要校验开始日期不能晚于结束日期请假日期不能包含已请假的日期年假类申请还需要校验剩余天数。PUT/api/leave/approve管理员审批。入参是申请ID和审批结果通过/驳回如果通过还需要自动联动调用统计更新逻辑把请假天数写入当月汇总表。审批逻辑里最容易被忽略的是“日期重叠校验”。假设员工A已经请了5号到7号的假再提交一份6号到8号的申请就会冲突。实现方案有两种一种是循环查出该员工所有状态为“待审批”或“通过”的请假记录和新申请逐条比对是否有交叉区间另一种是在SQL里用条件查询判断两个日期区间是否存在交集。从代码可读性上我推荐SQL方案一条语句就搞定。测试时记得覆盖几个边界场景完全重叠、部分重叠、首尾相连。联动更新的细节值得多说一句。审批通过后程序需要去重算一遍该员工当月统计。如果统计汇总表里已经有当月记录就更新请假天数和出勤天数如果没有就自动建一条。这套联动逻辑在代码里集中放在“统计服务类”里考勤打卡时也调用它。两个操作都指向同一套统计逻辑不会出现一边更新一边漏更新的情况。2.4 后端接口与权限控制权限控制我选用的是JWT方案登录成功后后端生成一个token返回给前端前端保存到本地存储每次请求在Header里带上这个token后端用拦截器解析token中的用户信息判断角色是否允许访问该接口。Spring Security也有不错的能力但配置起来学习成本稍高对于考勤系统这种体量的项目一个拦截器加自定义注解的方案就好用且清晰得多。我把接口按角色拆分成三类公共接口登录接口、获取验证码如果需要。用户接口打卡、查询自己的考勤记录、提交请假、查看自己的请假记录。管理接口用户管理、考勤明细列表、请假审批、统计报表查询。实现管理接口的权限校验时我在拦截器里做了两件事第一步解析token验证身份是否合法第二步读取用户角色根据访问的URL路径前缀放行或拒绝。比如/api/admin/**开头的路径只允许角色为admin的用户访问。加一个请求日志切面对系统上线后的排查会非常有利。哪个人几点几分调过哪个接口、传了什么参数、返回了什么结果都有迹可循。这不是一个必需模块但在真实业务场景里一旦出现“某人声称打了卡但系统没记录”这种扯皮情况日志就是判断依据。2.5 考勤统计与报表查询报表模块是考勤系统里的“技术含量担当”。统计逻辑本身并不难难点在于SQL的性能与可读性的平衡。一个典型的月度考勤报表SQL按照用户分组用SUM聚合每个用户的迟到次数、早退次数、请假天数。我写成MyBatis的动态SQL支持传入月份、部门、用户名三个条件进行过滤。核心语句大致是这样的SELECT u.id, u.name, u.department, COUNT(a.id) AS work_days, SUM(CASE WHEN a.status late THEN 1 ELSE 0 END) AS late_count, SUM(CASE WHEN a.status early THEN 1 ELSE 0 END) AS early_count, s.leave_days FROM user u LEFT JOIN attendance a ON u.id a.user_id AND DATE_FORMAT(a.date, %Y-%m) #{month} LEFT JOIN monthly_stat s ON u.id s.user_id AND s.month #{month} WHERE u.department LIKE CONCAT(%, #{department}, %) GROUP BY u.id这条SQL把“出勤天数”定义为“该月有考勤记录的日期数”因为上班打卡和下班打卡都在一行里所以按attendance表行数count即可。LEFT JOIN保证没有考勤记录的用户也能显示出来方便管理员一眼看出哪些人整天没打卡。统计结果不需要在代码里做二次加工MyBatis查询出来的结果直接就是报表数据。如果把报表换成图表展示前端可以用ECharts统计柱状图来展示部门出勤率。这块在业务流程上不重要但演示效果非常好做毕业设计或给领导演示时是很加分的功能。3. 前端实现与交互设计前端部分我选择了Vue Element UI的组合原因很简单组件全、文档完善、社区资料多。项目整体不需要特别复杂的前端工程化配置Vue CLI默认的那套已经足够。前端项目的目录结构推荐下面这种src/ ├── api/ # 接口请求封装 │ ├── attendance.js │ ├── auth.js │ └── admin.js ├── router/ # 路由配置 ├── views/ # 页面组件 │ ├── Login.vue │ ├── Dashboard.vue │ ├── Attendance.vue │ ├── Leave.vue │ └── Admin/ │ ├── UserManage.vue │ ├── AttendanceList.vue │ ├── LeaveAudit.vue │ └── StatReport.vue ├── store/ # 状态管理token、用户信息 └── utils/ # axios封装、日期处理工具3.1 用户端页面拆解登录页面没什么好说的账号、密码、登录按钮调后端登录接口拿token跳转到主页面。需要注意的一点是密码输入框必须支持回车提交这是很多初写前端的同学容易忽略的细节用户用起来的体感会差很多。打卡页面是整个系统交互最频繁的页面展示三个信息块当前时间、今日打卡状态、上班时间/下班时间配置。核心交互就一个“打卡”按钮点击后调后端打卡接口页面根据返回结果刷新状态。如果用户已经打过上班卡按钮文案自动切换成“下班打卡”如果两次卡都打完了按钮置灰不可用。我实际使用中发现打卡页面上显示“今天星期几和今日是否工作日”很重要不然员工周末不小心打卡后会产生困惑还会产生一条看起来奇怪的考勤记录。解决方式是前端判断当前日期是否为周六周日周末隐藏打卡按钮。法定节假日的情况更复杂需要维护一份节假日配置表考虑到考勤系统的使用频率我在第一版里只做了周末判断节假日调整留作扩展。考勤历史页面就是一个简单的表格展示打卡日期、上班时间、下班时间、当日状态正常/迟到/早退/缺卡。分页参数我设定为每页10条方便移动端查看虽然有同学说手机浏览器访问页面在小屏上Element UI表格体验较差但Vue项目要专门做移动端适配工作量大很多第一版先用桌面端优先后续可以再加响应式适配。3.2 管理员端核心页面用户管理页面是管理员最常用的页面之一。功能包括新增员工账号初始密码默认123456首次登录提示修改、编辑员工基本信息、启用/禁用账号、重置密码。这里有一个工程上的需要特别提醒删除用户要谨慎直接物理删除会造成历史考勤记录留下“孤儿数据”导致报表查不到那时是哪个员工打的卡。所以我设计的是“逻辑删除”——只把用户状态改为禁用考勤记录仍然保留报表查历史数据时仍然能关联上。考勤明细页面按日期范围和部门筛选表格展示员工姓名、部门、上班打卡时间、下班打卡时间、打卡状态。数据量较大时需要后端分页我用的是PageHelper插件参数传入页码和每页条数即可。筛选条件加上“只看异常”的开关可以帮助管理员快速找到迟到、早退、缺卡的人员。请假审批页面展示所有待审批的请假申请列表点击详情弹出抽屉或弹窗展示申请人的申请原因、请假起止日期和当前审批状态。审批人点击“通过”时后端会把结果同步到统计表页面上能实时刷新列表。3.3 前端请求封装与联调要点前端所有HTTP请求统一走Axios实例我在request.js里做了三件关键的事第一请求拦截器在请求头里自动附加token。service.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers[Authorization] token } return config })第二响应拦截器统一处理业务状态码和HTTP状态码。比如后端返回401token过期时自动清除本地存储的token并跳转登录页。第三统一错误提示。Axios的响应拦截器接收到非2xx状态时弹出全局的Message提示业务代码里就不用每个请求都写try-catch了。跨域问题在前后端联调时一定会碰到。本地开发时我的解决方式很粗暴后端接口加一个CORS配置类允许本地开发域名访问。生产环境直接用Nginx反向代理把/api路径转发到后端服务从根上规避跨域问题。这个方法后面部署部分还会详细展开。Vue和SpringBoot的联调过程中最耗时间的通常是字段名对不上。比如后端返回的是userName前端写成了username数据就是出不来。这个问题的根本解决办法是“前后端接口文档先行”——在编码前先对齐接口格式和字段命名。我项目里用的方案是直接维护一份Markdown文档注明每个接口的请求参数和返回结构前后端各自按文档开发联调时就少很多折腾。3.4 状态管理与路由守卫前端路由需要区分登录后才能访问和无需登录就能访问两类。我用Vue Router的全局前置守卫实现判断目标路由是否需要登录认证用户已登录再放行否则跳转到登录页。管理端的路由还需要校验角色定义路由时meta字段标记requiresAdmin: true守卫里再判断当前用户角色是否为admin。这里还有一个细节用户角色信息在登录成功时后端会一并返回前端存储在Vuex里并持久化到本地存储这样刷新页面后路由守卫还能读到角色信息不会因为store清空导致权限判断失效。Vuex的state我保持精简只放token、userInfo、sidebarCollapse这些全局需要共享的状态。考勤相关的页面数据都在组件内部管理不放到Vuex里避免状态冗余造成混乱。这是我在项目推进中频繁踩坑后形成的规范能不放store的数据就不放store全局状态只放各个页面都需要读取的跨页数据。4. 完整部署教程与踩坑记录一个系统做完只算完成了一半能稳定部署跑起来才叫交付。我在这部分把本地环境配置到线上部署的整个过程写一遍每一步都给出可复现的命令或配置照着操作就能把系统跑起来。4.1 本地开发环境搭建本地需要提前装好的软件清单如下软件版本建议用途JDK1.8及以上运行SpringBoot后端Maven3.6后端依赖管理和打包MySQL5.7或8.0数据存储Node.js14前端构建Nginx1.20生产环境静态资源服务和反向代理数据库初始化直接导入项目里提供的init.sql脚本会自动建库建表并插入一个管理员账号admin/admin123和一个测试员工账号。脚本里我特意加了几条预设的考勤和请假记录方便前端联调时能看到界面效果。如果不想用预设数据把insert语句删掉重新执行一遍即可。MySQL的时区设置必须重点说数据库连接串加上serverTimezoneAsia/Shanghai否则SpringBoot连接MySQL 8.0时会因为时区不匹配直接报错。另外数据库字符集设置为utf8mb4而不是utf8因为utf8mb4才能完整支持中文和emoji虽然考勤系统里基本用不到emoji但用户名和审批备注里的中文如果字符集不对会出现乱码的隐患。4.2 后端打包与启动在项目根目录执行Maven打包命令跳过单元测试加速构建mvn clean package -DskipTests构建成功后会在target目录生成一个attendance-system.jar文件。简化的启动方式就一条命令java -jar target/attendance-system.jar后台运行用nohupnohup java -jar attendance-system.jar --server.port8080 logs/app.log 21 日志文件单独存放是个好习惯排查问题时直接tail -f logs/app.log非常方便。JVM参数里建议加上-Xms256m -Xmx512m限制内存使用上限避免在1G内存的云服务器上占用过大内存把系统搞崩。这个参数在低配服务器上尤其重要小公司部署时经常踩这个坑。4.3 前端构建与Nginx配置前端项目里安装依赖并构建npm install npm run build构建完成后生成一个dist目录里面是纯静态文件。把这个目录上传到服务器上在Nginx配置里指定静态文件路径并配置反向代理转发API请求server { listen 80; server_name your-domain.com; root /var/www/dist; index index.html; location / { try_files $uri $uri/ /index.html; # 解决vue-router history模式刷新404问题 } location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }try_files这一行非常关键。Vue Router如果用history模式用户刷新非首页路径时比如访问/admin/userNginx会拿着这个路径去找对应文件找不到就返回404。加上try_files把它重定向到index.html由前端路由接管处理就不会出现刷新就404的问题了。生产环境不再需要后端CORS配置因为所有请求都走同源路径/apiNginx把请求转发到后端服务。这种方式不仅规避跨域管理也更安全API端口不会直接暴露到公网。4.4 常见问题排查手册我整理了一份开发部署过程中的典型问题速查表按照我踩过的真实场景记录拿去对照基本能定位大部分问题现象排查思路解决办法后端启动失败提示数据库连接异常检查数据库是否启动、连接串账号密码是否正确确认MySQL服务运行中检查application.yml配置前端请求接口返回404请求路径写错或Nginx转发路径不对对比接口文档检查/api前缀查看Nginx转发配置接口返回401token缺失或已过期重新登录检查Axios请求头是否带token打卡时间比本地时间晚8小时数据库时区或JVM时区设置问题数据库连接串加serverTimezoneAsia/Shanghai代码统一用时间戳Vue刷新页面404Nginx没有配置history模式回退在location中添加try_files $uri $uri/ /index.html;报表查询特别慢统计SQL未走索引或全表扫描给attendance表的user_id和date字段加联合索引上传构建文件后页面样式错乱静态资源路径不对或缓存检查vue.config.js中publicPath设为./加上location /assets的缓存清理表里那个“时间差8小时”的问题我再展开说下。根本原因是Java运行时的默认时区是服务器的系统时区云服务器很多默认是UTC时区代码里直接用new Date()存时间就会存成UTC时间比北京时间慢8小时。最有效的解决方式是在启动脚本里加上JVM参数-Duser.timezoneAsia/Shanghai或者在代码里指定日期处理用LocalDateTime并以字符串形式存储这个字符串就是北京时间的值从根上避开时区转换问题。4.5 安全加固建议如果这套系统真的要放在公网环境使用有几个安全层面的事建议直接做完改掉默认的管理员密码且要求强密码策略前端接口层加入参数校验防止SQL注入和XSS注入后端接口访问频率限制防止恶意刷打卡接口启用HTTPS加密传输尤其在考勤数据涉及员工姓名、部门这类敏感信息时墙裂建议上SSL证书。高级一点的需求还可以引入操作日志模块提供审计追踪出了问题可以追溯到具体操作者。5. 基于源码的二次开发方向整套系统按现在的架构做完我已经在考虑二次扩展的方向了。这里挑几个使用体验价值高、实现成本不高的功能点做个梳理如果你准备在这套系统上继续深耕这些方向性价比很高。第一个是增加节假日调休配置。现在的系统只能判断周末遇到法定节假日和调休日就会判定错误。扩展思路是建一张节假日配置表结构就两个字段——日期和类型节假日/工作日管理员页面预留导入和手动维护入口。打卡判断逻辑升级为先查调休配置表没有配置再按周判断。这个扩展对代码改动不大但业务实用性提升非常明显。第二个是增加移动端适配。很多公司员工是没有固定工位的用手机浏览器访问页面或者在企业微信/钉钉里通过工作台跳转访问。第一版我用Element UI的桌面端组件手机上虽然能用但体验确实一般。后期可以引入移动端组件库改造或者直接做一个轻量级的H5版本只提供打卡、请假和查看状态三个核心功能工作量可控使用体验会有质的提升。第三个是加班管理。考勤系统加加班记录其实很自然——员工在非工作时间打卡后自动生成加班申请草稿由管理员审批确认月底汇总加班时长。这块的业务逻辑和请假审批是镜像的代码结构上可以把审批流程抽象成一个通用的流程引擎后面再做调休、补卡申请这类需求就是套模板的事。第四个是引入图表可视化。考勤数据天然适合用图表展示——部门出勤趋势线、迟到分布柱状图、请假类型饼图用ECharts整合到管理员仪表盘页面上。对管理层来说一张趋势图比十个表格更有说服力。6. 经验总结与开发建议项目从启动到跑完整闭环我最大的体感是考勤系统看起来是个小项目但真正的坑都藏在业务复杂度和环境部署的细节里。总结几条我个人强烈推荐的做法给后来人参考。时序问题一定要在初始化阶段就处理干净。一套系统中存在前端展示时间、数据库存储时间、Java进程时间、服务器系统时间共四种时间状态只要有一个环节对不上用户就会觉得系统有Bug。常见的做法是统一定义“时间戳传参-本地时间字符串入库-前端格式化展示”的链路排查问题时直接从数据链路下手就快得多。不要等到部署阶段才考虑跨域和路径问题。前端开发时就约定好API请求统一走相对路径/api开头本地开发通过Vite或DevServer代理转发生产环境交给Nginx全流程走下来就不会出现“本地好好的一上线就挂了”的尴尬。权限设计宁简勿繁。第一版就按admin和employee两个角色做每个角色能看到的菜单固定写死通过前端路由守卫拦截加上后端拦截器双重校验基本够用。很多系统和项目一上来就整RBAC的模型恨不得建五张表来管权限实际上业务没有复杂到那个程度过度设计纯粹是自己给自己增加维护成本。合理的设计是业务发展确实出现了多角色多权限的需求再渐进式迁移。最后一点是文档的沉淀价值。我在这个项目里把接口文档、数据库设计文档、部署手册三个文档维护好中途接手的人可以快速上手。这套系统的完整源码里我保留了详尽的注释和一份部署视频照着操作二十分钟内就能在服务器上跑出一套可用的考勤系统。这也是我觉得整个项目最值得交付的部分——代码能跑只是基本前提让别人能快速理解并复现才真正体现工程能力。