ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

健康管理SaaS系统PRD实战解析:从需求到代码的完整落地路径

健康管理SaaS系统PRD实战解析:从需求到代码的完整落地路径

简介:本资源是传智教育出品的《传智健康PRD文档1》,面向软件产品设计初学者、需求分析师及Java健康类项目开发者,聚焦健康管理系统的标准化需求定义与功能建模。文档完整覆盖会员管理、预约管理、健康评估与干预四大核心模块,详细说明用户角色(患者、医护人员、管理员)职责、数据结构规范(如指标序号、名称、参考值、单位、性别适配性)及各功能操作流程图与特性描述,具备典型企业级PRD文档的结构完整性与工程落地参考价值。压缩包为单个890KB的Word(.docx)文件,内容含修订记录、目录、子系统功能详情及流程图嵌入,便于直接研读、复用或教学演示。目前已有600人学习下载,适合用于需求分析实训、健康类毕设选题参考、PRD撰写规范学习及SpringBoot+Vue健康项目需求对齐。

1. 这份PRD不是“写完就交差”的文档,而是能直接驱动开发、支撑答辩、经得起验收的健康系统骨架

你手头这份《传智健康PRD文档1》,表面看是2018年一份带页眉页脚、印着建材城西路地址和400电话的纸质感需求说明书;但真正让它在今天仍有实操价值的,是它把一个典型健康管理SaaS系统的业务逻辑闭环,用可落地的数据结构+角色动线+状态流转,全量固化下来了。它不讲微服务拆分,不提Spring Cloud,但每一条“档案号字符型否否”、每一个“预约状态文本是否”,都在替你回答:数据库表怎么建、接口字段怎么校验、前端表单要不要必填、管理员后台权限怎么切——这才是学生做毕设/课设最缺的“从需求到代码”的中间层翻译。适合三类人直接抄:一是正在写健康管理类毕业设计、卡在“功能点列不全、评委问‘你怎么保证覆盖真实业务’”的同学;二是需要快速搭出一套可演示原型的课程设计小组,拿它当模块划分蓝本;三是刚接手类似项目、想避开“评估建议和膳食库数据怎么关联”这类隐性坑的初级工程师。它不是教科书,是某高校实验室当年真跑通过的业务骨架,连“BMI字段类型为字符型”这种反直觉但符合当时PC端录入习惯的设计,都原样保留——因为真实项目里,数值计算可以后端转,但前端兼容性优先级永远更高。

2. 总体架构设计:B/S + 微信双入口、四角色驱动、七模块闭环的轻量级健康系统

传智健康虽未明确定义技术栈,但从其PC端管理后台与微信端患者操作并存的定位、以及所有功能均围绕“评估-干预-反馈”主流程展开的特点,可清晰还原出一套务实可行的总体架构。该架构不追求高并发或AI分析,核心目标是让健康管理师能当天录入、当天生成报告、当天制定计划,因此采用分层明确、职责内聚的三层结构:表现层(PC管理后台 + 微信H5)、业务逻辑层(统一API网关 + 角色权限中心)、数据层(单体MySQL + 文件存储)。关键在于,它用“角色-模块-状态”三维坐标锁定了所有功能边界,避免常见课设中“会员管理里混进预约逻辑”“知识库和评估建议数据孤岛”的问题。

2.1 四类用户角色的权限与数据视图隔离设计

系统明确定义了管理员、健康管理师、患者三类角色(文档中“用户”即患者),实际隐含第四类:系统初始化者(如首次导入体检项的运营人员)。这种划分直接决定了数据库设计和接口权限控制粒度:

  • 管理员:拥有全部7个模块的CRUD权限,但对“会员档案”中的BMI、血氧饱和度等计算字段仅可查看,不可手动修改(防止人为篡改影响评估结果);
  • 健康管理师:可操作会员管理(增删改查)、预约确认、健康评估(填写问卷/查看报告)、健康干预(制定/执行方案)、知识库(只读);其数据视图严格按健康管理师文本字段过滤,即只能看到自己名下分配的患者;
  • 患者:仅通过微信端访问,权限聚焦于“我的”维度——我的预约、我的报告、我的评估问卷、我的健康日记;其所有操作均需校验档案号与登录密码双重认证,且微信端不开放任何数据导出功能;
  • 系统初始化者(隐含):负责首次配置检测项、套餐、运动库等基础数据,其操作日志需独立审计,该角色通常由管理员兼任,但在PRD中已通过“系统预分类”“批量导入开诊时间”等描述预留了自动化入口。

