日期: 2026-07-28 状态: 待审核
当前系统有4类报告分散在不同模块:
| 报告类型 | 源表 | 当前前端入口 | 文件支持 |
|---|---|---|---|
| 菌群检测 / 体检 | health_reports |
pages/health/report-list.vue |
✅ PDF/图片 |
| DAN测评 | dan_report_uploads |
pages/dan-assessment/report-upload.vue |
⚠️ 部分有PDF |
| 保单 | insurance_policies |
pages/wealth-sub/insurance-list.vue |
❌ 纯结构化数据 |
| 家庭周报 | family_fortune_report |
无统一入口 |
用户需在多个入口之间切换查看不同类型报告,且无法统一搜索、下载、分享。
report_summaryCREATE TABLE IF NOT EXISTS report_summary (
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-- 分类标识
report_type VARCHAR(32) NOT NULL COMMENT '报告类型: gut_flora/physical_exam/dan/insurance/fortune',
source_table VARCHAR(32) NOT NULL COMMENT '来源表: health_reports/dan_report_uploads/insurance_policies/family_fortune_report',
source_id BIGINT NOT NULL COMMENT '来源表记录ID',
-- 归属信息
user_id BIGINT NOT NULL COMMENT '创建者/上传者用户ID',
family_id BIGINT COMMENT '家庭ID',
subject_id BIGINT COMMENT '报告主体ID(users/family_members)',
subject_name VARCHAR(50) COMMENT '报告主体名称',
-- 展示信息
title VARCHAR(200) COMMENT '报告标题',
summary TEXT COMMENT '摘要(列表页展示)',
-- 文件信息
file_url VARCHAR(500) COMMENT '报告文件URL(PDF/图片)',
file_size BIGINT COMMENT '文件大小(字节)',
file_name VARCHAR(200) COMMENT '原始文件名',
has_file TINYINT DEFAULT 0 COMMENT '是否有可下载文件: 1=有, 0=无',
-- 评分/日期
overall_score INT COMMENT '综合评分(0-100,如适用)',
report_date DATE COMMENT '报告日期(体检日期/测评日期等)',
-- 状态
status VARCHAR(20) COMMENT '状态: active/confirmed/completed/expired/archived/discarded',
-- 前端路由
detail_route VARCHAR(100) COMMENT '详情页路由(如 /pages/health/physical-exam-detail)',
-- 时间
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_user_id (user_id),
INDEX idx_family_id (family_id),
INDEX idx_subject_id (subject_id),
INDEX idx_report_type (report_type),
INDEX idx_report_date (report_date),
INDEX idx_status (status),
UNIQUE KEY uk_source (source_table, source_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='统一报告汇总表';
health_reports)report_summary 字段 |
映射来源 | 说明 |
|---|---|---|
report_type |
report_type (gut_flora/physical_exam) |
直接映射 |
source_table |
常量 health_reports |
— |
source_id |
id |
— |
user_id |
user_id |
上传者 |
family_id |
family_id |
— |
subject_id |
subject_id |
报告主体(可为null) |
subject_name |
从 users 表关联查询 |
按 subject_id |
title |
拼接: {报告主体姓名} 的 {report_type} 报告 |
体检报告/菌群检测报告 |
file_url |
file_url |
— |
overall_score |
overall_score |
— |
report_date |
report_date |
— |
status |
status |
active/archived |
detail_route |
gut_flora → /pages/health/gut-flora-detail, physical_exam → /pages/health/physical-exam-detail |
路由映射 |
has_file |
file_url IS NOT NULL → 1, else 0 |
— |
dan_report_uploads)report_summary 字段 |
映射来源 | 说明 |
|---|---|---|
report_type |
常量 dan |
— |
source_table |
常量 dan_report_uploads |
— |
source_id |
id |
— |
user_id |
uploader_user_id |
— |
family_id |
family_id |
— |
subject_id |
family_member_id |
测评对象 |
subject_name |
从 family_members 表关联查询 |
按 family_member_id |
title |
拼接: {subject_name} 的 {dimension} 测评 |
dimension=mind/wisdom |
file_url |
file_url |
— |
overall_score |
从 dan_assessment_results 关联查询 overall_score |
通过 linked_result_id |
report_date |
uploaded_at (DATE部分) |
上传日期 |
status |
draft_status → 映射为 active/confirmed/discarded |
— |
detail_route |
/pages/dan-assessment/report-upload (带id参数) |
— |
has_file |
file_url IS NOT NULL → 1, else 0 |
— |
insurance_policies)report_summary 字段 |
映射来源 | 说明 |
|---|---|---|
report_type |
常量 insurance |
— |
source_table |
常量 insurance_policies |
— |
source_id |
id |
— |
user_id |
user_id |
— |
subject_name |
insured_person |
被保人 |
title |
拼接: {policy_name} |
— |
summary |
拼接: {insurance_company} · {policy_type} · 保额 ¥{sum_insured} |
— |
file_url |
NULL | 保单无PDF |
has_file |
0 | 纯结构化数据 |
report_date |
start_date |
保单生效日期 |
status |
status |
active/expired/cancelled |
detail_route |
/pages/wealth-sub/insurance-list |
跳转到保单列表,标记选中 |
overall_score |
NULL | 不适用 |
family_fortune_report)report_summary 字段 |
映射来源 | 说明 |
|---|---|---|
report_type |
常量 fortune |
— |
source_table |
常量 family_fortune_report |
— |
source_id |
id |
— |
user_id |
从 family_members 关联查询(family主用户) |
— |
family_id |
family_id |
— |
title |
拼接: {element} 天盘周报 |
— |
summary |
拼接: {luckyDirection} · {createdAt} |
— |
file_url |
pdfPath |
— |
file_size |
fileSize |
— |
has_file |
pdfPath IS NOT NULL → 1, else 0 |
— |
report_date |
createdAt (DATE部分) |
— |
status |
active | — |
detail_route |
/pages/tianpan/index |
跳转到天盘 |
overall_score |
NULL | 不适用 |
新建 ReportSummaryService,提供 sync() 方法。在各源表的CRUD操作末尾调用。
// 各Service中的伪代码
// HealthReportService.save(report) 末尾:
reportSummaryService.syncFromHealthReport(report);
// DanReportUploadService.confirm(upload) 末尾:
reportSummaryService.syncFromDanReport(upload);
// InsurancePolicyService.create(policy) 末尾:
reportSummaryService.syncFromInsurancePolicy(policy);
// FamilyFortuneReport相关Service:
reportSummaryService.syncFromFortuneReport(report);
关键设计:
sync() 使用 INSERT ... ON DUPLICATE KEY UPDATE 保证幂等UNIQUE KEY uk_source (source_table, source_id) 去重report_summary.status = 'discarded',不物理删除新建 ReportSummarySyncTask,每天凌晨 2:00 执行:
POST /api/admin/report-summary/sync (管理员手动触发)
定时: cron 0 0 2 * * ? (每日凌晨2点自动)
执行逻辑:
health_reports → 更新/插入 report_summary(已删除的标记为 discarded)dan_report_uploads → 同上insurance_policies → 同上family_fortune_report → 同上异常处理:
POST /api/report-summary/list
请求体:
{
"page": 1,
"size": 20,
"type": "all", // gut_flora|physical_exam|dan|insurance|fortune|all
"keyword": "", // 搜索标题/主体名称
"subjectId": null, // 按报告主体筛选
"startDate": null, // 报告日期范围起
"endDate": null
}
响应:
{
"code": 200,
"data": {
"total": 156,
"list": [
{
"id": 1,
"reportType": "gut_flora",
"reportTypeName": "菌群检测",
"title": "小李的菌群检测报告",
"subjectName": "小李",
"reportDate": "2025-03-15",
"overallScore": 78,
"hasFile": true,
"status": "active",
"createdAt": "2025-03-16 10:30:00"
}
]
}
}
POST /api/report-summary/detail/{summaryId}
响应:
{
"code": 200,
"data": {
"id": 1,
"reportType": "gut_flora",
"reportTypeName": "菌群检测",
"title": "小李的菌群检测报告",
"subjectName": "小李",
"summary": "肠道菌群健康评分78分...",
"fileUrl": "https://cdn.xxx.com/reports/abc123.pdf",
"fileName": "gut_flora_report_20250315.pdf",
"fileSize": 2048576,
"hasFile": true,
"overallScore": 78,
"reportDate": "2025-03-15",
"status": "active",
"detailRoute": "/pages/health/gut-flora-detail",
"detailParams": { "reportId": 45 } // 跳转到详情页的额外参数
}
}
POST /api/report-summary/download/{summaryId}
响应:
{
"code": 200,
"data": {
"fileUrl": "https://cdn.xxx.com/reports/abc123.pdf",
"fileName": "gut_flora_report_20250315.pdf",
"fileSize": 2048576
}
}
POST /api/admin/report-summary/sync
响应:
{
"code": 200,
"message": "同步完成",
"data": {
"newCount": 5,
"updateCount": 12,
"discardedCount": 2,
"errorCount": 0
}
}
在 pages/profile/components/ProfileMenu.vue 的「个人」分组末尾添加:
<view class="menu-item" @click="goToReportManagement">
<text>📋 报告管理</text>
<text class="arrow">›</text>
</view>
对应方法:
goToReportManagement() {
uni.navigateTo({ url: '/pages/profile/report-management' })
}
pages/profile/report-management.vue页面结构:
┌─────────────────────────────┐
│ ← 报告管理 📥 │ ← 搜索按钮
├─────────────────────────────┤
│ [全部] [菌群] [体检] [DAN] [保单] [周报] │ ← 类型Tab
├─────────────────────────────┤
│ 🔍 搜索报告标题或成员名称... │ ← 搜索栏
├─────────────────────────────┤
│ ┌─────────────────────────┐ │
│ │ 菌群检测 2025-03 │ │
│ │ 小李的菌群检测报告 │ │
│ │ 综合评分: 78分 │ │ → 点击查看详情
│ └─────────────────────────┘ │
│ ┌─────────────────────────┐ │
│ │ DAN测评 2025-02 │ │
│ │ 小王的心智测评 │ │
│ │ 综合评分: 82分 │ │
│ └─────────────────────────┘ │
│ ┌─────────────────────────┐ │
│ │ 保单 2024-01 │ │
│ │ 重疾险 - 中国平安 │ │ → 点击查看详情
│ │ 保额: ¥500,000 │ │
│ └─────────────────────────┘ │
└─────────────────────────────┘
点击卡片后的操作菜单(右滑/长按):
底部Tab(可选):
新建 pages/profile/report-detail.vue,根据 hasFile 和 detailRoute 决定展示:
hasFile=1 → 显示PDF预览/下载按钮 + 报告摘要hasFile=0 → 显示结构化数据详情(如保单明细)onShareAppMessage)在 cfc-web/src/views/Layout.vue 左侧菜单新增「报告管理」分组:
/report-management — "报告管理"(perm: report:management)cfc-web/src/views/admin/ReportManagement.vue页面结构:Element UI表格 + 筛选 + 分页
| 字段 | 列 |
|---|---|
| 报告ID | id |
| 报告类型 | 菌群/体检/DAN/保单/周报 (tag) |
| 标题 | title |
| 报告主体 | subjectName |
| 报告日期 | reportDate |
| 综合评分 | overallScore (有条件色) |
| 状态 | status (tag) |
| 操作 | 查看/下载/同步 |
顶部筛选:
API:
POST /api/report-summary/admin-list(分页查询,管理员可见所有用户)POST /api/admin/report-summary/syncPOST /api/report-summary/detail/{id}POST /api/report-summary/download/{id}user_id)的报告family_id 关联)onShareAppMessage,生成分享卡片admin 角色可查看全平台所有报告teacher 角色可查看自己负责家庭的报告(通过 family_id 过滤)利用微信小程序开放能力:
// report-detail.vue 中
onShareAppMessage() {
return {
title: this.reportTitle,
path: '/pages/profile/report-detail?id=' + this.reportId,
imageUrl: '/static/share-report.png' // 分享封面图
}
}
对于有文件的报告,下载后使用 wx.shareFileMessage 转发文件。
| 文件 | 操作 | 说明 |
|---|---|---|
entity/ReportSummary.java |
新建 | 汇总表实体 |
mapper/ReportSummaryMapper.java |
新建 | MyBatis Mapper |
mapper/ReportSummaryMapper.xml |
新建 | XML映射 |
service/ReportSummaryService.java |
新建 | 同步+查询逻辑 |
controller/ReportSummaryController.java |
新建 | 前端API |
controller/admin/ReportSummaryAdminController.java |
新建 | 管理端API |
task/ReportSummarySyncTask.java |
新建 | 定时同步任务 |
config/DatabaseInitializer.java |
修改 | 添加建表迁移 |
resources/schema.sql |
修改 | 追加建表语句 |
service/HealthReportService.java |
修改 | 末尾加sync调用 |
service/DanReportUploadService.java |
修改 | 末尾加sync调用 |
service/InsurancePolicyService.java |
修改 | 末尾加sync调用 |
entity/FamilyFortuneReport.java 相关Service |
修改 | 末尾加sync调用 |
| 文件 | 操作 | 说明 |
|---|---|---|
pages/profile/components/ProfileMenu.vue |
修改 | 添加「报告管理」菜单项 |
pages/profile/report-management.vue |
新建 | 报告管理主页面 |
pages/profile/report-detail.vue |
新建 | 统一报告详情视图 |
utils/api.js |
修改 | 添加报告管理API函数 |
pages.json |
修改 | 注册新页面 |
| 文件 | 操作 | 说明 |
|---|---|---|
src/views/admin/ReportManagement.vue |
新建 | 管理端报告管理页面 |
src/views/Layout.vue |
修改 | 添加菜单入口 |
src/router/index.js |
修改 | 添加路由 |
@PostMapping 规范Result<T> 包装?.,禁用 CSS Gridsource_table + source_id 唯一关联@Scheduled