考勤登记管理系统三件套:原型、数据库、源码的完整落地路径
简介考勤登记管理系统完整资源包包含项目源码、原型设计图和数据库文件适合需要快速搭建考勤登记功能的学生开发者或小型项目团队。压缩包为rar格式共4个文件整体约963KB涵盖sql数据库脚本、bak数据库备份、pdf系统说明文档以及zip格式的源码/原型工程方便从数据库结构、界面原型到业务代码逐层查看与复用也可快速理清表结构关系、原型页面流转和核心业务逻辑。目前已有717人学习/下载可作为课程设计、毕业设计或日常办公考勤场景的参考底稿。拿到后可基于现有数据库设计扩展打卡、请假、统计等模块也可直接导入备份文件还原数据结合原型快速调整界面流程减少从零搭建系统的时间快速产出可演示的考勤管理系统。1. 考勤登记管理系统源码、原型、数据库三件套到底先动哪个考勤登记管理系统大概是所有管理系统里最容易被低估的一个。表面看就是“打个卡、记个时间、月底算个数”但真动手做一遍你就会发现原型的页面流画不清楚开发就会反复改数据库的表设计不严谨统计报表就全是脏数据源码里打卡判重写不严谨员工一天能打几十次卡。而“源码原型数据库”这个标题之所以会同时出现是因为这类项目最常见的交付形态就是一个完整的三件套——Axure 原型用来定需求和交互MySQL 脚本用来初始化表和演示数据后端源码把这些串成一个能跑的系统。适合谁准备毕设答辩的学生、想快速搭内部工具的小团队、以及第一次接触完整项目交付的初级开发。这篇就按先原型、再数据库、后源码的顺序把一条能复现的落地路径完整讲透。2. 原型先行先画页面流程再用 Axure 把考勤闭环走通2.1 考勤系统的页面地图5 个核心页面和 3 条主流程考勤登记管理系统听起来模块多拆开看核心页面其实就 5 个。登录页、员工打卡页、考勤记录页、考勤统计页、管理后台页。管理后台页里再挂员工管理、考勤规则、补卡审批三个子页面。先把这 5 个页面画出来整个系统的骨架就定了。比页面更重要的是流程。考勤系统的主流程有 3 条原型阶段必须把这 3 条走通否则开发期必然返工。第一条是打卡流程员工登录 → 进入打卡页 → 点击上班/下班按钮 → 系统记录时间 → 页面提示“打卡成功/已迟到”。第二条是补卡流程员工发现缺卡 → 提交补卡申请 → 选择补卡日期和时间 → 管理员审批 → 审批通过后状态变为已生效。第三条是统计流程考勤记录按日收集 → 月底按员工汇总 → 算出勤天数、迟到次数、早退次数 → 导出报表。画原型之前建议先用一张思维导图把这 3 条流程的所有分支节点列出来。比如打卡流程里要判断是否已打卡是否在考勤时间段内是否允许外勤打卡每个分支对应一个页面状态或弹窗提示。这样后面用 Axure 做交互时只需要把条件判断挂上去就行不会漏状态。实际做项目时这一步最容易被跳过但跳过的后果往往要在开发后期花好几倍时间补。2.2 用 Axure 做可交互原型的核心步骤Axure 做考勤系统原型不需要把每个页面画到像素级但关键交互一定要可点击可演示。我一般会按下面这套步骤来。第一步是搭页面框架。用 Axure 的“页面”面板按 2.1 的页面地图建好目录结构每个页面一个画板。登录页单独放员工端页面放一组管理端页面放一组。这样后续生成原型站点时目录层级也清楚。页面结构建议 ├─ 登录页 ├─ 员工端 │ ├─ 打卡页 │ ├─ 考勤记录页 │ └─ 补卡申请页 └─ 管理端 ├─ 员工管理页 ├─ 考勤规则页 └─ 补卡审批页第二步是画低保真线框。用矩形、文本框、按钮三类元件就够。打卡页核心是四个东西当前时间显示、员工姓名、上班按钮、下班按钮。考勤记录页核心是筛选条件和表格。管理后台核心是左侧导航栏加右侧内容区。不需要拖图片、不需要配色线框能表达信息层级就行。第三步是设置交互。这是原型阶段最花时间但也最值钱的部分。以打卡按钮为例选中“上班打卡”按钮在“交互”面板里新增“单击时”用例选择“设置文本”动作把打卡结果文本设置为“打卡成功2025-01-15 09:01:23”。再加一个“启用/禁用”动作把上班按钮设为禁用模拟“今天已经打过上班卡”的状态。Axure 交互配置打卡按钮 事件单击 用例 1设置文本【result_text】 打卡成功 当前时间 用例 2禁用【btn_morning】 用例 3设置文本【btn_morning】 已打卡这里的参数含义result_text 是页面上放提示信息的文本元件名称btn_morning 是上班按钮的元件名称。Axure 里所有交互都要基于元件名称元件名一定要在画原型时规范命名不然交互设置会找不到对象演示时点按钮没反应就称得上翻车现场了。第四步是加条件判断。考勤系统里最典型的就是迟到判断。Axure 的条件逻辑在“用例”里配置新增一个用例选择“如果”条件判断“打卡时间是否晚于 09:00:00”。条件为真时提示“已迟到”为假时提示“正常打卡”。这里的判断逻辑和开发时的代码判断是一一对应的原型阶段把这个写清楚开发直接照抄逻辑就行。2.3 原型里必须定义清楚的边界状态原型评审中最容易翻车的点不在主流程上而在边界状态。考勤系统的边界状态至少要有这几个重复打卡时按钮置灰并提示“今日已打卡”非考勤时间打卡时提示“不在考勤时段内”补卡申请里选择的日期不能是未来日期管理员审批时通过和驳回两个按钮要分状态。这几个状态如果不在原型里画出来开发大概率会漏。漏了之后的表现是测试时手动造数据才发现逻辑缺失再回头补接口、改表结构这就是返工。所以我在带项目时有个习惯原型评审会上要求把每个按钮的“空态、常态、加载态、异常态”过一遍。考勤系统最常见的空态是考勤记录页无数据时的提示异常态是提交补卡时接口报错的提示。原型里画了一个“系统异常请稍后重试”的弹窗开发就知道要给接口加异常捕获了。原型阶段还有一个容易忽略的交付物页面标注。不需要写复杂的规格说明但要在这几个位置加注释打卡按钮的打卡时间取客户端时间还是服务器时间、补卡申请的有效截止时间、统计报表的默认时间范围。这些参数直接决定数据库怎么设计和接口怎么写。原型不只是给用户看的更是给开发看的开发拿到原型后能不问一句话就开工这个原型才算合格。3. 数据库设计考勤数据表怎么建才不返工3.1 五张核心表和它们的字段设计数据库是考勤系统真正的根基。原型阶段确定的每一个边界状态最终都要落到表结构里。我常用的方案是五张表用户表、员工表、考勤规则表、打卡记录表、补卡申请表。用户表管登录账号和角色员工表管员工基本信息考勤规则表管上下班时间和考勤范围打卡记录表管每一次打卡明细补卡申请表管补卡审批流程。用户表和员工表为什么要分开因为一个用户可能对应多套员工信息也可能存在离职后账号保留但员工状态失效的情况。分开以后员工表里加一个状态字段1在职、0离职就够不会影响账号体系。两个表用 employee_id 做外键关联。打卡记录表是核心表字段设计直接决定统计逻辑怎么写。我建表的核心 SQL 参考下面这样CREATE TABLE attendance_record ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 主键ID, employee_id BIGINT NOT NULL COMMENT 员工ID关联 employee_info.id, work_date DATE NOT NULL COMMENT 考勤日期如 2025-01-15, clock_in_time DATETIME NULL COMMENT 上班打卡时间, clock_out_time DATETIME NULL COMMENT 下班打卡时间, status TINYINT NOT NULL DEFAULT 0 COMMENT 0正常 1迟到 2早退 3缺卡 4外勤, is_valid TINYINT NOT NULL DEFAULT 1 COMMENT 是否有效0无效被补卡覆盖1有效, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, UNIQUE KEY uk_employee_date (employee_id, work_date) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT考勤打卡记录表;这张表设计的核心思路是每天每个员工只生成一条记录上班和下班时间分别放在 clock_in_time 和 clock_out_time 两个字段里而不是每次打卡插一行。这样做的好处有两点。第一统计“某天是否出勤”只需要看这一行数据的两个时间字段是否为空不需要 GROUP BY 之后再判断条数。第二唯一索引 uk_employee_date 直接从数据库层面挡住了同一天重复生成记录的请求这是后面避免打卡翻车的关键防线。用户名和密码字段建议放用户表。用户表里存 password_hash 而不是明文密码字段类型用 VARCHAR(64) 存 SHA-256 或 BCrypt 结果。考勤规则表里存上下班时间、迟到容忍分钟数、早退判定分钟数这些参数后续在管理后台可配置但第一次建表时就要预留字段。3.2 打卡记录与考勤统计E-R 关系和索引设计表之间的关系简单说就是用户表一条记录对应一个员工员工表一条记录对应多天多条考勤记录考勤记录每次被一条补卡申请关联。画 E-R 图时核心就是这三条关系连线多了反而乱。索引设计是考勤系统性能的分水岭。考勤记录表随着时间增长数据量会非常大。一个 200 人的公司一年就是 200 × 250 个工作日 5 万条三年就是 15 万条。虽然看起来不多但统计报表是按员工范围和时间范围查询的所以索引要围绕这两个维度建。实际开发中我会建两个索引。第一个是上面的唯一索引 uk_employee_date用于防止重复打卡同时天然支持“查某个人某天的考勤”和“查某个人某段时间的考勤”两类查询。第二个是普通索引 idx_work_date (work_date)用于支持“查某一天所有人的考勤情况”比如管理员查看今天哪些人迟到。有了这两个索引绝大多数查询都能走索引不需要在 WHERE 条件里全表扫描。补卡申请表的核心字段包括申请员工、被补卡的日期、补卡类型上班/下班、补卡时间、申请原因、审批人、审批状态待审批/通过/驳回、审批意见。这里有个设计细节补卡申请通过后要不要回写打卡记录表要。而且回写方式不是更新原记录的 time 字段而是把原记录的 is_valid 置为 0再插入一条新的有效记录。这样保留了完整的操作痕迹统计报表只汇总 is_valid1 的数据。这个细节如果不做管理员想追溯“这条记录是补卡生成的还是正常打卡的”就完全无从下手。3.3 初始化数据与演示数据让系统能立刻跑起来很多拿到“源码原型数据库”三件套的人第一件事不是看代码而是把数据库脚本导进去跑一遍。所以初始化脚本里必须有两类数据基础配置数据和演示数据。基础配置数据至少包含一个管理员账号、一个普通员工账号、一条默认的考勤规则。管理员账号建议直接给角色字段为 admin密码初始化为一个固定值并在脚本注释里标明“首次登录后请修改密码”。考勤规则表插入一条默认规则比如上午 09:00 上班、下午 18:00 下班迟到容忍 5 分钟早退容忍 5 分钟。演示数据是为了让系统跑起来后立刻能看到统计效果。我会手动插入 3 个员工近 5 天的打卡记录覆盖正常、迟到、早退、缺卡四种状态再插入一条待审批的补卡申请。这样登录系统后考勤记录页有数据、统计页有图表、审批页有任务三个核心模块一眼就能看到功能效果。演示数据的时间建议用相对日期生成不要写死具体日期否则测试时看到的永远是过去某一天的数据体验很怪。-- 演示数据插入近5天打卡记录以 CURDATE() 为基准向前推 INSERT INTO attendance_record (employee_id, work_date, clock_in_time, clock_out_time, status, is_valid) VALUES (1, DATE_SUB(CURDATE(), INTERVAL 4 DAY), 09:01:00, 18:02:00, 0, 1), (1, DATE_SUB(CURDATE(), INTERVAL 3 DAY), 09:47:00, 18:00:00, 1, 1), (2, DATE_SUB(CURDATE(), INTERVAL 4 DAY), 08:58:00, 17:30:00, 2, 1);这段 SQL 的关键点在于用 DATE_SUB 和 CURDATE() 动态生成日期。你不需要每次跑脚本都手动改日期任何时候执行都能得到“昨天”“前天”“大前天”的合理数据。CURDATE() 取的是 MySQL 服务器的当前日期如果服务器时区配置不对日期偏移会产生意想不到的结果这个坑在第 5 章展开讲。数据库设计做完开发期的大部分问题其实已经提前解决了。表结构清晰、索引明确、演示数据齐全后端的接口开发就变成了“照着表写增删改查”的体力活。但恰恰是这个“体力活”里藏着一堆只有真正写代码才会遇见的坑。4. 源码落地把原型和数据库串成一套能跑的系统4.1 技术选型与 8 个关键接口设计考勤登记管理系统的后端开发我比较推荐用前后端分离的方案后端 Spring Boot 提供 RESTful 接口前端 Vue 开发页面。这个组合在维护成本和招聘熟悉度上都有优势也是这类管理系统项目最常见的落地方式。如果你只想要一个极简的单体应用用 Spring Boot 加 Thymeleaf 渲染模板也能做但前后端分离这个方案的代码结构更清晰原型页面和前端页面的对应关系也更直观。后端接口的设计是整个源码部分的重心。抛开登录和员工管理这两个通用模块考勤系统特有的接口就 8 个打卡登记、查询当日状态、查询考勤记录列表、查询考勤统计、提交补卡申请、审批补卡申请、配置考勤规则、导出考勤报表。接口设计遵循一个原则一个页面对应一个接口不要为了减少请求数去硬凑。接口路径设计参考POST /api/attendance/clock 打卡登记 GET /api/attendance/today 查询当日打卡状态 GET /api/attendance/records 考勤记录列表分页 GET /api/attendance/statistics 考勤统计 POST /api/attendance/remedy 提交补卡申请 PUT /api/attendance/remedy/{id} 审批补卡申请 GET /api/attendance/rule 查询考勤规则 POST /api/attendance/rule 更新考勤规则打卡登记接口是重头戏请求参数只需要 employeeId 和 clockType上班/下班时间从服务器取不用客户端传。这样设计的理由是客户端时间是可以被修改的。如果让前端传打卡时间员工把手机时间改成早上 8:50再点打卡系统就会认为他没迟到。这个接口设计是底线谁改谁背锅。取服务器时间同样要注意时区问题后面避坑章会详细展开。日志记录也建议在接口层统一做。用一个拦截器在响应返回前记录请求路径、参数、处理耗时。考勤系统的数据比较敏感哪天找出“这记录是谁打出来的”日志就是唯一的回溯依据。4.2 后端核心代码打卡登记与判重逻辑打卡登记接口的代码逻辑看起来简短但每一行都有讲究。核心流程是接收请求 → 验证员工存在 → 查询当天记录 → 判断是否重复 → 判断迟到早退 → 插入或更新记录。PostMapping(/clock) public Result clock(RequestBody ClockRequest request) { // 1. 参数校验 if (request.getEmployeeId() null || request.getClockType() null) { return Result.error(参数缺失); } // 2. 查询当天记录利用唯一索引防止并发重复 LocalDate today LocalDate.now(); AttendanceRecord record attendanceMapper.selectByEmployeeAndDate( request.getEmployeeId(), today); // 3. 第一次打卡插入新记录 if (record null) { record new AttendanceRecord(); record.setEmployeeId(request.getEmployeeId()); record.setWorkDate(today); record.setStatus(AttendanceStatus.NORMAL.getCode()); // 判断是上班打卡还是下班打卡 if (morning.equals(request.getClockType())) { record.setClockInTime(LocalDateTime.now()); checkLate(record); // 内部判断是否迟到 } else { record.setClockOutTime(LocalDateTime.now()); checkEarlyLeave(record); } attendanceMapper.insert(record); return Result.success(打卡成功); } // 4. 已存在记录更新对应时间字段 if (morning.equals(request.getClockType())) { if (record.getClockInTime() ! null) { return Result.error(今天已经打过上班卡); } record.setClockInTime(LocalDateTime.now()); checkLate(record); } else { if (record.getClockOutTime() ! null) { return Result.error(今天已经打过下班卡); } record.setClockOutTime(LocalDateTime.now()); checkEarlyLeave(record); } attendanceMapper.updateById(record); return Result.success(打卡成功); }kernel 里的细节第一步先查后更新虽然中间有并发窗口但数据库里 uk_employee_date 唯一索引会在第二次 insert 时直接抛异常捕获 DuplicateKeyException 返回“打卡过于频繁”即可。这里我选择用数据库约束作为最终防线而不是完全依赖业务代码里的判断就是因为业务代码在高并发下会存在时间差数据库约束才是唯一可靠的方式。checkLate 和 checkEarlyLeave 的逻辑是读取考勤规则表里的上班时间和迟到容忍分钟数把当前时间和规则时间比较。比如规则是 09:00 上班、迟到容忍 5 分钟那么 LocalTime.now() 晚于 09:05 就置状态为迟到。注意这里的比较基准是纯时间不考虑日期。打卡记录接口这样写完之后前端调用的逻辑就非常轻了点击按钮 → 发送请求 → 展示返回结果。业务重逻辑全部压在后端前端只负责把用户的动作翻译成请求。4.3 前端页面与原型之间的映射关系前端开发时最常犯的错是抛开原型自由发挥。正确做法是把原型里的每个页面当成前端页面的设计稿元件对应组件流程图对应路由。打卡页在原型里是“当前时间 两个按钮”前端就是“一个展示时间的卡片 两个提交按钮”。考勤记录页在原型里是“筛选区 表格”前端就是“日期选择器 el-table”。这样做的好处是一次性把样式和交互对齐不需要在开发过程中反复找需求方确认。前端权限控制是考勤系统的一个重点。普通员工登录后只能看到打卡页、自己的考勤记录和补卡申请页管理员登录后看到管理后台。实现方式采用前端路由守卫 后端接口权限双重校验。前端做体验控制后端做数据安全。// Vue Router 前置守卫 router.beforeEach((to, from, next) { const token localStorage.getItem(token); if (!token to.path ! /login) { next(/login); return; } // 管理员页面需要 admin 角色 if (to.meta.requiresAdmin) { const role localStorage.getItem(role); if (role ! admin) { next(/dashboard); return; } } next(); });这段守卫代码的逻辑有三层第一层没登录时一律弹回登录页第二层判断目标页面的 meta 标记是否需要管理员身份第三层检查本地存储里的角色字段不是 admin 就重定向到员工首页。但前端的守卫只是体验层面的限制真正的安全边界在后端接口。后端拦截器会再次校验请求路径的前缀如果 /api/attendance/rule 接口被普通角色调用直接返回 403。前后端两层同时检查权限才算闭环。前端页面还有一个细节值得多花时间打卡结果的即时反馈。打卡接口返回后前端要在页面上无刷新更新状态。如果打卡成功上班按钮置灰且文本变成“已打卡”页面上方的时间卡片保持继续走动并且提示“打卡成功09:01:23”。这些状态切换和原型阶段 Axure 里设置的交互逻辑是完全对应的相当于把原型里的“用例 2禁用按钮”翻译成前端的 disabled 属性绑定。5. 避坑手册考勤系统最常见的五个翻车现场5.1 打卡判重靠数据库约束还是业务代码现象开发环境测试时连续快速点击“上班打卡”按钮十次结果打卡记录表里出现两条同一天的上班时间记录。原因业务代码里先查记录是否存在、再决定插入还是更新这两步之间存在时间窗口。第一次请求还没完成插入第二次请求发起了同样的查询结果查不到已有记录于是也走了插入分支。数据库层面如果没有唯一约束重复记录就产生了。解决在数据库表上建唯一索引同时在后端代码里捕获 DuplicateKeyException。第一次插入成功第二次插入直接抛出唯一键冲突异常异常处理器统一返回“今日已打卡”的提示。记住一个原则凡是涉及“同一条数据只能存在一份”的场景永远不要把希望寄托在业务代码的判断上数据库约束才是最终防线。5.2 服务器时区错位导致的迟到误判现象打卡时间是上午 09:00系统却判定为迟到而且错误时间差正好是 8 小时。原因服务器部署在 UTC 时区而 Java 进程的默认时区没设置。LocalDateTime.now() 取到的是 UTC 时间在数据库里存成了 01:00前端展示时又没做时区转换员工看到的就是 UTC 的凌晨。类似的还有 MySQL 连接时区参数缺失JDBC 驱动把时间按系统默认时区解析。解决统一约定全链路使用北京时间。后端 JVM 启动参数加 -Duser.timezoneAsia/ShanghaiMySQL 连接串加 serverTimezoneAsia/Shanghai数据库初始化时 SET time_zone 08:00。这三个配置必须同时设置缺一个都可能出问题。上线前用一条 SQL 验证SELECT NOW()确认返回的时间是北京时间。5.3 中文乱码与 emoji 引发的存储故障现象补卡申请的“申请原因”里输入了“堵车迟到抱歉”提交后页面上显示问号管理端看到乱码。再往后插入数据直接报“Incorrect string value”错误。原因建表时用了 utf8 字符集MySQL 的 utf8 并不是真正的全量 Unicode它最多支持 3 字节字符而 emoji 是 4 字节导致插入失败。简体中文本身没问题一旦遇到生僻字或 emoji 就会暴露。解决建表时统一用 utf8mb4 字符集排序规则用 utf8mb4_general_ci 即可。连接串里也要带 characterEncodingutf8否则驱动层可能重新编码导致错乱。已有的表可以用 ALTER TABLE 语句批量转换但新项目直接在建表 SQL 里写对省掉这个麻烦。5.4 普通员工直闯管理后台的权限漏洞现象员工账号登录后手动在浏览器地址栏输入 /admin 路径竟然打开了员工管理页面还能看到所有人的薪资字段。原因前端只做了导航栏菜单的隐藏没有做路由级别和接口级别的权限控制。菜单不可见不等于接口不可访问。前端的每一步操作本质上是调用后端接口只要接口没校验角色绕过页面直接调接口就能拿到数据。解决三层同时加控制。前端路由守卫按 meta.requiresAdmin 拦截路由跳转后端接口用拦截器校验请求头里的角色标识并拒绝越权访问数据库层面敏感字段考虑脱敏。后端权限校验是最后一道闸门绝对不能省略。而且后端拦截器不能只判断路径前缀还要校验具体接口对应的权限码避免“前缀放行、后面的接口全裸奔”的情况。5.5 原型与最终实现不一致的验收风险现象原型里打卡成功后的提示是弹窗开发做成了页面顶部的通知条。评审时需求方说“这不一样”开发觉得“功能一样就行”双方僵住。原因原型评审阶段没有明确交互细节的优先级。Axure 里随意设置的提示样式、按钮位置、页面跳转方式都被开发当成了需求而需求方默认“原型只是示意”。解决原型评审时定一个“严格还原清单”把考勤系统里所有影响业务判断的元素列进去打卡结果提示方式、迟到提示文案、补卡审批按钮位置、统计报表的字段顺序。清单之外的元素可以自由发挥清单之内的必须按原型落地。这个清单可以直接作为测试用例的验收标准避免验收阶段的口水仗。6. 上线前最后一公里用一套演示脚本验证完整考勤闭环系统开发完后不要直接扔给业务方试用先用一套可复现的演示脚本把考勤闭环完整走一遍。这个脚本的意义是让所有人在 5 分钟内看到系统的完整能力同时验证数据库、接口、页面三个环节没有断点。我的做法是分四步演示。第一步用管理员账号登录进入考勤规则页确认默认上下班时间已生效。第二步登录员工账号模拟“正常打卡”先不打改时间的主意诚实打卡一次页面显示打卡成功。第三步在数据库手动把该员工昨天的考勤记录改成迟到状态再进入考勤记录页和统计页确认统计结果同步更新。第四步提交一条补卡申请用管理员账号审批通过回到员工端确认补卡生效。这个脚本需要一条辅助 SQL用于快速生成测试数据-- 将员工ID1 昨天的记录改为迟到状态 UPDATE attendance_record SET status 1, clock_in_time CONCAT(DATE_SUB(CURDATE(), INTERVAL 1 DAY), 09:47:00) WHERE employee_id 1 AND work_date DATE_SUB(CURDATE(), INTERVAL 1 DAY);这条 SQL 的核心是利用 CONCAT 拼接日期和时间字符串构造一个准确的迟到打卡时间同时更新状态字段。执行后刷新考勤记录页昨天那条记录就应该显示为迟到状态颜色标记和统计数字同步变化。验证完统计逻辑后再用补卡流程把状态改回正常确认整个闭环可逆。演示脚本走完后还有两个验证动作容易漏。一个是打卡防重的实测连续快速点击打卡按钮确认后端的唯一索引拦截生效页面不会出现“打卡成功”的重复提示。另一个是权限验证用普通员工账号手动访问管理后台的接口路径确认返回 403。这两个动作都通过系统才算真正达到交付标准。最后说一个我踩过不止一次的教训不要把演示数据留在正式环境里。演示脚本里插入的数据在系统真正上线前要清空否则第一个月统计报表会混入测试数据。我会在交付前跑一条清理 SQL把 attendance_record 表里 is_valid1 且 work_date 在初始化范围内的测试记录删掉保留规则配置和账号数据。这套流程走顺了不管是答辩还是内部交付底气都会足很多。希望帮到你。本文还有配套的精品资源点击获取