提示:角色权限不是简单RBAC模型,而是“模块+字段+状态”三级控制。例如健康管理师可编辑会员信息,但档案状态字段仅允许从“启用”改为“停用”,不可反向操作;体检报告上传功能对患者开放,但上传后状态自动置为“待审核”,必须经健康管理师点击“确认报告有效”才进入评估流程——这种状态机驱动的设计,正是PRD文档里反复出现“是否做过健康评估”“报告状态根据体检时间排序”等描述的底层逻辑。

2.2 七模块功能闭环与数据流向图

整个系统并非松散功能堆砌,而是以“患者健康旅程”为主线形成强闭环:

[会员管理] → [预约管理] → [健康评估] → [健康干预] → [知识库] ↑ ↓ ↓ ↓ ↓ [统计分析] ← [系统管理] ← [知识库] ← [健康干预] ← [健康评估]
  • 起点:会员管理不仅是增删改查,更是所有后续流程的数据源——档案号作为全局唯一键,贯穿预约、评估、干预、报告所有表;
  • 触发点:预约管理是业务启动开关,其预约状态字段(待确认/已确认/已取消/已到诊)直接驱动健康评估模块是否允许新建问卷;
  • 核心引擎:健康评估模块通过指标名称+参考值+单位+针对性别四元组定义评估标准,所有评估结果(体质/心理/风险)均基于此生成,而非简单打分;
  • 执行出口:健康干预模块的“制定干预方案”操作,本质是将知识库中运动项目库、膳食库、疾病库的编码ID,与患者档案号、人群分类绑定生成新记录;
  • 支撑底座:知识库所有子模块(评估建议、健康方案、运动库等)均采用“编码+名称+适用人群”结构,确保干预方案可被精准复用;
  • 价值放大器:统计分析模块的“工作量统计”不统计点击量,而统计干预方案总量、干预回访量、干预完成量三个硬指标,直指健康管理师KPI;
  • 治理中枢:系统管理中的“菜单管理”和“权限设置”采用树形结构,每个菜单节点对应一个具体URL路径(如/admin/member/list),权限校验时直接比对角色ID与菜单节点ID的映射关系,杜绝越权访问。

2.3 数据结构标准化:为什么“BMI”字段类型是字符型?

PRD中多处出现反常识的数据类型定义(如BMI字符型、体温字符型),这并非疏漏,而是面向真实医疗场景的务实妥协:

  • 兼容性优先:早期PC端录入常由非IT人员(如前台护士)操作,直接输入“23.5”或“23.5kg/m²”均可接受,若强制数值型,会因小数点误输、单位混入导致录入失败;
  • 历史数据迁移:体检机构原有Excel报告中BMI常含文字说明(如“BMI:23.5(正常)”),字符型可整段导入,后端再用正则提取数值;
  • 扩展性预留:当需记录“BMI趋势图”时,字符型字段可存储JSON格式的多时间点数据(如{"2023-01":22.1,"2023-06":23.5}),而数值型字段需额外建表;
  • 校验后置:所有数值型业务逻辑(如BMI区间判断)均在后端服务层完成,前端仅作格式提示(如“请输入0-100之间的数字”),避免前端校验规则与后端不一致。

这种设计思维直接影响数据库建表:

-- 会员档案表(简化核心字段) CREATE TABLE member_profile ( id BIGINT PRIMARY KEY AUTO_INCREMENT, archive_no VARCHAR(32) NOT NULL COMMENT '档案号,全局唯一', name VARCHAR(50) NOT NULL COMMENT '姓名', gender VARCHAR(10) COMMENT '性别:男/女/其他', id_card VARCHAR(18) COMMENT '身份证号', phone VARCHAR(15) COMMENT '手机号', bmi VARCHAR(20) COMMENT 'BMI值,支持数值或带单位字符串', blood_pressure VARCHAR(20) COMMENT '血压,格式如"120/80mmHg"', created_time DATETIME DEFAULT CURRENT_TIMESTAMP, updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP );

注意:bmi字段虽为VARCHAR,但后端Java服务中会定义@Pattern(regexp = "^\\d+(\\.\\d+)?(kg/m²)?$")校验注解,确保入库数据符合规范;前端Vue组件则使用v-model.number绑定,自动转换为Number类型供计算,实现“存储宽松、使用严谨”。

3. 核心模块实现:从PRD字段到可运行代码的关键落点

PRD文档的价值,在于它把模糊的“健康评估”需求,拆解成可编程的字段、状态、规则。以下选取三个最具代表性的模块,展示如何将PRD中的文字描述,转化为可调试、可验证的代码实现。重点不是炫技,而是解决学生最常卡壳的“知道要什么,但不知道代码怎么写”的断点。

3.1 会员管理:档案号生成与敏感字段脱敏策略

PRD中档案号字符型否否是所有模块的关联主键,其生成规则虽未明说,但结合“北京市昌平区”地域特征及医疗行业惯例,可采用地区码+年份+流水号组合:

// Java工具类:生成唯一档案号 public class ArchiveNoGenerator { private static final String REGION_CODE = "110114"; // 昌平区行政区划代码 private static final AtomicInteger SEQUENCE = new AtomicInteger(1000); // 初始流水号 public static String generate() { String year = String.valueOf(Calendar.getInstance().get(Calendar.YEAR)); int seq = SEQUENCE.getAndIncrement(); return REGION_CODE + year + String.format("%04d", seq); // 示例:11011420241001 } }

设计说明:REGION_CODE硬编码确保地域标识稳定;AtomicInteger保证高并发下流水号不重复;String.format("%04d", seq)强制4位补零,便于排序。此生成逻辑需在会员创建接口中调用,并作为事务一部分写入数据库,避免生成后插入失败导致号段浪费。

更关键的是敏感字段处理。PRD要求身份证号、手机号可修改,但生产环境必须脱敏显示(如110114******1234)。不能简单在SQL里用SUBSTR,而应在MyBatis ResultMap中配置:

<!-- MyBatis mapper.xml --> <resultMap id="MemberProfileMap" type="MemberProfile"> <id property="id" column="id"/> <result property="archiveNo" column="archive_no"/> <result property="name" column="name"/> <result property="idCard" column="id_card" typeHandler="com.example.handler.IdCardTypeHandler"/> <result property="phone" column="phone" typeHandler="com.example.handler.PhoneTypeHandler"/> </resultMap>

自定义TypeHandler实现脱敏:

// 身份证号脱敏处理器 public class IdCardTypeHandler implements TypeHandler<String> { @Override public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, parameter); // 写库不脱敏 } @Override public String getResult(ResultSet rs, String columnName) throws SQLException { String value = rs.getString(columnName); return StringUtils.isBlank(value) ? null : value.substring(0, 3) + "******" + value.substring(value.length()-4); } }

关键参数说明:setParameter方法保持原始值写入,确保业务逻辑(如身份证校验)正常;getResult方法在查询时自动脱敏,前端拿到的就是110******1234。这种“写库明文、读库脱敏”策略,既满足安全审计要求,又避免加密解密性能损耗。

3.2 健康评估:动态问卷引擎与指标关联逻辑

PRD中“评估问卷”功能要求支持体质、心理、风险三类测评,且评估结果需关联知识库中的评估建议。这不能靠静态HTML表单,而需构建动态问卷引擎。核心是将PRD中指标名称、参考值、单位、针对性别四元组,转化为可执行的评估规则:

// 知识库-指标管理表(knowledge_indicator)示例数据 { "id": 101, "indicator_name": "收缩压", "normal_range": "90-139", "unit": "mmHg", "gender_target": "all", "left_critical": 140, "right_critical": 180 }

后端根据此配置,动态生成评估问卷选项:

// 评估问卷DTO(简化) public class AssessmentQuestion { private Long indicatorId; // 指标ID,关联knowledge_indicator表 private String indicatorName; // 收缩压 private String unit; // mmHg private String options; // JSON字符串:["<90","90-139","140-179","≥180"] private Integer scoreWeight; // 该题权重,用于总分计算 }

评估结果计算逻辑(以收缩压为例):

