feat: 体重管理新增身高秤独立报告页

- 新增 height-scale-report.html 身高秤报告页,含基础指标/身体成分/体态分析
- 体重记录页身高秤来源记录改跳转 height-scale-report.html,不再复用体重秤模板
- PRD 补全身高秤报告页章节并重排页面序号
This commit is contained in:
liuyunqin
2026-08-20 17:50:44 +08:00
parent 1e98d476f7
commit a155c0d122
4 changed files with 239 additions and 19 deletions
+39 -18
View File
@@ -17,7 +17,7 @@
│ ├── 吃动平衡
│ ├── 饮食记录 → 饮食录入 → 拍照识别
│ ├── 运动记录 → 运动录入
│ ├── 体重记录 → 详细报告 / 体脂仪报告
│ ├── 体重记录 → 详细报告 / 体脂仪报告 / 身高秤报告
│ ├── 今日饮食建议 / 膳食偏好设置
│ ├── 智能运动计划
│ ├── 排行榜
@@ -88,18 +88,19 @@ stateDiagram-v2
| 18 | 体重记录 | weight-detail-v2.html | 页面 |
| 19 | 详细报告 | report-detail.html | 页面 |
| 20 | 体脂仪报告 | body-fat-report.html | 页面 |
| 21 | 体重报告 | weight-report.html | 页面 |
| 22 | 数据明细 | weight-record-detail-v2.html | 页面 |
| 23 | 排行榜 | weight-ranking.html | 页面 |
| 21 | 身高秤报告 | height-scale-report.html | 页面 |
| 22 | 体重报告 | weight-report.html | 页面 |
| 23 | 数据明细 | weight-record-detail-v2.html | 页面 |
| 24 | 排行榜 | weight-ranking.html | 页面 |
### 四、蓝牙体脂秤
| 序号 | 页面/弹窗 | 文件 | 类型 |
|------|-----------|------|------|
| 24 | 蓝牙称 | bluetooth-scale-v2.html | 页面 |
| 25 | 搜索设备 | bluetooth-search-v2.html | 页面 |
| 26 | WiFi 连接 | bluetooth-wifi-v2.html | 页面 |
| 27 | 用户管理 | bluetooth-device-members-v2.html | 页面 |
| 25 | 蓝牙称 | bluetooth-scale-v2.html | 页面 |
| 26 | 搜索设备 | bluetooth-search-v2.html | 页面 |
| 27 | WiFi 连接 | bluetooth-wifi-v2.html | 页面 |
| 28 | 用户管理 | bluetooth-device-members-v2.html | 页面 |
---
@@ -661,14 +662,14 @@ stateDiagram-v2
- 点击周历日期切换查看当日数据;点击周历标题打开月历弹窗,可在弹窗内切换月份并点选日期
- 点击指标 Tab(体重/体脂/腰围变化)切换趋势图表;点击时间范围 Tab 切换记录明细列表的时间范围
- 点击折线数据点显示悬浮提示
- 点击非自记记录行跳转到详细报告页(蓝牙称/身高秤跳 report-detail.html,体脂仪跳 body-fat-report.html
- 点击非自记记录行跳转到详细报告页(蓝牙称跳 report-detail.html,体脂仪跳 body-fat-report.html,身高秤跳 height-scale-report.html
- 点击"记录体重"打开记录弹窗
- 点击返回按钮返回上一页
**业务规则:**
- 无记录日期显示空状态("立即称重"按钮)
- BMI 分档:<18.5 偏瘦 / 18.5-24 正常 / 24-28 超重 / ≥28 肥胖
- 非自记来源(蓝牙称/身高秤/体脂仪)记录可点击查看详细报告,自记不可点击;身高秤来源记录跳转时复用体重秤(scale)报告模板,体脂仪来源记录跳转至独立体脂仪报告页(body-fat-report.html
- 非自记来源(蓝牙称/身高秤/体脂仪)记录可点击查看详细报告,自记不可点击;蓝牙称跳 report-detail.html,体脂仪跳 body-fat-report.html,身高秤跳 height-scale-report.html
- 当日最新记录与上一次记录对比显示变化,无历史记录时显示"首次记录"
---
@@ -693,7 +694,7 @@ stateDiagram-v2
| 蓝牙秤(device=bluetooth) | 基础指标、身体成分、脂肪分析、体态管理、体重管控、细胞液分析(8电极)、进阶成分(8电极)、躯干/四肢脂肪(8电极)、躯干/四肢肌肉(8电极) |
| 体脂仪(device=fat) | 基础指标、体脂分析、体成分、体重管理、节段脂肪、节段肌肉 |
注:体重记录页中"身高秤"来源的记录跳转本页时复用体重秤(scale)模板;"体脂仪"来源的记录已改跳转至独立页面 body-fat-report.html,本页 device=fat 模式保留用于兼容。
注:体重记录页中"身高秤"来源的记录已改跳转至独立页面 height-scale-report.html"体脂仪"来源的记录已改跳转至 body-fat-report.html,本页 device=fat / device=scale 模式保留用于兼容。
**交互说明:**
- 点击返回按钮返回来源页
@@ -725,7 +726,27 @@ stateDiagram-v2
---
### 21. 体重报告(weight-report.html
### 21. 身高秤报告(height-scale-report.html
![页面截图](screenshots/height-scale-report.jpg)
**功能说明:** 展示身高秤单次测量的身体成分报告,含身高、体重及身体成分、体态相关指标。
**页面状态:** 从体重记录页(weight-detail-v2.html)记录明细列表中身高秤来源的记录跳转进入,页面只读。
**主要UI元素:**
- 报告头部(蓝青渐变卡片):测量时间、设备标签「身高秤」、当前体重(大字)、BMI 状态标签、较上次变化
- 基础指标:身高 / 体重 / BMI / 体脂率(含 BMI 指示条:消瘦/正常/超重/肥胖四段色轨 + 指针)
- 身体成分:体脂肪 / 水分率 / 水分量 / 肌肉率 / 肌肉量 / 骨量 / 去脂体重
- 体态分析:内脏脂肪 / 体型 / 理想体重 / 超重百分比 / 体表面积
**交互说明:**
- 点击返回按钮返回体重记录页
- 页面为只读展示,无编辑操作
---
### 22. 体重报告(weight-report.html
![页面截图](screenshots/weight-report.jpg)
@@ -756,7 +777,7 @@ stateDiagram-v2
---
### 22. 数据明细(weight-record-detail-v2.html
### 23. 数据明细(weight-record-detail-v2.html
![页面截图](screenshots/weight-record-detail.jpg)
@@ -775,7 +796,7 @@ stateDiagram-v2
---
### 23. 排行榜(weight-ranking.html
### 24. 排行榜(weight-ranking.html
![页面截图](screenshots/weight-ranking.jpg)
@@ -813,7 +834,7 @@ stateDiagram-v2
## 四、蓝牙体脂秤
### 24. 蓝牙称(bluetooth-scale-v2.html
### 25. 蓝牙称(bluetooth-scale-v2.html
![页面截图](screenshots/bluetooth-scale.jpg)
@@ -840,7 +861,7 @@ stateDiagram-v2
---
### 25. 搜索设备(bluetooth-search-v2.html
### 26. 搜索设备(bluetooth-search-v2.html
![页面截图](screenshots/bluetooth-search.jpg)
@@ -862,7 +883,7 @@ stateDiagram-v2
---
### 26. WiFi 连接(bluetooth-wifi-v2.html
### 27. WiFi 连接(bluetooth-wifi-v2.html
![页面截图](screenshots/bluetooth-wifi.jpg)
@@ -882,7 +903,7 @@ stateDiagram-v2
---
### 27. 用户管理(bluetooth-device-members-v2.html
### 28. 用户管理(bluetooth-device-members-v2.html
![页面截图](screenshots/bluetooth-device-members.jpg)
Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

@@ -0,0 +1,199 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>详细报告 - 员工端 | 健康CQ原型</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
.phone-shell { width: 390px; height: 844px; background: #f5f7fa; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; }
.status-bar { height: 44px; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; background: #fff; }
.status-bar .time { font-size: 15px; font-weight: 700; color: #333; }
.status-bar .icons { display: flex; gap: 6px; align-items: center; }
.nav-bar { height: 44px; background: #fff; display: flex; align-items: center; padding: 0 16px; flex-shrink: 0; border-bottom: 1px solid #f0f0f0; }
.nav-back { width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; cursor: pointer; }
.nav-title { flex: 1; text-align: center; font-size: 17px; font-weight: 600; color: #1a1a1a; margin-right: 28px; }
.scroll-content { flex: 1; overflow-y: auto; background: #f5f7fa; padding: 12px; }
.scroll-content::-webkit-scrollbar { display: none; }
/* 头部 */
.report-header { background: linear-gradient(135deg, #5470c6 0%, #36cfc9 100%); border-radius: 16px; padding: 20px; color: #fff; margin-bottom: 12px; position: relative; overflow: hidden; }
.report-header::after { content: ''; position: absolute; top: -30px; right: -30px; width: 100px; height: 100px; background: rgba(255,255,255,0.08); border-radius: 50%; }
.report-header__top { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
.report-header__time { font-size: 13px; opacity: 0.85; display: flex; align-items: center; gap: 6px; }
.device-tag { display: inline-flex; align-items: center; font-size: 10px; padding: 2px 8px; border-radius: 4px; font-weight: 500; }
.device-tag--stadiometer { background: rgba(255,255,255,0.22); color: #e6fffb; }
.report-header__main { display: flex; align-items: center; gap: 20px; }
.report-header__weight { display: flex; align-items: baseline; gap: 4px; }
.report-header__weight-num { font-size: 42px; font-weight: 800; line-height: 1; }
.report-header__weight-unit { font-size: 16px; opacity: 0.85; }
.report-header__tags { display: flex; flex-direction: column; gap: 6px; }
.report-tag { display: inline-flex; align-items: center; gap: 4px; padding: 4px 10px; border-radius: 20px; font-size: 12px; font-weight: 500; }
.report-tag--normal { background: rgba(82,196,26,0.25); color: #d9f9d9; }
.report-tag--change { background: rgba(255,255,255,0.18); }
/* 数据分类 */
.data-section { background: #fff; border-radius: 16px; padding: 16px; margin-bottom: 12px; }
.data-section__title { font-size: 15px; font-weight: 700; color: #1a1a1a; margin-bottom: 4px; display: flex; align-items: center; gap: 8px; }
.data-section__title::before { content: ''; width: 3px; height: 16px; background: linear-gradient(135deg, #5470c6, #36cfc9); border-radius: 2px; }
.data-section__sub { font-size: 11px; color: #999; margin-bottom: 8px; }
/* 指标行 */
.metric { padding: 13px 0; border-bottom: 1px solid #f5f5f5; }
.metric:last-child { border-bottom: none; }
.metric__row { display: flex; justify-content: space-between; align-items: center; }
.metric__label { font-size: 14px; color: #666; }
.metric__value-wrap { display: flex; align-items: baseline; gap: 3px; }
.metric__value { font-size: 17px; font-weight: 700; color: #1a1a1a; }
.metric__unit { font-size: 12px; color: #999; }
/* BMI 指示条 */
.bmi-bar { margin-top: 14px; }
.bmi-bar__track { height: 8px; border-radius: 4px; background: linear-gradient(90deg, #69c0ff 0%, #69c0ff 17.5%, #52c41a 17.5%, #52c41a 45%, #faad14 45%, #faad14 65%, #ff4d4f 65%, #ff4d4f 100%); position: relative; }
.bmi-bar__pointer { position: absolute; top: -4px; width: 16px; height: 16px; background: #fff; border: 3px solid #5470c6; border-radius: 50%; transform: translateX(-50%); box-shadow: 0 2px 6px rgba(0,0,0,0.15); }
.bmi-bar__labels { display: flex; justify-content: space-between; margin-top: 6px; font-size: 10px; color: #999; }
.bottom-safe { height: 20px; flex-shrink: 0; }
</style>
</head>
<body>
<div class="phone-shell">
<div class="status-bar">
<span class="time">9:41</span>
<span class="icons">
<svg width="16" height="16" fill="none"><rect x="1" y="4" width="3" height="8" rx="1" fill="#333"/><rect x="5" y="3" width="3" height="9" rx="1" fill="#333"/><rect x="9" y="1" width="3" height="11" rx="1" fill="#333"/><rect x="13" y="0" width="3" height="12" rx="1" fill="#333" opacity=".3"/></svg>
<svg width="16" height="16" fill="none"><path d="M8 3C5.5 3 3.2 4 1.5 5.5l1.4 1.4C4.3 5.5 6.1 5 8 5s3.7.5 5.1 1.9l1.4-1.4C12.8 4 10.5 3 8 3zm0 4c-1.4 0-2.6.5-3.5 1.3L6 9.8c.6-.5 1.3-.8 2-.8s1.4.3 2 .8l1.5-1.5C10.6 7.5 9.4 7 8 7zm0 4c-.6 0-1 .4-1 1s.4 1 1 1 1-.4 1-1-.4-1-1-1z" fill="#333"/></svg>
<svg width="22" height="12" fill="none"><rect x=".5" y=".5" width="19" height="11" rx="2" stroke="#333"/><rect x="20" y="3.5" width="1.5" height="5" rx=".75" fill="#333"/><rect x="2" y="2" width="14" height="8" rx="1" fill="#333"/></svg>
</span>
</div>
<div class="nav-bar">
<div class="nav-back" onclick="goBack()">
<svg width="12" height="20" fill="none"><path d="M10 2L2 10l8 8" stroke="#1a1a1a" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
</div>
<div class="nav-title">详细报告</div>
</div>
<div class="scroll-content">
<!-- 头部 -->
<div class="report-header" id="reportHeader"></div>
<!-- 动态内容区域 -->
<div id="reportContent"></div>
<div class="bottom-safe"></div>
</div>
</div>
<script>
/* 返回来源页面 */
function goBack() {
if (document.referrer) {
location.href = document.referrer;
} else {
history.back();
}
}
/* ========================================================================
* 身高秤报告数据
* 字段名沿用统一后的命名:脂肪率→体脂率、脂肪量→体脂肪
* ======================================================================== */
var report = {
time: '2026-08-20 09:15',
weight: 72.5,
bmi: 23.7,
weightChange: -0.3
};
var sections = [
{
title: '基础指标',
sub: '身体整体状况概览',
rows: [
{ name: '身高', value: 175, unit: 'cm' },
{ name: '体重', value: 72.5, unit: 'kg' },
{ name: 'BMI', value: 23.7, unit: '' },
{ name: '体脂率', value: 21.0, unit: '%' }
],
bmiBar: true
},
{
title: '身体成分',
sub: '水分、肌肉、骨量与脂肪构成',
rows: [
{ name: '体脂肪', value: 15.2, unit: 'kg' },
{ name: '水分率', value: 53.2, unit: '%' },
{ name: '水分量', value: 38.6, unit: 'kg' },
{ name: '肌肉率', value: 42.6, unit: '%' },
{ name: '肌肉量', value: 30.9, unit: 'kg' },
{ name: '骨量', value: 3.1, unit: 'kg' },
{ name: '去脂体重', value: 57.3, unit: 'kg' }
]
},
{
title: '体态分析',
sub: '体型与体态指标',
rows: [
{ name: '内脏脂肪', value: 6, unit: '' },
{ name: '体型', value: '标准型', unit: '' },
{ name: '理想体重', value: 70.2, unit: 'kg' },
{ name: '超重百分比', value: 3.3, unit: '%' },
{ name: '体表面积', value: 1.88, unit: 'm²' }
]
}
];
/* ===== 渲染引擎 ===== */
function fmtVal(v) {
if (typeof v === 'number') {
return v.toLocaleString(undefined, { maximumFractionDigits: 2 });
}
return String(v);
}
function renderMetricRow(item) {
var html = '<div class="metric">';
html += '<div class="metric__row">';
html += '<span class="metric__label">' + item.name + '</span>';
html += '<span class="metric__value-wrap">';
html += '<span class="metric__value">' + fmtVal(item.value) + '</span>';
if (item.unit) html += '<span class="metric__unit">' + item.unit + '</span>';
html += '</span></div>';
html += '</div>';
return html;
}
function renderSection(sec) {
var html = '<div class="data-section">';
html += '<div class="data-section__title">' + sec.title + '</div>';
if (sec.sub) html += '<div class="data-section__sub">' + sec.sub + '</div>';
sec.rows.forEach(function(item) { html += renderMetricRow(item); });
if (sec.bmiBar) {
var bmi = report.bmi;
var bmiPct = Math.min(Math.max((bmi - 14) / 26 * 100, 2), 98);
html += '<div class="bmi-bar"><div class="bmi-bar__track"><div class="bmi-bar__pointer" style="left:' + bmiPct + '%"></div></div><div class="bmi-bar__labels"><span>BMI&lt;18.5 消瘦</span><span>18.5≤BMI&lt;24 正常</span><span>24≤BMI&lt;28 超重</span><span>BMI≥28 肥胖</span></div></div>';
}
html += '</div>';
return html;
}
/* 头部渲染 */
function getBMITag(bmi) {
if (bmi < 18.5) return '消瘦';
if (bmi < 24) return '正常';
if (bmi < 28) return '超重';
return '肥胖';
}
var bmiLabel = getBMITag(report.bmi);
var changeText = (report.weightChange < 0 ? '' : '+') + fmtVal(report.weightChange);
document.getElementById('reportHeader').innerHTML =
'<div class="report-header__top">' +
'<div class="report-header__time"><svg width="14" height="14" fill="none"><circle cx="7" cy="7" r="6" stroke="#fff" stroke-width="1.5"/><path d="M7 4v3.5l2.5 1.5" stroke="#fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg> ' + report.time + '</div>' +
'<span class="device-tag device-tag--stadiometer">身高秤</span>' +
'</div>' +
'<div class="report-header__main">' +
'<div class="report-header__weight"><span class="report-header__weight-num">' + fmtVal(report.weight) + '</span><span class="report-header__weight-unit">kg</span></div>' +
'<div class="report-header__tags"><span class="report-tag report-tag--normal">BMI ' + bmiLabel + '</span><span class="report-tag report-tag--change">较上次 ' + changeText + 'kg</span></div>' +
'</div>';
/* 渲染各分区 */
var contentHtml = '';
sections.forEach(function(sec) { contentHtml += renderSection(sec); });
document.getElementById('reportContent').innerHTML = contentHtml;
</script>
</body>
</html>
@@ -1407,7 +1407,7 @@ function renderRecordList(range) {
// 来源 → 详细报告页跳转地址(体脂仪跳转独立报告页,其余复用 report-detail.html
var reportUrlMap = {
bluetooth: 'report-detail.html?device=bluetooth',
stadiometer: 'report-detail.html?device=scale',
stadiometer: 'height-scale-report.html',
bodyanalyzer: 'body-fat-report.html'
};