- 新增 VeepooBridge API:精准睡眠读取(readPreciseSleepData)、B3自动测量配置 (readAutoTestConfig/setAutoTestConfig)、开关设置(setAutoHeartRate/BP/Temp)、 体温自动数据读取(readAutoTemperatureData),共 10 个新 API - 新增 SDK 事件类型:SDK_EVENT_SLEEP(4)、SDK_EVENT_AUTO_TEST(54) - VeepooPipeline 新增:readSleepData/readAllSleepData(enableAutoMeasurement 睡眠数据 Promise 化读取 + 自动测量一键开启 - VeepooHistoryReader 新增:uploadSleepReadings 睡眠数据上传 - stores/veepoo.ts 实装:注册 onSleepData 回调、syncHistory 实际读取+上传、 readSleepData 状态管理、enableAutoMeasurement、连接后自动触发三件事 - 原生页面(native/pkg-veepoo):_onReady 后自动读取 3 天睡眠 + 开启自动测量, 新增 _readSleepData/_handleSleepEvent/_enableAutoMeasurement - UI 重构:测量页药丸式选择器+SVG 圆环仪表盘+健康评估标签 - 数据上传页:2 列结果卡片网格+彩色条标识+睡眠数据卡片(★评分+总时长) - 修复上传按钮无响应 bug:patientId 增加 URL fallback + 错误提示不再静默 - 设计原型:docs/design/veepoo-measure-prototype.html(4 状态预览)
880 lines
26 KiB
HTML
880 lines
26 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Veepoo M2 手环 — 测量页 & 上传页原型</title>
|
||
<style>
|
||
/* ═══════════════════════════════════════
|
||
Design Token — 复刻小程序 var(--tk-*)
|
||
═══════════════════════════════════════ */
|
||
:root {
|
||
--tk-pri: #C4623A;
|
||
--tk-pri-l: #F0DDD4;
|
||
--tk-pri-d: #8B3E1F;
|
||
--tk-pri-surface: #F5F0EB;
|
||
--tk-acc: #5B7A5E;
|
||
--tk-acc-l: #E8F0E8;
|
||
--tk-bg: #F5F0EB;
|
||
--tk-card: #FFFFFF;
|
||
--tk-tx: #2D2A26;
|
||
--tk-tx2: #5A554F;
|
||
--tk-tx3: #78716C;
|
||
--tk-bd: #E8E2DC;
|
||
--tk-dan: #B54A4A;
|
||
--tk-dan-l: #FDEAEA;
|
||
--tk-wrn: #C4873A;
|
||
--tk-wrn-l: #FFF3E0;
|
||
|
||
--tk-font-h2: 22px;
|
||
--tk-font-body-lg: 18px;
|
||
--tk-font-body: 16px;
|
||
--tk-font-body-sm: 14px;
|
||
--tk-font-num: 30px;
|
||
--tk-font-num-lg: 34px;
|
||
--tk-font-cap: 13px;
|
||
--tk-font-micro: 11px;
|
||
--tk-line-height: 1.5;
|
||
|
||
--tk-card-radius: 16px;
|
||
--tk-gap-sm: 12px;
|
||
--tk-gap-md: 16px;
|
||
--tk-gap-lg: 24px;
|
||
--tk-gap-xl: 32px;
|
||
--tk-page-padding: 20px;
|
||
|
||
--tk-shadow-sm: 0 1px 4px rgba(45,42,38,0.06);
|
||
--tk-shadow-md: 0 2px 12px rgba(45,42,38,0.10);
|
||
--tk-shadow-btn: 0 4px 16px rgba(196,98,58,0.3);
|
||
|
||
--tk-duration-fast: 150ms;
|
||
--tk-duration-normal: 200ms;
|
||
--tk-easing: cubic-bezier(0.16,1,0.3,1);
|
||
}
|
||
|
||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||
body {
|
||
font-family: -apple-system, 'PingFang SC', 'Helvetica Neue', sans-serif;
|
||
background: #E8E2DC;
|
||
display: flex;
|
||
gap: 40px;
|
||
justify-content: center;
|
||
align-items: flex-start;
|
||
padding: 40px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
/* ═══════════════════════════════════════
|
||
Phone Frame — 模拟小程序容器
|
||
═══════════════════════════════════════ */
|
||
.phone {
|
||
width: 375px;
|
||
height: 812px;
|
||
background: var(--tk-bg);
|
||
border-radius: 40px;
|
||
overflow: hidden;
|
||
position: relative;
|
||
box-shadow: 0 20px 60px rgba(0,0,0,0.15), 0 0 0 1px rgba(0,0,0,0.05);
|
||
flex-shrink: 0;
|
||
}
|
||
.phone-inner {
|
||
height: 100%;
|
||
overflow-y: auto;
|
||
-webkit-overflow-scrolling: touch;
|
||
}
|
||
.phone-label {
|
||
text-align: center;
|
||
font-size: 13px;
|
||
color: var(--tk-tx3);
|
||
margin-bottom: 12px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
/* 状态栏 */
|
||
.status-bar {
|
||
height: 44px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 0 20px;
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
color: var(--tk-tx);
|
||
}
|
||
.status-bar-right {
|
||
display: flex;
|
||
gap: 4px;
|
||
align-items: center;
|
||
font-size: 12px;
|
||
}
|
||
|
||
/* ═══════════════════════════════════════
|
||
页面 1 — 测量页面(就绪态 + 测量中心率)
|
||
═══════════════════════════════════════ */
|
||
.measure-page {
|
||
background: var(--tk-bg);
|
||
min-height: 100%;
|
||
padding-bottom: 40px;
|
||
}
|
||
|
||
/* 设备状态栏 */
|
||
.device-bar {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 10px var(--tk-page-padding);
|
||
background: var(--tk-card);
|
||
border-bottom: 1px solid var(--tk-bd);
|
||
}
|
||
.device-bar__left {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
.device-bar__dot {
|
||
width: 8px;
|
||
height: 8px;
|
||
border-radius: 50%;
|
||
background: var(--tk-acc);
|
||
}
|
||
.device-bar__name {
|
||
font-size: var(--tk-font-body);
|
||
font-weight: 600;
|
||
color: var(--tk-tx);
|
||
}
|
||
.device-bar__battery {
|
||
font-size: var(--tk-font-cap);
|
||
color: var(--tk-tx3);
|
||
margin-left: 4px;
|
||
}
|
||
.device-bar__disconnect {
|
||
font-size: var(--tk-font-cap);
|
||
color: var(--tk-tx3);
|
||
padding: 6px 12px;
|
||
background: transparent;
|
||
border: 1px solid var(--tk-bd);
|
||
border-radius: 999px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
/* 指标选择器 — 横向滚动药丸 */
|
||
.selector {
|
||
display: flex;
|
||
gap: 0;
|
||
padding: var(--tk-gap-md) var(--tk-page-padding);
|
||
overflow-x: auto;
|
||
-webkit-overflow-scrolling: touch;
|
||
}
|
||
.selector::-webkit-scrollbar { display: none; }
|
||
.selector__pill {
|
||
flex-shrink: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 4px;
|
||
padding: 10px 14px;
|
||
border-radius: 16px;
|
||
cursor: pointer;
|
||
transition: all var(--tk-duration-normal) var(--tk-easing);
|
||
position: relative;
|
||
min-width: 64px;
|
||
}
|
||
.selector__pill--active {
|
||
background: var(--tk-card);
|
||
box-shadow: var(--tk-shadow-md);
|
||
}
|
||
.selector__pill--done::after {
|
||
content: '✓';
|
||
position: absolute;
|
||
top: 4px;
|
||
right: 6px;
|
||
font-size: 10px;
|
||
color: #fff;
|
||
background: var(--tk-acc);
|
||
width: 16px;
|
||
height: 16px;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
.selector__icon {
|
||
width: 36px;
|
||
height: 36px;
|
||
border-radius: 12px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 18px;
|
||
color: #fff;
|
||
transition: transform var(--tk-duration-normal) var(--tk-easing);
|
||
}
|
||
.selector__pill--active .selector__icon {
|
||
transform: scale(1.15);
|
||
}
|
||
.selector__label {
|
||
font-size: var(--tk-font-cap);
|
||
color: var(--tk-tx3);
|
||
white-space: nowrap;
|
||
}
|
||
.selector__pill--active .selector__label {
|
||
color: var(--tk-tx);
|
||
font-weight: 600;
|
||
}
|
||
|
||
/* 仪表盘区域 */
|
||
.gauge-section {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
padding: var(--tk-gap-md) 0 var(--tk-gap-lg);
|
||
}
|
||
.gauge {
|
||
position: relative;
|
||
width: 220px;
|
||
height: 220px;
|
||
}
|
||
.gauge__ring-bg {
|
||
fill: none;
|
||
stroke: var(--tk-bd);
|
||
stroke-width: 10;
|
||
}
|
||
.gauge__ring-progress {
|
||
fill: none;
|
||
stroke-width: 10;
|
||
stroke-linecap: round;
|
||
transition: stroke-dasharray 0.4s ease-out;
|
||
}
|
||
.gauge__center {
|
||
position: absolute;
|
||
inset: 20px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
.gauge__value {
|
||
font-family: Georgia, 'Times New Roman', serif;
|
||
font-size: 52px;
|
||
font-weight: 700;
|
||
color: var(--tk-tx);
|
||
line-height: 1;
|
||
}
|
||
.gauge__unit {
|
||
font-size: var(--tk-font-body-sm);
|
||
color: var(--tk-tx3);
|
||
margin-top: 4px;
|
||
}
|
||
/* 测量中脉冲动画 */
|
||
.gauge--measuring {
|
||
animation: gauge-breathe 2s ease-in-out infinite;
|
||
}
|
||
@keyframes gauge-breathe {
|
||
0%, 100% { transform: scale(1); }
|
||
50% { transform: scale(1.03); }
|
||
}
|
||
|
||
/* 测量进度条 */
|
||
.progress-bar {
|
||
width: 240px;
|
||
height: 4px;
|
||
background: var(--tk-bd);
|
||
border-radius: 2px;
|
||
margin-top: var(--tk-gap-md);
|
||
overflow: hidden;
|
||
}
|
||
.progress-bar__fill {
|
||
height: 100%;
|
||
border-radius: 2px;
|
||
transition: width 0.3s ease-out;
|
||
}
|
||
|
||
/* 健康评估标签 */
|
||
.assessment {
|
||
margin-top: var(--tk-gap-md);
|
||
padding: 8px 20px;
|
||
border-radius: 999px;
|
||
font-size: var(--tk-font-body-sm);
|
||
font-weight: 500;
|
||
}
|
||
.assessment--normal {
|
||
background: var(--tk-acc-l);
|
||
color: var(--tk-acc);
|
||
}
|
||
.assessment--warning {
|
||
background: var(--tk-wrn-l);
|
||
color: var(--tk-wrn);
|
||
}
|
||
.assessment--danger {
|
||
background: var(--tk-dan-l);
|
||
color: var(--tk-dan);
|
||
}
|
||
|
||
/* 免责声明 */
|
||
.disclaimer {
|
||
text-align: center;
|
||
padding: 0 var(--tk-page-padding);
|
||
margin: var(--tk-gap-sm) 0 var(--tk-gap-lg);
|
||
}
|
||
.disclaimer__text {
|
||
font-size: var(--tk-font-micro);
|
||
color: var(--tk-tx3);
|
||
line-height: 1.5;
|
||
}
|
||
|
||
/* 操作按钮 */
|
||
.actions {
|
||
padding: 0 var(--tk-page-padding);
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--tk-gap-sm);
|
||
}
|
||
.btn {
|
||
height: 52px;
|
||
border-radius: 16px;
|
||
border: none;
|
||
font-size: var(--tk-font-body-lg);
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 8px;
|
||
transition: opacity var(--tk-duration-fast);
|
||
}
|
||
.btn:active { opacity: 0.85; }
|
||
.btn--primary {
|
||
background: var(--tk-pri);
|
||
color: #fff;
|
||
box-shadow: var(--tk-shadow-btn);
|
||
}
|
||
.btn--secondary {
|
||
background: var(--tk-card);
|
||
color: var(--tk-tx);
|
||
border: 1px solid var(--tk-bd);
|
||
}
|
||
.btn--text {
|
||
background: transparent;
|
||
color: var(--tk-tx3);
|
||
height: 44px;
|
||
font-size: var(--tk-font-body-sm);
|
||
}
|
||
|
||
/* ═══════════════════════════════════════
|
||
页面 2 — 数据上传页面
|
||
═══════════════════════════════════════ */
|
||
.upload-page {
|
||
background: var(--tk-bg);
|
||
min-height: 100%;
|
||
padding-bottom: 40px;
|
||
}
|
||
|
||
/* 页面标题区 */
|
||
.page-header {
|
||
padding: var(--tk-gap-lg) var(--tk-page-padding) var(--tk-gap-md);
|
||
}
|
||
.page-header__title {
|
||
font-family: Georgia, 'Times New Roman', serif;
|
||
font-size: var(--tk-font-h2);
|
||
font-weight: 700;
|
||
color: var(--tk-tx);
|
||
line-height: 1.3;
|
||
}
|
||
.page-header__subtitle {
|
||
font-size: var(--tk-font-body-sm);
|
||
color: var(--tk-tx3);
|
||
margin-top: 4px;
|
||
}
|
||
|
||
/* 结果卡片网格 */
|
||
.results-grid {
|
||
padding: 0 var(--tk-page-padding);
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: var(--tk-gap-sm);
|
||
}
|
||
.result-card {
|
||
background: var(--tk-card);
|
||
border-radius: var(--tk-card-radius);
|
||
padding: var(--tk-gap-md);
|
||
box-shadow: var(--tk-shadow-sm);
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
.result-card--full {
|
||
grid-column: 1 / -1;
|
||
}
|
||
.result-card__badge {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 4px;
|
||
height: 100%;
|
||
border-radius: 0 4px 4px 0;
|
||
}
|
||
.result-card__label {
|
||
font-size: var(--tk-font-cap);
|
||
color: var(--tk-tx2);
|
||
margin-bottom: 8px;
|
||
padding-left: 8px;
|
||
}
|
||
.result-card__value-row {
|
||
display: flex;
|
||
align-items: baseline;
|
||
gap: 4px;
|
||
padding-left: 8px;
|
||
}
|
||
.result-card__value {
|
||
font-family: Georgia, 'Times New Roman', serif;
|
||
font-size: var(--tk-font-num-lg);
|
||
font-weight: 700;
|
||
color: var(--tk-tx);
|
||
line-height: 1;
|
||
}
|
||
.result-card__unit {
|
||
font-size: var(--tk-font-cap);
|
||
color: var(--tk-tx3);
|
||
}
|
||
.result-card__tag {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 3px;
|
||
margin-top: 8px;
|
||
margin-left: 8px;
|
||
padding: 2px 8px;
|
||
border-radius: 999px;
|
||
font-size: var(--tk-font-micro);
|
||
font-weight: 500;
|
||
}
|
||
.result-card__tag--normal {
|
||
background: var(--tk-acc-l);
|
||
color: var(--tk-acc);
|
||
}
|
||
.result-card__tag--warning {
|
||
background: var(--tk-wrn-l);
|
||
color: var(--tk-wrn);
|
||
}
|
||
|
||
/* 未测量占位 */
|
||
.result-card--empty {
|
||
opacity: 0.5;
|
||
}
|
||
.result-card__placeholder {
|
||
padding-left: 8px;
|
||
font-size: var(--tk-font-body-sm);
|
||
color: var(--tk-tx3);
|
||
}
|
||
|
||
/* 底部上传播区 */
|
||
.upload-footer {
|
||
padding: var(--tk-gap-lg) var(--tk-page-padding) var(--tk-gap-xl);
|
||
}
|
||
.upload-footer__hint {
|
||
font-size: var(--tk-font-cap);
|
||
color: var(--tk-tx3);
|
||
text-align: center;
|
||
margin-bottom: var(--tk-gap-sm);
|
||
}
|
||
.upload-footer__time {
|
||
font-size: var(--tk-font-micro);
|
||
color: var(--tk-tx3);
|
||
text-align: center;
|
||
margin-top: var(--tk-gap-sm);
|
||
}
|
||
|
||
/* ═══════════════════════════════════════
|
||
长者模式覆盖
|
||
═══════════════════════════════════════ */
|
||
.elder-mode {
|
||
--tk-font-h2: 25px;
|
||
--tk-font-body-lg: 22px;
|
||
--tk-font-body: 22px;
|
||
--tk-font-body-sm: 19px;
|
||
--tk-font-num: 34px;
|
||
--tk-font-num-lg: 40px;
|
||
--tk-font-cap: 18px;
|
||
--tk-font-micro: 17px;
|
||
}
|
||
.elder-mode .selector {
|
||
flex-wrap: wrap;
|
||
gap: var(--tk-gap-sm);
|
||
}
|
||
.elder-mode .selector__pill {
|
||
min-width: 80px;
|
||
padding: 14px 18px;
|
||
}
|
||
.elder-mode .gauge {
|
||
width: 260px;
|
||
height: 260px;
|
||
}
|
||
.elder-mode .gauge__value {
|
||
font-size: 64px;
|
||
}
|
||
.elder-mode .results-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
.elder-mode .btn {
|
||
height: 60px;
|
||
}
|
||
|
||
/* ═══════════════════════════════════════
|
||
状态切换按钮(原型交互用)
|
||
═══════════════════════════════════════ */
|
||
.state-switcher {
|
||
display: flex;
|
||
gap: 8px;
|
||
padding: 12px var(--tk-page-padding);
|
||
background: var(--tk-card);
|
||
border-top: 1px solid var(--tk-bd);
|
||
position: sticky;
|
||
bottom: 0;
|
||
}
|
||
.state-btn {
|
||
flex: 1;
|
||
height: 36px;
|
||
border-radius: 8px;
|
||
border: 1px solid var(--tk-bd);
|
||
background: var(--tk-bg);
|
||
font-size: 12px;
|
||
color: var(--tk-tx2);
|
||
cursor: pointer;
|
||
}
|
||
.state-btn--active {
|
||
background: var(--tk-pri);
|
||
color: #fff;
|
||
border-color: var(--tk-pri);
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<!-- ══════════════════════════════════════════════════════════════
|
||
页面 1 — 测量页面(就绪态,正在测量心率)
|
||
══════════════════════════════════════════════════════════════ -->
|
||
<div>
|
||
<div class="phone-label">页面 1 · 测量页(就绪态 — 心率测量中)</div>
|
||
<div class="phone">
|
||
<div class="phone-inner">
|
||
<!-- 状态栏 -->
|
||
<div class="status-bar">
|
||
<span>9:41</span>
|
||
<div class="status-bar-right">
|
||
<span>●●●●</span>
|
||
<span>WiFi</span>
|
||
<span>85%</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="measure-page">
|
||
<!-- 设备状态栏 -->
|
||
<div class="device-bar">
|
||
<div class="device-bar__left">
|
||
<div class="device-bar__dot"></div>
|
||
<span class="device-bar__name">M2 手环</span>
|
||
<span class="device-bar__battery">85%</span>
|
||
</div>
|
||
<button class="device-bar__disconnect">断开</button>
|
||
</div>
|
||
|
||
<!-- 5 指标选择器 -->
|
||
<div class="selector">
|
||
<!-- 心率(选中 + 已完成) -->
|
||
<div class="selector__pill selector__pill--active selector__pill--done">
|
||
<div class="selector__icon" style="background: #EF4444;">♥</div>
|
||
<span class="selector__label">心率</span>
|
||
</div>
|
||
<!-- 血氧(已完成) -->
|
||
<div class="selector__pill selector__pill--done">
|
||
<div class="selector__icon" style="background: #3B82F6;">O₂</div>
|
||
<span class="selector__label">血氧</span>
|
||
</div>
|
||
<!-- 血压 -->
|
||
<div class="selector__pill">
|
||
<div class="selector__icon" style="background: #8B5CF6;">↕</div>
|
||
<span class="selector__label">血压</span>
|
||
</div>
|
||
<!-- 体温 -->
|
||
<div class="selector__pill">
|
||
<div class="selector__icon" style="background: #F59E0B;">T</div>
|
||
<span class="selector__label">体温</span>
|
||
</div>
|
||
<!-- 压力 -->
|
||
<div class="selector__pill">
|
||
<div class="selector__icon" style="background: #6366F1;">~</div>
|
||
<span class="selector__label">压力</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 仪表盘 -->
|
||
<div class="gauge-section">
|
||
<div class="gauge gauge--measuring">
|
||
<svg width="220" height="220" viewBox="0 0 220 220">
|
||
<circle cx="110" cy="110" r="100" class="gauge__ring-bg"/>
|
||
<circle cx="110" cy="110" r="100" class="gauge__ring-progress"
|
||
stroke="#EF4444"
|
||
stroke-dasharray="471"
|
||
stroke-dashoffset="141"
|
||
transform="rotate(-90 110 110)"/>
|
||
</svg>
|
||
<div class="gauge__center">
|
||
<span class="gauge__value" style="color: #EF4444;">72</span>
|
||
<span class="gauge__unit">bpm</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 进度条 -->
|
||
<div class="progress-bar">
|
||
<div class="progress-bar__fill" style="width: 70%; background: #EF4444;"></div>
|
||
</div>
|
||
|
||
<!-- 评估标签 -->
|
||
<div class="assessment assessment--normal">♥ 心率正常</div>
|
||
</div>
|
||
|
||
<!-- 免责声明 -->
|
||
<div class="disclaimer">
|
||
<p class="disclaimer__text">测量数据仅供参考,不作为医学诊断依据。如有不适请及时就医。</p>
|
||
</div>
|
||
|
||
<!-- 操作按钮 -->
|
||
<div class="actions">
|
||
<button class="btn btn--primary" style="background: #EF4444; box-shadow: 0 4px 16px rgba(239,68,68,0.3);">
|
||
停止测量
|
||
</button>
|
||
<button class="btn btn--secondary">
|
||
完成并查看结果
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<!-- ══════════════════════════════════════════════════════════════
|
||
页面 2 — 数据上传页面(测量结果汇总)
|
||
══════════════════════════════════════════════════════════════ -->
|
||
<div>
|
||
<div class="phone-label">页面 2 · 数据上传页(结果汇总 + 上传)</div>
|
||
<div class="phone">
|
||
<div class="phone-inner">
|
||
<!-- 状态栏 -->
|
||
<div class="status-bar">
|
||
<span>9:41</span>
|
||
<div class="status-bar-right">
|
||
<span>●●●●</span>
|
||
<span>WiFi</span>
|
||
<span>85%</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="upload-page">
|
||
<!-- 页面标题 -->
|
||
<div class="page-header">
|
||
<h1 class="page-header__title">测量结果</h1>
|
||
<p class="page-header__subtitle">Veepoo M2 · 刚刚完成测量</p>
|
||
</div>
|
||
|
||
<!-- 结果卡片网格 -->
|
||
<div class="results-grid">
|
||
<!-- 心率 — 已测量,正常 -->
|
||
<div class="result-card">
|
||
<div class="result-card__badge" style="background: #EF4444;"></div>
|
||
<div class="result-card__label">心率</div>
|
||
<div class="result-card__value-row">
|
||
<span class="result-card__value">72</span>
|
||
<span class="result-card__unit">bpm</span>
|
||
</div>
|
||
<div class="result-card__tag result-card__tag--normal">● 正常</div>
|
||
</div>
|
||
|
||
<!-- 血氧 — 已测量,正常 -->
|
||
<div class="result-card">
|
||
<div class="result-card__badge" style="background: #3B82F6;"></div>
|
||
<div class="result-card__label">血氧</div>
|
||
<div class="result-card__value-row">
|
||
<span class="result-card__value">98</span>
|
||
<span class="result-card__unit">%</span>
|
||
</div>
|
||
<div class="result-card__tag result-card__tag--normal">● 正常</div>
|
||
</div>
|
||
|
||
<!-- 血压 — 已测量,注意 -->
|
||
<div class="result-card result-card--full">
|
||
<div class="result-card__badge" style="background: #8B5CF6;"></div>
|
||
<div class="result-card__label">血压</div>
|
||
<div class="result-card__value-row">
|
||
<span class="result-card__value">135</span>
|
||
<span class="result-card__unit">/ 88 mmHg</span>
|
||
</div>
|
||
<div class="result-card__tag result-card__tag--warning">● 偏高</div>
|
||
</div>
|
||
|
||
<!-- 体温 — 未测量 -->
|
||
<div class="result-card result-card--empty">
|
||
<div class="result-card__badge" style="background: #F59E0B; opacity: 0.3;"></div>
|
||
<div class="result-card__label">体温</div>
|
||
<div class="result-card__placeholder">未测量</div>
|
||
</div>
|
||
|
||
<!-- 压力 — 未测量 -->
|
||
<div class="result-card result-card--empty">
|
||
<div class="result-card__badge" style="background: #6366F1; opacity: 0.3;"></div>
|
||
<div class="result-card__label">压力</div>
|
||
<div class="result-card__placeholder">未测量</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 底部上传播区 -->
|
||
<div class="upload-footer">
|
||
<p class="upload-footer__hint">测量数据将上传至您的健康档案</p>
|
||
<button class="btn btn--primary">
|
||
上传测量数据(3 项)
|
||
</button>
|
||
<p class="upload-footer__time">测量时间:2026-05-30 14:35</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<!-- ══════════════════════════════════════════════════════════════
|
||
页面 3 — 测量页面(未连接态)
|
||
══════════════════════════════════════════════════════════════ -->
|
||
<div>
|
||
<div class="phone-label">页面 1 · 测量页(未连接态)</div>
|
||
<div class="phone">
|
||
<div class="phone-inner">
|
||
<div class="status-bar">
|
||
<span>9:41</span>
|
||
<div class="status-bar-right">
|
||
<span>●●●●</span>
|
||
<span>WiFi</span>
|
||
<span>85%</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="measure-page" style="display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 720px;">
|
||
<!-- 蓝牙脉冲动画 -->
|
||
<div style="position: relative; width: 120px; height: 120px; margin-bottom: 28px;">
|
||
<div style="position: absolute; inset: 0; border-radius: 50%; border: 3px solid var(--tk-pri); animation: pulse-ring 2s ease-out infinite;"></div>
|
||
<div style="position: absolute; inset: 20px; border-radius: 50%; background: var(--tk-pri); display: flex; align-items: center; justify-content: center;">
|
||
<span style="color: #fff; font-size: 20px; font-weight: 700;">BT</span>
|
||
</div>
|
||
</div>
|
||
|
||
<h2 style="font-family: Georgia, serif; font-size: var(--tk-font-h2); font-weight: 700; color: var(--tk-tx); margin-bottom: 8px;">
|
||
M2 手环健康测量
|
||
</h2>
|
||
<p style="font-size: var(--tk-font-body-sm); color: var(--tk-tx3); margin-bottom: 32px; text-align: center; padding: 0 40px;">
|
||
请确保手环已佩戴且蓝牙已开启
|
||
</p>
|
||
|
||
<button class="btn btn--primary" style="width: 200px;">
|
||
连接 M2 手环
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<!-- ══════════════════════════════════════════════════════════════
|
||
页面 4 — 测量页面(血压已测量完成态)
|
||
══════════════════════════════════════════════════════════════ -->
|
||
<div>
|
||
<div class="phone-label">页面 1 · 测量页(血压测量完成)</div>
|
||
<div class="phone">
|
||
<div class="phone-inner">
|
||
<div class="status-bar">
|
||
<span>9:42</span>
|
||
<div class="status-bar-right">
|
||
<span>●●●●</span>
|
||
<span>WiFi</span>
|
||
<span>85%</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="measure-page">
|
||
<div class="device-bar">
|
||
<div class="device-bar__left">
|
||
<div class="device-bar__dot"></div>
|
||
<span class="device-bar__name">M2 手环</span>
|
||
<span class="device-bar__battery">85%</span>
|
||
</div>
|
||
<button class="device-bar__disconnect">断开</button>
|
||
</div>
|
||
|
||
<!-- 5 指标选择器 — 血压选中 -->
|
||
<div class="selector">
|
||
<div class="selector__pill selector__pill--done">
|
||
<div class="selector__icon" style="background: #EF4444;">♥</div>
|
||
<span class="selector__label">心率</span>
|
||
</div>
|
||
<div class="selector__pill selector__pill--done">
|
||
<div class="selector__icon" style="background: #3B82F6;">O₂</div>
|
||
<span class="selector__label">血氧</span>
|
||
</div>
|
||
<div class="selector__pill selector__pill--active selector__pill--done">
|
||
<div class="selector__icon" style="background: #8B5CF6;">↕</div>
|
||
<span class="selector__label">血压</span>
|
||
</div>
|
||
<div class="selector__pill">
|
||
<div class="selector__icon" style="background: #F59E0B;">T</div>
|
||
<span class="selector__label">体温</span>
|
||
</div>
|
||
<div class="selector__pill">
|
||
<div class="selector__icon" style="background: #6366F1;">~</div>
|
||
<span class="selector__label">压力</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 仪表盘 — 血压完成态 -->
|
||
<div class="gauge-section">
|
||
<div class="gauge">
|
||
<svg width="220" height="220" viewBox="0 0 220 220">
|
||
<circle cx="110" cy="110" r="100" class="gauge__ring-bg"/>
|
||
<circle cx="110" cy="110" r="100" class="gauge__ring-progress"
|
||
stroke="#8B5CF6"
|
||
stroke-dasharray="471"
|
||
stroke-dashoffset="0"
|
||
transform="rotate(-90 110 110)"/>
|
||
</svg>
|
||
<div class="gauge__center">
|
||
<span class="gauge__value" style="color: #8B5CF6;">135<span style="font-size: 24px; color: var(--tk-tx3);">/</span>88</span>
|
||
<span class="gauge__unit">mmHg</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 评估标签 — 偏高 -->
|
||
<div class="assessment assessment--warning">↕ 血压偏高,建议关注</div>
|
||
</div>
|
||
|
||
<div class="disclaimer">
|
||
<p class="disclaimer__text">测量数据仅供参考,不作为医学诊断依据。如有不适请及时就医。</p>
|
||
</div>
|
||
|
||
<div class="actions">
|
||
<button class="btn btn--primary" style="background: #8B5CF6; box-shadow: 0 4px 16px rgba(139,92,246,0.3);">
|
||
重新测量
|
||
</button>
|
||
<button class="btn btn--secondary">
|
||
完成并查看结果
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<style>
|
||
@keyframes pulse-ring {
|
||
0% { transform: scale(1); opacity: 1; }
|
||
100% { transform: scale(1.4); opacity: 0; }
|
||
}
|
||
</style>
|
||
|
||
</body>
|
||
</html>
|