// 评估服务核心方法 public AssessmentResult calculateResult(Long patientId, Map<Long, String> answers) { // 1. 获取患者基本信息(含性别) MemberProfile patient = memberProfileMapper.selectById(patientId); // 2. 遍历所有指标,匹配患者答案 List<AssessmentResultItem> items = new ArrayList<>(); for (Map.Entry<Long, String> entry : answers.entrySet()) { Long indicatorId = entry.getKey(); String answer = entry.getValue(); // 如"140-179" KnowledgeIndicator indicator = indicatorMapper.selectById(indicatorId); AssessmentResultItem item = new AssessmentResultItem(); item.setIndicatorName(indicator.getIndicatorName()); item.setUnit(indicator.getUnit()); // 3. 根据指标临界值判断等级(此处简化为字符串匹配) if ("≥180".equals(answer)) { item.setLevel("高危"); item.setAdvice(getAdviceByLevel(indicatorId, "high_risk")); } else if ("140-179".equals(answer)) { item.setLevel("异常"); item.setAdvice(getAdviceByLevel(indicatorId, "abnormal")); } else { item.setLevel("正常"); item.setAdvice(getAdviceByLevel(indicatorId, "normal")); } items.add(item); } // 4. 生成综合报告 AssessmentResult result = new AssessmentResult(); result.setPatientId(patientId); result.setItems(items); result.setReportTime(new Date()); result.setSummary(generateSummary(items)); // 生成"您的血压处于异常范围,建议..."摘要 return result; }

关键设计点:getAdviceByLevel()方法会查询knowledge_advice表,根据indicator_id+level_code(如101_high_risk)精准匹配预置建议,确保“收缩压≥180mmHg”时返回“立即就医,避免剧烈运动”而非泛泛的“注意休息”。这种强关联设计,正是PRD中强调“评估建议库为评估结果反馈,根据指标关联内容”的技术实现。

3.3 健康干预:人群分类确认与干预方案模板化

PRD中“系统预分类”与“健康管理师确认分类”是健康干预的前置条件。预分类非AI算法,而是基于评估结果的规则引擎:

// 人群预分类服务(简化版规则) public class PopulationClassifier { public String classifyByAssessment(AssessmentResult result) { // 统计各指标异常数量 long abnormalCount = result.getItems().stream() .filter(item -> "异常".equals(item.getLevel()) || "高危".equals(item.getLevel())) .count(); // 规则1:血压+血糖均异常 → 心血管高风险 boolean hasHypertension = result.getItems().stream() .anyMatch(item -> "收缩压".equals(item.getIndicatorName()) && ("异常".equals(item.getLevel()) || "高危".equals(item.getLevel()))); boolean hasHyperglycemia = result.getItems().stream() .anyMatch(item -> "空腹血糖".equals(item.getIndicatorName()) && ("异常".equals(item.getLevel()) || "高危".equals(item.getLevel()))); if (hasHypertension && hasHyperglycemia) { return "心血管高风险"; } // 规则2:BMI≥28且腰围超标 → 代谢综合征 if (abnormalCount >= 3) { return "多重风险"; } return "一般关注"; } }

健康管理师在“人群分类界面”看到系统预分类结果后,可点击“确认”或“重新分类”,此时更新member_profile.population_category字段。干预方案制定时,系统自动加载该分类对应的模板:

-- 干预模板表(intervention_template)关键字段 SELECT * FROM intervention_template WHERE category = '心血管高风险' AND status = '启用' ORDER BY priority DESC LIMIT 1;

模板内容包含运动方案、膳食方案、健康方案三个外键,分别关联exercise_library、diet_library、health_plan_library表。制定方案时,后端将模板ID与患者档案号绑定,生成intervention_plan记录:

// 制定干预方案DTO public class CreateInterventionPlanRequest { private Long patientId; // 档案号 private Long templateId; // 模板ID private String startDate; // 开始日期 private String endDate; // 结束日期 private String remark; // 备注 }

关键参数说明:templateId非必填,允许健康管理师手动选择模板或完全自定义;startDate/endDate决定干预周期,统计分析模块的“干预完成量”即按此时间范围统计;remark字段用于记录个性化调整(如“患者膝盖不好,替换跑步为游泳”),确保方案可追溯。

