尧图精选

Spring Boot社区医院人员管理系统设计:从需求分析到排班考勤实现

🕒 发布时间:2026/9/14 9:53:03 📁 来源:尧图网络
康美社区医院人事科办公室的墙上至今还挂着一块白板上面用马克笔排了下个月的门诊班次箭头、圆圈、改签的痕迹叠了好几层。旁边是一摞按姓氏字母整理的纸质花名册护士长每次想查一个人是哪个学校毕业的要翻两分钟。这大概是很多基层医疗机构人事管理的真实缩影——不是没有系统是系统停留在Excel 白板 微信群的原始阶段。康美社区医院人员管理系统这个题目就是冲着这个问题去的。这篇内容适合三类人看正在做 Spring Boot 毕业设计、需要从零搭建一套人员管理系统的同学社区医院或小型医疗机构的信息科工作人员想把手头零散的人事数据整理成正规系统以及任何想搞清楚人员管理系统除了增删改查到底还要做什么的开发者。我会从需求分析、技术选型、数据库设计、核心模块实现到开发调试踩坑完整过一遍这套系统的设计与落地过程里面涉及的代码和 SQL 都是可以直接复制改用的。1. 任务书背后的真实业务社区医院的人到底要怎么管做毕业设计也好做真实项目也罢最忌讳一上来就建表写代码。先搞清楚业务方是谁、痛点在哪里系统才有魂。康美社区医院是个典型的一级社区医院规模不大但科室齐全人员构成复杂管理系统设计的核心不是大而全而是贴合基层医疗机构的现实场景。1.1 社区医院和三甲医院的人员管理差异三甲医院上万名员工管理系统必须面向组织架构、职称评审、排班考勤、绩效核算这些重流程场景一个科室甚至要配专职的排班秘书。社区医院不一样通常 50 到 200 人人员规模小但业务交叉非常严重。一个人可能既在门诊坐诊又是家庭医生团队的签约医生周末还要轮值预防接种门诊。所以社区医院人员管理系统的第一诉求不是管理组织架构的纵深而是管理人在不同岗位、不同任务之间的交叉关系。另一个差异是信息化基础。三甲医院一般有 HISPACS 等成熟系统人员数据可以同步。社区医院很多还是手工台账系统建成后往往需要一次性的批量导入。这意味着系统必须考虑 Excel 导入导出的可用性不能只做界面上一条条录入。我见过不少团队在这个环节翻车原因后面会专门说。1.2 四类岗位角色管理重点各不相同社区医院的人员大致可以分成四类每类的管理字段和关注点差异很大角色类型典型岗位管理重点特有字段/操作医疗岗全科医生、护士、医技执业证书有效期、排班、定期考核执业证编号、职称、轮班偏好公卫岗预防保健人员、慢病管理专员所负责社区网格、随访任务负责片区、下社区时间行政岗办公室、财务、人事科请假考勤、文件审批请假记录、审批流程后勤岗保洁、保安、食堂考勤、排班制打卡记录、外包信息这四类人的管理粒度完全不同。给医生做排班要考虑不能连续两晚夜班给行政人员做考勤要考虑法定节假日的调休给后勤人员做管理要考虑早上六点半到岗的早餐岗。任务书里通常只写完成人员信息管理、排班管理、考勤管理但细拆之后你会明白每个模块背后的业务规则是不同的。1.3 任务书没写、但答辩时一定会被问到的功能任务书是抽象的评委和用人单位的关注点却很具体。有几个功能任务书里往往没有明确写到但在真实场景里属于刚需做完非常加分证件到期提醒。医生的执业医师证、护士执业证都有有效期过期是重大医疗安全隐患。系统要能定时扫描证件表提前 90 天提醒人事科。排班冲突检测。同一个人不能在同一天被排到两个班次系统必须刚性拦截不能靠人工肉眼检查。离职人员归档。员工离职不是删掉记录而是把状态改为离职保留历史排班和考勤记录供审计回溯。操作日志。谁在什么时间修改了谁的证件号全程留痕。这个需求在真实项目里无可避免毕设里加上也显得专业。花名册导出。按科室、按岗位导出 Excel社区医院每季度要向街道卫生科报送人员名单手工整理非常痛苦。也就是说这套系统表面上是人员信息管理系统本质上是社区医院人事业务的信息化容器。需求分析阶段把这些想清楚了后面的表结构设计和技术实现才不会走偏。2. 技术方案定型给这个量级的系统选择合适的 Spring Boot 组合需求清楚了技术选型就好办。康美社区医院这个量级的系统第一原则是稳定、可维护、一个人能搞定不是为了秀技术引入一堆中间件。我最终确定的组合是 Spring Boot 2.7 MyBatis-Plus 3.5 MySQL 8.0 Redis Vue 2 Element UI下面逐个说为什么。2.1 为什么放弃 SSM/SSH 选择 Spring Boot现在的毕业设计和中小型项目我基本不会建议再写传统的 SSM 了。SSM 的 XML 配置确实能帮助理解 Spring 的底层原理但社区医院系统追求的是快速交付和持续可维护。Spring Boot 的 starter 机制把大部分配置自动化了内嵌 Tomcat 让部署从装 Tomcat、丢 war 包、配数据源变成java -jar 一行命令启动对维护者极其友好。Spring Boot 2.7 是我在这类项目里的首选版本属于 2.x 的收尾版本稳定性和资料丰富度都很好。不建议一上来就用 Spring Boot 3.x除非你已经清楚 javax 到 jakarta 包名的迁移差异否则搜资料的时候新旧版本混着会非常痛苦。Spring Boot 2.7 搭配 JDK 8 或 JDK 11 是这套组合里兼容性最好的搭配。2.2 MyBatis-Plus 让单表 CRUD 变简单的代价MyBatis-Plus 的价值在毕设和中小型系统里体现得非常明显。BaseMapper 内置了 selectById、insert、updateById 这些常用方法配 LambdaQueryWrapper 写条件查询基本不用手写 SQL开发效率比原生 MyBatis 高一大截。排班冲突检测就是一条 wrapper 查询搞定LambdaQueryWrapperSchedule wrapper Wrappers.lambdaQuery(); wrapper.eq(Schedule::getStaffId, schedule.getStaffId()) .eq(Schedule::getWorkDate, schedule.getWorkDate()); Long count scheduleMapper.selectCount(wrapper); if (count 0) { throw new BizException(该员工当天已有排班记录请重新选择); }但代价也很明确一旦涉及多表关联查询、报表统计、复杂分组wrapper 就力不从心了。比如考勤月度统计要 join 人员表拿姓名和科室还要按科室分组汇总这种 SQL 必须写在 Mapper XML 里。所以选型的时候要有个心理预期——MyBatis-Plus 处理的是 80% 的单表操作另外 20% 的统计类需求需要手写 SQL这两部分要形成互补别硬用 wrapper 去拼复杂查询拼出来的 SQL 又难读又难调。2.3 前端两条路线服务端渲染和前后端分离怎么选人员管理系统有两种常见的前端做法各有利弊关键看你的时间和维护能力。一条是 Thymeleaf Bootstrap 服务端渲染。整个系统一个 Spring Boot 应用就搞定部署简单没有跨域问题页面直接通过 ModelAndView 渲染数据。缺点是交互体验一般做不出复杂的联动效果分页、日期选择这些组件都要自己拼。另一条是 Vue 2 Element UI 前后端分离。Element UI 的分页表格、日期选择器、弹窗表单都是现成的做出来的界面专业感强演示时观感明显好。代价是多了一层前端工程要处理跨域、Token 存储、构建部署这些问题开发链路更长。我的建议是如果你的时间是两个月以上选 Vue这套系统的展示效果在答辩中是很加分的如果时间只剩两三周选 Thymeleaf先保证功能完整能跑起来再考虑界面优化。我后面讲的实现细节以 Vue 前后端分离为主这是比较典型也是收获更大的路线。2.4 环境版本搭配与本地开发环境建议版本问题看起来琐碎实际踩坑率极高。我给一套稳的配置组件推荐版本备注JDK1.8 或 11与 Spring Boot 2.7 兼容避免 17 的模块化坑MySQL8.0连接驱动用 mysql-connector-java 8.x注意 serverTimezoneAsia/ShanghaiRedis5.x 以上Windows 开发机可用 tporadowski 维护的 Windows 版仅限本地Node14/16Vue 2 项目建议 14 或 16新版本 Node 编译老项目会报 OpenSSL 错误Maven3.6配置阿里云镜像否则依赖下载等到怀疑人生本地开发环境与生产环境尽量保持版本一致尤其是字符集。MySQL 建库时统一用 utf8mb4排序规则选 utf8mb4_general_ci 或 utf8mb4_unicode_ci否则中文排序和 emoji 兼容都容易出问题。3. 数据表设计从一张人员表演进到九张核心表的过程数据库设计是这套系统的地基。我刚上手时天真地以为人员管理系统就是一张人员表加一个用户表做着做着才发现排班、考勤、证件、职称变动、角色权限全都要独立的表承载。下面按演进顺序讲这套表结构以及每张表背后的业务逻辑。3.1 人员信息表区分登录账号和员工档案第一张核心表是人员档案表staff存储员工的基础信息。字段设计如下CREATE TABLE staff ( id BIGINT NOT NULL AUTO_INCREMENT COMMENT 主键, staff_no VARCHAR(20) NOT NULL COMMENT 工号, name VARCHAR(50) NOT NULL COMMENT 姓名, gender TINYINT DEFAULT NULL COMMENT 性别0男 1女, id_card VARCHAR(255) DEFAULT NULL COMMENT 身份证号加密存储, phone VARCHAR(20) DEFAULT NULL COMMENT 手机号, email VARCHAR(100) DEFAULT NULL COMMENT 邮箱, hire_date DATE DEFAULT NULL COMMENT 入职日期, education VARCHAR(20) DEFAULT NULL COMMENT 学历, title VARCHAR(50) DEFAULT NULL COMMENT 职称, job_type TINYINT DEFAULT NULL COMMENT 岗位类型1医疗 2公卫 3行政 4后勤, status TINYINT DEFAULT 0 COMMENT 状态0在职 1离职 2休假, deleted TINYINT DEFAULT 0 COMMENT 逻辑删除, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_staff_no (staff_no, deleted) ) ENGINEInnoDB COMMENT人员档案表;这里说几个容易犯错的点身份证号为什么不直接明文存储。身份证号属于敏感信息有心的评委一定会问安全方案。我用 AES 加密后存密文展示时做脱敏比如只显示前六位和后四位查询时通过一个加密查询的 Service 来处理。这个设计在公卫项目里尤其重要。工号唯一索引必须带上 deleted 字段。如果不带逻辑删除的员工会永久占用工号新员工可能无法使用同一工号或产生冲突。带上了 deleted逻辑上允许同一个工号只能有一个在职记录离职后该工号理论上可以释放重新分配。status 与 deleted 不冲突。status 表示业务状态deleted 表示数据是否可见两者是不同维度的标记不要混用。离职员工 status1 且 deleted0还能查到档案停用某条错误记录才用 deleted1。登录账号单独放一张sys_user表与staff是一对一关系。它的作用是把账号和员工档案解耦员工离职后账号可以停用但档案保留互不污染。sys_user 表至少包含 id、staff_id、username、password、role_id、status 字段密码用 BCrypt 加密。3.2 科室与人员多对多关系为什么会在这里出现刚开始做表结构时我直接在staff表里加了一个dept_id字段认为一个人只属于一个科室。直到真实业务调研发现社区医院的公卫医生既属于全科门诊又属于慢病管理科还要对接家庭医生团队。如果把 dept_id 做成单值字段排班统计时这个人只能归属到一个科室绩效算起来全是纠纷。正确做法是引入一张关联表staff_departmentCREATE TABLE staff_department ( id BIGINT NOT NULL AUTO_INCREMENT, staff_id BIGINT NOT NULL, dept_id BIGINT NOT NULL, is_main_dept TINYINT DEFAULT 0 COMMENT 是否主科室, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_staff_dept (staff_id, dept_id) ) ENGINEInnoDB COMMENT人员科室关联表;is_main_dept这个字段非常关键。一个人挂多个科室时必须有一个主科室作为考勤统计、工资核算的默认归属。列表展示时按主科室显示点击详情时才展开所有关联科室。这个细节是从真实报销流程里学到的——行政科室人少但要管所有科室的采购报表如果不区分主科室数据会算重。3.3 排班表和时间约束唯一索引如何防冲突排班表解决的核心问题是什么人在什么时间在什么岗位。基本字段为CREATE TABLE schedule ( id BIGINT NOT NULL AUTO_INCREMENT, staff_id BIGINT NOT NULL COMMENT 员工ID, dept_id BIGINT NOT NULL COMMENT 科室ID, work_date DATE NOT NULL COMMENT 排班日期, shift_type TINYINT NOT NULL COMMENT 班次0白班 1夜班 2休息, remark VARCHAR(255) DEFAULT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_staff_date (staff_id, work_date) ) ENGINEInnoDB COMMENT排班表;这里最重要的设计是唯一索引uk_staff_date它的作用是防止同一个人同一天重复排班。即使代码里的冲突检测漏了数据库层面也能兜底两行 insert 直接有一行会报 Duplicate entry 错误。对这个量级的系统来说双保险已经足够。排班界面的核心交互逻辑是人事科在日历上选择日期拖拽员工到班次区域提交时后端批量校验。批量插入时多行 schedule 一起提交任意一行冲突就整体回滚返回冲突的员工姓名和日期前端高亮提示。为了查询效率排班列表页按周视图拉取数据一次查 7 天某个科室所有人员的排班避免频繁访问数据库。3.4 证件、考勤、职称变动容易被忽略的扩展表人员信息表只是骨架支撑业务流转的还得有下面三张表。证件表certificate。核心字段为 staff_id、cert_name、cert_no、issue_date、expire_date。配套一个定时任务每天扫描 expire_date 在 90 天内的证件生成待办提醒推送给人事科账号。这里要注意证件类型不能只存一个文本字段否则统计全院有多少张执业医师证快到期时非常难写 SQL。建议加一个 cert_type 字典字段或者单独建证件类型字典表。考勤表attendance。我采用一天一条记录而不是每次打卡一条记录因为社区医院的考勤粒度是天。字段为 staff_id、work_date、first_punch、last_punch、status正常/迟到/早退/缺卡。这样月度统计时只需按 staff_id 分组聚合不用处理一天多条打卡记录的杂音。如果将来要对接门禁打卡机再调整数据来源即可。职称变动表position_change。记录员工的职称晋升历史包括 old_title、new_title、change_date、approve_doc。这张表的存在让系统能回答某某护师是什么时候从护师晋升为主管护师的这类履历查询问题也符合医院对职称评审过程的档案留存要求。加上角色表、菜单权限表、操作日志表这套系统的核心表共有九张彼此之间的关系清晰撑起所有功能绰绰有余。很多毕设系统最后被评委挑刺问题往往出在表结构一张 person 表 一张 user 表就完了业务数据没有承载对象自然讲不出深度。4. 关键模块的编码思路与实现细节表结构定好之后开发阶段的核心就是几个关键模块的落地登录权限、人员信息管理、排班冲突检测、考勤统计。下面按模块拆解实现要点代码尽量给核心片段。4.1 登录认证与 RBAC 权限控制权限模型采用 RBAC基于角色的访问控制共三张表用户表、角色表、用户角色关联表。角色设计成四种系统管理员 ROLE_ADMIN、人事科 ROLE_HR、科室主任 ROLE_DEPT_MANAGER、普通员工 ROLE_STAFF。不同角色的菜单权限不同系统管理员全部菜单包括用户管理和操作日志。人事科人员档案、排班管理、考勤管理、证件提醒但看不到系统配置。科室主任查询本科室人员、查看本科室排班和考勤统计。普通员工查看自己的排班、提交请假申请、查看个人考勤。技术实现上我选 Spring Security JWT。流程如下登录接口校验用户名和密码BCrypt 匹配认证成功后生成 JWT过期时间设为 2 小时同时放到 Redis 里做服务端状态校验。之后前端每次请求在 Authorization 头带上 Bearer token后端通过 OncePerRequestFilter 解析 token设置 SecurityContext接口层面用 PreAuthorize 注解控制权限例如PreAuthorize(hasRole(HR)) PostMapping(/staff) public Result addStaff(Valid RequestBody StaffDTO dto) { return Result.success(staffService.addStaff(dto)); }实际开发中有两个细节值得注意JWT 过期时间不要设太长。社区医院用的是内网系统2 小时过期已经足够设置一天反而在演示时出现token 过期要重新登录的尴尬情况。过期后前端拦截 401 响应弹窗提示重新登录。用户表和员工档案表解耦。登录用户关联 staff_id但不要求一一对应。比如人事科某账号可以对多个员工档案操作系统管理员账号可以不关联任何具体员工。这在演示权限控制时也是一个很好的话术。4.2 人员信息的增删改查逻辑删除与字段校验人员信息管理是系统的门面功能上无外乎增删改查、导出导入但实现质量差别很大。新增人员的 Service 层要做三件事校验唯一性工号、手机号、身份证号加密、插入 staff 表并建立与部门的多对多关联。手机号校验用正则^1[3-9]\d{9}$身份证号做 18 位加权校验规则可以写成一个工具方法导入时复用同一套校验逻辑。删除采用逻辑删除MyBatis-Plus 里通过 TableLogic 注解实现TableLogic private Integer deleted;这个注解会让 MyBatis-Plus 自动把 deleteById 变成 update set deleted1所有查询自动追加deleted0条件。但有个坑前面提到的工号唯一索引 (staff_no, deleted) 就是为逻辑删除设计的如果 MyBatis-Plus 的自动填充没有正确处理deleted 字段不会变化唯一索引依然可能冲突。所以逻辑删除字段建议手动管理插入时显式 set 0删除时才置 1不要依赖数据库默认值。列表查询时默认只查出在职人员部门筛选通过 staff_department 关联表做 left join按主科室过滤。导出的花名册 Excel 要按科室分组、职称排序生成这一步在部门筛选的场景里简直是刚需——街道卫生科随时可能来要一份全科门诊所有主治医师名单。4.3 排班冲突检测从 Service 校验到数据库索引双层防护排班的业务规则不复杂但必须做扎实。核心方法是冲突检测前文已经给了首版实现。编辑排班时要特别注意需要排除当前记录自身public void updateSchedule(Schedule schedule) { LambdaQueryWrapperSchedule wrapper Wrappers.lambdaQuery(); wrapper.eq(Schedule::getStaffId, schedule.getStaffId()) .eq(Schedule::getWorkDate, schedule.getWorkDate()) .ne(Schedule::getId, schedule.getId()); Long count scheduleMapper.selectCount(wrapper); if (count 0) { throw new BizException(该员工当天已有排班记录); } scheduleMapper.updateById(schedule); }除了基础的同日冲突真实的社区医院排班还有一条潜规则某员工不能连续工作过长时间。比如护士夜班后至少要休息一天才能安排白班。这种规则我用一个检查方法来实现查询该员工前一天的排班如果 shift_type 是夜班且今天安排的是白班则抛出提示该员工昨日夜班今日不建议安排白班。规则可以抽成策略类后续医院提出新规则加一个实现类即可不需要改动原有检测逻辑。排班模块的另一个实用功能是跨科室借调。社区医院经常出现接种门诊高峰期从全科门诊借护士的情况我的实现方式是 schedule 表里允许同一人同一天存在两条记录但 dept_id 不同、shift_type 不同此时唯一索引需要改成(staff_id, work_date, shift_type)而不是(staff_id, work_date)。这个调整要看真实业务有没有借调场景提前问清楚比事后改表结构容易得多。4.4 考勤月度统计一条 SQL 如何算清全勤考勤管理模块的核心输出是月度统计报表。因为考勤表按一天一条存储月度统计的 SQL 就不需要处理打卡流水去重的麻烦SELECT s.name AS staff_name, s.staff_no, s.title, COUNT(DISTINCT a.work_date) AS total_days, SUM(CASE WHEN a.status 迟到 THEN 1 ELSE 0 END) AS late_count, SUM(CASE WHEN a.status 早退 THEN 1 ELSE 0 END) AS early_count, SUM(CASE WHEN a.status 缺卡 THEN 1 ELSE 0 END) AS miss_count, SUM(CASE WHEN a.status 正常 THEN 1 ELSE 0 END) AS normal_count FROM attendance a LEFT JOIN staff s ON a.staff_id s.id WHERE a.work_date BETWEEN #{startDate} AND #{endDate} AND s.deleted 0 GROUP BY s.id ORDER BY s.dept_id, s.staff_no注意COUNT(DISTINCT a.work_date)——即使考勤表已经按天一条保留这个去重仍然安全防止历史数据或外部导入产生脏数据。至于正常天数的判断如果某天 status正常表示该员工按排班时间正常上下班如果排班是休息日考勤表里不生成记录所以正常天数 各类异常天数不一定等于应出勤天数需要在报表里单独展示应出勤字段。月度报表的展示我用 EasyExcel 导出表头包含序号、工号、姓名、科室、职称、应出勤、实出勤、迟到、早退、缺卡、备注。导出接口放到异步线程里执行比较稳妥因为统计几百号人一个月的数据在毫秒级但加上 Excel 渲染就不一定了用户连续点击导出会导致线程阻塞。异步导出的实现不复杂先返回一个正在生成的任务 ID前端轮询下载接口生成完成后自动下载。这个体验细节在演示时很加分。5. 开发调试阶段的真实踩坑记录最后这部分聊聊我自己在开发这套系统过程中踩过的坑每一个都花了不少时间排查写出来希望能帮你省点调试时间。5.1 跨域问题的三条处理路线前后端分离开发时前端跑在 8080后端跑在 8081直接访问必然报跨域错误。我当时遇到的是登录接口正常但带上 Token 的请求全部被拦截排查了半天才发现是预检请求 OPTIONS 没处理。跨域有三级解决方案按场景选择开发阶段用前端代理。在 Vue 项目的 vue.config.js 里配置 devServer.proxy把 /api 前缀的请求代理到后端地址。这样浏览器看到的请求是同源的完全不触发跨域是开发阶段最干净的方案。后端全局 CORS 配置。Spring Boot 里实现 WebMvcConfigurer 的 addCorsMappings 方法允许前端地址跨域。要注意 allowedOrigins 不要配置成 * 同时 allowCredentials 为 true浏览器会拒绝这种组合。生产环境用 Nginx 反向代理。同一个域名下通过 location /api 转发到后端服务彻底规避跨域。这也是推荐的生产部署方式。我踩的坑来自第二种方案允许跨域的路径写成了/staff/**但排班接口路径是/schedule/**漏了一条导致排班模块的接口全部报跨域。后来统一改成/api/**所有后端接口路径加上 /api 前缀一劳永逸。5.2 LocalDateTime 序列化后变成数组前端拿到的人员信息数据里入职日期一栏显示的是[2023, 6, 15, 10, 30, 0]这样一个数组页面上完全没法看。原因是 Jackson 默认序列化 Java 8 时间类型时如果没有配置 JavaTimeModule就会走到默认的数组序列化。解决方式有两种我推荐配置全局的 Jackson 序列化规则spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8这种方式只能处理 java.util.Date对 LocalDateTime 不一定生效。彻底的做法是加一个 Jackson 自定义配置类注册 JavaTimeModule统一格式为 yyyy-MM-dd HH:mm:ss日期类型用 yyyy-MM-dd。如果你只希望在个别字段生效也可以在实体字段上加 JsonFormat(pattern yyyy-MM-dd)前端接收字符串展示和提交都不会出错。另一个关联问题是前端向后端传日期时间参数Controller 接收参数时如果拿到的也是字符串需要加 DateTimeFormat(pattern yyyy-MM-dd HH:mm:ss) 注解否则 Spring 无法完成字符串到 LocalDateTime 的类型转换。前后端联调时日期格式务必提前约定好我这里统一用 yyyy-MM-dd HH:mm:ss日期只用 yyyy-MM-dd。5.3 EasyExcel 导入时的格式与校验问题批量导入人员信息是人事科用得最多的功能也是出问题最多的地方。第一次做导入时测试人员放了一份正常的 Excel结果 300 行数据只导进去 200 行剩下的全是校验失败。检查日志发现工号列是文本格式没问题但身份证号列被 Excel 自动转成了科学计数法EasyExcel 读取出来的值变成了1.10681419901101002E17即便是用 String 接收也无法还原成正确的身份证号。解决方案分两步在导入模板里把身份证号、手机号列的单元格格式设置为文本从源头杜绝科学计数法。读取时用 EasyExcel 的 CellData 注解或自定义 Converter把数字单元格的原始值按字符串处理避免 17 位以上的数字丢失精度。更常见的坑在于批量导入的校验策略。我一开始遇到第一条数据格式错误就整体回滚结果前端报错信息很模糊用户根本不知道哪几行错了。后来改成逐行校验每条数据独立校验错误行收集到结果集里导入完成后返回一个错误报告格式为第 3 行手机号格式不正确第 7 行工号已存在。正确的数据照常入库错误数据生成下载文件供用户查看。这个交互方式在真实使用中非常受欢迎人事科的人可以拿着错误报告直接去改源文件不用反复试错。5.4 分页查询变慢count 语句的优化人员列表的分页查询越往后越慢排查发现 MyBatis-Plus 分页插件在每页查询时自动执行一条 count 语句。数据量只有几百条时感受不明显但当连表查询涉及 staff_department 和用户表后count * 查询要关联多张表一旦数据量增长到几千条每翻一页都要全表关联扫一遍接口响应时间显著上升。优化手段有三个按收益排序分页插件设置不执行 count。如果前端只是上一页、下一页而不是显示总页数可以直接关掉 count。但社区医院的人事科习惯看总条数和总页数所以这条只能用于部分场景。count 查询指定别名和简化关联。MyBatis-Plus 支持手动指定 count SQL只关联必要的表去掉多余的 join。我的列表查询本意只是按部门过滤关联 staff_department 是唯一的必要 joinuser 表根本不需要进 count手动优化后 count 时间大幅降低。列表查询字段最小化。避免 select 所有列列表页只需要展示工号、姓名、科室、职称、状态、手机号把 create_time、update_time 这些字段排除掉减少数据传输量和 SQL 解析耗时。这几个问题都是开发调试阶段真实碰到的每个都卡了我至少一晚上。它们有一个共同特点不是功能做不出来而是做得出来但做不好而恰恰是这些细节撑起了一个项目的完成度。最后再分享一点个人体会。康美社区医院人员管理系统这类题目真正决定上限的不是技术栈选得多新而是你有没有把业务场景吃透。我花了整整一个下午坐在社区医院人事科旁边看他们怎么排班、怎么发工资、怎么临时调人、怎么应付上级检查很多比代码更重要的需求都藏在那些日常动作里。比如那位护士长的换班需求——护士之间经常私下换班但纸质排班表上改了字迹容易看不清系统里必须有一个换班申请流程经护士长确认后两边的排班自动互换。这个需求任务书里一个字没提但它才是让用户真正觉得这个系统是给我用的的关键。做项目的时候多跟业务方聊半小时胜过闭门造车写一百行代码。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →