2025年还在做基于SpringBoot+Vue的人口老龄化社区服务与管理平台,听起来好像不够“新潮”,但如果你真的跑过几个基层社区项目,就会明白这套组合在落地场景里依然是稳妥度最高的选择。这篇文章想跟你从头到尾聊聊我做这类系统时踩过的坑、反复琢磨过的设计,以及为什么最终敲定了SpringBoot+MyBatis+MySQL+Vue这套技术栈。不管是应届生拿来做毕业设计,还是接社区信息化的私活,又或者纯粹想了解基层管理系统怎么做,这篇都能给你一份可以直接抄作业的复盘。
先说结论:这个项目表面上是个“管理系统”,实际核心是三件事——把老人档案数字化、把上门服务流程化、把管理报表自动化。凡是围绕这三件事做扎实的,系统就没有白做;凡是只做了一堆花哨页面但流程闭环没打通,上线一个月就会被社区工作人员丢到角落里。下面我按需求、选型、数据库、后端、前端、部署实测的顺序,把整个项目的关键细节拆开讲。
1. 需求拆解:社区老龄服务的痛点到底卡在哪里
1.1 老人、社工、管理员三方各有各的难处
做这种项目,最忌讳直接照着竞品抄菜单。你得先弄清楚:这个系统每天被谁打开、打开之后要解决什么问题。我接触过的社区老龄服务场景,使用者基本分成三类。
第一类是老人和家属。老人需要的不是“管理”,而是实实在在的服务:助餐、助浴、助医、上门理发、家政维修、陪诊买药。常见的痛点是——老人不会用复杂App,家属不在身边不知道服务有没有人上门,服务做完了质量怎么样也说不清。所以面向这端的系统功能,不是“功能多”,而是“入口少、路径短”:一键呼叫、一键预约、进度可查,就足够了。
第二类是社区社工和网格员。他们手上往往同时管着几十位高龄、独居、失能老人。问题也很现实:靠本子记走访记录,靠Excel排服务计划,老人们这个月该量血压了、那家的药该送了、哪位独居老人三天没出门了,这些事基本全凭脑子记。老人档案散在纸质材料里,临时查某个老人的家属电话,要翻半天文件夹。
第三类是街道或社区的管理层。他们需要看的是整体运行数据:这个季度买了多少服务、助餐覆盖了多少人次、独居老人走访完成率是多少、哪个片区的工单积压了。这些数据在纸质台账里根本拉不出来,只能靠下面报,报上来的数字对不对也没法验证。
1.2 市面现有系统的三个通病
我在动手前专门调研过一批号称“智慧养老”的产品,也走访了一些社区,最后发现市面上多数系统的共性问题非常集中。
重后台、轻上门。管理端的菜单做得又全又深,但社工入户时根本没有合适的移动端工具,只能拿纸质表格记录,回到办公室再二次录入。这不但增加工作量,还容易漏录、错录,服务的时间点也没法真实记录。
数据孤岛严重。老人档案在一个系统里,健康测量数据在另一个设备配套的软件里,服务工单又在一个单独的小程序后台里。三者之间互不打通,社工给老人做一次血压测量,要先翻档案确认老人基本信息,测完再手动把数据抄进健康记录。每一步都是重复劳动。
权限设计粗糙。很多系统就一种管理员账号,登录进去所有老人姓名、身份证号、住址、病史全部可见。老人信息属于高度敏感的个人数据,内部的社工只需要看到自己负责片区的老人,管理层也只需要看统计数据而不是个人明细。权限不做隔离,等于把隐私数据敞着门放。
这个项目就是冲着这些痛点来的:一套系统里把老人档案、服务工单、健康记录、活动公告全部打通,权限按角色分好,核心数据流从“建档”一直走到“服务完成+评价归档”。
1.3 项目边界:做到什么程度才算完整
要控制开发范围,必须明确“平台”不等于“万能系统”。我当时定的边界是这样的:
- 老人信息管理:档案的新增、修改、查看、导出,支持按片区、年龄段、健康等级检索;
- 服务工单闭环:家属/老人提交服务需求,管理员派单给社工,社工接单、开始服务、完成回传,家属可查看进度和评价;
- 健康数据记录:社工入户测量血压、血糖等指标后录入,形成连续的健康趋势记录;
- 社区活动与通知:活动发布、报名、参与名单管理;
- 统计看板:按年龄段、服务类型、片区展示工作量与覆盖率。
整个项目面向的是内网部署或云端部署的Web管理系统,后端接口可以同时供未来的小程序端调用。这个范围的开发量,一个人全职大概四到六周能完成,正好适配毕业设计或小团队接单的节奏。
2. 技术选型复盘:为什么还是这套组合
2.1 SpringBoot赢在生态成熟和救火效率
社区管理类项目有一个特殊性:它不是高并发、大数据量的互联网应用,而是低并发、事务型、强管理流程的内部系统。老人档案、服务工单、健康记录,这些都是典型的关系型数据,需要强一致性和事务保护。
选SpringBoot的理由很朴素:生态最成熟,遇到问题网上资料最多。做项目最怕的不是功能难写,而是中间件版本冲突、依赖报错这种环境问题卡住进度。Spring Boot 2.x在JDK8下跑得极其稳定,Spring Security、MyBatis、Redis这些配套组件都有大量现成方案,一个普通开发者也能快速上手。
这里给个选型建议:JDK8环境就用SpringBoot 2.7.x,JDK17环境可以直接上SpringBoot 3.x。不要盲目追新,社区项目的服务器配置往往一般,稳定性优先。如果只是为了毕业答辩,SpringBoot 2.7 + JDK8的组合能省掉很多不兼容的坑。
2.2 MyBatis:复杂查询和多条件检索的主场
有人会问:现在MyBatis-Plus那么火,为什么不直接用?我的回答是:可以用,但没必要作为首选依赖。
这个系统的核心操作是两类:一类是老人档案的多条件组合查询,另一类是服务工单的状态流转更新,再有就是统计报表的聚合SQL。这些都是典型的“SQL敏感”场景,用MyBatis手写XML反而控制力更强。比如“按年龄段、健康等级、片区、关键字动态拼条件”,在XML里写<where>配合<if>一目了然,排查问题也方便。MyBatis-Plus的LambdaQueryWrapper虽然在简单CRUD上很快,但一旦涉及复杂的group by或动态表关联,反而要绕来绕去。
直接使用MyBatis还有个好处:锻炼SQL能力。社区管理系统的表之间关联其实不复杂,手写SQL的维护成本完全可控;同时保留自定义SQL的灵活性,后面要加统计口径,不用大改代码。
2.3 MySQL:关系型数据场景下的省心选择
老人档案、工单、健康记录这些数据具有强结构化特征,字段清晰、关系固定,MySQL天然契合。社区级的数据量级,撑死几十万条记录,MySQL配上一个好点的索引就能跑得非常顺。
我在数据库上做的核心决策有两条:第一,所有表使用InnoDB引擎,保证事务;第二,统一编码用utf8mb4,避免生僻字或表情符号导致存储报错。这两条看起来基础,但在实际项目里确实见过很多人在这里翻车。
2.4 Vue + Element UI:管理后台的成熟搭档
前端我选了Vue 2 + Element UI,原因是这套管理后台不含复杂交互,主要就是表格、表单、弹窗、图表。Element UI组件齐全、文档丰富,做后台系统效率极高。如果你在2025年新起项目,也可以用Vue 3 + Element Plus,思路完全一样,只是依赖版本不同。
至于为什么不直接上更炫的组件库或可视化大屏框架?社区管理系统的使用者多半是社区工作人员,他们要的是“打开就会用、别花里胡哨”。界面稳定、响应快、操作步骤少,才是真正的用户体验。
下面是选型对比,方便你做决策时参考:
| 环节 | 选择 | 核心理由 | 备选方向 |
|---|---|---|---|
| 后端框架 | SpringBoot 2.7 | 生态成熟、资料全、部署简单 | SpringBoot 3.x(JDK17) |
| ORM | MyBatis | 动态SQL灵活、统计查询可控 | MyBatis-Plus(简单CRUD友好) |
| 数据库 | MySQL 8.0 | 关系型数据契合、运维成本低 | MariaDB / PostgreSQL |
| 鉴权 | Spring Security + JWT | 角色权限体系完善 | Sa-Token(更简洁) |
| 前端 | Vue 2 + Element UI | 后台开发效率高、组件齐全 | Vue 3 + Element Plus |
| 图表 | ECharts | 健康趋势、统计报表展示成熟 | AntV G2Plot |
3. 数据库设计:三张核心表决定系统成败
3.1 整体表结构:先建好数据地图
这个系统的表不算多,核心就八张左右,但表与表之间的关系必须设计清楚。我先把整体清单列出来:
| 表名 | 用途 | 关键关联 |
|---|---|---|
sys_user | 系统用户(管理员、社工、老人账号) | 关联角色表 |
sys_role | 角色定义 | 用户-角色中间表 |
elder_info | 老人档案主表 | 关联家属、服务工单 |
family_member | 家属及紧急联系人 | 关联老人表 |
service_item | 服务项目目录 | 助餐、助浴、助医等 |
service_order | 服务工单表 | 关联老人、社工、服务项目 |
elder_health_record | 健康指标记录表 | 关联老人表 |
activity_info | 社区活动表 | 参与记录可另建中间表 |
设计原则很简单:老人档案是“主数据”,一切业务都围绕它展开;工单表是“流水数据”,记录每一次服务过程;健康记录是“时序数据”,只增不改。理解了这三个数据性质,后面的坑就能避开大半。
3.2 老人档案表的字段设计:两个容易踩坑的细节
elder_info这张表我单独强调一下,因为它是整个系统的数据源头。字段大致包含:姓名、性别、出生日期、身份证号、所在片区、详细住址、联系电话、健康等级、居住状态(独居/与子女同住/养老机构)、紧急联系人、备注。
这里有两个很容易踩的坑要特别说明。
第一个坑:年龄字段不要存数字,要存出生日期。很多人图省事,建表时直接放一个age字段。但老人的年龄每年都在变,如果存档的是静态数字,第二年所有档案全部过期,还得想个定时任务批量更新。正确做法是只存birth_date,页面展示或统计时用SQL或Java实时计算年龄。年龄段分组统计也直接用birth_date算,一劳永逸。
第二个坑:服务地址要和档案地址分离。很多老人平时住在自己家,但有些季节会去子女家短住;还有的老人户口在A片区,人长住在B片区的养老院。如果服务地址就取档案里的住址,社工上门就会跑空。我在表里加了一个service_address字段,默认复制档案地址,但允许每次派单时按实际情况修改。
另外,身份证号字段一定要加唯一索引。老人建档时最怕重复录入,同一个老人被建两次档案,后面的服务记录就会对不上。
3.3 服务工单表:状态机字段是流程闭环的骨架
service_order表是整个系统业务流转的中枢。它把“老人需要服务”和“社工提供服务”连接起来,所以我专门用一张表来设计它的状态流转:
| 状态值 | 含义 | 触发动作 |
|---|---|---|
| 0 | 待派单 | 老人/家属提交需求,或管理员代录 |
| 1 | 已接单 | 社工接受任务 |
| 2 | 服务中 | 社工上门开始服务 |
| 3 | 已完成 | 社工提交完成记录 |
| 4 | 已取消 | 管理员/家属取消 |
| 5 | 已评价 | 家属/老人完成评价 |
工单表的核心字段包括:工单编号、老人ID、服务项目ID、分配社工ID、状态、预约时间、实际开始时间、实际完成时间、服务地址、服务备注、评价内容、评价星级、创建人。这些字段建议一个都不要省。尤其“实际开始时间”和“实际完成时间”,它们是后续统计社工工作时长和工单完结时效的关键依据,必须由社工在客户端点击按钮时由后端写入,而不是手填。
状态流转在后端要严格控制,不能允许从“待派单”直接跳到“已完成”。我的实现办法是写了一个状态校验工具,每次更新都校验当前状态和下一次状态是否匹配,不匹配直接抛业务异常。
3.4 健康记录表:时序数据只增不改
健康记录的录入场景是这样的:社工带着血压计、血糖仪上门,给老人测量后,把数值录入系统。这些数据天然是时序数据,一条条累加下来,才能看出老人的健康趋势。elder_health_record表设计如下:
id:主键elder_id:老人ID,建立普通索引record_type:指标类型,比如血压、血糖、心率record_value:指标数值,血压存“128/85”这样的字符串measure_time:测量时间operator_id:录入社工IDremark:备注
我特别提醒一点:血压这种指标,收缩压和舒张压分开存更利于后期做趋势分析和图表展示,不要图省事存成一个字符串。我当时为了偷懒把“128/85”存成了一个字段,结果做ECharts折线图时还得写代码去解析字符串,非常被动。所以正确的做法是收缩压systolic、舒张压diastolic各一个字段,数值化存储。
数据表里还要设置measure_time和elder_id的联合索引,因为最常用的查询就是“查某位老人最近N条健康记录”,这个索引能直接命中,避免全表扫描。
4. 后端核心实现:从登录鉴权到服务派单的完整链路
4.1 登录与权限:Spring Security + JWT的角色隔离
社区管理系统的用户角色我分成三类:admin(系统管理员)、worker(社工)、elder(老人/家属账号)。权限设计上遵循最小够用原则:社工只能看到自己片区的老人档案和自己名下的工单,管理员能看全部和统计报表,老人账号只能看到本人或本家庭的信息以及自己的工单进度。
技术实现用的是Spring Security + JWT。逻辑不复杂:登录成功后签发JWT,后续请求通过过滤器解析Token,再根据角色判断接口访问权限。我直接在接口上用了自定义注解@RequireRole("worker")来标记接口角色,代码直观也方便维护。
这里有一个实际经验:不要把Spring Security的过滤器链配得太复杂。社区项目的接口数量不多,只需要区分“需要登录的接口”和“白名单接口”即可。登录接口、获取验证码接口放行,其余全部需要认证。角色校验放在Service层做,比放在Security过滤器里写一堆antMatchers要清晰得多。
4.2 老人档案的动态多条件查询:MyBatis动态SQL的经典用法
老人档案查询是使用频次最高的功能,社工经常会组合条件找人:先选片区,再选年龄段,再输入姓名关键字,可能还要按健康等级过滤。如果每个条件都写一个独立的查询方法,代码会爆炸。MyBatis动态SQL就是干这个的。
核心XML写法大概长这样:
<select id="selectElderPage" resultType="ElderInfoVO"> SELECT id, name, gender, birth_date, district, health_level, live_status, phone FROM elder_info <where> <if test="name != null and name != ''"> AND name LIKE CONCAT('%', #{name}, '%') </if> <if test="district != null and district != ''"> AND district = #{district} </if> <if test="ageMin != null"> AND TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) >= #{ageMin} </if> <if test="ageMax != null"> AND TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) <= #{ageMax} </if> <if test="healthLevel != null"> AND health_level = #{healthLevel} </if> </where> ORDER BY id DESC LIMIT #{offset}, #{pageSize} </select>这段SQL有几个细节值得解释。
年龄查询直接用TIMESTAMPDIFF(YEAR, birth_date, CURDATE())实时计算,完全不依赖冗余字段,这正是上一节我强调“只存出生日期”的原因。
姓名查询用了LIKE CONCAT('%', #{name}, '%'),这个写法能模糊匹配姓名中间任意位置,比前置'abc%'查得更全。代价是这种写法用不上普通索引,但在社区几千上万条老人的数据规模下,全表扫描性能毫无压力。如果哪天真到了几十万条老人数据,再上全文索引或Elasticsearch不迟,过早优化反而是负担。
4.3 服务派单的并发保护:防止同一时间段重复指派
服务派单的逻辑是:管理员在后台看到待派单的任务,选择一个社工,点击“派单”。如果社工手里同一时段已经有多个工单,会安排不过来。我在后端做了两层保护。
第一层,数据库层:service_order表增加了worker_id和plan_time的联合唯一索引,注意这是针对同一个社工同一个预约时间去重的兜底手段。
第二层,应用层:更新工单状态时使用“乐观状态校验”,用一条SQL完成“确认当前状态+更新状态”两个动作:
UPDATE service_order SET status = 1, worker_id = #{workerId}, update_time = NOW() WHERE id = #{orderId} AND status = 0这条SQL的关键在于WHERE status = 0——如果工单已经被其他管理员派走,状态不再是0,这条更新影响行数就是0。Java代码里只要判断影响行数为0,就说明“该工单已被派过”,直接提示管理员刷新即可。这套逻辑比“先select再update”安全得多,天然避免并发问题,也不用引入分布式锁。
4.4 统计报表:一条group by SQL胜过十次人工统计
管理端最常要的报表无非这几种:老人年龄段分布、各类服务工单数量统计、各片区走访覆盖率。这些用原生SQL聚合都能轻松搞定。
比如统计各年龄段人口分布:
SELECT CASE WHEN TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) < 60 THEN '60岁以下' WHEN TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) BETWEEN 60 AND 69 THEN '60-69岁' WHEN TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) BETWEEN 70 AND 79 THEN '70-79岁' ELSE '80岁以上' END AS age_group, COUNT(*) AS cnt FROM elder_info GROUP BY age_group再比如统计本月各服务类型完成数量:
SELECT si.item_name, COUNT(so.id) AS order_count FROM service_order so LEFT JOIN service_item si ON so.item_id = si.id WHERE so.status IN (3, 5) AND DATE_FORMAT(so.update_time, '%Y-%m') = DATE_FORMAT(CURDATE(), '%Y-%m') GROUP BY si.item_name ORDER BY order_count DESC这类SQL在MyBatis里只需要把resultType写成一个对应的统计VO类,就能直接返回前端。前期设计表结构时把字段拆干净了,写统计SQL就会很顺;如果前期字段设计得混乱,统计阶段就是噩梦。
5. Vue前端要点:管理后台的交互效率和适老化考量
5.1 工程结构怎么搭
前端我推荐直接基于现成的中后台脚手架模板,而不是从零搭。原因很简单:路由权限、Axios封装、状态管理这些轮子,模板里都已经有成熟方案,自己搭容易漏掉细节。
整体的结构可以这样规划:
src/api:按模块拆分的接口请求文件,比如elder.js、order.js、statistics.js;src/router:路由配置,配合角色字段在前端做菜单级别的显示控制;src/views:页面组件,老人档案、工单管理、健康记录、统计看板、活动管理等;src/utils/request.js:Axios实例封装,统一附加Token、统一处理错误码。
request.js里有一个特别容易忽略的细节:所有接口请求都要带上Token,但Token过期时不能只在前端弹个错误就完事,要跳回登录页并清理本地缓存。不然用户会以为系统坏了,实际是登录状态失效了。我通常会在响应拦截器里判断HTTP 401状态码,统一做退出处理。
5.2 三个核心页面的实现要点
老人档案列表页是使用频率最高的页面。表格列固定显示姓名、性别、年龄、片区、健康等级、居住状态、联系电话和操作按钮。搜索区放四个条件:姓名关键字、片区下拉、年龄段区间、健康等级下拉。表格加分页,默认每页10条。这个页面的核心是“一屏完成筛选+定位”,不要堆太多列,关键信息突出即可。
工单看板页我做成三个Tab:待派单、进行中、已完成。每个Tab下面按工单卡片展示,卡片上显示老人姓名、服务项目、预约时间、地址、当前状态。管理员在“待派单”卡片上点击“派单”,弹出社工选择框;社工在“进行中”标签下可以看到自己名下所有任务。这种看板形式比单纯表格直观,也方便移动端适配。
健康趋势页用ECharts画折线图。选中一位老人,默认展示最近30天的血压收缩压和舒张压变化曲线,横轴是测量日期,纵轴是数值。这里要注意:后端返回的数据不要传处理过的图例,直接把原始测量时间和数值传给前端,前端用ECharts的dataZoom组件做缩放。数据库里把血压拆成systolic和diastolic两个字段的好处,在这一步就体现出来了——前端两个series各取一个字段,完全不用解析字符串。
5.3 界面适老化:不只是老人端的事
很多人以为“适老化”只是给老人用的App才需要考虑,实际上社区管理系统的使用者也未必都是年轻人。我去试点社区调研时发现,很多一线社工年龄在40到55岁之间,视力、操作习惯和年轻人有差异。所以管理后台本身也要做适老化设计。
我在这套系统里落实了几条非常具体的设计:
- 基础字号加大到14px-16px,关键数据模块用20px以上;
- 可点击区域最小尺寸不低于40px×40px,避免“按钮太小点不准”;
- 表格斑马纹+行hover高亮,减少看错行的概率;
- 表单提交前做二次确认弹窗,防止误操作;
- 高频操作(新增档案、派单、录健康数据)放在页面首屏可见位置,不折叠进二级菜单。
这些改动成本不高,但对一线使用体验的提升非常明显。技术上的“适老化”不等于把界面做成老年机风格,而是降低认知负担和误操作概率。
6. 联调、部署与实测:真正上线后的那些坑
6.1 跨域、文件上传、时区:三个最常见的联调刺客
前后端分离项目联调,第一个冒出来的问题永远是跨域。开发环境下可以用Vite的代理转发解决,但生产环境如果前端静态文件放在Nginx、后端是一个独立服务,就必须在后端配置CORS。SpringBoot里最省事的做法是写一个全局配置类,允许指定来源或直接允许所有来源(内网部署可以接受)。
直接贴一个简单配置:
@Configuration public class CorsConfig { @Bean public CorsFilter corsFilter() { CorsConfiguration config = new CorsConfiguration(); config.addAllowedOriginPattern("*"); config.addAllowedHeader("*"); config.addAllowedMethod("*"); config.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); return new CorsFilter(source); } }第二个坑是文件上传大小。社区系统要传老人的体检报告、活动照片,SpringBoot默认单文件最大1MB,传大一点的图片直接报错。必须在application.yml里调大:
spring: servlet: multipart: max-file-size: 20MB max-request-size: 50MB第三个坑是时区。连接MySQL时如果serverTimezone设置不当,数据库时间会比本地时间差8小时。我通常在JDBC连接串里直接指定:
jdbc:mysql://localhost:3306/community?useUnicode=true&characterEncoding=utf8mb4&serverTimezone=Asia/Shanghai这三个问题看着都小,但任何一个都能卡掉半天进度。
6.2 数据量上来之后的分页性能问题
系统上线跑了一个多月,老人档案到了接近一万条、健康记录到了几万条的时候,档案查询页开始变慢。排查后发现主要瓶颈不在LIMIT分页本身,而在于搜索时姓名同时用了前后置模糊匹配,导致索引完全失效。
我当时做的一个优化方案是:姓名检索改成“前置匹配优先”,用户输入姓“张”,SQL优化成name LIKE '张%',这个写法能正常走name字段的普通索引。如果需要中间模糊匹配,就在表格页单独提供一个“精确检索”入口,避免每次查询都全表扫描。
另外一个容易被忽略的点是:分页排序的字段一定要建索引。老人档案默认按id DESC排序没问题,但如果改成按update_time排序,就要给update_time字段建索引,否则MySQL会把全表捞出来排序,数据量一大就慢。
6.3 导出Excel时中文乱码和科学计数法
社区管理层的报表习惯还是离不开Excel,系统里我加了“导出当前查询结果”的功能。这里有两个经典问题必须处理。
第一,文件名和内容中文乱码。解决办法是设置响应头时显式指定编码:
response.setCharacterEncoding("UTF-8"); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xlsx");第二,身份证号导出到Excel变成科学计数法或者丢失精度。这个问题很典型,Excel单元格对于超过15位的数字会转成科学计数法,身份证号是18位。解决思路是导出时把身份证号强转成字符串,并且在写入单元格时设置为文本格式。用常见Java Excel导出库时,把身份证号列调用setCellType为字符串类型即可,千万别让它按数字写。
6.4 真实试点反馈:系统好用,但使用习惯需要陪跑
系统在真实社区跑了大概三周,最明显的反馈不是功能缺什么,而是使用习惯的问题。
老人端的App(我做了个简化版)老人自己基本不会用,真正高频使用的是家属和社工。很多老人不会点“呼叫服务”,都是家属在家帮老人操作,或者社工入户时顺手代录。这个观察很重要——意味着系统在设计时绝不能假设“老人会自己操作”,必须做好“代录”和“家属绑定”这两条路径。
社工端的核心反馈是:录入字段太多、太慢。我给健康记录页面加了“上次测量值自动展示”,社工能看到这位老人上一次的血压数值作为参考;同时加了“一键复制上次填写内容”的快捷操作。这种小优化非常讨好使用者,能明显降低抵触情绪。
管理员这边最关心的是“工单完成率”和“走访覆盖率”这两个指标,所以我在统计看板把这两个数字放到了首页顶部,用大号字体展示,点进去才能看到明细。这比一进去就甩一堆表格要符合实际决策场景。
最后说点实操体会
项目做完本身只是一半,真正让它有价值的是在真实环境里跑起来、被一线人员使用、然后根据反馈修改。技术栈本身不复杂,SpringBoot+MyBatis+MySQL+Vue这套组合已经被验证过无数次,最大的工作量永远在需求理解、数据模型设计和流程闭环上。
如果让我再重做一次,我会在一开始就把“健康指标拆分字段”“出生日期替代年龄”“工单状态机字段”“联合索引设计”这四件事定死,因为它们是后期所有功能的地基。前面多花两天建模,后面能省下两周改代码的时间。做社区类管理系统尤其如此,老人档案一旦录进了几千条,再想回头改表结构,那真是牵一发而动全身。