4. 常见问题排查:PRD落地时最容易翻车的5个点及解决方案

PRD文档写得再细,落到代码实现时仍会遇到大量“文档没写但系统必须处理”的灰色地带。以下是我在多个健康类项目中踩过的坑,按发生频率和破坏性排序,每条均给出可立即验证的解决方案。

4.1 现象:微信端患者提交预约后,PC后台“预约列表”不显示,或显示为“待确认”但无法操作

原因:PRD中“预约状态”字段有5种取值(待确认/已确认/已取消/已到诊/已过期),但微信端API未正确传递状态,或PC后台查询SQL遗漏状态条件。
解决:

  1. 检查微信端预约接口请求体,确认status字段值为"pending"(对应PRD“待确认”);
  2. 检查PC后台预约列表查询SQL,必须包含WHERE status IN ('pending','confirmed','arrived'),不能只查status='pending';
  3. 在预约创建接口中,强制设置默认状态:
// 预约实体类 public class Appointment { private String status = "pending"; // 默认待确认,避免null导致查询丢失 // ...其他字段 }

4.2 现象:患者上传体检报告PDF后,健康管理师在“报告上传”界面看不到文件,或点击下载提示404

原因:PRD中“报告状态”字段为文件类型,但实际存储时未保存文件路径,或Nginx/Apache未配置静态资源目录。
解决:

  1. 数据库增加report_path字段(VARCHAR),上传成功后存入相对路径(如/reports/2024/05/11011420241001_20240520.pdf);
  2. 后端提供文件下载接口,通过response.getOutputStream()流式传输,禁止直接返回路径字符串;
  3. Nginx配置静态资源:
location /reports/ { alias /var/www/health-system/reports/; expires 1h; }

4.3 现象:健康评估问卷提交后,“评估结果”页面显示空白,或所有指标等级均为“正常”

原因:PRD中“指标管理”表的left_critical/right_critical字段为空,或前端传入的答案值未按规则解析(如传入"140"但数据库存的是"140-179"区间)。
解决:

  1. 初始化数据脚本中,为所有指标设置合理临界值(如收缩压left_critical=140);
  2. 评估计算逻辑增加兜底:
if (StringUtils.isBlank(answer) || !answer.matches("\\d+(-\\d+)?")) { item.setLevel("未填写"); item.setAdvice("请完成所有题目"); continue; }

4.4 现象:知识库中“运动项目库”的千步当量字段为数值,但PC后台编辑时输入小数报错

原因:PRD中千步当量字符型,但前端Element UI的el-input-number组件强制数值类型,导致输入3.5时被截断为3。
解决:

  1. 前端改用普通el-input,添加自定义校验规则:
rules: { stepEquivalent: [ { required: true, message: '请输入千步当量', trigger: 'blur' }, { pattern: /^(\d+\.?\d*|\.\d+)$/, message: '请输入有效数字', trigger: 'blur' } ] }
  1. 后端接收参数类型改为String,入库前转BigDecimal:
BigDecimal stepEq = new BigDecimal(stepEquivalentStr);

4.5 现象:统计分析模块的“工作量统计”数据与实际不符,如“干预方案总量”比后台创建记录少

原因:PRD中“工作量统计”按时间选择字符型查询,但数据库created_time为DATETIME类型,SQL中用字符串比较(如WHERE created_time > '2024-05')导致索引失效,部分数据未被扫描。
解决:

  1. 修改查询SQL,使用日期函数:
SELECT COUNT(*) FROM intervention_plan WHERE DATE_FORMAT(created_time, '%Y-%m') = '2024-05';
  1. 或在intervention_plan表增加stat_month字段(VARCHAR),每月1号定时任务填充,查询时直接WHERE stat_month='2024-05',确保走索引。

5. 方案验收与答辩技巧:用PRD文档本身作为你的答辩武器

答辩不是背诵功能列表,而是证明你理解了业务本质,并能用技术手段解决真实问题。我带过的学生里,90%的答辩失败,源于把PRD当“需求说明书”读,而不是当“验收检查清单”用。以下是我总结的三步法,让你的答辩从“我做了什么”升级为“我为什么这么做,且它真的有效”。

5.1 第一步:用PRD原文构建验收测试用例表

不要自己编测试场景,直接从PRD中抠出可验证的句子,转化为测试用例。例如:

PRD原文位置原文摘录验收测试用例预期结果
1.3.1 功能操作-会员档案“a)显示所有患者信息 b)可以对患者进行增删改查”1. 登录管理员账号,进入会员档案页
2. 点击“新增会员”,填写姓名、身份证号、手机号
3. 提交后刷新页面
页面显示新会员,且档案号字段自动生成(如11011420241001)
3.2.3.1 功能操作-评估问卷“1)患者在前台使用评估问卷评估后,健管师可以在评估列表查看患者评估结果”1. 患者微信端提交体质测评
2. 健管师PC端登录,进入评估列表页
3. 搜索该患者档案号
列表中显示该患者最新评估记录,状态为“已完成”,点击可查看详细报告
4.2.3.2 功能操作-制定方案“健康管理师制定干预方案,通过知识库内维护的内容组成干预模板。”1. 健管师进入“制定干预方案”页
2. 选择“心血管高风险”分类
3. 点击“加载模板”
自动填充运动方案(如“快走30分钟/天”)、膳食方案(如“低盐饮食”)、健康方案(如“每周监测血压2次”)

关键技巧:每条用例必须包含操作步骤(谁、在哪、做什么)、预期结果(精确到字段值),且全部源自PRD原文。答辩时把这张表打印出来,评委问“这个功能怎么验证”,你就直接翻到对应行,现场演示。这比说“我测试过了”有力十倍。

5.2 第二步:用PRD的“业务规则”解释技术选型

评委常问:“为什么用MySQL不用MongoDB?”“为什么权限用角色控制不用URL白名单?”这时千万别答“因为简单”“因为学过”。要回到PRD找依据:

  • 选MySQL:PRD中所有数据表均有明确主键(档案号)、外键关联(评估问卷关联指标名称)、复杂查询(“按条件搜索会员”需多字段联合索引),且无文档型数据需求。MongoDB的灵活Schema在此场景反而是累赘。
  • 选角色权限:PRD中“管理员”“健康管理师”“患者”三类角色职责边界极其清晰,且同一角色在不同模块权限不同(如健管师可编辑会员但不可删知识库),RBAC模型天然匹配。若用URL白名单,需为每个接口单独配置,而PRD中“菜单管理”明确要求“管理员可对菜单进行增删改查”,证明菜单是权限载体。

关键技巧:把技术决策包装成“对PRD业务规则的必然响应”。例如:“PRD第7.3.1节要求‘菜单管理为系统管理员对系统菜单进行管理’,这意味着菜单是权限的最小单元,因此我们采用RBAC模型,将菜单节点ID作为权限标识符,确保管理员增删菜单时,权限自动同步。”

5.3 第三步:用PRD的“数据结构”证明系统健壮性

学生常被问:“如果患者同时预约了体检和评估,系统怎么保证数据一致性?”这时展示PRD中的数据结构就是最佳答案:

  • 打开PRD第1.3.1节“会员档案”数据结构表,指出档案号字段“否否”(不可为空、不可重复);
  • 打开PRD第2.3节“预约列表”数据结构,指出档案号同样“否否”,且与会员档案表同名;
  • 结论:两个模块共享同一主键,所有关联操作(如预约后自动创建评估入口)均基于档案号,天然保证数据指向同一患者。

更进一步,可现场演示数据库约束:

-- 查看会员档案表主键约束 SHOW CREATE TABLE member_profile; -- 输出中必有:PRIMARY KEY (`archive_no`) -- 查看预约表外键约束(若已建) SHOW CREATE TABLE appointment; -- 输出中应有:FOREIGN KEY (`archive_no`) REFERENCES `member_profile` (`archive_no`)

关键技巧:把抽象的“健壮性”转化为PRD中白纸黑字的字段约束。评委看到你连archive_no的“否否”属性都记得,自然相信你吃透了整个文档。从那以后我每次带学生做健康类毕设,都强制他们先用Excel把PRD中所有数据结构表重绘一遍,标出主键、外键、是否为空——这比写一万行代码更能建立系统认知。希望帮到你。

本文还有配套的精品资源,点击获取

返回列表