feat: 健康监测多端原型新增与优化
- 员工端新增体重监测模块(主页/历史数据/详细报告),支持按设备来源(体重秤/蓝牙秤/体脂仪)显示不同字段 - 员工端新增健康排查模块(首页/打卡填写/打卡记录/问卷详情/题目设置),含打卡成功dialog弹窗 - 管理端体重监测数据明细页使用次数统计靠右显示 - 管理端体重监测dialog弹窗改为分类展示监测字段 - 导航页SITE_MAP同步更新新增页面条目 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>打卡记录 - 员工端 | 健康长庆原型</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; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
/* 日历区域 */
|
||||
.calendar-section { background: #fff; margin: 0; padding: 16px; }
|
||||
.calendar-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
|
||||
.calendar-month { font-size: 16px; font-weight: 700; color: #1a1a1a; display: flex; align-items: center; gap: 8px; }
|
||||
.calendar-nav { display: flex; align-items: center; gap: 12px; }
|
||||
.calendar-nav-btn { width: 28px; height: 28px; border: none; background: #f5f5f5; border-radius: 50%; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: background 0.15s; }
|
||||
.calendar-nav-btn:active { background: #e8e8e8; }
|
||||
.calendar-toggle { border: none; background: none; font-size: 12px; color: #667eea; cursor: pointer; display: flex; align-items: center; gap: 4px; }
|
||||
.calendar-weekdays { display: grid; grid-template-columns: repeat(7, 1fr); margin-bottom: 8px; }
|
||||
.calendar-weekdays span { text-align: center; font-size: 12px; color: #999; padding: 4px 0; }
|
||||
.calendar-days { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }
|
||||
.calendar-day { height: 44px; display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: 14px; color: #333; border-radius: 8px; position: relative; cursor: pointer; gap: 2px; }
|
||||
.calendar-day--empty { visibility: hidden; }
|
||||
.calendar-day--today { font-weight: 700; color: #667eea; background: #f0edff; }
|
||||
.calendar-day--checked .calendar-dot { display: block; }
|
||||
.calendar-dot { display: none; width: 6px; height: 6px; border-radius: 50%; background: #667eea; }
|
||||
.calendar-day--other { color: #ccc; }
|
||||
.calendar-collapsed .calendar-days { max-height: 44px; overflow: hidden; }
|
||||
/* 历史记录 */
|
||||
.history-section { padding: 16px 12px; }
|
||||
.history-title { font-size: 15px; font-weight: 700; color: #1a1a1a; margin-bottom: 12px; padding: 0 4px; }
|
||||
.history-list { display: flex; flex-direction: column; gap: 10px; }
|
||||
.history-item { background: #fff; border-radius: 12px; padding: 14px 16px; display: flex; align-items: center; justify-content: space-between; cursor: pointer; transition: transform 0.15s; text-decoration: none; }
|
||||
.history-item:active { transform: scale(0.98); }
|
||||
.history-item__left { display: flex; flex-direction: column; gap: 4px; }
|
||||
.history-item__time { font-size: 14px; font-weight: 500; color: #1a1a1a; }
|
||||
.history-item__date { font-size: 12px; color: #999; }
|
||||
.history-item__right { display: flex; align-items: center; gap: 8px; }
|
||||
.history-item__score { font-size: 14px; font-weight: 700; color: #667eea; }
|
||||
.history-item__arrow { width: 16px; height: 16px; display: flex; align-items: center; justify-content: center; }
|
||||
/* 底部安全区 */
|
||||
.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="location.href='index.html'">
|
||||
<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="calendar-section" id="calendarSection">
|
||||
<div class="calendar-header">
|
||||
<div class="calendar-month">
|
||||
<span id="monthLabel">2026年5月</span>
|
||||
</div>
|
||||
<div class="calendar-nav">
|
||||
<button class="calendar-nav-btn" onclick="changeMonth(-1)"><svg width="10" height="10" fill="none"><path d="M7 1L2 5l5 4" stroke="#666" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></button>
|
||||
<button class="calendar-nav-btn" onclick="changeMonth(1)"><svg width="10" height="10" fill="none"><path d="M3 1l5 4-5 4" stroke="#666" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></button>
|
||||
<button class="calendar-toggle" id="toggleBtn" onclick="toggleCalendar()">
|
||||
<span id="toggleText">收起</span>
|
||||
<svg id="toggleIcon" width="12" height="12" fill="none" style="transition:transform .2s"><path d="M2 5l4 4 4-4" stroke="#667eea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="calendar-weekdays">
|
||||
<span>日</span><span>一</span><span>二</span><span>三</span><span>四</span><span>五</span><span>六</span>
|
||||
</div>
|
||||
<div class="calendar-days" id="calendarDays">
|
||||
<!-- JS动态渲染 -->
|
||||
</div>
|
||||
</div>
|
||||
<!-- 历史记录 -->
|
||||
<div class="history-section">
|
||||
<div class="history-title">历史记录</div>
|
||||
<div class="history-list">
|
||||
<a class="history-item" href="questionnaire-detail.html">
|
||||
<div class="history-item__left">
|
||||
<div class="history-item__time">08:15 完成打卡</div>
|
||||
<div class="history-item__date">2026-05-14</div>
|
||||
</div>
|
||||
<div class="history-item__right">
|
||||
<div class="history-item__score">+10 积分</div>
|
||||
<div class="history-item__arrow"><svg width="7" height="12" fill="none"><path d="M1 1l5 5-5 5" stroke="#ccc" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="history-item" href="questionnaire-detail.html">
|
||||
<div class="history-item__left">
|
||||
<div class="history-item__time">07:52 完成打卡</div>
|
||||
<div class="history-item__date">2026-05-13</div>
|
||||
</div>
|
||||
<div class="history-item__right">
|
||||
<div class="history-item__score">+10 积分</div>
|
||||
<div class="history-item__arrow"><svg width="7" height="12" fill="none"><path d="M1 1l5 5-5 5" stroke="#ccc" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="history-item" href="questionnaire-detail.html">
|
||||
<div class="history-item__left">
|
||||
<div class="history-item__time">08:30 完成打卡</div>
|
||||
<div class="history-item__date">2026-05-12</div>
|
||||
</div>
|
||||
<div class="history-item__right">
|
||||
<div class="history-item__score">+10 积分</div>
|
||||
<div class="history-item__arrow"><svg width="7" height="12" fill="none"><path d="M1 1l5 5-5 5" stroke="#ccc" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="history-item" href="questionnaire-detail.html">
|
||||
<div class="history-item__left">
|
||||
<div class="history-item__time">09:05 完成打卡</div>
|
||||
<div class="history-item__date">2026-05-11</div>
|
||||
</div>
|
||||
<div class="history-item__right">
|
||||
<div class="history-item__score">+10 积分</div>
|
||||
<div class="history-item__arrow"><svg width="7" height="12" fill="none"><path d="M1 1l5 5-5 5" stroke="#ccc" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="history-item" href="questionnaire-detail.html">
|
||||
<div class="history-item__left">
|
||||
<div class="history-item__time">08:20 完成打卡</div>
|
||||
<div class="history-item__date">2026-05-10</div>
|
||||
</div>
|
||||
<div class="history-item__right">
|
||||
<div class="history-item__score">+10 积分</div>
|
||||
<div class="history-item__arrow"><svg width="7" height="12" fill="none"><path d="M1 1l5 5-5 5" stroke="#ccc" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="history-item" href="questionnaire-detail.html">
|
||||
<div class="history-item__left">
|
||||
<div class="history-item__time">07:45 完成打卡</div>
|
||||
<div class="history-item__date">2026-05-09</div>
|
||||
</div>
|
||||
<div class="history-item__right">
|
||||
<div class="history-item__score">+10 积分</div>
|
||||
<div class="history-item__arrow"><svg width="7" height="12" fill="none"><path d="M1 1l5 5-5 5" stroke="#ccc" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
|
||||
</div>
|
||||
</a>
|
||||
<a class="history-item" href="questionnaire-detail.html">
|
||||
<div class="history-item__left">
|
||||
<div class="history-item__time">08:10 完成打卡</div>
|
||||
<div class="history-item__date">2026-05-08</div>
|
||||
</div>
|
||||
<div class="history-item__right">
|
||||
<div class="history-item__score">+10 积分</div>
|
||||
<div class="history-item__arrow"><svg width="7" height="12" fill="none"><path d="M1 1l5 5-5 5" stroke="#ccc" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom-safe"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var currentYear = 2026, currentMonth = 5;
|
||||
var checkedDays = [8,9,10,11,12,13,14];
|
||||
var collapsed = false;
|
||||
|
||||
function renderCalendar() {
|
||||
var firstDay = new Date(currentYear, currentMonth - 1, 1).getDay();
|
||||
var daysInMonth = new Date(currentYear, currentMonth, 0).getDate();
|
||||
var html = '';
|
||||
for (var i = 0; i < firstDay; i++) html += '<div class="calendar-day calendar-day--empty"></div>';
|
||||
for (var d = 1; d <= daysInMonth; d++) {
|
||||
var cls = 'calendar-day';
|
||||
var isToday = (d === 14 && currentMonth === 5 && currentYear === 2026);
|
||||
var isChecked = (checkedDays.indexOf(d) !== -1 && currentMonth === 5 && currentYear === 2026);
|
||||
if (isToday) cls += ' calendar-day--today';
|
||||
if (isChecked) cls += ' calendar-day--checked';
|
||||
html += '<div class="' + cls + '"><span>' + d + '</span><span class="calendar-dot"></span></div>';
|
||||
}
|
||||
document.getElementById('calendarDays').innerHTML = html;
|
||||
document.getElementById('monthLabel').textContent = currentYear + '年' + currentMonth + '月';
|
||||
}
|
||||
|
||||
function changeMonth(dir) {
|
||||
currentMonth += dir;
|
||||
if (currentMonth > 12) { currentMonth = 1; currentYear++; }
|
||||
if (currentMonth < 1) { currentMonth = 12; currentYear--; }
|
||||
renderCalendar();
|
||||
}
|
||||
|
||||
function toggleCalendar() {
|
||||
collapsed = !collapsed;
|
||||
var section = document.getElementById('calendarSection');
|
||||
var days = document.getElementById('calendarDays');
|
||||
var text = document.getElementById('toggleText');
|
||||
var icon = document.getElementById('toggleIcon');
|
||||
if (collapsed) {
|
||||
days.style.maxHeight = '44px';
|
||||
days.style.overflow = 'hidden';
|
||||
text.textContent = '展开';
|
||||
icon.style.transform = 'rotate(180deg)';
|
||||
} else {
|
||||
days.style.maxHeight = '';
|
||||
days.style.overflow = '';
|
||||
text.textContent = '收起';
|
||||
icon.style.transform = '';
|
||||
}
|
||||
}
|
||||
|
||||
renderCalendar();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,213 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>健康排查 - 员工端 | 健康长庆原型</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; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
/* 顶部积分卡片 */
|
||||
.score-card { margin: 12px 12px 0; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 16px; padding: 20px; color: #fff; position: relative; overflow: hidden; }
|
||||
.score-card::after { content: ''; position: absolute; top: -30px; right: -30px; width: 120px; height: 120px; background: rgba(255,255,255,0.08); border-radius: 50%; }
|
||||
.score-card__top { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; }
|
||||
.score-card__points { display: flex; align-items: baseline; gap: 4px; }
|
||||
.score-card__num { font-size: 36px; font-weight: 800; line-height: 1; }
|
||||
.score-card__unit { font-size: 13px; opacity: 0.8; }
|
||||
.score-card__streak { display: flex; align-items: center; gap: 4px; font-size: 13px; opacity: 0.9; background: rgba(255,255,255,0.15); padding: 4px 10px; border-radius: 20px; }
|
||||
.score-card__streak strong { font-weight: 700; }
|
||||
.score-card__actions { display: flex; gap: 10px; }
|
||||
.btn-checkin { flex: 1; height: 44px; background: #fff; border: none; border-radius: 22px; font-size: 15px; font-weight: 600; color: #667eea; cursor: pointer; display: flex; align-items: center; justify-content: center; gap: 6px; transition: transform 0.15s; }
|
||||
.btn-checkin:active { transform: scale(0.96); }
|
||||
.btn-record { height: 44px; background: rgba(255,255,255,0.2); border: none; border-radius: 22px; cursor: pointer; display: flex; align-items: center; justify-content: center; gap: 4px; padding: 0 14px; font-size: 13px; color: #fff; font-weight: 500; transition: transform 0.15s; }
|
||||
.btn-record:active { transform: scale(0.9); }
|
||||
/* 积分榜 */
|
||||
.rank-section { margin: 16px 12px 0; }
|
||||
.rank-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; padding: 0 4px; }
|
||||
.rank-header__title { font-size: 16px; font-weight: 700; color: #1a1a1a; display: flex; align-items: center; gap: 6px; }
|
||||
.rank-header__sub { font-size: 12px; color: #999; }
|
||||
.rank-me-top { background: linear-gradient(135deg, #f8f6ff 0%, #ede9fe 100%); border-radius: 12px; padding: 14px 16px; margin-bottom: 10px; display: flex; align-items: center; gap: 12px; border: 1px solid #e0d4fc; }
|
||||
.rank-me-top .rank-no { background: linear-gradient(135deg, #667eea, #764ba2); color: #fff; }
|
||||
.rank-me-top .rank-score { color: #667eea; }
|
||||
.rank-list { background: #fff; border-radius: 16px; overflow: hidden; }
|
||||
.rank-item { display: flex; align-items: center; padding: 14px 16px; gap: 12px; border-bottom: 1px solid #f5f5f5; }
|
||||
.rank-item:last-child { border-bottom: none; }
|
||||
.rank-no { width: 24px; height: 24px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; flex-shrink: 0; }
|
||||
.rank-no--1 { background: linear-gradient(135deg, #ffd700, #ffb800); color: #fff; }
|
||||
.rank-no--2 { background: linear-gradient(135deg, #c0c0c0, #a8a8a8); color: #fff; }
|
||||
.rank-no--3 { background: linear-gradient(135deg, #cd7f32, #b8690e); color: #fff; }
|
||||
.rank-no--normal { background: #f5f5f5; color: #999; }
|
||||
.rank-info { flex: 1; min-width: 0; }
|
||||
.rank-name { font-size: 14px; font-weight: 500; color: #1a1a1a; }
|
||||
.rank-dept { font-size: 12px; color: #999; margin-top: 2px; }
|
||||
.rank-score { font-size: 15px; font-weight: 700; color: #667eea; }
|
||||
.rank-me { background: #f8f6ff; }
|
||||
.rank-me-tag { font-size: 10px; color: #667eea; background: #ede9fe; padding: 1px 6px; border-radius: 4px; margin-left: 6px; }
|
||||
/* 底部安全区 */
|
||||
.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="location.href='../index.html'">
|
||||
<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="score-card">
|
||||
<div class="score-card__top">
|
||||
<div class="score-card__points">
|
||||
<span class="score-card__num">1,280</span>
|
||||
<span class="score-card__unit">积分</span>
|
||||
</div>
|
||||
<div class="score-card__streak">🔥 连续签到 <strong>7</strong> 天</div>
|
||||
</div>
|
||||
<div class="score-card__actions">
|
||||
<button class="btn-checkin" onclick="location.href='questionnaire-fill.html'">
|
||||
<svg width="18" height="18" fill="none"><path d="M9 1v16M1 9h16" stroke="#667eea" stroke-width="2.5" stroke-linecap="round"/></svg>
|
||||
立即打卡
|
||||
</button>
|
||||
<button class="btn-record" onclick="location.href='checkin-record.html'">
|
||||
<svg width="16" height="16" fill="none"><path d="M3 4h10M3 8h10M3 12h7" stroke="#fff" stroke-width="1.5" stroke-linecap="round"/></svg>
|
||||
打卡记录
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 积分榜排名 -->
|
||||
<div class="rank-section">
|
||||
<div class="rank-header">
|
||||
<div class="rank-header__title">🏆 积分榜</div>
|
||||
<div class="rank-header__sub">采油一厂</div>
|
||||
</div>
|
||||
<div class="rank-me-top">
|
||||
<div class="rank-no">12</div>
|
||||
<div class="rank-info">
|
||||
<div class="rank-name">我<span class="rank-me-tag">我的排名</span></div>
|
||||
<div class="rank-dept">生产运行部</div>
|
||||
</div>
|
||||
<div class="rank-score">1,280</div>
|
||||
</div>
|
||||
<div class="rank-list">
|
||||
<div class="rank-item">
|
||||
<div class="rank-no rank-no--1">1</div>
|
||||
<div class="rank-info">
|
||||
<div class="rank-name">张*明</div>
|
||||
<div class="rank-dept">生产运行部</div>
|
||||
</div>
|
||||
<div class="rank-score">2,580</div>
|
||||
</div>
|
||||
<div class="rank-item">
|
||||
<div class="rank-no rank-no--2">2</div>
|
||||
<div class="rank-info">
|
||||
<div class="rank-name">李*华</div>
|
||||
<div class="rank-dept">安全环保部</div>
|
||||
</div>
|
||||
<div class="rank-score">2,340</div>
|
||||
</div>
|
||||
<div class="rank-item">
|
||||
<div class="rank-no rank-no--3">3</div>
|
||||
<div class="rank-info">
|
||||
<div class="rank-name">王*强</div>
|
||||
<div class="rank-dept">技术发展部</div>
|
||||
</div>
|
||||
<div class="rank-score">2,120</div>
|
||||
</div>
|
||||
<div class="rank-item">
|
||||
<div class="rank-no rank-no--normal">4</div>
|
||||
<div class="rank-info">
|
||||
<div class="rank-name">赵*丽</div>
|
||||
<div class="rank-dept">综合管理部</div>
|
||||
</div>
|
||||
<div class="rank-score">1,950</div>
|
||||
</div>
|
||||
<div class="rank-item">
|
||||
<div class="rank-no rank-no--normal">5</div>
|
||||
<div class="rank-info">
|
||||
<div class="rank-name">刘*伟</div>
|
||||
<div class="rank-dept">地质研究所</div>
|
||||
</div>
|
||||
<div class="rank-score">1,820</div>
|
||||
</div>
|
||||
<div class="rank-item">
|
||||
<div class="rank-no rank-no--normal">6</div>
|
||||
<div class="rank-info">
|
||||
<div class="rank-name">孙*芳</div>
|
||||
<div class="rank-dept">人力资源部</div>
|
||||
</div>
|
||||
<div class="rank-score">1,680</div>
|
||||
</div>
|
||||
<div class="rank-item">
|
||||
<div class="rank-no rank-no--normal">7</div>
|
||||
<div class="rank-info">
|
||||
<div class="rank-name">陈*军</div>
|
||||
<div class="rank-dept">设备管理部</div>
|
||||
</div>
|
||||
<div class="rank-score">1,520</div>
|
||||
</div>
|
||||
<div class="rank-item">
|
||||
<div class="rank-no rank-no--normal">8</div>
|
||||
<div class="rank-info">
|
||||
<div class="rank-name">周*霞</div>
|
||||
<div class="rank-dept">财务资产部</div>
|
||||
</div>
|
||||
<div class="rank-score">1,410</div>
|
||||
</div>
|
||||
<div class="rank-item">
|
||||
<div class="rank-no rank-no--normal">9</div>
|
||||
<div class="rank-info">
|
||||
<div class="rank-name">吴*涛</div>
|
||||
<div class="rank-dept">工程技术部</div>
|
||||
</div>
|
||||
<div class="rank-score">1,380</div>
|
||||
</div>
|
||||
<div class="rank-item">
|
||||
<div class="rank-no rank-no--normal">10</div>
|
||||
<div class="rank-info">
|
||||
<div class="rank-name">郑*娜</div>
|
||||
<div class="rank-dept">党群工作部</div>
|
||||
</div>
|
||||
<div class="rank-score">1,350</div>
|
||||
</div>
|
||||
<div class="rank-item">
|
||||
<div class="rank-no rank-no--normal">11</div>
|
||||
<div class="rank-info">
|
||||
<div class="rank-name">马*飞</div>
|
||||
<div class="rank-dept">物资供应部</div>
|
||||
</div>
|
||||
<div class="rank-score">1,310</div>
|
||||
</div>
|
||||
<div class="rank-item rank-me">
|
||||
<div class="rank-no rank-no--normal">12</div>
|
||||
<div class="rank-info">
|
||||
<div class="rank-name">我<span class="rank-me-tag">我的排名</span></div>
|
||||
<div class="rank-dept">生产运行部</div>
|
||||
</div>
|
||||
<div class="rank-score">1,280</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom-safe"></div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,171 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>问卷详情 - 员工端 | 健康长庆原型</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; }
|
||||
/* 问卷信息 */
|
||||
.detail-header { background: #fff; border-radius: 12px; padding: 16px; margin-bottom: 12px; }
|
||||
.detail-header__title { font-size: 16px; font-weight: 700; color: #1a1a1a; margin-bottom: 6px; }
|
||||
.detail-header__meta { font-size: 12px; color: #999; display: flex; gap: 16px; }
|
||||
/* 分类标题 */
|
||||
.category-title { font-size: 15px; font-weight: 700; color: #1a1a1a; margin: 8px 0 10px; padding-left: 10px; border-left: 3px solid #667eea; }
|
||||
/* 问题卡片 */
|
||||
.question-card { background: #fff; border-radius: 12px; padding: 16px; margin-bottom: 12px; }
|
||||
.question-card__header { display: flex; align-items: center; gap: 6px; margin-bottom: 10px; }
|
||||
.question-card__title { font-size: 14px; font-weight: 600; color: #1a1a1a; line-height: 1.5; flex: 1; }
|
||||
.tag-required { font-size: 10px; color: #ff4d4f; background: #fff2f0; padding: 1px 6px; border-radius: 3px; flex-shrink: 0; border: 1px solid #ffccc7; }
|
||||
.tag-optional { font-size: 10px; color: #999; background: #f5f5f5; padding: 1px 6px; border-radius: 3px; flex-shrink: 0; }
|
||||
.question-card__options { display: flex; flex-direction: column; gap: 8px; }
|
||||
.option-item { padding: 10px 14px; border-radius: 8px; border: 1px solid #e8e8e8; font-size: 13px; color: #666; display: flex; align-items: center; gap: 8px; }
|
||||
.option-item--selected { border-color: #667eea; background: #f8f6ff; color: #667eea; font-weight: 500; }
|
||||
.option-item__check { width: 18px; height: 18px; border-radius: 50%; border: 2px solid #ddd; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
|
||||
.option-item--selected .option-item__check { border-color: #667eea; background: #667eea; }
|
||||
.option-item--selected .option-item__check::after { content: '✓'; color: #fff; font-size: 10px; font-weight: 700; }
|
||||
/* 底部安全区 */
|
||||
.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="location.href='checkin-record.html'">
|
||||
<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="detail-header">
|
||||
<div class="detail-header__title">每日健康自查问卷</div>
|
||||
<div class="detail-header__meta">
|
||||
<span>提交时间:2026-05-14 08:15</span>
|
||||
<span>+10 积分</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 身体状况 -->
|
||||
<div class="category-title">身体状况</div>
|
||||
<div class="question-card">
|
||||
<div class="question-card__header">
|
||||
<div class="question-card__title">1. 今天您的整体身体感觉如何?</div>
|
||||
<span class="tag-required">必填</span>
|
||||
</div>
|
||||
<div class="question-card__options">
|
||||
<div class="option-item option-item--selected"><span class="option-item__check"></span>精力充沛,状态良好</div>
|
||||
<div class="option-item"><span class="option-item__check"></span>一般,没有明显不适</div>
|
||||
<div class="option-item"><span class="option-item__check"></span>有些疲惫或不适</div>
|
||||
<div class="option-item"><span class="option-item__check"></span>身体明显不舒服</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="question-card">
|
||||
<div class="question-card__header">
|
||||
<div class="question-card__title">2. 昨晚的睡眠质量如何?</div>
|
||||
<span class="tag-required">必填</span>
|
||||
</div>
|
||||
<div class="question-card__options">
|
||||
<div class="option-item"><span class="option-item__check"></span>很好,一觉到天亮</div>
|
||||
<div class="option-item option-item--selected"><span class="option-item__check"></span>还行,中途醒过1-2次</div>
|
||||
<div class="option-item"><span class="option-item__check"></span>较差,多次醒来或难以入睡</div>
|
||||
<div class="option-item"><span class="option-item__check"></span>几乎没怎么睡着</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="question-card">
|
||||
<div class="question-card__header">
|
||||
<div class="question-card__title">3. 是否有头痛、头晕等不适症状?</div>
|
||||
<span class="tag-optional">选填</span>
|
||||
</div>
|
||||
<div class="question-card__options">
|
||||
<div class="option-item option-item--selected"><span class="option-item__check"></span>没有任何不适</div>
|
||||
<div class="option-item"><span class="option-item__check"></span>轻微不适,不影响工作</div>
|
||||
<div class="option-item"><span class="option-item__check"></span>有明显不适,但可以坚持</div>
|
||||
<div class="option-item"><span class="option-item__check"></span>不适严重,需要休息</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 心理状态 -->
|
||||
<div class="category-title">心理状态</div>
|
||||
<div class="question-card">
|
||||
<div class="question-card__header">
|
||||
<div class="question-card__title">4. 今天的情绪状态如何?</div>
|
||||
<span class="tag-required">必填</span>
|
||||
</div>
|
||||
<div class="question-card__options">
|
||||
<div class="option-item option-item--selected"><span class="option-item__check"></span>心情愉悦,积极乐观</div>
|
||||
<div class="option-item"><span class="option-item__check"></span>平静,情绪稳定</div>
|
||||
<div class="option-item"><span class="option-item__check"></span>有些焦虑或烦躁</div>
|
||||
<div class="option-item"><span class="option-item__check"></span>情绪低落,压力较大</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="question-card">
|
||||
<div class="question-card__header">
|
||||
<div class="question-card__title">5. 近期是否感到工作压力较大?</div>
|
||||
<span class="tag-optional">选填</span>
|
||||
</div>
|
||||
<div class="question-card__options">
|
||||
<div class="option-item option-item--selected"><span class="option-item__check"></span>压力适中,能正常应对</div>
|
||||
<div class="option-item"><span class="option-item__check"></span>略有压力,基本可控</div>
|
||||
<div class="option-item"><span class="option-item__check"></span>压力较大,有些吃力</div>
|
||||
<div class="option-item"><span class="option-item__check"></span>压力很大,需要帮助</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 生活习惯 -->
|
||||
<div class="category-title">生活习惯</div>
|
||||
<div class="question-card">
|
||||
<div class="question-card__header">
|
||||
<div class="question-card__title">6. 昨天是否进行了运动锻炼?</div>
|
||||
<span class="tag-required">必填</span>
|
||||
</div>
|
||||
<div class="question-card__options">
|
||||
<div class="option-item"><span class="option-item__check"></span>是,运动30分钟以上</div>
|
||||
<div class="option-item option-item--selected"><span class="option-item__check"></span>是,运动了15-30分钟</div>
|
||||
<div class="option-item"><span class="option-item__check"></span>简单活动了一下</div>
|
||||
<div class="option-item"><span class="option-item__check"></span>没有运动</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="question-card">
|
||||
<div class="question-card__header">
|
||||
<div class="question-card__title">7. 昨天的饮食是否规律?</div>
|
||||
<span class="tag-required">必填</span>
|
||||
</div>
|
||||
<div class="question-card__options">
|
||||
<div class="option-item option-item--selected"><span class="option-item__check"></span>三餐规律,营养均衡</div>
|
||||
<div class="option-item"><span class="option-item__check"></span>基本规律,偶尔不均衡</div>
|
||||
<div class="option-item"><span class="option-item__check"></span>有一餐没按时吃</div>
|
||||
<div class="option-item"><span class="option-item__check"></span>饮食很不规律</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="question-card">
|
||||
<div class="question-card__header">
|
||||
<div class="question-card__title">8. 昨天饮水量是否充足(8杯以上)?</div>
|
||||
<span class="tag-optional">选填</span>
|
||||
</div>
|
||||
<div class="question-card__options">
|
||||
<div class="option-item"><span class="option-item__check"></span>充足,达到8杯以上</div>
|
||||
<div class="option-item option-item--selected"><span class="option-item__check"></span>基本够,5-8杯</div>
|
||||
<div class="option-item"><span class="option-item__check"></span>偏少,不到5杯</div>
|
||||
<div class="option-item"><span class="option-item__check"></span>很少喝水</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom-safe"></div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,207 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>每日打卡 - 员工端 | 健康长庆原型</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; }
|
||||
.nav-setting { font-size: 12px; color: #667eea; cursor: pointer; white-space: nowrap; text-decoration: none; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f5f7fa; padding: 12px; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
/* 分类标题 */
|
||||
.category-title { font-size: 15px; font-weight: 700; color: #1a1a1a; margin: 8px 0 10px; padding-left: 10px; border-left: 3px solid #667eea; }
|
||||
.category-title:first-child { margin-top: 0; }
|
||||
/* 问题卡片 */
|
||||
.question-card { background: #fff; border-radius: 12px; padding: 16px; margin-bottom: 12px; }
|
||||
.question-card__header { display: flex; align-items: center; gap: 6px; margin-bottom: 10px; }
|
||||
.question-card__title { font-size: 14px; font-weight: 600; color: #1a1a1a; line-height: 1.5; flex: 1; }
|
||||
.tag-required { font-size: 10px; color: #ff4d4f; background: #fff2f0; padding: 1px 6px; border-radius: 3px; flex-shrink: 0; border: 1px solid #ffccc7; }
|
||||
.tag-optional { font-size: 10px; color: #999; background: #f5f5f5; padding: 1px 6px; border-radius: 3px; flex-shrink: 0; }
|
||||
.question-card__options { display: flex; flex-direction: column; gap: 8px; }
|
||||
.option-item { padding: 10px 14px; border-radius: 8px; border: 1px solid #e8e8e8; font-size: 13px; color: #666; display: flex; align-items: center; gap: 8px; cursor: pointer; transition: all 0.15s; }
|
||||
.option-item:active { transform: scale(0.98); }
|
||||
.option-item.selected { border-color: #667eea; background: #f8f6ff; color: #667eea; font-weight: 500; }
|
||||
.option-item__radio { width: 18px; height: 18px; border-radius: 50%; border: 2px solid #ddd; display: flex; align-items: center; justify-content: center; flex-shrink: 0; transition: all 0.15s; }
|
||||
.option-item.selected .option-item__radio { border-color: #667eea; background: #667eea; }
|
||||
.option-item.selected .option-item__radio::after { content: ''; width: 6px; height: 6px; background: #fff; border-radius: 50%; }
|
||||
/* 底部提交 */
|
||||
.submit-bar { padding: 12px 16px; background: #fff; border-top: 1px solid #f0f0f0; flex-shrink: 0; }
|
||||
.btn-submit { width: 100%; height: 48px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border: none; border-radius: 24px; font-size: 16px; font-weight: 600; color: #fff; cursor: pointer; transition: transform 0.15s; }
|
||||
.btn-submit:active { transform: scale(0.97); }
|
||||
.bottom-safe { height: 20px; flex-shrink: 0; background: #fff; }
|
||||
/* 打卡成功弹窗 */
|
||||
.dialog-mask { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.45); z-index: 300; display: none; align-items: center; justify-content: center; }
|
||||
.dialog-mask.show { display: flex; }
|
||||
.dialog { background: #fff; border-radius: 20px; width: 320px; padding: 32px 24px 24px; text-align: center; box-shadow: 0 12px 48px rgba(0,0,0,0.2); animation: dialogIn 0.25s ease; }
|
||||
@keyframes dialogIn { from { transform: scale(0.85); opacity: 0; } to { transform: scale(1); opacity: 1; } }
|
||||
.dialog__icon { width: 64px; height: 64px; margin: 0 auto 16px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 50%; display: flex; align-items: center; justify-content: center; }
|
||||
.dialog__title { font-size: 20px; font-weight: 800; color: #1a1a1a; margin-bottom: 6px; }
|
||||
.dialog__points { font-size: 14px; color: #667eea; font-weight: 600; margin-bottom: 16px; display: flex; align-items: center; justify-content: center; gap: 4px; }
|
||||
.dialog__points-num { font-size: 24px; font-weight: 800; }
|
||||
.dialog__divider { width: 40px; height: 2px; background: linear-gradient(90deg, #667eea, #764ba2); border-radius: 1px; margin: 0 auto 16px; }
|
||||
.dialog__quote { font-size: 13px; color: #666; line-height: 1.8; padding: 12px 16px; background: #f8f6ff; border-radius: 10px; margin-bottom: 20px; position: relative; font-style: italic; }
|
||||
.dialog__quote::before { content: '\201C'; font-size: 28px; color: #667eea; opacity: 0.3; position: absolute; top: 2px; left: 8px; line-height: 1; font-style: normal; }
|
||||
.dialog__btn { width: 100%; height: 44px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border: none; border-radius: 22px; font-size: 16px; font-weight: 600; color: #fff; cursor: pointer; transition: transform 0.15s; }
|
||||
.dialog__btn:active { transform: scale(0.97); }
|
||||
</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="location.href='index.html'">
|
||||
<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>
|
||||
<a class="nav-setting" href="questionnaire-setting.html">题目设置</a>
|
||||
</div>
|
||||
<div class="scroll-content">
|
||||
<!-- 身体状况 -->
|
||||
<div class="category-title">身体状况</div>
|
||||
<div class="question-card">
|
||||
<div class="question-card__header">
|
||||
<div class="question-card__title">1. 今天您的整体身体感觉如何?</div>
|
||||
<span class="tag-required">必填</span>
|
||||
</div>
|
||||
<div class="question-card__options">
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>精力充沛,状态良好</div>
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>一般,没有明显不适</div>
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>有些疲惫或不适</div>
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>身体明显不舒服</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="question-card">
|
||||
<div class="question-card__header">
|
||||
<div class="question-card__title">2. 昨晚的睡眠质量如何?</div>
|
||||
<span class="tag-required">必填</span>
|
||||
</div>
|
||||
<div class="question-card__options">
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>很好,一觉到天亮</div>
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>还行,中途醒过1-2次</div>
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>较差,多次醒来或难以入睡</div>
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>几乎没怎么睡着</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="question-card">
|
||||
<div class="question-card__header">
|
||||
<div class="question-card__title">3. 是否有头痛、头晕等不适症状?</div>
|
||||
<span class="tag-optional">选填</span>
|
||||
</div>
|
||||
<div class="question-card__options">
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>没有任何不适</div>
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>轻微不适,不影响工作</div>
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>有明显不适,但可以坚持</div>
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>不适严重,需要休息</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 心理状态 -->
|
||||
<div class="category-title">心理状态</div>
|
||||
<div class="question-card">
|
||||
<div class="question-card__header">
|
||||
<div class="question-card__title">4. 今天的情绪状态如何?</div>
|
||||
<span class="tag-required">必填</span>
|
||||
</div>
|
||||
<div class="question-card__options">
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>心情愉悦,积极乐观</div>
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>平静,情绪稳定</div>
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>有些焦虑或烦躁</div>
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>情绪低落,压力较大</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="question-card">
|
||||
<div class="question-card__header">
|
||||
<div class="question-card__title">5. 近期是否感到工作压力较大?</div>
|
||||
<span class="tag-optional">选填</span>
|
||||
</div>
|
||||
<div class="question-card__options">
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>压力适中,能正常应对</div>
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>略有压力,基本可控</div>
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>压力较大,有些吃力</div>
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>压力很大,需要帮助</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 生活习惯 -->
|
||||
<div class="category-title">生活习惯</div>
|
||||
<div class="question-card">
|
||||
<div class="question-card__header">
|
||||
<div class="question-card__title">6. 昨天是否进行了运动锻炼?</div>
|
||||
<span class="tag-required">必填</span>
|
||||
</div>
|
||||
<div class="question-card__options">
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>是,运动30分钟以上</div>
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>是,运动了15-30分钟</div>
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>简单活动了一下</div>
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>没有运动</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="question-card">
|
||||
<div class="question-card__header">
|
||||
<div class="question-card__title">7. 昨天的饮食是否规律?</div>
|
||||
<span class="tag-required">必填</span>
|
||||
</div>
|
||||
<div class="question-card__options">
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>三餐规律,营养均衡</div>
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>基本规律,偶尔不均衡</div>
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>有一餐没按时吃</div>
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>饮食很不规律</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="question-card">
|
||||
<div class="question-card__header">
|
||||
<div class="question-card__title">8. 昨天饮水量是否充足(8杯以上)?</div>
|
||||
<span class="tag-optional">选填</span>
|
||||
</div>
|
||||
<div class="question-card__options">
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>充足,达到8杯以上</div>
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>基本够,5-8杯</div>
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>偏少,不到5杯</div>
|
||||
<div class="option-item" onclick="selectOption(this)"><span class="option-item__radio"></span>很少喝水</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="submit-bar">
|
||||
<button class="btn-submit" onclick="showSuccess()">提交打卡</button>
|
||||
</div>
|
||||
<div class="bottom-safe"></div>
|
||||
<!-- 打卡成功弹窗 -->
|
||||
<div class="dialog-mask" id="dialogMask">
|
||||
<div class="dialog">
|
||||
<div class="dialog__icon">
|
||||
<svg width="32" height="32" fill="none"><path d="M8 16l5 5 11-11" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
</div>
|
||||
<div class="dialog__title">打卡成功!</div>
|
||||
<div class="dialog__points">积分 +<span class="dialog__points-num">10</span></div>
|
||||
<div class="dialog__divider"></div>
|
||||
<div class="dialog__quote">健康是人生第一财富,每一次坚持打卡,都是对自己最好的投资。</div>
|
||||
<button class="dialog__btn" onclick="location.href='index.html'">确 认</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
function selectOption(el) {
|
||||
var siblings = el.parentElement.querySelectorAll('.option-item');
|
||||
siblings.forEach(function(s) { s.classList.remove('selected'); });
|
||||
el.classList.add('selected');
|
||||
}
|
||||
function showSuccess() {
|
||||
document.getElementById('dialogMask').classList.add('show');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,176 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>题目设置 - 员工端 | 健康长庆原型</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; }
|
||||
/* 提示 */
|
||||
.setting-tip { background: #fffbe6; border: 1px solid #ffe58f; border-radius: 10px; padding: 12px 14px; margin-bottom: 12px; font-size: 12px; color: #ad8b00; line-height: 1.6; display: flex; gap: 8px; }
|
||||
.setting-tip__icon { flex-shrink: 0; font-size: 16px; }
|
||||
/* 分类标题 */
|
||||
.category-title { font-size: 14px; font-weight: 700; color: #1a1a1a; margin: 8px 0 10px; padding-left: 10px; border-left: 3px solid #667eea; }
|
||||
.category-title:first-child { margin-top: 0; }
|
||||
/* 题目卡片 */
|
||||
.setting-card { background: #fff; border-radius: 12px; padding: 14px 16px; margin-bottom: 10px; display: flex; align-items: flex-start; gap: 12px; }
|
||||
.setting-card__content { flex: 1; min-width: 0; }
|
||||
.setting-card__header { display: flex; align-items: center; gap: 6px; margin-bottom: 4px; }
|
||||
.setting-card__title { font-size: 13px; font-weight: 500; color: #1a1a1a; line-height: 1.5; flex: 1; }
|
||||
.tag-required { font-size: 10px; color: #ff4d4f; background: #fff2f0; padding: 1px 6px; border-radius: 3px; flex-shrink: 0; border: 1px solid #ffccc7; }
|
||||
.tag-optional { font-size: 10px; color: #999; background: #f5f5f5; padding: 1px 6px; border-radius: 3px; flex-shrink: 0; }
|
||||
.setting-card__toggle { flex-shrink: 0; margin-top: 4px; }
|
||||
/* 开关 */
|
||||
.toggle-switch { width: 44px; height: 24px; background: #ddd; border-radius: 12px; position: relative; cursor: pointer; transition: background 0.2s; }
|
||||
.toggle-switch.on { background: #667eea; }
|
||||
.toggle-switch__knob { width: 20px; height: 20px; background: #fff; border-radius: 50%; position: absolute; top: 2px; left: 2px; transition: left 0.2s; box-shadow: 0 1px 3px rgba(0,0,0,0.15); }
|
||||
.toggle-switch.on .toggle-switch__knob { left: 22px; }
|
||||
/* 必填项开关置灰 */
|
||||
.toggle-switch.disabled { background: #c5cbe8; opacity: 0.6; cursor: not-allowed; }
|
||||
.toggle-switch.disabled .toggle-switch__knob { left: 22px; }
|
||||
/* 底部保存 */
|
||||
.save-bar { padding: 12px 16px; background: #fff; border-top: 1px solid #f0f0f0; flex-shrink: 0; }
|
||||
.btn-save { width: 100%; height: 48px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border: none; border-radius: 24px; font-size: 16px; font-weight: 600; color: #fff; cursor: pointer; transition: transform 0.15s; }
|
||||
.btn-save:active { transform: scale(0.97); }
|
||||
.bottom-safe { height: 20px; flex-shrink: 0; background: #fff; }
|
||||
</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="location.href='questionnaire-fill.html'">
|
||||
<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="setting-tip">
|
||||
<span class="setting-tip__icon">💡</span>
|
||||
<span>必填题目无法隐藏,仅选填题目可以控制显示或隐藏。隐藏后将不会在每日打卡中显示。</span>
|
||||
</div>
|
||||
<!-- 身体状况 -->
|
||||
<div class="category-title">身体状况</div>
|
||||
<div class="setting-card">
|
||||
<div class="setting-card__content">
|
||||
<div class="setting-card__header">
|
||||
<div class="setting-card__title">1. 今天您的整体身体感觉如何?</div>
|
||||
<span class="tag-required">必填</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-card__toggle">
|
||||
<div class="toggle-switch disabled"><div class="toggle-switch__knob"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-card">
|
||||
<div class="setting-card__content">
|
||||
<div class="setting-card__header">
|
||||
<div class="setting-card__title">2. 昨晚的睡眠质量如何?</div>
|
||||
<span class="tag-required">必填</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-card__toggle">
|
||||
<div class="toggle-switch disabled"><div class="toggle-switch__knob"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-card">
|
||||
<div class="setting-card__content">
|
||||
<div class="setting-card__header">
|
||||
<div class="setting-card__title">3. 是否有头痛、头晕等不适症状?</div>
|
||||
<span class="tag-optional">选填</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-card__toggle">
|
||||
<div class="toggle-switch on" onclick="toggleSwitch(this)"><div class="toggle-switch__knob"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 心理状态 -->
|
||||
<div class="category-title">心理状态</div>
|
||||
<div class="setting-card">
|
||||
<div class="setting-card__content">
|
||||
<div class="setting-card__header">
|
||||
<div class="setting-card__title">4. 今天的情绪状态如何?</div>
|
||||
<span class="tag-required">必填</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-card__toggle">
|
||||
<div class="toggle-switch disabled"><div class="toggle-switch__knob"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-card">
|
||||
<div class="setting-card__content">
|
||||
<div class="setting-card__header">
|
||||
<div class="setting-card__title">5. 近期是否感到工作压力较大?</div>
|
||||
<span class="tag-optional">选填</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-card__toggle">
|
||||
<div class="toggle-switch on" onclick="toggleSwitch(this)"><div class="toggle-switch__knob"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 生活习惯 -->
|
||||
<div class="category-title">生活习惯</div>
|
||||
<div class="setting-card">
|
||||
<div class="setting-card__content">
|
||||
<div class="setting-card__header">
|
||||
<div class="setting-card__title">6. 昨天是否进行了运动锻炼?</div>
|
||||
<span class="tag-required">必填</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-card__toggle">
|
||||
<div class="toggle-switch disabled"><div class="toggle-switch__knob"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-card">
|
||||
<div class="setting-card__content">
|
||||
<div class="setting-card__header">
|
||||
<div class="setting-card__title">7. 昨天的饮食是否规律?</div>
|
||||
<span class="tag-required">必填</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-card__toggle">
|
||||
<div class="toggle-switch disabled"><div class="toggle-switch__knob"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-card">
|
||||
<div class="setting-card__content">
|
||||
<div class="setting-card__header">
|
||||
<div class="setting-card__title">8. 昨天饮水量是否充足(8杯以上)?</div>
|
||||
<span class="tag-optional">选填</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-card__toggle">
|
||||
<div class="toggle-switch" onclick="toggleSwitch(this)"><div class="toggle-switch__knob"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="save-bar">
|
||||
<button class="btn-save" onclick="alert('设置已保存')">保存设置</button>
|
||||
</div>
|
||||
<div class="bottom-safe"></div>
|
||||
</div>
|
||||
<script>
|
||||
function toggleSwitch(el) {
|
||||
if (el.classList.contains('disabled')) return;
|
||||
el.classList.toggle('on');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -11,65 +11,30 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
.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; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; padding: 20px 16px; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
/* 设备状态 */
|
||||
.device-bar { margin: 12px 12px 0; background: linear-gradient(135deg, #13c2c2 0%, #0d9b9b 100%); border-radius: 12px; padding: 14px 16px; display: flex; align-items: center; gap: 12px; color: #fff; }
|
||||
.device-icon { width: 44px; height: 44px; background: rgba(255,255,255,0.2); border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 24px; flex-shrink: 0; }
|
||||
.device-info { flex: 1; }
|
||||
.device-name { font-size: 15px; font-weight: 600; }
|
||||
.device-meta { font-size: 12px; opacity: 0.85; margin-top: 2px; }
|
||||
.device-battery { display: flex; align-items: center; gap: 4px; font-size: 13px; font-weight: 600; }
|
||||
.battery-icon { width: 22px; height: 12px; border: 1.5px solid #fff; border-radius: 2px; position: relative; }
|
||||
.battery-icon::after { content: ''; position: absolute; right: -4px; top: 2.5px; width: 2px; height: 5px; background: #fff; border-radius: 0 1px 1px 0; }
|
||||
.battery-fill { height: 100%; background: #fff; border-radius: 1px; }
|
||||
/* 监测卡片网格 */
|
||||
.monitor-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; padding: 12px; }
|
||||
.monitor-card { background: #fff; border-radius: 12px; padding: 16px; cursor: pointer; position: relative; transition: transform 0.15s; }
|
||||
.monitor-card:active { transform: scale(0.97); }
|
||||
.monitor-card--full { grid-column: 1 / -1; }
|
||||
.card-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
|
||||
.card-header__left { display: flex; align-items: center; min-width: 0; flex: 1; }
|
||||
.card-header__right { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
|
||||
.card-icon { width: 32px; height: 32px; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 18px; flex-shrink: 0; }
|
||||
.card-label { font-size: 13px; color: #666; margin-left: 8px; flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.card-meta { font-size: 12px; color: #999; }
|
||||
.card-alert-badge { width: 18px; height: 18px; background: #ff4d4f; border-radius: 50%; font-size: 10px; color: #fff; display: flex; align-items: center; justify-content: center; font-weight: 700; }
|
||||
.card-arrow { width: 16px; height: 16px; display: flex; align-items: center; justify-content: center; }
|
||||
.card-arrow svg { width: 16px; height: 16px; display: block; }
|
||||
.card-sync { font-size: 10px; color: #bbb; margin-top: 8px; }
|
||||
.card-value { font-size: 28px; font-weight: 800; color: #1a1a1a; line-height: 1.1; }
|
||||
.card-unit { font-size: 13px; color: #999; font-weight: 400; margin-left: 2px; }
|
||||
.card-status { display: inline-block; font-size: 11px; padding: 2px 8px; border-radius: 4px; margin-top: 6px; }
|
||||
.card-status--normal { color: #52c41a; background: #f6ffed; }
|
||||
.card-status--warn { color: #faad14; background: #fffbe6; }
|
||||
.card-status--danger { color: #ff4d4f; background: #fff2f0; }
|
||||
.card-sub { font-size: 11px; color: #999; margin-top: 6px; }
|
||||
.card-progress { margin-top: 8px; }
|
||||
.card-progress__bar { height: 6px; background: #f0f0f0; border-radius: 3px; overflow: hidden; }
|
||||
.card-progress__fill { height: 100%; border-radius: 3px; transition: width 0.3s; }
|
||||
.card-progress__text { font-size: 11px; color: #999; margin-top: 4px; }
|
||||
/* 睡眠分段 */
|
||||
.sleep-segments { display: flex; gap: 4px; margin-top: 8px; height: 6px; border-radius: 3px; overflow: hidden; }
|
||||
.sleep-seg { height: 100%; border-radius: 3px; }
|
||||
.sleep-seg--deep { background: #1890ff; }
|
||||
.sleep-seg--light { background: #91d5ff; }
|
||||
.sleep-seg--rem { background: #b37feb; }
|
||||
.sleep-seg--awake { background: #ffd591; }
|
||||
.sleep-legend { display: flex; gap: 8px; margin-top: 6px; flex-wrap: wrap; }
|
||||
.sleep-legend__item { display: flex; align-items: center; gap: 3px; font-size: 10px; color: #999; }
|
||||
.sleep-legend__dot { width: 6px; height: 6px; border-radius: 50%; }
|
||||
/* 锻炼卡片 */
|
||||
.exercise-stats { display: flex; gap: 12px; margin-top: 8px; }
|
||||
.exercise-stat { flex: 1; text-align: center; background: #f5f7fa; border-radius: 8px; padding: 8px 4px; }
|
||||
.exercise-stat__val { font-size: 16px; font-weight: 700; color: #1a1a1a; }
|
||||
.exercise-stat__label { font-size: 10px; color: #999; margin-top: 2px; }
|
||||
/* 预警入口 */
|
||||
.card-alert-link { display: flex; align-items: center; justify-content: center; gap: 4px; font-size: 11px; color: #ff4d4f; margin-top: 8px; padding-top: 8px; border-top: 1px solid #f5f5f5; cursor: pointer; }
|
||||
/* 入口卡片 */
|
||||
.entry-grid { display: flex; flex-direction: column; gap: 12px; }
|
||||
.entry-card { background: #fff; border-radius: 16px; padding: 16px; display: flex; align-items: center; gap: 14px; cursor: pointer; transition: transform 0.15s, box-shadow 0.15s; text-decoration: none; }
|
||||
.entry-card:active { transform: scale(0.98); }
|
||||
.entry-card:hover { box-shadow: 0 4px 16px rgba(0,0,0,0.08); }
|
||||
.entry-icon { width: 48px; height: 48px; border-radius: 14px; display: flex; align-items: center; justify-content: center; font-size: 24px; flex-shrink: 0; }
|
||||
.entry-icon--wearable { background: linear-gradient(135deg, #e6fffb 0%, #b5f5ec 100%); }
|
||||
.entry-icon--weight { background: linear-gradient(135deg, #f0f5ff 0%, #d6e4ff 100%); }
|
||||
.entry-icon--environment { background: linear-gradient(135deg, #f6ffed 0%, #d9f7be 100%); }
|
||||
.entry-icon--screening { background: linear-gradient(135deg, #fff7e6 0%, #ffe7ba 100%); }
|
||||
.entry-info { flex: 1; min-width: 0; }
|
||||
.entry-name { font-size: 15px; font-weight: 600; color: #1a1a1a; display: flex; align-items: center; justify-content: space-between; }
|
||||
.entry-time { font-size: 11px; color: #bbb; font-weight: 400; }
|
||||
.entry-data { display: flex; gap: 12px; align-items: baseline; margin-top: 4px; }
|
||||
.entry-data__value { font-size: 13px; color: #666; }
|
||||
.entry-data__value strong { font-size: 18px; font-weight: 700; color: #1a1a1a; }
|
||||
.entry-status { font-size: 11px; padding: 2px 8px; border-radius: 4px; }
|
||||
.entry-status--good { color: #52c41a; background: #f6ffed; }
|
||||
.entry-arrow { width: 16px; height: 16px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; }
|
||||
/* 底部安全区 */
|
||||
.bottom-safe { height: 20px; flex-shrink: 0; }
|
||||
</style>
|
||||
@@ -78,201 +43,72 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
<div class="phone-shell">
|
||||
<div class="status-bar">
|
||||
<span class="time">9:41</span>
|
||||
<div class="icons">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2"><path d="M1 6l5 5 5-5"/><path d="M4 9l3 3 3-3" opacity="0.5"/></svg>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2"><rect x="1" y="6" width="18" height="12" rx="2"/><path d="M21 10v4"/></svg>
|
||||
</div>
|
||||
<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="history.back()">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2" stroke-linecap="round"><path d="M15 19l-7-7 7-7"/></svg>
|
||||
<div class="nav-back" onclick="location.href='../home/index.html'">
|
||||
<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="device-bar">
|
||||
<div class="device-icon">⌚</div>
|
||||
<div class="device-info">
|
||||
<div class="device-name">华为 WATCH GT5 Pro</div>
|
||||
<div class="device-meta">SF55996622586 · 已连接</div>
|
||||
</div>
|
||||
<!-- <div class="device-battery">-->
|
||||
<!-- <div class="battery-icon"><div class="battery-fill" style="width:72%"></div></div>-->
|
||||
<!-- 72%-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
<!-- 监测卡片网格 -->
|
||||
<div class="monitor-grid">
|
||||
<!-- 步数 -->
|
||||
<div class="monitor-card" onclick="location.href='steps.html'">
|
||||
<div class="card-header">
|
||||
<div class="card-header__left">
|
||||
<div class="card-icon" style="background:#e6f7ff">🏃</div>
|
||||
<span class="card-label">步数</span>
|
||||
</div>
|
||||
<div class="card-header__right">
|
||||
<div class="card-arrow">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
|
||||
</div>
|
||||
<div class="entry-grid">
|
||||
<!-- 穿戴监测 -->
|
||||
<a class="entry-card" href="wearable/index.html">
|
||||
<div class="entry-icon entry-icon--wearable">⌚</div>
|
||||
<div class="entry-info">
|
||||
<div class="entry-name">穿戴监测<span class="entry-time">05-12 09:38</span></div>
|
||||
<div class="entry-data">
|
||||
<span class="entry-data__value">步数 <strong>6,832</strong></span>
|
||||
<span class="entry-data__value">心率 <strong>72</strong>bpm</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-value">8,562<span class="card-unit">步</span></div>
|
||||
<div class="card-progress">
|
||||
<div class="card-progress__text">相当于步行5.2公里</div>
|
||||
</div>
|
||||
<div class="card-sync">同步至 04-30 09:38</div>
|
||||
</div>
|
||||
<!-- 睡眠 -->
|
||||
<div class="monitor-card" onclick="location.href='sleep.html'">
|
||||
<div class="card-header">
|
||||
<div class="card-header__left">
|
||||
<div class="card-icon" style="background:#f0e6ff">🌙</div>
|
||||
<span class="card-label">睡眠</span>
|
||||
</div>
|
||||
<div class="card-header__right">
|
||||
<div class="card-arrow">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
|
||||
</div>
|
||||
<div class="entry-arrow"><svg width="7" height="12" fill="none"><path d="M1 1l5 5-5 5" stroke="#ccc" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
|
||||
</a>
|
||||
<!-- 体重监测 -->
|
||||
<a class="entry-card" href="weight/index.html">
|
||||
<div class="entry-icon entry-icon--weight">⚖️</div>
|
||||
<div class="entry-info">
|
||||
<div class="entry-name">体重监测<span class="entry-time">05-11 07:15</span></div>
|
||||
<div class="entry-data">
|
||||
<span class="entry-data__value"><strong>68.5</strong>kg</span>
|
||||
<span class="entry-data__value">BMI <strong>22.3</strong></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-value">7<span class="card-unit">h</span>32<span class="card-unit">min</span></div>
|
||||
<div class="card-progress__text">平均睡眠8小时57分</div>
|
||||
<div class="card-sync">同步至 04-30 07:05</div>
|
||||
<!-- <div class="sleep-segments">-->
|
||||
<!-- <div class="sleep-seg sleep-seg--deep" style="width:28%"></div>-->
|
||||
<!-- <div class="sleep-seg sleep-seg--light" style="width:42%"></div>-->
|
||||
<!-- <div class="sleep-seg sleep-seg--rem" style="width:20%"></div>-->
|
||||
<!-- <div class="sleep-seg sleep-seg--awake" style="width:10%"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="sleep-legend">-->
|
||||
<!-- <div class="sleep-legend__item"><div class="sleep-legend__dot" style="background:#1890ff"></div>深睡</div>-->
|
||||
<!-- <div class="sleep-legend__item"><div class="sleep-legend__dot" style="background:#91d5ff"></div>浅睡</div>-->
|
||||
<!-- <div class="sleep-legend__item"><div class="sleep-legend__dot" style="background:#b37feb"></div>REM</div>-->
|
||||
<!-- <div class="sleep-legend__item"><div class="sleep-legend__dot" style="background:#ffd591"></div>清醒</div>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
<!-- 心率 -->
|
||||
<div class="monitor-card" onclick="location.href='heart-rate.html'">
|
||||
<div class="card-header">
|
||||
<div class="card-header__left">
|
||||
<div class="card-icon" style="background:#fff1f0">❤️</div>
|
||||
<span class="card-label">心率</span>
|
||||
</div>
|
||||
<div class="card-header__right">
|
||||
<div class="card-arrow">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
|
||||
</div>
|
||||
<div class="entry-arrow"><svg width="7" height="12" fill="none"><path d="M1 1l5 5-5 5" stroke="#ccc" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
|
||||
</a>
|
||||
<!-- 环境监测 -->
|
||||
<a class="entry-card" href="environment/index.html">
|
||||
<div class="entry-icon entry-icon--environment">🌿</div>
|
||||
<div class="entry-info">
|
||||
<div class="entry-name">环境监测<span class="entry-time">05-12 09:30</span></div>
|
||||
<div class="entry-data">
|
||||
<span class="entry-data__value">AQI <strong>45</strong></span>
|
||||
<span class="entry-status entry-status--good">优</span>
|
||||
<span class="entry-data__value"><strong>24</strong>°C</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-value">72<span class="card-unit">bpm</span></div>
|
||||
<div class="card-sub">范围:89~120</div>
|
||||
<div class="card-sync">同步至 04-30 09:37</div>
|
||||
<div class="card-alert-link" onclick="event.stopPropagation();location.href='heart-rate-alerts.html'">
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#ff4d4f" stroke-width="2"><path d="M12 9v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
|
||||
查看预警历史
|
||||
</div>
|
||||
</div>
|
||||
<!-- 体温 -->
|
||||
<div class="monitor-card" onclick="location.href='temperature.html'">
|
||||
<div class="card-header">
|
||||
<div class="card-header__left">
|
||||
<div class="card-icon" style="background:#f9f0ff">🌡️</div>
|
||||
<span class="card-label">体温</span>
|
||||
</div>
|
||||
<div class="card-header__right">
|
||||
<div class="card-arrow">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
|
||||
</div>
|
||||
<div class="entry-arrow"><svg width="7" height="12" fill="none"><path d="M1 1l5 5-5 5" stroke="#ccc" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
|
||||
</a>
|
||||
<!-- 健康排查 -->
|
||||
<a class="entry-card" href="health-screening/index.html">
|
||||
<div class="entry-icon entry-icon--screening">🔍</div>
|
||||
<div class="entry-info">
|
||||
<div class="entry-name">健康排查<span class="entry-time">05-12 08:00</span></div>
|
||||
<div class="entry-data">
|
||||
<span class="entry-data__value">积分 <strong>1,280</strong></span>
|
||||
<span class="entry-data__value">连续签到 <strong>7</strong>天</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-value">36.5<span class="card-unit">°C</span></div>
|
||||
<div class="card-sub">范围 36.2~37.1°C</div>
|
||||
<div class="card-sync">同步至 04-30 09:30</div>
|
||||
<div class="card-alert-link" onclick="event.stopPropagation();location.href='temperature-alerts.html'">
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#ff4d4f" stroke-width="2"><path d="M12 9v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
|
||||
查看预警历史
|
||||
</div>
|
||||
</div>
|
||||
<!-- 血氧 -->
|
||||
<div class="monitor-card" onclick="location.href='blood-oxygen.html'">
|
||||
<div class="card-header">
|
||||
<div class="card-header__left">
|
||||
<div class="card-icon" style="background:#f6ffed">💧</div>
|
||||
<span class="card-label">血氧</span>
|
||||
</div>
|
||||
<div class="card-header__right">
|
||||
<div class="card-arrow">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-value">98<span class="card-unit">%</span></div>
|
||||
<div class="card-sub">范围 95~99%</div>
|
||||
<div class="card-sync">同步至 04-30 09:35</div>
|
||||
<div class="card-alert-link" onclick="event.stopPropagation();location.href='blood-oxygen-alerts.html'">
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#ff4d4f" stroke-width="2"><path d="M12 9v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
|
||||
查看预警历史
|
||||
</div>
|
||||
</div>
|
||||
<!-- 压力 -->
|
||||
<div class="monitor-card" onclick="location.href='stress.html'">
|
||||
<div class="card-header">
|
||||
<div class="card-header__left">
|
||||
<div class="card-icon" style="background:#fffbe6">🧠</div>
|
||||
<span class="card-label">压力</span>
|
||||
</div>
|
||||
<div class="card-header__right">
|
||||
<div class="card-arrow">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-value">42</div>
|
||||
<div class="card-sub">范围 18~82</div>
|
||||
<div class="card-sync">同步至 04-30 09:36</div>
|
||||
<div class="card-alert-link" onclick="event.stopPropagation();location.href='stress-alerts.html'">
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#ff4d4f" stroke-width="2"><path d="M12 9v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
|
||||
查看预警历史
|
||||
</div>
|
||||
</div>
|
||||
<!-- 锻炼 -->
|
||||
<!-- <div class="monitor-card monitor-card--full" onclick="location.href='exercise.html'">-->
|
||||
<!-- <div class="card-header">-->
|
||||
<!-- <div class="card-header__left">-->
|
||||
<!-- <div class="card-icon" style="background:#fff7e6">🏋️</div>-->
|
||||
<!-- <span class="card-label">锻炼</span>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="card-header__right">-->
|
||||
<!-- <span class="card-meta">本周</span>-->
|
||||
<!-- <div class="card-arrow">-->
|
||||
<!-- <svg viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="exercise-stats">-->
|
||||
<!-- <div class="exercise-stat">-->
|
||||
<!-- <div class="exercise-stat__val">3<span style="font-size:12px;color:#999;font-weight:400"> 次</span></div>-->
|
||||
<!-- <div class="exercise-stat__label">锻炼次数</div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="exercise-stat">-->
|
||||
<!-- <div class="exercise-stat__val">2h15<span style="font-size:12px;color:#999;font-weight:400"> min</span></div>-->
|
||||
<!-- <div class="exercise-stat__label">累计时长</div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="exercise-stat">-->
|
||||
<!-- <div class="exercise-stat__val">680<span style="font-size:12px;color:#999;font-weight:400"> kcal</span></div>-->
|
||||
<!-- <div class="exercise-stat__label">消耗热量</div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="exercise-stat">-->
|
||||
<!-- <div class="exercise-stat__val">4.2<span style="font-size:12px;color:#999;font-weight:400"> km</span></div>-->
|
||||
<!-- <div class="exercise-stat__label">运动距离</div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="card-sync">同步至 04-30 09:20</div>-->
|
||||
<!-- </div>-->
|
||||
<div class="entry-arrow"><svg width="7" height="12" fill="none"><path d="M1 1l5 5-5 5" stroke="#ccc" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom-safe"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -1,309 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>睡眠详情 - 健康监测 | 健康长庆原型</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; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
/* 核心数据区 */
|
||||
.hero { background: #fff; padding: 24px 16px 20px; text-align: center; }
|
||||
/* 评分圆环 */
|
||||
.hero__ring { width: 160px; height: 160px; margin: 0 auto 12px; position: relative; }
|
||||
.hero__ring svg { width: 100%; height: 100%; transform: rotate(-90deg); }
|
||||
.hero__ring-center { position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); text-align: center; }
|
||||
.hero__score { font-size: 38px; font-weight: 800; color: #1a1a1a; line-height: 1; }
|
||||
.hero__score-label { font-size: 12px; color: #999; margin-top: 2px; }
|
||||
/* 睡眠时长 */
|
||||
.hero__duration { font-size: 22px; font-weight: 700; color: #1a1a1a; margin-bottom: 4px; }
|
||||
.hero__duration span { font-size: 14px; font-weight: 400; color: #666; }
|
||||
/* 入睡/起床时间 */
|
||||
.hero-times { display: flex; justify-content: center; gap: 40px; margin-top: 14px; }
|
||||
.hero-time { text-align: center; }
|
||||
.hero-time__val { font-size: 20px; font-weight: 700; color: #1a1a1a; }
|
||||
.hero-time__label { font-size: 11px; color: #999; margin-top: 2px; }
|
||||
.hero-time__icon { font-size: 16px; margin-bottom: 2px; }
|
||||
/* 分隔线 */
|
||||
.divider { width: 1px; height: 40px; background: #f0f0f0; align-self: center; }
|
||||
/* 睡眠分段条形图区 */
|
||||
.section { margin: 10px 12px 0; background: #fff; border-radius: 12px; padding: 16px; }
|
||||
.section-title { font-size: 14px; font-weight: 600; color: #1a1a1a; margin-bottom: 14px; }
|
||||
/* 横向分段条 */
|
||||
.stage-bar-wrap { display: flex; border-radius: 6px; overflow: hidden; height: 14px; margin-bottom: 14px; }
|
||||
.stage-bar-seg { height: 100%; transition: width 0.4s; }
|
||||
/* 图例列表 */
|
||||
.stage-legend { display: flex; flex-direction: column; gap: 8px; }
|
||||
.stage-item { display: flex; align-items: center; gap: 8px; }
|
||||
.stage-dot { width: 10px; height: 10px; border-radius: 2px; flex-shrink: 0; }
|
||||
.stage-name { font-size: 12px; color: #666; width: 36px; }
|
||||
.stage-bar-bg { flex: 1; height: 6px; background: #f5f7fa; border-radius: 3px; overflow: hidden; }
|
||||
.stage-bar-fill { height: 100%; border-radius: 3px; }
|
||||
.stage-pct { font-size: 12px; color: #999; width: 30px; text-align: right; }
|
||||
.stage-dur { font-size: 12px; font-weight: 600; color: #1a1a1a; width: 56px; text-align: right; }
|
||||
/* 时间维度Tab */
|
||||
.time-tabs { display: flex; margin: 10px 12px 0; background: #fff; border-radius: 10px; overflow: hidden; }
|
||||
.time-tab { flex: 1; text-align: center; padding: 10px 0; font-size: 13px; color: #666; cursor: pointer; }
|
||||
.time-tab.active { background: #1890ff; color: #fff; border-radius: 10px; font-weight: 600; }
|
||||
/* 睡眠深度曲线 */
|
||||
.depth-chart { width: 100%; height: 80px; }
|
||||
.depth-axis { display: flex; justify-content: space-between; font-size: 10px; color: #bbb; margin-top: 4px; }
|
||||
/* 近7天趋势 */
|
||||
.trend-chart { width: 100%; height: 100px; }
|
||||
.trend-axis { display: flex; justify-content: space-between; font-size: 10px; color: #bbb; margin-top: 4px; }
|
||||
/* 统计摘要 */
|
||||
.summary { display: flex; gap: 8px; margin: 10px 12px 0; }
|
||||
.summary-card { flex: 1; background: #fff; border-radius: 12px; padding: 14px 8px; text-align: center; }
|
||||
.summary-card__val { font-size: 18px; font-weight: 700; color: #1a1a1a; line-height: 1.2; }
|
||||
.summary-card__unit { font-size: 11px; color: #999; }
|
||||
.summary-card__label { font-size: 11px; color: #999; margin-top: 4px; }
|
||||
/* 底部安全区 */
|
||||
.bottom-safe { height: 20px; flex-shrink: 0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
<!-- 状态栏 -->
|
||||
<div class="status-bar">
|
||||
<span class="time">9:41</span>
|
||||
<div class="icons">
|
||||
<!-- WiFi图标 -->
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2"><path d="M1 6l5 5 5-5"/><path d="M4 9l3 3 3-3" opacity="0.5"/></svg>
|
||||
<!-- 电池图标 -->
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2"><rect x="1" y="6" width="18" height="12" rx="2"/><path d="M21 10v4"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 导航栏 -->
|
||||
<div class="nav-bar">
|
||||
<div class="nav-back" onclick="location.href='index.html'">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2" stroke-linecap="round"><path d="M15 19l-7-7 7-7"/></svg>
|
||||
</div>
|
||||
<div class="nav-title">睡眠</div>
|
||||
</div>
|
||||
<!-- 滚动内容区 -->
|
||||
<div class="scroll-content">
|
||||
<!-- 核心数据区:评分圆环 + 时长 + 入睡/起床 -->
|
||||
<div class="hero">
|
||||
<!-- 睡眠评分圆环 -->
|
||||
<div class="hero__ring">
|
||||
<svg viewBox="0 0 160 160">
|
||||
<defs>
|
||||
<linearGradient id="sleepGrad" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0%" stop-color="#1890ff"/>
|
||||
<stop offset="100%" stop-color="#b37feb"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<!-- 背景圆环 -->
|
||||
<circle cx="80" cy="80" r="70" fill="none" stroke="#f0f0f0" stroke-width="10"/>
|
||||
<!-- 评分圆弧:85分 = 85% 周长,周长=2π×70≈439.8,85%≈373.8,偏移=439.8-373.8=66 -->
|
||||
<circle cx="80" cy="80" r="70" fill="none" stroke="url(#sleepGrad)" stroke-width="10" stroke-linecap="round" stroke-dasharray="439.8" stroke-dashoffset="66"/>
|
||||
</svg>
|
||||
<div class="hero__ring-center">
|
||||
<div class="hero__score">85</div>
|
||||
<div class="hero__score-label">睡眠评分</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 睡眠时长 -->
|
||||
<div class="hero__duration">7<span>h</span> 32<span>min</span></div>
|
||||
<!-- 入睡 / 起床时间 -->
|
||||
<div class="hero-times">
|
||||
<div class="hero-time">
|
||||
<div class="hero-time__icon">🌙</div>
|
||||
<div class="hero-time__val">23:12</div>
|
||||
<div class="hero-time__label">入睡</div>
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
<div class="hero-time">
|
||||
<div class="hero-time__icon">☀️</div>
|
||||
<div class="hero-time__val">06:44</div>
|
||||
<div class="hero-time__label">起床</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 睡眠分段条形图 -->
|
||||
<div class="section">
|
||||
<div class="section-title">睡眠阶段</div>
|
||||
<!-- 横向分段总条 -->
|
||||
<div class="stage-bar-wrap">
|
||||
<!-- 深睡 28% -->
|
||||
<div class="stage-bar-seg" style="width:28%;background:#1890ff;"></div>
|
||||
<!-- 浅睡 42% -->
|
||||
<div class="stage-bar-seg" style="width:42%;background:#91d5ff;"></div>
|
||||
<!-- REM 20% -->
|
||||
<div class="stage-bar-seg" style="width:20%;background:#b37feb;"></div>
|
||||
<!-- 清醒 10% -->
|
||||
<div class="stage-bar-seg" style="width:10%;background:#ffd591;"></div>
|
||||
</div>
|
||||
<!-- 各阶段图例 + 进度条 -->
|
||||
<div class="stage-legend">
|
||||
<!-- 深睡 -->
|
||||
<div class="stage-item">
|
||||
<div class="stage-dot" style="background:#1890ff;"></div>
|
||||
<div class="stage-name">深睡</div>
|
||||
<div class="stage-bar-bg"><div class="stage-bar-fill" style="width:28%;background:#1890ff;"></div></div>
|
||||
<div class="stage-pct">28%</div>
|
||||
<div class="stage-dur">2h 06min</div>
|
||||
</div>
|
||||
<!-- 浅睡 -->
|
||||
<div class="stage-item">
|
||||
<div class="stage-dot" style="background:#91d5ff;"></div>
|
||||
<div class="stage-name">浅睡</div>
|
||||
<div class="stage-bar-bg"><div class="stage-bar-fill" style="width:42%;background:#91d5ff;"></div></div>
|
||||
<div class="stage-pct">42%</div>
|
||||
<div class="stage-dur">3h 10min</div>
|
||||
</div>
|
||||
<!-- REM -->
|
||||
<div class="stage-item">
|
||||
<div class="stage-dot" style="background:#b37feb;"></div>
|
||||
<div class="stage-name">REM</div>
|
||||
<div class="stage-bar-bg"><div class="stage-bar-fill" style="width:20%;background:#b37feb;"></div></div>
|
||||
<div class="stage-pct">20%</div>
|
||||
<div class="stage-dur">1h 30min</div>
|
||||
</div>
|
||||
<!-- 清醒 -->
|
||||
<div class="stage-item">
|
||||
<div class="stage-dot" style="background:#ffd591;"></div>
|
||||
<div class="stage-name">清醒</div>
|
||||
<div class="stage-bar-bg"><div class="stage-bar-fill" style="width:10%;background:#ffd591;"></div></div>
|
||||
<div class="stage-pct">10%</div>
|
||||
<div class="stage-dur">46min</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 时间维度Tab -->
|
||||
<div class="time-tabs">
|
||||
<div class="time-tab active">日</div>
|
||||
<div class="time-tab">周</div>
|
||||
<div class="time-tab">月</div>
|
||||
</div>
|
||||
<!-- 24h睡眠深度曲线 -->
|
||||
<div class="section">
|
||||
<div class="section-title">睡眠深度曲线</div>
|
||||
<svg class="depth-chart" id="depthChart" viewBox="0 0 320 80" preserveAspectRatio="none"></svg>
|
||||
<div class="depth-axis"><span>22:00</span><span>00:00</span><span>02:00</span><span>04:00</span><span>06:00</span><span>07:00</span></div>
|
||||
</div>
|
||||
<!-- 近7天趋势 -->
|
||||
<div class="section">
|
||||
<div class="section-title">近 7 天趋势</div>
|
||||
<svg class="trend-chart" id="trendChart" viewBox="0 0 320 100" preserveAspectRatio="none"></svg>
|
||||
<div class="trend-axis"><span>4/24</span><span>4/25</span><span>4/26</span><span>4/27</span><span>4/28</span><span>4/29</span><span>4/30</span></div>
|
||||
</div>
|
||||
<!-- 统计摘要 -->
|
||||
<div class="summary">
|
||||
<div class="summary-card">
|
||||
<div class="summary-card__val">7h<br>20min</div>
|
||||
<div class="summary-card__label">7日平均</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-card__val">8h<br>06min</div>
|
||||
<div class="summary-card__label">最长睡眠</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-card__val">82</div>
|
||||
<div class="summary-card__unit">分</div>
|
||||
<div class="summary-card__label">睡眠规律性</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom-safe"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
/* ---- 24h睡眠深度曲线(SVG路径,模拟真实睡眠波形) ---- */
|
||||
(function() {
|
||||
/* 睡眠深度数据:0=清醒, 1=浅睡, 2=深睡, 3=REM,共48个采样点(每15分钟一个) */
|
||||
/* 时间范围:22:00 ~ 07:00,共9小时 = 36个15分钟 */
|
||||
var depthData = [
|
||||
0, 0, 1, 1, 2, 2, 2, 3, 3, 2, /* 22:00-24:30 入睡过渡 */
|
||||
2, 2, 3, 3, 1, 1, 2, 2, 2, 3, /* 00:30-03:00 深睡阶段 */
|
||||
3, 2, 1, 1, 0, 1, 2, 2, 3, 3, /* 03:00-05:30 REM循环 */
|
||||
2, 1, 1, 0, 0, 0 /* 05:30-07:00 浅睡至清醒 */
|
||||
];
|
||||
var n = depthData.length;
|
||||
var w = 320, h = 80;
|
||||
var padT = 8, padB = 8;
|
||||
var chartH = h - padT - padB;
|
||||
/* 深度值映射:0=清醒(顶部), 3=深睡(底部) */
|
||||
function yOf(d) { return padT + (d / 3) * chartH; }
|
||||
/* 生成平滑路径点 */
|
||||
var pts = depthData.map(function(d, i) {
|
||||
return { x: (i / (n - 1)) * w, y: yOf(d) };
|
||||
});
|
||||
/* 构建平滑曲线(使用三次贝塞尔近似) */
|
||||
var path = 'M ' + pts[0].x.toFixed(1) + ',' + pts[0].y.toFixed(1);
|
||||
for (var i = 1; i < pts.length; i++) {
|
||||
var prev = pts[i - 1], cur = pts[i];
|
||||
var cpx = (prev.x + cur.x) / 2;
|
||||
path += ' C ' + cpx.toFixed(1) + ',' + prev.y.toFixed(1) + ' ' + cpx.toFixed(1) + ',' + cur.y.toFixed(1) + ' ' + cur.x.toFixed(1) + ',' + cur.y.toFixed(1);
|
||||
}
|
||||
/* 填充区域路径 */
|
||||
var areaPath = path + ' L ' + w + ',' + h + ' L 0,' + h + ' Z';
|
||||
var svg = document.getElementById('depthChart');
|
||||
svg.innerHTML =
|
||||
'<defs>' +
|
||||
'<linearGradient id="depthGrad" x1="0" y1="0" x2="0" y2="1">' +
|
||||
'<stop offset="0%" stop-color="#1890ff" stop-opacity="0.35"/>' +
|
||||
'<stop offset="100%" stop-color="#1890ff" stop-opacity="0.04"/>' +
|
||||
'</linearGradient>' +
|
||||
'</defs>' +
|
||||
'<path d="' + areaPath + '" fill="url(#depthGrad)"/>' +
|
||||
'<path d="' + path + '" fill="none" stroke="#1890ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>';
|
||||
})();
|
||||
|
||||
/* ---- 近7天睡眠时长趋势折线图 ---- */
|
||||
(function() {
|
||||
/* 单位:小时 */
|
||||
var weekData = [7.2, 6.8, 7.5, 8.1, 6.5, 7.8, 7.5];
|
||||
var n = weekData.length;
|
||||
var w = 320, h = 100;
|
||||
var padT = 10, padB = 10;
|
||||
var chartH = h - padT - padB;
|
||||
var wMax = Math.max.apply(null, weekData);
|
||||
var wMin = Math.min.apply(null, weekData);
|
||||
var range = wMax - wMin || 1;
|
||||
/* 计算各点坐标 */
|
||||
var pts = weekData.map(function(v, i) {
|
||||
return {
|
||||
x: (i / (n - 1)) * w,
|
||||
y: padT + (1 - (v - wMin) / range) * chartH
|
||||
};
|
||||
});
|
||||
var line = pts.map(function(p) { return p.x.toFixed(1) + ',' + p.y.toFixed(1); }).join(' ');
|
||||
var area = '0,' + h + ' ' + line + ' ' + w + ',' + h;
|
||||
var svg = document.getElementById('trendChart');
|
||||
svg.innerHTML =
|
||||
'<defs>' +
|
||||
'<linearGradient id="trendGrad" x1="0" y1="0" x2="0" y2="1">' +
|
||||
'<stop offset="0%" stop-color="#1890ff" stop-opacity="0.3"/>' +
|
||||
'<stop offset="100%" stop-color="#1890ff" stop-opacity="0.02"/>' +
|
||||
'</linearGradient>' +
|
||||
'</defs>' +
|
||||
'<polygon points="' + area + '" fill="url(#trendGrad)"/>' +
|
||||
'<polyline points="' + line + '" fill="none" stroke="#1890ff" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>';
|
||||
/* 数据点圆圈 */
|
||||
pts.forEach(function(p) {
|
||||
svg.innerHTML += '<circle cx="' + p.x.toFixed(1) + '" cy="' + p.y.toFixed(1) + '" r="4" fill="#fff" stroke="#1890ff" stroke-width="2"/>';
|
||||
});
|
||||
})();
|
||||
|
||||
/* ---- 时间维度Tab切换 ---- */
|
||||
document.querySelectorAll('.time-tab').forEach(function(tab) {
|
||||
tab.onclick = function() {
|
||||
document.querySelectorAll('.time-tab').forEach(function(t) { t.classList.remove('active'); });
|
||||
tab.classList.add('active');
|
||||
};
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,406 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>血压预警历史 - 健康监测 | 健康长庆原型</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;
|
||||
}
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
|
||||
.stats-card {
|
||||
margin: 12px 12px 0;
|
||||
background: #fff;
|
||||
border-radius: 14px;
|
||||
padding: 20px 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.stats-card__left { display: flex; flex-direction: column; align-items: flex-start; }
|
||||
.stats-card__label { font-size: 13px; color: #999; margin-bottom: 6px; }
|
||||
.stats-card__count-row { display: flex; align-items: baseline; gap: 4px; }
|
||||
.stats-card__count { font-size: 40px; font-weight: 800; color: #7c5cfc; line-height: 1; }
|
||||
.stats-card__unit { font-size: 14px; color: #7c5cfc; font-weight: 600; }
|
||||
.stats-card__right { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; }
|
||||
.stats-card__recent-label { font-size: 12px; color: #999; }
|
||||
.stats-card__recent-time { font-size: 13px; font-weight: 600; color: #333; }
|
||||
.stats-card__icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
background: #f3f0ff;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 13px;
|
||||
color: #999;
|
||||
padding: 14px 16px 8px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.alert-card {
|
||||
margin: 0 12px 10px;
|
||||
background: #fff;
|
||||
border-radius: 14px;
|
||||
padding: 14px 14px 14px 12px;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.alert-card__dot-col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding-top: 3px;
|
||||
gap: 4px;
|
||||
}
|
||||
.alert-card__dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.alert-card__dot--critical { background: #ff4d4f; box-shadow: 0 0 0 3px rgba(255,77,79,0.18); }
|
||||
.alert-card__dot--warning { background: #faad14; box-shadow: 0 0 0 3px rgba(250,173,20,0.18); }
|
||||
|
||||
.alert-card__body { flex: 1; min-width: 0; }
|
||||
.alert-card__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.alert-card__time { font-size: 13px; color: #666; }
|
||||
.alert-card__badge {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
padding: 2px 8px;
|
||||
border-radius: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.alert-card__badge--critical { background: #fff1f0; color: #ff4d4f; }
|
||||
.alert-card__badge--warning { background: #fffbe6; color: #d48806; }
|
||||
|
||||
.alert-card__value-row {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 4px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.alert-card__value { font-size: 24px; font-weight: 800; color: #1a1a1a; line-height: 1; }
|
||||
.alert-card__value-unit { font-size: 13px; color: #999; }
|
||||
|
||||
.alert-card__detail-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.alert-card__detail-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
.alert-card__detail-item svg { flex-shrink: 0; }
|
||||
|
||||
.alert-card__reason {
|
||||
margin-top: 8px;
|
||||
font-size: 12px;
|
||||
color: #bbb;
|
||||
background: #fafafa;
|
||||
border-radius: 6px;
|
||||
padding: 6px 8px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.bottom-safe { height: 20px; flex-shrink: 0; }
|
||||
|
||||
.filter-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 6px 12px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 6px;
|
||||
background: #fff;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
cursor: pointer;
|
||||
}
|
||||
.filter-btn:active { background: #f5f5f5; border-color: #bbb; }
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
|
||||
<div class="status-bar">
|
||||
<span class="time">9:41</span>
|
||||
<div class="icons">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2">
|
||||
<path d="M5 12.55a11 11 0 0 1 14.08 0"/>
|
||||
<path d="M1.42 9a16 16 0 0 1 21.16 0"/>
|
||||
<path d="M8.53 16.11a6 6 0 0 1 6.95 0"/>
|
||||
<circle cx="12" cy="20" r="1" fill="#333" stroke="none"/>
|
||||
</svg>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2">
|
||||
<rect x="1" y="6" width="18" height="12" rx="2"/>
|
||||
<path d="M21 10v4"/>
|
||||
<rect x="3" y="8" width="12" height="8" rx="1" fill="#333" stroke="none"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="nav-bar">
|
||||
<div class="nav-back" onclick="location.href='blood-pressure.html'">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2" stroke-linecap="round">
|
||||
<path d="M15 19l-7-7 7-7"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="nav-title">血压预警历史</div>
|
||||
</div>
|
||||
|
||||
<div class="scroll-content">
|
||||
|
||||
<div class="stats-card">
|
||||
<div class="stats-card__left">
|
||||
<div class="stats-card__label">本月预警</div>
|
||||
<div class="stats-card__count-row">
|
||||
<span class="stats-card__count">4</span>
|
||||
<span class="stats-card__unit">次</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stats-card__right">
|
||||
<div class="stats-card__icon">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
|
||||
<path d="M12 2C8 2 4 5 4 9c0 5 8 13 8 13s8-8 8-13c0-4-4-7-8-7z" fill="#7c5cfc" stroke="#7c5cfc" stroke-width="1.5"/>
|
||||
<circle cx="12" cy="9" r="3" fill="#fff"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="stats-card__recent-label">最近预警时间</div>
|
||||
<div class="stats-card__recent-time">2026-05-11 08:45</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; align-items: center; justify-content: space-between; padding: 14px 16px 8px;">
|
||||
<div class="section-title" style="margin: 0; padding: 0;">预警记录(共 4 条)</div>
|
||||
<button class="filter-btn">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<rect x="3" y="4" width="18" height="18" rx="2"/>
|
||||
<path d="M16 2v4M8 2v4M3 10h18"/>
|
||||
</svg>
|
||||
筛选
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 预警记录 1:严重 -->
|
||||
<div class="alert-card">
|
||||
<div class="alert-card__dot-col">
|
||||
<div class="alert-card__dot alert-card__dot--critical"></div>
|
||||
</div>
|
||||
<div class="alert-card__body">
|
||||
<div class="alert-card__header">
|
||||
<span class="alert-card__time">2026-05-11 08:45</span>
|
||||
<span class="alert-card__badge alert-card__badge--critical">严重</span>
|
||||
</div>
|
||||
<div class="alert-card__value-row">
|
||||
<span class="alert-card__value">158/98</span>
|
||||
<span class="alert-card__value-unit">mmHg</span>
|
||||
</div>
|
||||
<div class="alert-card__detail-row">
|
||||
<div class="alert-card__detail-item">
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2">
|
||||
<circle cx="12" cy="12" r="10"/>
|
||||
<polyline points="12 6 12 12 16 14"/>
|
||||
</svg>
|
||||
<span>持续 15 分钟</span>
|
||||
</div>
|
||||
<div class="alert-card__detail-item">
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2">
|
||||
<path d="M12 2C8 2 4 5 4 9c0 5 8 13 8 13s8-8 8-13c0-4-4-7-8-7z"/>
|
||||
</svg>
|
||||
<span>血压</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert-card__reason">触发原因:收缩压超过 150 mmHg 阈值</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 预警记录 2:警告 -->
|
||||
<div class="alert-card">
|
||||
<div class="alert-card__dot-col">
|
||||
<div class="alert-card__dot alert-card__dot--warning"></div>
|
||||
</div>
|
||||
<div class="alert-card__body">
|
||||
<div class="alert-card__header">
|
||||
<span class="alert-card__time">2026-05-08 14:20</span>
|
||||
<span class="alert-card__badge alert-card__badge--warning">警告</span>
|
||||
</div>
|
||||
<div class="alert-card__value-row">
|
||||
<span class="alert-card__value">142/92</span>
|
||||
<span class="alert-card__value-unit">mmHg</span>
|
||||
</div>
|
||||
<div class="alert-card__detail-row">
|
||||
<div class="alert-card__detail-item">
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2">
|
||||
<circle cx="12" cy="12" r="10"/>
|
||||
<polyline points="12 6 12 12 16 14"/>
|
||||
</svg>
|
||||
<span>持续 8 分钟</span>
|
||||
</div>
|
||||
<div class="alert-card__detail-item">
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2">
|
||||
<path d="M12 2C8 2 4 5 4 9c0 5 8 13 8 13s8-8 8-13c0-4-4-7-8-7z"/>
|
||||
</svg>
|
||||
<span>血压</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert-card__reason">触发原因:收缩压超过 140 mmHg 阈值</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 预警记录 3:警告 -->
|
||||
<div class="alert-card">
|
||||
<div class="alert-card__dot-col">
|
||||
<div class="alert-card__dot alert-card__dot--warning"></div>
|
||||
</div>
|
||||
<div class="alert-card__body">
|
||||
<div class="alert-card__header">
|
||||
<span class="alert-card__time">2026-05-05 07:30</span>
|
||||
<span class="alert-card__badge alert-card__badge--warning">警告</span>
|
||||
</div>
|
||||
<div class="alert-card__value-row">
|
||||
<span class="alert-card__value">145/90</span>
|
||||
<span class="alert-card__value-unit">mmHg</span>
|
||||
</div>
|
||||
<div class="alert-card__detail-row">
|
||||
<div class="alert-card__detail-item">
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2">
|
||||
<circle cx="12" cy="12" r="10"/>
|
||||
<polyline points="12 6 12 12 16 14"/>
|
||||
</svg>
|
||||
<span>持续 10 分钟</span>
|
||||
</div>
|
||||
<div class="alert-card__detail-item">
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2">
|
||||
<path d="M12 2C8 2 4 5 4 9c0 5 8 13 8 13s8-8 8-13c0-4-4-7-8-7z"/>
|
||||
</svg>
|
||||
<span>血压</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert-card__reason">触发原因:收缩压超过 140 mmHg 阈值</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 预警记录 4:警告 -->
|
||||
<div class="alert-card">
|
||||
<div class="alert-card__dot-col">
|
||||
<div class="alert-card__dot alert-card__dot--warning"></div>
|
||||
</div>
|
||||
<div class="alert-card__body">
|
||||
<div class="alert-card__header">
|
||||
<span class="alert-card__time">2026-05-02 19:15</span>
|
||||
<span class="alert-card__badge alert-card__badge--warning">警告</span>
|
||||
</div>
|
||||
<div class="alert-card__value-row">
|
||||
<span class="alert-card__value">138/94</span>
|
||||
<span class="alert-card__value-unit">mmHg</span>
|
||||
</div>
|
||||
<div class="alert-card__detail-row">
|
||||
<div class="alert-card__detail-item">
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2">
|
||||
<circle cx="12" cy="12" r="10"/>
|
||||
<polyline points="12 6 12 12 16 14"/>
|
||||
</svg>
|
||||
<span>持续 6 分钟</span>
|
||||
</div>
|
||||
<div class="alert-card__detail-item">
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2">
|
||||
<path d="M12 2C8 2 4 5 4 9c0 5 8 13 8 13s8-8 8-13c0-4-4-7-8-7z"/>
|
||||
</svg>
|
||||
<span>血压</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert-card__reason">触发原因:舒张压超过 90 mmHg 阈值</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bottom-safe"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,317 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>血压详情 - 健康监测 | 健康长庆原型</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; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
|
||||
:root { --theme: #7c5cfc; --theme2: #a78bfa; --theme-dia: #f97066; --theme-dia2: #fca5a1; }
|
||||
|
||||
.top-panel { background: #fff; padding-top: 2px; }
|
||||
.time-tabs { display: flex; justify-content: center; gap: 42px; padding: 2px 0 8px; }
|
||||
.time-tab { position: relative; font-size: 18px; color: #444; cursor: pointer; padding: 0 2px 6px; user-select: none; }
|
||||
.time-tab.active { color: var(--theme); }
|
||||
.time-tab.active::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; margin: auto; width: 22px; height: 3px; border-radius: 2px; background: var(--theme); }
|
||||
|
||||
.summary-area { text-align: center; padding: 12px 24px 6px; }
|
||||
.date-row { display: inline-flex; align-items: center; gap: 6px; font-size: 16px; color: #666; font-weight: 500; }
|
||||
.range-text { margin-top: 4px; font-size: 16px; color: #666; }
|
||||
.main-row { margin-top: 2px; display: inline-flex; align-items: baseline; gap: 4px; }
|
||||
.main-row__value { font-size: 48px; line-height: 1; font-weight: 500; color: #1f1f1f; letter-spacing: -1px; }
|
||||
.main-row__slash { font-size: 28px; color: #999; margin: 0 2px; }
|
||||
.main-row__unit { font-size: 18px; color: #333; }
|
||||
.main-badge { display: inline-flex; align-items: center; justify-content: center; margin-top: 6px; padding: 3px 12px; border-radius: 18px; font-size: 12px; font-weight: 600; background: #f6ffed; color: #52c41a; }
|
||||
|
||||
.chart-wrap { position: relative; background: #fff; padding: 6px 16px 0; }
|
||||
.chart-box { position: relative; height: 160px; }
|
||||
.chart-svg { width: 100%; height: 100%; display: block; }
|
||||
.chart-grid line { stroke: #ececec; stroke-width: 1; }
|
||||
.chart-path { fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
|
||||
.chart-path--sys { stroke: var(--theme); }
|
||||
.chart-path--dia { stroke: var(--theme-dia); }
|
||||
.chart-dot--sys { fill: var(--theme); }
|
||||
.chart-dot--dia { fill: var(--theme-dia); }
|
||||
.y-axis-labels { position: absolute; top: 6px; right: 0; width: 56px; height: 208px; pointer-events: none; }
|
||||
.y-axis-label { position: absolute; right: 0; transform: translateY(50%); font-size: 12px; color: #666; }
|
||||
.chart-legend { display: flex; justify-content: center; gap: 20px; padding: 8px 0 4px; }
|
||||
.legend-item { display: flex; align-items: center; gap: 4px; font-size: 12px; color: #666; }
|
||||
.legend-item i { display: inline-block; width: 12px; height: 3px; border-radius: 2px; }
|
||||
.legend-item--sys i { background: var(--theme); }
|
||||
.legend-item--dia i { background: var(--theme-dia); }
|
||||
.x-axis { display: grid; gap: 0; padding: 4px 14px 8px 0; font-size: 12px; color: #666; }
|
||||
.x-axis span { text-align: center; white-space: nowrap; }
|
||||
.x-axis--dense { font-size: 10px; }
|
||||
|
||||
.timeline-knob-row { position: relative; margin: 0; height: 24px; }
|
||||
.timeline-track { position: absolute; left: 0; right: 0; top: 10px; height: 1px; background: #e8e8e8; }
|
||||
.timeline-knob { position: absolute; right: 16px; top: -4px; width: 24px; height: 24px; border-radius: 50%; background: #fff; box-shadow: 0 2px 10px rgba(0,0,0,0.12); }
|
||||
|
||||
|
||||
.card { margin: 8px 12px 0; background: #fff; border-radius: 22px; padding: 14px 12px; display: flex; gap: 0; }
|
||||
.metric-row { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 6px 6px; }
|
||||
.metric-left__label { font-size: 12px; color: #777; margin-bottom: 4px; }
|
||||
.metric-left__value { display: flex; align-items: baseline; gap: 2px; }
|
||||
.metric-left__num { font-size: 16px; font-weight: 600; color: #222; }
|
||||
.metric-left__unit { font-size: 12px; color: #777; }
|
||||
.metric-right { font-size: 12px; color: #777; text-align: center; }
|
||||
.metric-split { width: 1px; background: #ececec; margin: 0; }
|
||||
|
||||
.foot-note { padding: 10px 0 12px; text-align: center; font-size: 11px; color: #b3b3b3; }
|
||||
.alert-btn { margin: 8px 12px 0; border: 1.5px solid var(--theme); border-radius: 12px; padding: 11px; text-align: center; font-size: 13px; color: var(--theme); font-weight: 600; cursor: pointer; background: #fff; display: flex; align-items: center; justify-content: center; gap: 6px; }
|
||||
.bottom-safe { height: 12px; flex-shrink: 0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
<div class="status-bar">
|
||||
<span class="time">9:41</span>
|
||||
<div class="icons">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2"><path d="M1 6l5 5 5-5"/><path d="M4 9l3 3 3-3" opacity="0.5"/></svg>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2"><rect x="1" y="6" width="18" height="12" rx="2"/><path d="M21 10v4"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-bar">
|
||||
<div class="nav-back" onclick="location.href='index.html'">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2" stroke-linecap="round"><path d="M15 19l-7-7 7-7"/></svg>
|
||||
</div>
|
||||
<div class="nav-title">血压</div>
|
||||
</div>
|
||||
|
||||
<div class="scroll-content">
|
||||
<div class="top-panel">
|
||||
<div class="time-tabs">
|
||||
<div class="time-tab active" data-mode="day">日</div>
|
||||
<div class="time-tab" data-mode="week">周</div>
|
||||
<div class="time-tab" data-mode="month">月</div>
|
||||
<div class="time-tab" data-mode="year">年</div>
|
||||
</div>
|
||||
<div class="summary-area">
|
||||
<div class="date-row">
|
||||
<span id="dateText">5月12日 周一</span>
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="#666"><path d="M7 10l5 5 5-5z"/></svg>
|
||||
</div>
|
||||
<div class="range-text" id="rangeText">00:00-23:59</div>
|
||||
<div class="main-row">
|
||||
<span class="main-row__value" id="sysValue">120</span>
|
||||
<span class="main-row__slash">/</span>
|
||||
<span class="main-row__value" id="diaValue">78</span>
|
||||
<span class="main-row__unit">mmHg</span>
|
||||
</div>
|
||||
<div class="main-badge" id="statusBadge">正常</div>
|
||||
</div>
|
||||
|
||||
<div class="chart-wrap">
|
||||
<div class="chart-box">
|
||||
<svg class="chart-svg" id="chart" viewBox="0 0 358 258" preserveAspectRatio="none">
|
||||
<g class="chart-grid" id="chartGrid"></g>
|
||||
<path id="lineSys" class="chart-path chart-path--sys"></path>
|
||||
<path id="lineDia" class="chart-path chart-path--dia"></path>
|
||||
<circle id="dotSys" class="chart-dot chart-dot--sys" r="3.2"></circle>
|
||||
<circle id="dotDia" class="chart-dot chart-dot--dia" r="3.2"></circle>
|
||||
</svg>
|
||||
<div class="y-axis-labels" id="yAxisLabels"></div>
|
||||
|
||||
</div>
|
||||
<div class="chart-legend">
|
||||
<span class="legend-item legend-item--sys"><i></i>收缩压</span>
|
||||
<span class="legend-item legend-item--dia"><i></i>舒张压</span>
|
||||
</div>
|
||||
<div class="x-axis" id="xAxis"></div>
|
||||
<div class="timeline-knob-row">
|
||||
<div class="timeline-track"></div>
|
||||
<div class="timeline-knob"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="metric-row">
|
||||
<div class="metric-left">
|
||||
<div class="metric-left__label">收缩压最高</div>
|
||||
<div class="metric-left__value"><span class="metric-left__num" id="sysMax">135</span><span class="metric-left__unit">mmHg</span></div>
|
||||
</div>
|
||||
<div class="metric-right" id="sysMaxHint">08:30</div>
|
||||
</div>
|
||||
<div class="metric-split"></div>
|
||||
<div class="metric-row">
|
||||
<div class="metric-left">
|
||||
<div class="metric-left__label">舒张压最高</div>
|
||||
<div class="metric-left__value"><span class="metric-left__num" id="diaMax">88</span><span class="metric-left__unit">mmHg</span></div>
|
||||
</div>
|
||||
<div class="metric-right" id="diaMaxHint">08:30</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="metric-row">
|
||||
<div class="metric-left">
|
||||
<div class="metric-left__label">收缩压最低</div>
|
||||
<div class="metric-left__value"><span class="metric-left__num" id="sysMin">112</span><span class="metric-left__unit">mmHg</span></div>
|
||||
</div>
|
||||
<div class="metric-right" id="sysMinHint">22:00</div>
|
||||
</div>
|
||||
<div class="metric-split"></div>
|
||||
<div class="metric-row">
|
||||
<div class="metric-left">
|
||||
<div class="metric-left__label">舒张压最低</div>
|
||||
<div class="metric-left__value"><span class="metric-left__num" id="diaMin">72</span><span class="metric-left__unit">mmHg</span></div>
|
||||
</div>
|
||||
<div class="metric-right" id="diaMinHint">22:00</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert-btn" onclick="location.href='blood-pressure-alerts.html'">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="var(--theme)" stroke-width="2"><path d="M12 9v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
|
||||
查看预警历史 ›
|
||||
</div>
|
||||
|
||||
<div class="foot-note">以上数据为原型示例,实际以设备同步为准</div>
|
||||
<div class="bottom-safe"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var dataMap = {
|
||||
day: {
|
||||
dateText: '5月12日 周一',
|
||||
rangeText: '00:00-23:59',
|
||||
sys: [122,118,125,130,135,128,124,120],
|
||||
dia: [78,75,80,85,88,82,79,78],
|
||||
yTicks: [160, 140, 120, 100, 80, 60],
|
||||
xLabels: ['07:00','09:00','11:00','13:00','15:00','17:00','19:00','21:00'],
|
||||
status: '正常',
|
||||
sysMax: { v:135, hint:'15:00' }, sysMin: { v:118, hint:'09:00' },
|
||||
diaMax: { v:88, hint:'15:00' }, diaMin: { v:75, hint:'09:00' }
|
||||
},
|
||||
week: {
|
||||
dateText: '5月5日-5月11日',
|
||||
rangeText: '周一-周日',
|
||||
sys: [122,125,120,128,124,118,121],
|
||||
dia: [78,82,76,84,80,75,77],
|
||||
yTicks: [160, 140, 120, 100, 80, 60],
|
||||
xLabels: ['周一','周二','周三','周四','周五','周六','周日'],
|
||||
status: '正常',
|
||||
sysMax: { v:128, hint:'周四' }, sysMin: { v:118, hint:'周六' },
|
||||
diaMax: { v:84, hint:'周四' }, diaMin: { v:75, hint:'周六' }
|
||||
},
|
||||
month: {
|
||||
dateText: '2026年5月',
|
||||
rangeText: '5月1日-5月12日',
|
||||
sys: [120,122,118,125,130,124,121,119,126,122,120,120],
|
||||
dia: [78,80,76,82,86,80,77,75,83,79,78,78],
|
||||
yTicks: [160, 140, 120, 100, 80, 60],
|
||||
xLabels: ['1日','4日','7日','10日','12日'],
|
||||
status: '正常',
|
||||
sysMax: { v:130, hint:'05-05' }, sysMin: { v:118, hint:'05-03' },
|
||||
diaMax: { v:86, hint:'05-05' }, diaMin: { v:75, hint:'05-08' }
|
||||
},
|
||||
year: {
|
||||
dateText: '2026年',
|
||||
rangeText: '1月-5月',
|
||||
sys: [122,120,125,118,121,124,120,122,119,123,121,120],
|
||||
dia: [79,78,82,76,78,80,77,79,76,80,78,78],
|
||||
yTicks: [160, 140, 120, 100, 80, 60],
|
||||
xLabels: ['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'],
|
||||
status: '正常',
|
||||
sysMax: { v:138, hint:'03月' }, sysMin: { v:115, hint:'01月' },
|
||||
diaMax: { v:90, hint:'03月' }, diaMin: { v:72, hint:'01月' }
|
||||
}
|
||||
};
|
||||
|
||||
function renderChart(cfg) {
|
||||
var chartWidth = 330, chartHeight = 208, startY = 22;
|
||||
var len = cfg.sys.length;
|
||||
var stepX = chartWidth / (len - 1 || 1);
|
||||
var maxY = cfg.yTicks[0], minY = cfg.yTicks[cfg.yTicks.length - 1];
|
||||
var range = maxY - minY;
|
||||
|
||||
var grid = document.getElementById('chartGrid');
|
||||
var yAxis = document.getElementById('yAxisLabels');
|
||||
var xAxis = document.getElementById('xAxis');
|
||||
|
||||
grid.innerHTML = '';
|
||||
cfg.yTicks.forEach(function(_, i) {
|
||||
var y = startY + (chartHeight / (cfg.yTicks.length - 1)) * i;
|
||||
grid.innerHTML += '<line x1="0" y1="'+y.toFixed(1)+'" x2="330" y2="'+y.toFixed(1)+'"></line>';
|
||||
});
|
||||
|
||||
yAxis.innerHTML = cfg.yTicks.map(function(tick, i) {
|
||||
return '<span class="y-axis-label" style="top:'+(i * (208/(cfg.yTicks.length-1)))+'px">'+tick+'</span>';
|
||||
}).join('');
|
||||
|
||||
function toPoints(arr) {
|
||||
return arr.map(function(v, i) {
|
||||
var x = i * stepX;
|
||||
var y = startY + chartHeight - ((v - minY) / range) * chartHeight;
|
||||
return { x: x, y: y };
|
||||
});
|
||||
}
|
||||
|
||||
function toPath(pts) {
|
||||
return pts.map(function(p, i) {
|
||||
return (i === 0 ? 'M' : 'L') + p.x.toFixed(1) + ',' + p.y.toFixed(1);
|
||||
}).join(' ');
|
||||
}
|
||||
|
||||
var sysPts = toPoints(cfg.sys);
|
||||
var diaPts = toPoints(cfg.dia);
|
||||
|
||||
document.getElementById('lineSys').setAttribute('d', toPath(sysPts));
|
||||
document.getElementById('lineDia').setAttribute('d', toPath(diaPts));
|
||||
|
||||
var lastSys = sysPts[sysPts.length - 1];
|
||||
var lastDia = diaPts[diaPts.length - 1];
|
||||
document.getElementById('dotSys').setAttribute('cx', lastSys.x.toFixed(1));
|
||||
document.getElementById('dotSys').setAttribute('cy', lastSys.y.toFixed(1));
|
||||
document.getElementById('dotDia').setAttribute('cx', lastDia.x.toFixed(1));
|
||||
document.getElementById('dotDia').setAttribute('cy', lastDia.y.toFixed(1));
|
||||
|
||||
xAxis.className = 'x-axis' + (cfg.xLabels.length > 7 ? ' x-axis--dense' : '');
|
||||
xAxis.style.gridTemplateColumns = 'repeat(' + cfg.xLabels.length + ', 1fr)';
|
||||
xAxis.innerHTML = cfg.xLabels.map(function(l) { return '<span>'+l+'</span>'; }).join('');
|
||||
}
|
||||
|
||||
function renderMode(mode) {
|
||||
var cfg = dataMap[mode];
|
||||
document.getElementById('dateText').textContent = cfg.dateText;
|
||||
document.getElementById('rangeText').textContent = cfg.rangeText;
|
||||
document.getElementById('sysValue').textContent = cfg.sys[cfg.sys.length - 1];
|
||||
document.getElementById('diaValue').textContent = cfg.dia[cfg.dia.length - 1];
|
||||
document.getElementById('statusBadge').textContent = cfg.status;
|
||||
|
||||
document.getElementById('sysMax').textContent = cfg.sysMax.v;
|
||||
document.getElementById('sysMaxHint').textContent = cfg.sysMax.hint;
|
||||
document.getElementById('sysMin').textContent = cfg.sysMin.v;
|
||||
document.getElementById('sysMinHint').textContent = cfg.sysMin.hint;
|
||||
document.getElementById('diaMax').textContent = cfg.diaMax.v;
|
||||
document.getElementById('diaMaxHint').textContent = cfg.diaMax.hint;
|
||||
document.getElementById('diaMin').textContent = cfg.diaMin.v;
|
||||
document.getElementById('diaMinHint').textContent = cfg.diaMin.hint;
|
||||
|
||||
renderChart(cfg);
|
||||
}
|
||||
|
||||
document.querySelectorAll('.time-tab').forEach(function(tab) {
|
||||
tab.onclick = function() {
|
||||
document.querySelectorAll('.time-tab').forEach(function(t) { t.classList.remove('active'); });
|
||||
tab.classList.add('active');
|
||||
renderMode(tab.getAttribute('data-mode'));
|
||||
};
|
||||
});
|
||||
|
||||
renderMode('day');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,245 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>心电图详情 - 健康监测 | 健康长庆原型</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: #1a1a1a; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #333; 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; }
|
||||
.status-bar .time { font-size: 15px; font-weight: 700; color: #fff; }
|
||||
.status-bar .icons { display: flex; gap: 6px; align-items: center; }
|
||||
.nav-bar { height: 44px; display: flex; align-items: center; padding: 0 16px; flex-shrink: 0; border-bottom: 1px solid #333; }
|
||||
.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: #fff; margin-right: 28px; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
|
||||
/* 顶部信息 */
|
||||
.info-section { padding: 24px 20px 16px; }
|
||||
.info-type { font-size: 28px; font-weight: 700; color: #fff; margin-bottom: 4px; }
|
||||
.info-time { font-size: 14px; color: #999; margin-bottom: 16px; }
|
||||
.info-hr { display: flex; align-items: center; gap: 6px; font-size: 15px; color: #ddd; }
|
||||
.info-hr__icon { color: #ff5a6e; font-size: 18px; }
|
||||
.info-hr__value { font-size: 32px; font-weight: 700; color: #fff; }
|
||||
.info-hr__unit { font-size: 14px; color: #999; }
|
||||
|
||||
/* 心电图区域 */
|
||||
.ecg-section { padding: 16px 0; }
|
||||
.ecg-hint { padding: 0 20px 8px; font-size: 12px; color: #666; display: flex; align-items: center; gap: 4px; }
|
||||
.ecg-scroll-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
|
||||
.ecg-scroll-wrap::-webkit-scrollbar { display: none; }
|
||||
.ecg-canvas { width: 1200px; height: 200px; padding: 0 20px; }
|
||||
.ecg-canvas svg { width: 100%; height: 100%; display: block; }
|
||||
.ecg-grid line { stroke: #2a2a2a; stroke-width: 0.5; }
|
||||
.ecg-grid line.major { stroke: #3a3a3a; stroke-width: 1; }
|
||||
.ecg-line { fill: none; stroke: #ff5a6e; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
|
||||
|
||||
/* 时间刻度 */
|
||||
.ecg-time-axis { width: 1200px; padding: 6px 20px 0; display: flex; justify-content: space-between; }
|
||||
.ecg-time-axis span { font-size: 10px; color: #666; }
|
||||
|
||||
/* 详细信息卡片 */
|
||||
.detail-card { margin: 16px 16px 0; background: #262626; border-radius: 16px; padding: 16px; }
|
||||
.detail-row { display: flex; align-items: center; justify-content: space-between; padding: 12px 0; border-bottom: 1px solid #333; }
|
||||
.detail-row:last-child { border-bottom: none; }
|
||||
.detail-row__label { font-size: 14px; color: #999; }
|
||||
.detail-row__value { font-size: 14px; color: #fff; font-weight: 500; }
|
||||
|
||||
/* 状态标签 */
|
||||
.status-tag { display: inline-flex; align-items: center; padding: 4px 10px; border-radius: 12px; font-size: 12px; font-weight: 600; }
|
||||
.status-tag--normal { background: rgba(82,196,26,0.15); color: #52c41a; }
|
||||
.status-tag--warning { background: rgba(250,173,20,0.15); color: #faad14; }
|
||||
.status-tag--danger { background: rgba(255,77,79,0.15); color: #ff4d4f; }
|
||||
|
||||
.bottom-safe { height: 20px; flex-shrink: 0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
<div class="status-bar">
|
||||
<span class="time">9:41</span>
|
||||
<div class="icons">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2"><path d="M1 6l5 5 5-5"/><path d="M4 9l3 3 3-3" opacity="0.5"/></svg>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2"><rect x="1" y="6" width="18" height="12" rx="2"/><path d="M21 10v4"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-bar">
|
||||
<div class="nav-back" onclick="location.href='ecg.html'">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round"><path d="M15 19l-7-7 7-7"/></svg>
|
||||
</div>
|
||||
<div class="nav-title">心电图详情</div>
|
||||
</div>
|
||||
|
||||
<div class="scroll-content">
|
||||
<!-- 顶部信息 -->
|
||||
<div class="info-section">
|
||||
<div class="info-type" id="infoType">窦性心律</div>
|
||||
<div class="info-time" id="infoTime">2026年5月12日 13:58</div>
|
||||
<div class="info-hr">
|
||||
<span class="info-hr__icon">❤️</span>
|
||||
<span>平均心率</span>
|
||||
<span class="info-hr__value" id="infoHr">82</span>
|
||||
<span class="info-hr__unit">次/分</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 心电图横向滑动区域 -->
|
||||
<div class="ecg-section">
|
||||
<div class="ecg-hint">
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#666" stroke-width="2"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
|
||||
左右滑动查看完整心电图
|
||||
</div>
|
||||
<div class="ecg-scroll-wrap">
|
||||
<div class="ecg-canvas">
|
||||
<svg viewBox="0 0 1160 200" preserveAspectRatio="none" id="ecgSvg">
|
||||
<g class="ecg-grid" id="ecgGrid"></g>
|
||||
<path class="ecg-line" id="ecgLine"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ecg-time-axis" id="ecgTimeAxis"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 详细信息 -->
|
||||
<div class="detail-card">
|
||||
<div class="detail-row">
|
||||
<span class="detail-row__label">分类结果</span>
|
||||
<span class="detail-row__value"><span class="status-tag status-tag--normal" id="statusTag">窦性心律</span></span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-row__label">开始时间</span>
|
||||
<span class="detail-row__value" id="startTime">13:58:00</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-row__label">结束时间</span>
|
||||
<span class="detail-row__value" id="endTime">13:58:30</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-row__label">记录时长</span>
|
||||
<span class="detail-row__value" id="duration">30秒</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-row__label">平均心率</span>
|
||||
<span class="detail-row__value" id="detailHr">82 次/分</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bottom-safe"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 从URL参数读取数据
|
||||
var params = new URLSearchParams(window.location.search);
|
||||
var type = params.get('type') || 'sinus';
|
||||
var label = params.get('label') || '窦性心律';
|
||||
var time = params.get('time') || '今天 13:58';
|
||||
var hr = parseInt(params.get('hr')) || 82;
|
||||
|
||||
// 填充页面信息
|
||||
document.getElementById('infoType').textContent = label;
|
||||
document.getElementById('infoTime').textContent = time;
|
||||
document.getElementById('infoHr').textContent = hr;
|
||||
document.getElementById('detailHr').textContent = hr + ' 次/分';
|
||||
document.getElementById('statusTag').textContent = label;
|
||||
|
||||
// 状态标签颜色
|
||||
var tagEl = document.getElementById('statusTag');
|
||||
if (type === 'afib') { tagEl.className = 'status-tag status-tag--danger'; }
|
||||
else if (type === 'highlow' || type === 'uncertain') { tagEl.className = 'status-tag status-tag--warning'; }
|
||||
|
||||
// 模拟开始/结束时间
|
||||
var timeMatch = time.match(/(\d+):(\d+)/);
|
||||
if (timeMatch) {
|
||||
var h = timeMatch[1], m = timeMatch[2];
|
||||
document.getElementById('startTime').textContent = h + ':' + m + ':00';
|
||||
document.getElementById('endTime').textContent = h + ':' + m + ':30';
|
||||
}
|
||||
|
||||
// 生成网格
|
||||
var gridHtml = '';
|
||||
for (var x = 0; x <= 1160; x += 58) {
|
||||
gridHtml += '<line x1="'+x+'" y1="0" x2="'+x+'" y2="200"' + (x % 232 === 0 ? ' class="major"' : '') + '/>';
|
||||
}
|
||||
for (var y = 0; y <= 200; y += 25) {
|
||||
gridHtml += '<line x1="0" y1="'+y+'" x2="1160" y2="'+y+'"' + (y % 50 === 0 ? ' class="major"' : '') + '/>';
|
||||
}
|
||||
document.getElementById('ecgGrid').innerHTML = gridHtml;
|
||||
|
||||
// 生成长心电图波形
|
||||
function generateLongEcg(type, hr) {
|
||||
var w = 1160, h = 200, cy = h / 2;
|
||||
var points = [];
|
||||
var cycles = Math.round(hr / 2.5);
|
||||
|
||||
if (type === 'sinus') {
|
||||
for (var i = 0; i <= w; i += 1.5) {
|
||||
var phase = (i / w) * cycles * Math.PI * 2;
|
||||
var seg = phase % (Math.PI * 2);
|
||||
var y = cy;
|
||||
if (seg > 2.7 && seg < 2.9) y = cy + 8;
|
||||
else if (seg > 2.9 && seg < 3.05) y = cy - 60;
|
||||
else if (seg > 3.05 && seg < 3.2) y = cy + 20;
|
||||
else if (seg > 3.2 && seg < 3.5) y = cy - 3;
|
||||
else if (seg > 4.0 && seg < 4.4) y = cy + 10;
|
||||
else y = cy + Math.sin(seg * 0.3) * 1.5;
|
||||
points.push(i.toFixed(1) + ',' + y.toFixed(1));
|
||||
}
|
||||
} else if (type === 'afib') {
|
||||
for (var i = 0; i <= w; i += 1.5) {
|
||||
var phase = (i / w) * cycles * Math.PI * 2;
|
||||
var seg = phase % (Math.PI * 2);
|
||||
var jitter = (Math.random() - 0.5) * 8;
|
||||
var y = cy;
|
||||
if (seg > 2.6 && seg < 2.9) y = cy - 50 + jitter;
|
||||
else if (seg > 2.9 && seg < 3.1) y = cy + 18 + jitter;
|
||||
else y = cy + jitter + Math.sin(seg * 2) * 4;
|
||||
points.push(i.toFixed(1) + ',' + y.toFixed(1));
|
||||
}
|
||||
} else if (type === 'highlow') {
|
||||
for (var i = 0; i <= w; i += 1.5) {
|
||||
var phase = (i / w) * cycles * Math.PI * 2;
|
||||
var seg = phase % (Math.PI * 2);
|
||||
var y = cy;
|
||||
if (seg > 2.7 && seg < 2.9) y = cy + 6;
|
||||
else if (seg > 2.9 && seg < 3.05) y = cy - 70;
|
||||
else if (seg > 3.05 && seg < 3.2) y = cy + 25;
|
||||
else if (seg > 3.2 && seg < 3.5) y = cy - 3;
|
||||
else y = cy + Math.sin(seg * 0.3) * 2;
|
||||
points.push(i.toFixed(1) + ',' + y.toFixed(1));
|
||||
}
|
||||
} else {
|
||||
for (var i = 0; i <= w; i += 1.5) {
|
||||
var phase = (i / w) * cycles * Math.PI * 2;
|
||||
var seg = phase % (Math.PI * 2);
|
||||
var noise = Math.sin(i * 0.08) * 5;
|
||||
var y = cy;
|
||||
if (i > w * 0.5 && i < w * 0.7) {
|
||||
if (seg > 2.5 && seg < 3.2) y = cy - 65;
|
||||
else if (seg > 3.2 && seg < 3.6) y = cy + 20;
|
||||
else y = cy + noise + Math.sin(seg) * 6;
|
||||
} else {
|
||||
if (seg > 2.8 && seg < 3.0) y = cy - 40;
|
||||
else if (seg > 3.0 && seg < 3.15) y = cy + 12;
|
||||
else y = cy + noise * 0.5;
|
||||
}
|
||||
points.push(i.toFixed(1) + ',' + y.toFixed(1));
|
||||
}
|
||||
}
|
||||
return 'M' + points.join(' L');
|
||||
}
|
||||
|
||||
document.getElementById('ecgLine').setAttribute('d', generateLongEcg(type, hr));
|
||||
|
||||
// 时间轴刻度
|
||||
var axisHtml = '';
|
||||
for (var s = 0; s <= 30; s += 5) {
|
||||
axisHtml += '<span>' + s + 's</span>';
|
||||
}
|
||||
document.getElementById('ecgTimeAxis').innerHTML = axisHtml;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,209 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>心电图 - 健康监测 | 健康长庆原型</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; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
|
||||
/* 统计筛选 */
|
||||
.filter-tabs { display: flex; gap: 8px; padding: 12px 12px 8px; overflow-x: auto; flex-wrap: nowrap; }
|
||||
.filter-tabs::-webkit-scrollbar { display: none; }
|
||||
.filter-tab { flex-shrink: 0; padding: 6px 12px; border-radius: 16px; font-size: 12px; color: #666; background: #fff; border: 1px solid #e8e8e8; cursor: pointer; white-space: nowrap; transition: all 0.2s; }
|
||||
.filter-tab.active { background: #1a1a1a; color: #fff; border-color: #1a1a1a; }
|
||||
.filter-tab__count { margin-left: 4px; font-weight: 600; }
|
||||
|
||||
/* ECG 卡片 */
|
||||
.ecg-list { padding: 0 12px 12px; display: flex; flex-direction: column; gap: 10px; }
|
||||
.ecg-card { background: #1a1a1a; border-radius: 16px; padding: 16px; cursor: pointer; transition: transform 0.15s; }
|
||||
.ecg-card:active { transform: scale(0.98); }
|
||||
.ecg-card__header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
|
||||
.ecg-card__type { font-size: 16px; font-weight: 700; color: #fff; }
|
||||
.ecg-card__time { font-size: 12px; color: #999; display: flex; align-items: center; gap: 4px; }
|
||||
.ecg-card__arrow { color: #666; }
|
||||
.ecg-card__hr { display: flex; align-items: center; gap: 4px; font-size: 13px; color: #ccc; margin-bottom: 10px; }
|
||||
.ecg-card__hr-icon { color: #ff5a6e; }
|
||||
.ecg-card__chart { position: relative; height: 100px; border: 1px solid #333; border-radius: 8px; overflow: hidden; }
|
||||
.ecg-card__chart svg { width: 100%; height: 100%; display: block; }
|
||||
.ecg-card__grid line { stroke: #333; stroke-width: 0.5; }
|
||||
.ecg-card__line { fill: none; stroke: #ff5a6e; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
|
||||
|
||||
/* 底部 */
|
||||
.bottom-safe { height: 20px; flex-shrink: 0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
<div class="status-bar">
|
||||
<span class="time">9:41</span>
|
||||
<div class="icons">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2"><path d="M1 6l5 5 5-5"/><path d="M4 9l3 3 3-3" opacity="0.5"/></svg>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2"><rect x="1" y="6" width="18" height="12" rx="2"/><path d="M21 10v4"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-bar">
|
||||
<div class="nav-back" onclick="location.href='index.html'">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2" stroke-linecap="round"><path d="M15 19l-7-7 7-7"/></svg>
|
||||
</div>
|
||||
<div class="nav-title">心电图</div>
|
||||
</div>
|
||||
|
||||
<div class="scroll-content">
|
||||
<!-- 筛选标签 -->
|
||||
<div class="filter-tabs">
|
||||
<div class="filter-tab active" data-filter="all">所有数据<span class="filter-tab__count">12</span></div>
|
||||
<div class="filter-tab" data-filter="sinus">窦性心律<span class="filter-tab__count">8</span></div>
|
||||
<div class="filter-tab" data-filter="afib">房颤<span class="filter-tab__count">1</span></div>
|
||||
<div class="filter-tab" data-filter="highlow">高低心率<span class="filter-tab__count">1</span></div>
|
||||
<div class="filter-tab" data-filter="uncertain">不确定<span class="filter-tab__count">2</span></div>
|
||||
</div>
|
||||
|
||||
<!-- ECG 记录列表 -->
|
||||
<div class="ecg-list" id="ecgList"></div>
|
||||
<div class="bottom-safe"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var ecgData = [
|
||||
{ type: 'sinus', label: '窦性心律', time: '今天 13:58', hr: 82 },
|
||||
{ type: 'sinus', label: '窦性心律', time: '今天 09:20', hr: 75 },
|
||||
{ type: 'afib', label: '房颤', time: '05/11 22:30', hr: 112 },
|
||||
{ type: 'sinus', label: '窦性心律', time: '05/11 14:10', hr: 78 },
|
||||
{ type: 'highlow', label: '高心率', time: '05/10 16:45', hr: 135 },
|
||||
{ type: 'uncertain', label: '不确定', time: '05/10 15:14', hr: 100 },
|
||||
{ type: 'sinus', label: '窦性心律', time: '05/09 08:30', hr: 68 },
|
||||
{ type: 'sinus', label: '窦性心律', time: '05/08 20:15', hr: 72 },
|
||||
{ type: 'uncertain', label: '不确定', time: '05/07 11:40', hr: 95 },
|
||||
{ type: 'sinus', label: '窦性心律', time: '05/06 09:00', hr: 70 },
|
||||
{ type: 'sinus', label: '窦性心律', time: '05/05 14:22', hr: 76 },
|
||||
{ type: 'sinus', label: '窦性心律', time: '05/04 08:10', hr: 65 }
|
||||
];
|
||||
|
||||
// 生成不同类型的ECG波形路径
|
||||
function generateEcgPath(type, hr) {
|
||||
var w = 320, h = 80, cy = h / 2;
|
||||
var points = [];
|
||||
var cycles, amp;
|
||||
|
||||
if (type === 'sinus') {
|
||||
cycles = 6;
|
||||
amp = 28;
|
||||
for (var i = 0; i <= w; i += 2) {
|
||||
var phase = (i / w) * cycles * Math.PI * 2;
|
||||
var seg = phase % (Math.PI * 2);
|
||||
var y = cy;
|
||||
if (seg > 2.8 && seg < 3.0) y = cy - amp;
|
||||
else if (seg > 3.0 && seg < 3.2) y = cy + amp * 0.4;
|
||||
else if (seg > 3.2 && seg < 3.5) y = cy - amp * 0.08;
|
||||
else y = cy + Math.sin(seg * 0.5) * 2;
|
||||
points.push(i + ',' + y.toFixed(1));
|
||||
}
|
||||
} else if (type === 'afib') {
|
||||
cycles = 8;
|
||||
for (var i = 0; i <= w; i += 2) {
|
||||
var phase = (i / w) * cycles * Math.PI * 2;
|
||||
var seg = phase % (Math.PI * 2);
|
||||
var y = cy;
|
||||
var jitter = (Math.random() - 0.5) * 6;
|
||||
if (seg > 2.5 && seg < 2.8) y = cy - 22 + jitter;
|
||||
else if (seg > 2.8 && seg < 3.1) y = cy + 12 + jitter;
|
||||
else y = cy + jitter * 0.8 + Math.sin(seg) * 3;
|
||||
points.push(i + ',' + y.toFixed(1));
|
||||
}
|
||||
} else if (type === 'highlow') {
|
||||
cycles = 9;
|
||||
amp = 32;
|
||||
for (var i = 0; i <= w; i += 2) {
|
||||
var phase = (i / w) * cycles * Math.PI * 2;
|
||||
var seg = phase % (Math.PI * 2);
|
||||
var y = cy;
|
||||
if (seg > 2.6 && seg < 2.9) y = cy - amp;
|
||||
else if (seg > 2.9 && seg < 3.1) y = cy + amp * 0.5;
|
||||
else y = cy + Math.sin(seg * 0.5) * 2;
|
||||
points.push(i + ',' + y.toFixed(1));
|
||||
}
|
||||
} else {
|
||||
// uncertain - 不规则波形
|
||||
cycles = 5;
|
||||
for (var i = 0; i <= w; i += 2) {
|
||||
var phase = (i / w) * cycles * Math.PI * 2;
|
||||
var seg = phase % (Math.PI * 2);
|
||||
var y = cy;
|
||||
var noise = Math.sin(i * 0.15) * 4;
|
||||
if (i > w * 0.55) {
|
||||
// 后半段异常
|
||||
if (seg > 2.5 && seg < 3.2) y = cy - 35;
|
||||
else if (seg > 3.2 && seg < 3.8) y = cy + 15;
|
||||
else y = cy + noise + Math.sin(seg) * 5;
|
||||
} else {
|
||||
if (seg > 2.8 && seg < 3.0) y = cy - 20;
|
||||
else if (seg > 3.0 && seg < 3.2) y = cy + 8;
|
||||
else y = cy + noise;
|
||||
}
|
||||
points.push(i + ',' + y.toFixed(1));
|
||||
}
|
||||
}
|
||||
return 'M' + points.join(' L');
|
||||
}
|
||||
|
||||
function generateGridLines() {
|
||||
var lines = '';
|
||||
for (var x = 0; x <= 320; x += 64) {
|
||||
lines += '<line x1="'+x+'" y1="0" x2="'+x+'" y2="80"></line>';
|
||||
}
|
||||
for (var y = 0; y <= 80; y += 20) {
|
||||
lines += '<line x1="0" y1="'+y+'" x2="320" y2="'+y+'"></line>';
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
function renderList(filter) {
|
||||
var list = document.getElementById('ecgList');
|
||||
var filtered = filter === 'all' ? ecgData : ecgData.filter(function(d) { return d.type === filter; });
|
||||
var gridLines = generateGridLines();
|
||||
|
||||
list.innerHTML = filtered.map(function(item) {
|
||||
var path = generateEcgPath(item.type, item.hr);
|
||||
var detailUrl = 'ecg-detail.html?type=' + encodeURIComponent(item.type) + '&label=' + encodeURIComponent(item.label) + '&time=' + encodeURIComponent(item.time) + '&hr=' + item.hr;
|
||||
return '<div class="ecg-card" onclick="location.href=\'' + detailUrl + '\'">' +
|
||||
'<div class="ecg-card__header">' +
|
||||
'<span class="ecg-card__type">' + item.label + '</span>' +
|
||||
'<span class="ecg-card__time">' + item.time + ' <span class="ecg-card__arrow">›</span></span>' +
|
||||
'</div>' +
|
||||
'<div class="ecg-card__hr">' +
|
||||
'<span class="ecg-card__hr-icon">❤️</span> 平均' + item.hr + '次/分' +
|
||||
'</div>' +
|
||||
'<div class="ecg-card__chart">' +
|
||||
'<svg viewBox="0 0 320 80" preserveAspectRatio="none">' +
|
||||
'<g class="ecg-card__grid">' + gridLines + '</g>' +
|
||||
'<path class="ecg-card__line" d="' + path + '"/>' +
|
||||
'</svg>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
}).join('');
|
||||
}
|
||||
|
||||
document.querySelectorAll('.filter-tab').forEach(function(tab) {
|
||||
tab.onclick = function() {
|
||||
document.querySelectorAll('.filter-tab').forEach(function(t) { t.classList.remove('active'); });
|
||||
tab.classList.add('active');
|
||||
renderList(tab.getAttribute('data-filter'));
|
||||
};
|
||||
});
|
||||
|
||||
renderList('all');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
+98
-103
@@ -190,7 +190,7 @@
|
||||
background: #ffffff;
|
||||
border-radius: 16px;
|
||||
padding: 6px;
|
||||
margin-bottom: 12px;
|
||||
margin-bottom: 0;
|
||||
display: flex;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
@@ -207,13 +207,41 @@
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
/* 激活状态的 Tab */
|
||||
.tab-item.active {
|
||||
background: #fa8c16;
|
||||
color: #ffffff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 日期切换器 */
|
||||
.date-switcher {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 16px;
|
||||
padding: 12px 0;
|
||||
}
|
||||
|
||||
.date-arrow {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 50%;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,0.08);
|
||||
}
|
||||
|
||||
.date-arrow:active { background: #f5f5f5; }
|
||||
|
||||
.date-text {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* ===== 锻炼记录列表 ===== */
|
||||
.section-title {
|
||||
font-size: 15px;
|
||||
@@ -456,42 +484,46 @@
|
||||
<!-- 滚动内容区 -->
|
||||
<div class="scroll-content">
|
||||
|
||||
<!-- ① 本周概览卡片 -->
|
||||
<div class="overview-card">
|
||||
<div class="card-title">本周概览</div>
|
||||
<!-- ① 时间维度 Tab + 日期切换 -->
|
||||
<div class="tab-bar">
|
||||
<div class="tab-item active" onclick="switchTab(this, 'week')">周</div>
|
||||
<div class="tab-item" onclick="switchTab(this, 'month')">月</div>
|
||||
</div>
|
||||
<div class="date-switcher">
|
||||
<div class="date-arrow" onclick="switchDate(-1)">
|
||||
<svg width="7" height="12" viewBox="0 0 7 12" fill="none"><path d="M6 1L1 6l5 5" stroke="#666" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
</div>
|
||||
<span class="date-text" id="dateText">5月5日 - 5月11日</span>
|
||||
<div class="date-arrow" onclick="switchDate(1)">
|
||||
<svg width="7" height="12" viewBox="0 0 7 12" fill="none"><path d="M1 1l5 5-5 5" stroke="#666" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ② 概览卡片 -->
|
||||
<div class="overview-card" id="overviewCard">
|
||||
<div class="card-title" id="overviewTitle">本周概览</div>
|
||||
<div class="overview-stats">
|
||||
<!-- 锻炼次数 -->
|
||||
<div class="stat-item">
|
||||
<div class="stat-value">3<span class="stat-unit">次</span></div>
|
||||
<div class="stat-value" id="statCount">3<span class="stat-unit">次</span></div>
|
||||
<div class="stat-label">锻炼次数</div>
|
||||
</div>
|
||||
<!-- 累计时长 -->
|
||||
<div class="stat-item">
|
||||
<div class="stat-value">2h<span class="stat-unit">15min</span></div>
|
||||
<div class="stat-value" id="statDuration">2h<span class="stat-unit">15min</span></div>
|
||||
<div class="stat-label">累计时长</div>
|
||||
</div>
|
||||
<!-- 消耗热量 -->
|
||||
<div class="stat-item">
|
||||
<div class="stat-value">680<span class="stat-unit">kcal</span></div>
|
||||
<div class="stat-value" id="statCalorie">680<span class="stat-unit">kcal</span></div>
|
||||
<div class="stat-label">消耗热量</div>
|
||||
</div>
|
||||
<!-- 运动距离 -->
|
||||
<div class="stat-item">
|
||||
<div class="stat-value">4.2<span class="stat-unit">km</span></div>
|
||||
<div class="stat-value" id="statDistance">4.2<span class="stat-unit">km</span></div>
|
||||
<div class="stat-label">运动距离</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ② 时间维度 Tab:周 / 月 切换 -->
|
||||
<div class="tab-bar">
|
||||
<!-- 默认选中"周" -->
|
||||
<div class="tab-item active" onclick="switchTab(this, 'week')">周</div>
|
||||
<div class="tab-item" onclick="switchTab(this, 'month')">月</div>
|
||||
</div>
|
||||
|
||||
<!-- ③ 本周锻炼记录列表 -->
|
||||
<div class="section-title">本周锻炼记录</div>
|
||||
<!-- ③ 锻炼记录列表 -->
|
||||
<div class="section-title" id="sectionTitle">本周锻炼记录</div>
|
||||
|
||||
<!-- 记录 a:户外跑步 -->
|
||||
<div class="exercise-card">
|
||||
@@ -516,11 +548,6 @@
|
||||
<div class="metric-value">320<span class="metric-unit">kcal</span></div>
|
||||
<div class="metric-label">消耗</div>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<!-- 心率用橙色高亮 -->
|
||||
<div class="metric-value heart-rate">138<span class="metric-unit">bpm</span></div>
|
||||
<div class="metric-label">平均心率</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -546,10 +573,6 @@
|
||||
<div class="metric-value">240<span class="metric-unit">kcal</span></div>
|
||||
<div class="metric-label">消耗</div>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<div class="metric-value heart-rate">125<span class="metric-unit">bpm</span></div>
|
||||
<div class="metric-label">平均心率</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -575,71 +598,6 @@
|
||||
<div class="metric-value">280<span class="metric-unit">kcal</span></div>
|
||||
<div class="metric-label">消耗</div>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<div class="metric-value heart-rate">132<span class="metric-unit">bpm</span></div>
|
||||
<div class="metric-label">平均心率</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ④ 锻炼趋势:近4周柱状图 -->
|
||||
<div class="trend-card">
|
||||
<div class="card-title">锻炼趋势</div>
|
||||
<!-- 柱状图:数据 [2次, 4次, 3次, 3次],最大值4次对应100px高度 -->
|
||||
<div class="bar-chart">
|
||||
<!-- 第1周:2次,高度 = 2/4 * 80 = 40px -->
|
||||
<div class="bar-group">
|
||||
<span class="bar-value-label">2</span>
|
||||
<div class="bar" style="height: 40px;"></div>
|
||||
</div>
|
||||
<!-- 第2周:4次,高度 = 4/4 * 80 = 80px -->
|
||||
<div class="bar-group">
|
||||
<span class="bar-value-label">4</span>
|
||||
<div class="bar" style="height: 80px;"></div>
|
||||
</div>
|
||||
<!-- 第3周:3次,高度 = 3/4 * 80 = 60px -->
|
||||
<div class="bar-group">
|
||||
<span class="bar-value-label">3</span>
|
||||
<div class="bar" style="height: 60px;"></div>
|
||||
</div>
|
||||
<!-- 第4周(本周):3次,高亮橙色 -->
|
||||
<div class="bar-group">
|
||||
<span class="bar-value-label">3</span>
|
||||
<div class="bar current" style="height: 60px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- X轴标签 -->
|
||||
<div class="bar-x-labels">
|
||||
<span class="bar-x-label">第1周</span>
|
||||
<span class="bar-x-label">第2周</span>
|
||||
<span class="bar-x-label">第3周</span>
|
||||
<span class="bar-x-label current">本周</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ⑤ 统计摘要:本月累计 / 总时长 / 总消耗 -->
|
||||
<div class="section-title">本月统计</div>
|
||||
<div class="summary-grid">
|
||||
<!-- 本月累计次数 -->
|
||||
<div class="summary-card">
|
||||
<div class="summary-icon">🏅</div>
|
||||
<div class="summary-value">12</div>
|
||||
<div class="summary-sub">次</div>
|
||||
<div class="summary-label">本月累计</div>
|
||||
</div>
|
||||
<!-- 总时长 -->
|
||||
<div class="summary-card">
|
||||
<div class="summary-icon">⏱️</div>
|
||||
<div class="summary-value">8h</div>
|
||||
<div class="summary-sub">30min</div>
|
||||
<div class="summary-label">总时长</div>
|
||||
</div>
|
||||
<!-- 总消耗 -->
|
||||
<div class="summary-card">
|
||||
<div class="summary-icon">🔥</div>
|
||||
<div class="summary-value">2,450</div>
|
||||
<div class="summary-sub">kcal</div>
|
||||
<div class="summary-label">总消耗</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -651,19 +609,56 @@
|
||||
</div><!-- /phone-shell -->
|
||||
|
||||
<script>
|
||||
/**
|
||||
* Tab 切换:周 / 月
|
||||
* 切换激活样式,实际数据切换可在此扩展
|
||||
*/
|
||||
var currentMode = 'week';
|
||||
var weekOffset = 0;
|
||||
var monthOffset = 0;
|
||||
|
||||
var weekData = [
|
||||
{ date: '5月5日 - 5月11日', count: '3', duration: '2h<span class="stat-unit">15min</span>', calorie: '680', distance: '4.2' },
|
||||
{ date: '4月28日 - 5月4日', count: '4', duration: '3h<span class="stat-unit">10min</span>', calorie: '920', distance: '6.8' },
|
||||
{ date: '4月21日 - 4月27日', count: '2', duration: '1h<span class="stat-unit">30min</span>', calorie: '450', distance: '3.1' }
|
||||
];
|
||||
|
||||
var monthData = [
|
||||
{ date: '2026年5月', count: '7', duration: '5h<span class="stat-unit">45min</span>', calorie: '1,680', distance: '12.5' },
|
||||
{ date: '2026年4月', count: '12', duration: '8h<span class="stat-unit">30min</span>', calorie: '2,450', distance: '18.2' },
|
||||
{ date: '2026年3月', count: '10', duration: '7h<span class="stat-unit">20min</span>', calorie: '2,100', distance: '15.6' }
|
||||
];
|
||||
|
||||
function renderView() {
|
||||
var data = currentMode === 'week' ? weekData : monthData;
|
||||
var offset = currentMode === 'week' ? weekOffset : monthOffset;
|
||||
var idx = Math.min(Math.abs(offset), data.length - 1);
|
||||
var item = data[idx];
|
||||
|
||||
document.getElementById('dateText').textContent = item.date;
|
||||
document.getElementById('overviewTitle').textContent = currentMode === 'week' ? '本周概览' : '本月概览';
|
||||
document.getElementById('statCount').innerHTML = item.count + '<span class="stat-unit">次</span>';
|
||||
document.getElementById('statDuration').innerHTML = item.duration;
|
||||
document.getElementById('statCalorie').innerHTML = item.calorie + '<span class="stat-unit">kcal</span>';
|
||||
document.getElementById('statDistance').innerHTML = item.distance + '<span class="stat-unit">km</span>';
|
||||
document.getElementById('sectionTitle').textContent = currentMode === 'week' ? '本周锻炼记录' : '本月锻炼记录';
|
||||
}
|
||||
|
||||
function switchTab(el, period) {
|
||||
// 移除所有 tab 的激活状态
|
||||
document.querySelectorAll('.tab-item').forEach(function(item) {
|
||||
item.classList.remove('active');
|
||||
});
|
||||
// 激活当前点击的 tab
|
||||
el.classList.add('active');
|
||||
// TODO: 根据 period 切换对应数据('week' | 'month')
|
||||
currentMode = period;
|
||||
renderView();
|
||||
}
|
||||
|
||||
function switchDate(dir) {
|
||||
if (currentMode === 'week') {
|
||||
weekOffset = Math.max(Math.min(weekOffset + dir, 0), -(weekData.length - 1));
|
||||
} else {
|
||||
monthOffset = Math.max(Math.min(monthOffset + dir, 0), -(monthData.length - 1));
|
||||
}
|
||||
renderView();
|
||||
}
|
||||
|
||||
renderView();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
+1
@@ -362,6 +362,7 @@ body {
|
||||
.filter-btn-confirm:active {
|
||||
background: #ff5a7a;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
@@ -0,0 +1,295 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>健康监测 - 员工端 | 健康长庆原型</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; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
/* 设备状态 */
|
||||
.device-bar { margin: 12px 12px 0; background: linear-gradient(135deg, #13c2c2 0%, #0d9b9b 100%); border-radius: 12px; padding: 14px 16px; display: flex; align-items: center; gap: 12px; color: #fff; }
|
||||
.device-icon { width: 44px; height: 44px; background: rgba(255,255,255,0.2); border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 24px; flex-shrink: 0; }
|
||||
.device-info { flex: 1; }
|
||||
.device-name { font-size: 15px; font-weight: 600; }
|
||||
.device-meta { font-size: 12px; opacity: 0.85; margin-top: 2px; }
|
||||
.device-battery { display: flex; align-items: center; gap: 4px; font-size: 13px; font-weight: 600; }
|
||||
.battery-icon { width: 22px; height: 12px; border: 1.5px solid #fff; border-radius: 2px; position: relative; }
|
||||
.battery-icon::after { content: ''; position: absolute; right: -4px; top: 2.5px; width: 2px; height: 5px; background: #fff; border-radius: 0 1px 1px 0; }
|
||||
.battery-fill { height: 100%; background: #fff; border-radius: 1px; }
|
||||
/* 监测卡片网格 */
|
||||
.monitor-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; padding: 12px; }
|
||||
.monitor-card { background: #fff; border-radius: 12px; padding: 16px; cursor: pointer; position: relative; transition: transform 0.15s; }
|
||||
.monitor-card:active { transform: scale(0.97); }
|
||||
.monitor-card--full { grid-column: 1 / -1; }
|
||||
.card-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
|
||||
.card-header__left { display: flex; align-items: center; min-width: 0; flex: 1; }
|
||||
.card-header__right { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
|
||||
.card-icon { width: 32px; height: 32px; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 18px; flex-shrink: 0; }
|
||||
.card-label { font-size: 13px; color: #666; margin-left: 8px; flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.card-meta { font-size: 12px; color: #999; }
|
||||
.card-alert-badge { width: 18px; height: 18px; background: #ff4d4f; border-radius: 50%; font-size: 10px; color: #fff; display: flex; align-items: center; justify-content: center; font-weight: 700; }
|
||||
.card-arrow { width: 16px; height: 16px; display: flex; align-items: center; justify-content: center; }
|
||||
.card-arrow svg { width: 16px; height: 16px; display: block; }
|
||||
.card-sync { font-size: 10px; color: #bbb; margin-top: 8px; }
|
||||
.card-value { font-size: 28px; font-weight: 800; color: #1a1a1a; line-height: 1.1; }
|
||||
.card-unit { font-size: 13px; color: #999; font-weight: 400; margin-left: 2px; }
|
||||
.card-status { display: inline-block; font-size: 11px; padding: 2px 8px; border-radius: 4px; margin-top: 6px; }
|
||||
.card-status--normal { color: #52c41a; background: #f6ffed; }
|
||||
.card-status--warn { color: #faad14; background: #fffbe6; }
|
||||
.card-status--danger { color: #ff4d4f; background: #fff2f0; }
|
||||
.card-sub { font-size: 11px; color: #999; margin-top: 6px; }
|
||||
.card-progress { margin-top: 8px; }
|
||||
.card-progress__bar { height: 6px; background: #f0f0f0; border-radius: 3px; overflow: hidden; }
|
||||
.card-progress__fill { height: 100%; border-radius: 3px; transition: width 0.3s; }
|
||||
.card-progress__text { font-size: 11px; color: #999; margin-top: 4px; }
|
||||
/* 睡眠分段 */
|
||||
.sleep-segments { display: flex; gap: 4px; margin-top: 8px; height: 6px; border-radius: 3px; overflow: hidden; }
|
||||
.sleep-seg { height: 100%; border-radius: 3px; }
|
||||
.sleep-seg--deep { background: #1890ff; }
|
||||
.sleep-seg--light { background: #91d5ff; }
|
||||
.sleep-seg--rem { background: #b37feb; }
|
||||
.sleep-seg--awake { background: #ffd591; }
|
||||
.sleep-legend { display: flex; gap: 8px; margin-top: 6px; flex-wrap: wrap; }
|
||||
.sleep-legend__item { display: flex; align-items: center; gap: 3px; font-size: 10px; color: #999; }
|
||||
.sleep-legend__dot { width: 6px; height: 6px; border-radius: 50%; }
|
||||
/* 锻炼卡片 */
|
||||
.exercise-stats { display: flex; gap: 12px; margin-top: 8px; }
|
||||
.exercise-stat { flex: 1; text-align: center; background: #f5f7fa; border-radius: 8px; padding: 8px 4px; }
|
||||
.exercise-stat__val { font-size: 16px; font-weight: 700; color: #1a1a1a; }
|
||||
.exercise-stat__label { font-size: 10px; color: #999; margin-top: 2px; }
|
||||
/* 预警入口 */
|
||||
.card-alert-link { display: flex; align-items: center; justify-content: center; gap: 4px; font-size: 11px; color: #ff4d4f; margin-top: 8px; padding-top: 8px; border-top: 1px solid #f5f5f5; cursor: pointer; }
|
||||
/* 底部安全区 */
|
||||
.bottom-safe { height: 20px; flex-shrink: 0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
<div class="status-bar">
|
||||
<span class="time">9:41</span>
|
||||
<div class="icons">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2"><path d="M1 6l5 5 5-5"/><path d="M4 9l3 3 3-3" opacity="0.5"/></svg>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2"><rect x="1" y="6" width="18" height="12" rx="2"/><path d="M21 10v4"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-bar">
|
||||
<div class="nav-back" onclick="location.href='../index.html'">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2" stroke-linecap="round"><path d="M15 19l-7-7 7-7"/></svg>
|
||||
</div>
|
||||
<div class="nav-title">健康监测</div>
|
||||
</div>
|
||||
<div class="scroll-content">
|
||||
<!-- 设备连接状态 -->
|
||||
<div class="device-bar">
|
||||
<div class="device-icon">⌚</div>
|
||||
<div class="device-info">
|
||||
<div class="device-name">华为 WATCH GT5 Pro</div>
|
||||
<div class="device-meta">SF55996622586 · 已连接</div>
|
||||
</div>
|
||||
<!-- <div class="device-battery">-->
|
||||
<!-- <div class="battery-icon"><div class="battery-fill" style="width:72%"></div></div>-->
|
||||
<!-- 72%-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
<!-- 监测卡片网格 -->
|
||||
<div class="monitor-grid">
|
||||
<!-- 步数 -->
|
||||
<div class="monitor-card" onclick="location.href='steps.html'">
|
||||
<div class="card-header">
|
||||
<div class="card-header__left">
|
||||
<div class="card-icon" style="background:#e6f7ff">🏃</div>
|
||||
<span class="card-label">步数</span>
|
||||
</div>
|
||||
<div class="card-header__right">
|
||||
<div class="card-arrow">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-value">8,562<span class="card-unit">步</span></div>
|
||||
<div class="card-progress">
|
||||
<div class="card-progress__text">相当于步行5.2公里</div>
|
||||
</div>
|
||||
<div class="card-sync">同步至 04-30 09:38</div>
|
||||
</div>
|
||||
<!-- 睡眠 -->
|
||||
<div class="monitor-card" onclick="location.href='sleep.html'">
|
||||
<div class="card-header">
|
||||
<div class="card-header__left">
|
||||
<div class="card-icon" style="background:#f0e6ff">🌙</div>
|
||||
<span class="card-label">睡眠</span>
|
||||
</div>
|
||||
<div class="card-header__right">
|
||||
<div class="card-arrow">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-value">7<span class="card-unit">h</span>32<span class="card-unit">min</span></div>
|
||||
<div class="card-progress__text">平均睡眠8小时57分</div>
|
||||
<div class="card-sync">同步至 04-30 07:05</div>
|
||||
<!-- <div class="sleep-segments">-->
|
||||
<!-- <div class="sleep-seg sleep-seg--deep" style="width:28%"></div>-->
|
||||
<!-- <div class="sleep-seg sleep-seg--light" style="width:42%"></div>-->
|
||||
<!-- <div class="sleep-seg sleep-seg--rem" style="width:20%"></div>-->
|
||||
<!-- <div class="sleep-seg sleep-seg--awake" style="width:10%"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="sleep-legend">-->
|
||||
<!-- <div class="sleep-legend__item"><div class="sleep-legend__dot" style="background:#1890ff"></div>深睡</div>-->
|
||||
<!-- <div class="sleep-legend__item"><div class="sleep-legend__dot" style="background:#91d5ff"></div>浅睡</div>-->
|
||||
<!-- <div class="sleep-legend__item"><div class="sleep-legend__dot" style="background:#b37feb"></div>REM</div>-->
|
||||
<!-- <div class="sleep-legend__item"><div class="sleep-legend__dot" style="background:#ffd591"></div>清醒</div>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
<!-- 心率 -->
|
||||
<div class="monitor-card" onclick="location.href='heart-rate.html'">
|
||||
<div class="card-header">
|
||||
<div class="card-header__left">
|
||||
<div class="card-icon" style="background:#fff1f0">❤️</div>
|
||||
<span class="card-label">心率</span>
|
||||
</div>
|
||||
<div class="card-header__right">
|
||||
<div class="card-arrow">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-value">72<span class="card-unit">bpm</span></div>
|
||||
<div class="card-sub">范围:89~120</div>
|
||||
<div class="card-sync">同步至 04-30 09:37</div>
|
||||
<!-- <div class="card-alert-link" onclick="event.stopPropagation();location.href='heart-rate-alerts.html'">-->
|
||||
<!-- <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#ff4d4f" stroke-width="2"><path d="M12 9v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>-->
|
||||
<!-- 查看预警历史-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
<!-- 体温 -->
|
||||
<div class="monitor-card" onclick="location.href='temperature.html'">
|
||||
<div class="card-header">
|
||||
<div class="card-header__left">
|
||||
<div class="card-icon" style="background:#f9f0ff">🌡️</div>
|
||||
<span class="card-label">体温</span>
|
||||
</div>
|
||||
<div class="card-header__right">
|
||||
<div class="card-arrow">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-value">36.5<span class="card-unit">°C</span></div>
|
||||
<div class="card-sub">范围 36.2~37.1°C</div>
|
||||
<div class="card-sync">同步至 04-30 09:30</div>
|
||||
<!-- <div class="card-alert-link" onclick="event.stopPropagation();location.href='temperature-alerts.html'">-->
|
||||
<!-- <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#ff4d4f" stroke-width="2"><path d="M12 9v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>-->
|
||||
<!-- 查看预警历史-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
<!-- 血氧 -->
|
||||
<div class="monitor-card" onclick="location.href='blood-oxygen.html'">
|
||||
<div class="card-header">
|
||||
<div class="card-header__left">
|
||||
<div class="card-icon" style="background:#f6ffed">💧</div>
|
||||
<span class="card-label">血氧</span>
|
||||
</div>
|
||||
<div class="card-header__right">
|
||||
<div class="card-arrow">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-value">98<span class="card-unit">%</span></div>
|
||||
<div class="card-sub">范围 95~99%</div>
|
||||
<div class="card-sync">同步至 04-30 09:35</div>
|
||||
<!-- <div class="card-alert-link" onclick="event.stopPropagation();location.href='blood-oxygen-alerts.html'">-->
|
||||
<!-- <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#ff4d4f" stroke-width="2"><path d="M12 9v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>-->
|
||||
<!-- 查看预警历史-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
<!-- 压力 -->
|
||||
<div class="monitor-card" onclick="location.href='stress.html'">
|
||||
<div class="card-header">
|
||||
<div class="card-header__left">
|
||||
<div class="card-icon" style="background:#fffbe6">🧠</div>
|
||||
<span class="card-label">压力</span>
|
||||
</div>
|
||||
<div class="card-header__right">
|
||||
<div class="card-arrow">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-value">42</div>
|
||||
<div class="card-sub">范围 18~82</div>
|
||||
<div class="card-sync">同步至 04-30 09:36</div>
|
||||
<!-- <div class="card-alert-link" onclick="event.stopPropagation();location.href='stress-alerts.html'">-->
|
||||
<!-- <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#ff4d4f" stroke-width="2"><path d="M12 9v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>-->
|
||||
<!-- 查看预警历史-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
<!-- 血压 -->
|
||||
<div class="monitor-card" onclick="location.href='blood-pressure.html'">
|
||||
<div class="card-header">
|
||||
<div class="card-header__left">
|
||||
<div class="card-icon" style="background:#fff0f6">🩸</div>
|
||||
<span class="card-label">血压</span>
|
||||
</div>
|
||||
<div class="card-header__right">
|
||||
<div class="card-arrow">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-value">120<span class="card-unit">/</span>78<span class="card-unit"> mmHg</span></div>
|
||||
<div class="card-status card-status--normal">正常</div>
|
||||
<div class="card-sync">同步至 05-12 09:20</div>
|
||||
</div>
|
||||
<!-- 心电图 -->
|
||||
<div class="monitor-card" onclick="location.href='ecg.html'">
|
||||
<div class="card-header">
|
||||
<div class="card-header__left">
|
||||
<div class="card-icon" style="background:#f0f5ff">📈</div>
|
||||
<span class="card-label">心电图</span>
|
||||
</div>
|
||||
<div class="card-header__right">
|
||||
<div class="card-arrow">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-value" style="font-size:22px">75<span class="card-unit"> 次/分钟 </span></div>
|
||||
<div class="card-status card-status--normal">窦性心律</div>
|
||||
<div class="card-sync">同步至 05-12 08:45</div>
|
||||
</div>
|
||||
<!-- 锻炼 -->
|
||||
<div class="monitor-card" onclick="location.href='exercise.html'">
|
||||
<div class="card-header">
|
||||
<div class="card-header__left">
|
||||
<div class="card-icon" style="background:#fff7e6">🏋️</div>
|
||||
<span class="card-label">锻炼</span>
|
||||
</div>
|
||||
<div class="card-header__right">
|
||||
<div class="card-arrow">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-value">680<span class="card-unit">kcal</span></div>
|
||||
<div class="card-sub">锻炼时长:52分钟</div>
|
||||
<div class="card-sync">同步至 05-12 09:20</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom-safe"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,357 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>睡眠详情 - 健康监测 | 健康长庆原型</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; }
|
||||
.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; }
|
||||
/* Tab */
|
||||
.time-tabs { display: flex; background: #fff; padding: 8px 16px 12px; gap: 0; flex-shrink: 0; }
|
||||
.time-tab { flex: 1; text-align: center; padding: 6px 0; font-size: 13px; color: #666; cursor: pointer; border-radius: 8px; transition: all 0.2s; }
|
||||
.time-tab.active { background: #1890ff; color: #fff; font-weight: 600; }
|
||||
/* 日期切换器 */
|
||||
.date-switcher { display: flex; align-items: center; justify-content: center; gap: 16px; background: #fff; padding: 10px 16px 14px; flex-shrink: 0; border-bottom: 1px solid #f0f0f0; }
|
||||
.date-switcher__btn { width: 28px; height: 28px; border-radius: 50%; border: 1px solid #e0e0e0; display: flex; align-items: center; justify-content: center; cursor: pointer; background: #fff; }
|
||||
.date-switcher__btn svg { width: 14px; height: 14px; }
|
||||
.date-switcher__text { font-size: 15px; font-weight: 600; color: #1a1a1a; min-width: 120px; text-align: center; }
|
||||
/* 滚动内容区 */
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f5f7fa; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
/* 睡眠时长卡片 */
|
||||
.duration-card { background: #fff; margin: 12px 12px 0; border-radius: 12px; padding: 20px 16px; text-align: center; }
|
||||
.duration-card__title { font-size: 13px; color: #999; margin-bottom: 8px; }
|
||||
.duration-card__value { font-size: 32px; font-weight: 700; color: #1a1a1a; }
|
||||
.duration-card__value span { font-size: 14px; font-weight: 400; color: #666; }
|
||||
.duration-card__sub { display: flex; justify-content: center; gap: 32px; margin-top: 12px; }
|
||||
.duration-card__sub-item { text-align: center; }
|
||||
.duration-card__sub-val { font-size: 15px; font-weight: 600; color: #1a1a1a; }
|
||||
.duration-card__sub-label { font-size: 11px; color: #999; margin-top: 2px; }
|
||||
/* 通用section */
|
||||
.section { margin: 10px 12px 0; background: #fff; border-radius: 12px; padding: 16px; }
|
||||
.section-title { font-size: 14px; font-weight: 600; color: #1a1a1a; margin-bottom: 14px; }
|
||||
/* Hypnogram */
|
||||
.hypnogram-wrap { position: relative; }
|
||||
.hypnogram-times { display: flex; justify-content: space-between; margin-bottom: 8px; font-size: 11px; color: #666; font-weight: 500; }
|
||||
.hypnogram-canvas { width: 100%; height: 120px; display: block; }
|
||||
.hypnogram-axis { display: flex; justify-content: space-between; font-size: 10px; color: #bbb; margin-top: 4px; padding: 0 2px; }
|
||||
/* 堆积柱状图 */
|
||||
.stacked-chart-wrap { position: relative; }
|
||||
.stacked-chart { width: 100%; height: 180px; display: block; }
|
||||
.stacked-chart-axis-x { display: flex; justify-content: space-around; font-size: 10px; color: #999; margin-top: 6px; }
|
||||
/* 图例 */
|
||||
.chart-legend { display: flex; justify-content: center; gap: 12px; margin-top: 12px; flex-wrap: wrap; }
|
||||
.legend-item { display: flex; align-items: center; gap: 4px; font-size: 11px; color: #666; }
|
||||
.legend-dot { width: 8px; height: 8px; border-radius: 50%; }
|
||||
/* 阶段时长统计 */
|
||||
.stage-stats { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 16px; }
|
||||
.stage-stat-item { flex: 1; min-width: calc(50% - 5px); background: #f8f9fc; border-radius: 10px; padding: 12px; display: flex; align-items: center; gap: 10px; }
|
||||
.stage-stat-icon { width: 36px; height: 36px; border-radius: 8px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
|
||||
.stage-stat-info { flex: 1; }
|
||||
.stage-stat-name { font-size: 12px; color: #666; }
|
||||
.stage-stat-val { font-size: 16px; font-weight: 700; color: #1a1a1a; margin-top: 2px; }
|
||||
/* 视图切换隐藏 */
|
||||
.view-day, .view-period { display: none; }
|
||||
.view-day.active, .view-period.active { display: block; }
|
||||
.bottom-safe { height: 20px; flex-shrink: 0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
<div class="status-bar">
|
||||
<span class="time">9:41</span>
|
||||
<div class="icons">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2"><path d="M1 6l5 5 5-5"/><path d="M4 9l3 3 3-3" opacity="0.5"/></svg>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2"><rect x="1" y="6" width="18" height="12" rx="2"/><path d="M21 10v4"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-bar">
|
||||
<div class="nav-back" onclick="location.href='index.html'">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#333" stroke-width="2" stroke-linecap="round"><path d="M15 19l-7-7 7-7"/></svg>
|
||||
</div>
|
||||
<div class="nav-title">睡眠</div>
|
||||
</div>
|
||||
<!-- Tab -->
|
||||
<div class="time-tabs">
|
||||
<div class="time-tab active" data-view="day">日</div>
|
||||
<div class="time-tab" data-view="week">周</div>
|
||||
<div class="time-tab" data-view="month">月</div>
|
||||
<div class="time-tab" data-view="year">年</div>
|
||||
</div>
|
||||
<!-- 日期切换器 -->
|
||||
<div class="date-switcher">
|
||||
<div class="date-switcher__btn" id="datePrev">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="#666" stroke-width="2" stroke-linecap="round"><path d="M15 19l-7-7 7-7"/></svg>
|
||||
</div>
|
||||
<div class="date-switcher__text" id="dateText">5月11日 周日</div>
|
||||
<div class="date-switcher__btn" id="dateNext">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="#666" stroke-width="2" stroke-linecap="round"><path d="M9 5l7 7-7 7"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 滚动内容区 -->
|
||||
<div class="scroll-content">
|
||||
<!-- ===== 日视图 ===== -->
|
||||
<div class="view-day active" id="viewDay">
|
||||
<div class="duration-card">
|
||||
<div class="duration-card__title">夜间睡眠时长</div>
|
||||
<div class="duration-card__value">7<span>h</span> 42<span>min</span></div>
|
||||
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="section-title">睡眠阶段</div>
|
||||
<div class="hypnogram-wrap">
|
||||
<div class="hypnogram-times"><span>入睡 23:48</span><span>醒来 07:30</span></div>
|
||||
<canvas class="hypnogram-canvas" id="hypnogramCanvas" width="640" height="240"></canvas>
|
||||
<div class="hypnogram-axis"><span>01:00</span><span>03:00</span><span>05:00</span><span>07:00</span></div>
|
||||
</div>
|
||||
<div class="chart-legend">
|
||||
<div class="legend-item"><div class="legend-dot" style="background:#7c3aed;"></div>深睡</div>
|
||||
<div class="legend-item"><div class="legend-dot" style="background:#a78bfa;"></div>浅睡</div>
|
||||
<div class="legend-item"><div class="legend-dot" style="background:#f87171;"></div>快速眼动</div>
|
||||
<div class="legend-item"><div class="legend-dot" style="background:#fbbf24;"></div>清醒</div>
|
||||
</div>
|
||||
<div class="stage-stats">
|
||||
<div class="stage-stat-item">
|
||||
<div class="stage-stat-icon" style="background:rgba(124,58,237,0.1);"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#7c3aed" stroke-width="2"><path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/></svg></div>
|
||||
<div class="stage-stat-info"><div class="stage-stat-name">深睡</div><div class="stage-stat-val">2h 08min</div></div>
|
||||
</div>
|
||||
<div class="stage-stat-item">
|
||||
<div class="stage-stat-icon" style="background:rgba(167,139,250,0.1);"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#a78bfa" stroke-width="2"><path d="M17 18a5 5 0 00-10 0"/><circle cx="12" cy="9" r="4"/></svg></div>
|
||||
<div class="stage-stat-info"><div class="stage-stat-name">浅睡</div><div class="stage-stat-val">3h 24min</div></div>
|
||||
</div>
|
||||
<div class="stage-stat-item">
|
||||
<div class="stage-stat-icon" style="background:rgba(248,113,113,0.1);"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#f87171" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M12 1v2m0 18v2m11-11h-2M3 12H1"/></svg></div>
|
||||
<div class="stage-stat-info"><div class="stage-stat-name">快速眼动</div><div class="stage-stat-val">1h 38min</div></div>
|
||||
</div>
|
||||
<div class="stage-stat-item">
|
||||
<div class="stage-stat-icon" style="background:rgba(251,191,36,0.1);"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#fbbf24" stroke-width="2"><path d="M18 8A6 6 0 006 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 01-3.46 0"/></svg></div>
|
||||
<div class="stage-stat-info"><div class="stage-stat-name">清醒</div><div class="stage-stat-val">32min</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ===== 周/月/年视图 ===== -->
|
||||
<div class="view-period" id="viewPeriod">
|
||||
<div class="duration-card">
|
||||
<div class="duration-card__title" id="periodAvgTitle">日均睡眠时长</div>
|
||||
<div class="duration-card__value" id="periodAvgValue">7<span>h</span> 28<span>min</span></div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="section-title">睡眠趋势</div>
|
||||
<div class="stacked-chart-wrap">
|
||||
<canvas class="stacked-chart" id="stackedChart" width="640" height="360"></canvas>
|
||||
<div class="stacked-chart-axis-x" id="stackedAxisX"></div>
|
||||
</div>
|
||||
<div class="chart-legend">
|
||||
<div class="legend-item"><div class="legend-dot" style="background:#7c3aed;"></div>深睡</div>
|
||||
<div class="legend-item"><div class="legend-dot" style="background:#a78bfa;"></div>浅睡</div>
|
||||
<div class="legend-item"><div class="legend-dot" style="background:#f87171;"></div>快速眼动</div>
|
||||
<div class="legend-item"><div class="legend-dot" style="background:#fbbf24;"></div>清醒</div>
|
||||
<div class="legend-item"><div class="legend-dot" style="background:#38bdf8;"></div>零星小睡</div>
|
||||
</div>
|
||||
<div class="stage-stats" id="periodStats">
|
||||
<div class="stage-stat-item">
|
||||
<div class="stage-stat-icon" style="background:rgba(124,58,237,0.1);"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#7c3aed" stroke-width="2"><path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/></svg></div>
|
||||
<div class="stage-stat-info"><div class="stage-stat-name">日均深睡</div><div class="stage-stat-val">1h 56min</div></div>
|
||||
</div>
|
||||
<div class="stage-stat-item">
|
||||
<div class="stage-stat-icon" style="background:rgba(167,139,250,0.1);"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#a78bfa" stroke-width="2"><path d="M17 18a5 5 0 00-10 0"/><circle cx="12" cy="9" r="4"/></svg></div>
|
||||
<div class="stage-stat-info"><div class="stage-stat-name">日均浅睡</div><div class="stage-stat-val">3h 18min</div></div>
|
||||
</div>
|
||||
<div class="stage-stat-item">
|
||||
<div class="stage-stat-icon" style="background:rgba(248,113,113,0.1);"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#f87171" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M12 1v2m0 18v2m11-11h-2M3 12H1"/></svg></div>
|
||||
<div class="stage-stat-info"><div class="stage-stat-name">日均快速眼动</div><div class="stage-stat-val">1h 32min</div></div>
|
||||
</div>
|
||||
<div class="stage-stat-item">
|
||||
<div class="stage-stat-icon" style="background:rgba(251,191,36,0.1);"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#fbbf24" stroke-width="2"><path d="M18 8A6 6 0 006 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 01-3.46 0"/></svg></div>
|
||||
<div class="stage-stat-info"><div class="stage-stat-name">日均清醒</div><div class="stage-stat-val">28min</div></div>
|
||||
</div>
|
||||
<div class="stage-stat-item">
|
||||
<div class="stage-stat-icon" style="background:rgba(56,189,248,0.1);"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#38bdf8" stroke-width="2"><path d="M12 3v1m0 16v1m-7-9H4m16 0h1m-2.64-6.36l-.7.7M6.34 17.66l-.7.7m12.02 0l-.7-.7M6.34 6.34l-.7-.7"/><circle cx="12" cy="12" r="4"/></svg></div>
|
||||
<div class="stage-stat-info"><div class="stage-stat-name">日均零星小睡</div><div class="stage-stat-val">14min</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom-safe"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
/* ---- 状态管理 ---- */
|
||||
var currentView = 'day';
|
||||
var currentDate = new Date(2026, 4, 11); /* 2026-05-11 */
|
||||
var weekDays = ['周日','周一','周二','周三','周四','周五','周六'];
|
||||
|
||||
function formatDateText(view, date) {
|
||||
var m = date.getMonth() + 1, d = date.getDate();
|
||||
if (view === 'day') return m + '月' + d + '日 ' + weekDays[date.getDay()];
|
||||
if (view === 'week') {
|
||||
var start = new Date(date); start.setDate(date.getDate() - date.getDay() + 1);
|
||||
var end = new Date(start); end.setDate(start.getDate() + 6);
|
||||
return (start.getMonth()+1) + '/' + start.getDate() + ' - ' + (end.getMonth()+1) + '/' + end.getDate();
|
||||
}
|
||||
if (view === 'month') return date.getFullYear() + '年' + m + '月';
|
||||
return date.getFullYear() + '年';
|
||||
}
|
||||
|
||||
function updateDateDisplay() {
|
||||
document.getElementById('dateText').textContent = formatDateText(currentView, currentDate);
|
||||
}
|
||||
|
||||
function switchView(view) {
|
||||
currentView = view;
|
||||
document.getElementById('viewDay').classList.toggle('active', view === 'day');
|
||||
document.getElementById('viewPeriod').classList.toggle('active', view !== 'day');
|
||||
updateDateDisplay();
|
||||
if (view !== 'day') drawStackedChart(view);
|
||||
}
|
||||
|
||||
/* 日期前后切换 */
|
||||
document.getElementById('datePrev').onclick = function() {
|
||||
if (currentView === 'day') currentDate.setDate(currentDate.getDate() - 1);
|
||||
else if (currentView === 'week') currentDate.setDate(currentDate.getDate() - 7);
|
||||
else if (currentView === 'month') currentDate.setMonth(currentDate.getMonth() - 1);
|
||||
else currentDate.setFullYear(currentDate.getFullYear() - 1);
|
||||
updateDateDisplay();
|
||||
};
|
||||
document.getElementById('dateNext').onclick = function() {
|
||||
if (currentView === 'day') currentDate.setDate(currentDate.getDate() + 1);
|
||||
else if (currentView === 'week') currentDate.setDate(currentDate.getDate() + 7);
|
||||
else if (currentView === 'month') currentDate.setMonth(currentDate.getMonth() + 1);
|
||||
else currentDate.setFullYear(currentDate.getFullYear() + 1);
|
||||
updateDateDisplay();
|
||||
};
|
||||
|
||||
/* Tab切换 */
|
||||
document.querySelectorAll('.time-tab').forEach(function(tab) {
|
||||
tab.onclick = function() {
|
||||
document.querySelectorAll('.time-tab').forEach(function(t) { t.classList.remove('active'); });
|
||||
tab.classList.add('active');
|
||||
switchView(tab.dataset.view);
|
||||
};
|
||||
});
|
||||
|
||||
/* ---- Hypnogram 日视图 ---- */
|
||||
(function() {
|
||||
var canvas = document.getElementById('hypnogramCanvas');
|
||||
var ctx = canvas.getContext('2d');
|
||||
var W = canvas.width, H = canvas.height;
|
||||
var padT = 10, padB = 10, chartH = H - padT - padB;
|
||||
var stages = [
|
||||
0,0,2,2,2,2,3,3,3,3,3,2,2,1,1,1,0,0,2,2,2,3,3,3,3,3,3,2,2,1,1,1,1,0,
|
||||
2,2,2,2,3,3,3,3,3,2,2,2,1,1,1,0,0,2,2,2,3,3,3,3,2,2,1,1,1,1,0,
|
||||
2,2,2,2,2,3,3,3,3,3,3,2,2,2,1,1,1,1,0,0,2,2,2,2,3,3,3,3,3,2,2,1,1,1,0,
|
||||
2,2,2,2,2,2,3,3,3,3,3,3,2,2,1,1,1,1,0,0,2,2,2,3,3,3,3,2,2,1,1,0,
|
||||
2,2,2,2,3,3,3,3,3,2,2,2,1,1,1,1,0,2,2,2,2,2,3,3,3,2,2,1,1,1,0,0,
|
||||
2,2,2,2,2,1,1,1,1,2,2,2,2,1,1,1,0,2,2,2,2,1,1,1,1,2,2,2,1,1,0,0,0
|
||||
];
|
||||
var colors = { 0:'#fbbf24', 1:'#f87171', 2:'#a78bfa', 3:'#7c3aed' };
|
||||
var levelH = chartH / 4;
|
||||
var n = stages.length, barW = W / n;
|
||||
for (var i = 0; i < n; i++) {
|
||||
var s = stages[i];
|
||||
ctx.fillStyle = colors[s];
|
||||
ctx.fillRect(i * barW, padT + s * levelH, barW + 0.5, chartH - s * levelH);
|
||||
}
|
||||
})();
|
||||
|
||||
/* ---- 堆积柱状图 (周/月/年) ---- */
|
||||
function drawStackedChart(view) {
|
||||
var canvas = document.getElementById('stackedChart');
|
||||
var ctx = canvas.getContext('2d');
|
||||
var W = canvas.width, H = canvas.height;
|
||||
ctx.clearRect(0, 0, W, H);
|
||||
|
||||
var padL = 30, padR = 10, padT = 10, padB = 20;
|
||||
var chartW = W - padL - padR, chartH = H - padT - padB;
|
||||
var maxHours = 12;
|
||||
|
||||
/* 模拟数据生成 */
|
||||
var data = [], labels = [];
|
||||
var count = view === 'week' ? 7 : view === 'month' ? 30 : 12;
|
||||
for (var i = 0; i < count; i++) {
|
||||
var deep = 1.5 + Math.random() * 1.2;
|
||||
var light = 2.5 + Math.random() * 1.5;
|
||||
var rem = 0.8 + Math.random() * 1.0;
|
||||
var awake = 0.2 + Math.random() * 0.5;
|
||||
var nap = Math.random() > 0.6 ? 0.2 + Math.random() * 0.4 : 0;
|
||||
data.push([deep, light, rem, awake, nap]);
|
||||
if (view === 'week') labels.push(weekDays[(i + 1) % 7]);
|
||||
else if (view === 'month') labels.push(i % 5 === 0 ? (i + 1) + '日' : '');
|
||||
else labels.push((i + 1) + '月');
|
||||
}
|
||||
|
||||
var colors = ['#7c3aed','#a78bfa','#f87171','#fbbf24','#38bdf8'];
|
||||
var barGap = view === 'month' ? 2 : 6;
|
||||
var barW = (chartW - barGap * count) / count;
|
||||
|
||||
/* Y轴网格线和标签 */
|
||||
ctx.strokeStyle = 'rgba(0,0,0,0.06)';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.fillStyle = '#999';
|
||||
ctx.font = '20px sans-serif';
|
||||
ctx.textAlign = 'right';
|
||||
for (var h = 0; h <= maxHours; h += 3) {
|
||||
var y = padT + chartH - (h / maxHours) * chartH;
|
||||
ctx.beginPath(); ctx.moveTo(padL, y); ctx.lineTo(padL + chartW, y); ctx.stroke();
|
||||
ctx.fillText(h.toString(), padL - 6, y + 5);
|
||||
}
|
||||
|
||||
/* 绘制柱子 */
|
||||
for (var i = 0; i < count; i++) {
|
||||
var x = padL + i * (barW + barGap) + barGap / 2;
|
||||
var yBase = padT + chartH;
|
||||
for (var j = 0; j < 5; j++) {
|
||||
var segH = (data[i][j] / maxHours) * chartH;
|
||||
if (segH < 0.5) continue;
|
||||
yBase -= segH;
|
||||
ctx.fillStyle = colors[j];
|
||||
/* 最顶层圆角 */
|
||||
if (j === 4 || (j < 4 && data[i].slice(j+1).reduce(function(a,b){return a+b;},0) < 0.01)) {
|
||||
roundRect(ctx, x, yBase, barW, segH, 3);
|
||||
} else {
|
||||
ctx.fillRect(x, yBase, barW, segH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* X轴标签 */
|
||||
var axisEl = document.getElementById('stackedAxisX');
|
||||
axisEl.innerHTML = '';
|
||||
var step = view === 'month' ? 5 : 1;
|
||||
for (var i = 0; i < count; i += step) {
|
||||
if (labels[i]) {
|
||||
var span = document.createElement('span');
|
||||
span.textContent = labels[i];
|
||||
axisEl.appendChild(span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function roundRect(ctx, x, y, w, h, r) {
|
||||
if (h < r * 2) r = h / 2;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x + r, y);
|
||||
ctx.lineTo(x + w - r, y);
|
||||
ctx.quadraticCurveTo(x + w, y, x + w, y + r);
|
||||
ctx.lineTo(x + w, y + h);
|
||||
ctx.lineTo(x, y + h);
|
||||
ctx.lineTo(x, y + r);
|
||||
ctx.quadraticCurveTo(x, y, x + r, y);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
}
|
||||
|
||||
/* 初始化 */
|
||||
updateDateDisplay();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,360 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>历史数据 - 员工端 | 健康长庆原型</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; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
/* Tab 栏 */
|
||||
.tab-bar { display: flex; background: #fff; padding: 0 16px; gap: 0; border-bottom: 1px solid #f0f0f0; }
|
||||
.tab-item { flex: 1; height: 44px; display: flex; align-items: center; justify-content: center; font-size: 14px; color: #999; cursor: pointer; position: relative; transition: color 0.2s; }
|
||||
.tab-item.active { color: #667eea; font-weight: 600; }
|
||||
.tab-item.active::after { content: ''; position: absolute; bottom: 0; left: 50%; transform: translateX(-50%); width: 24px; height: 3px; background: #667eea; border-radius: 2px; }
|
||||
/* 切换按钮 */
|
||||
.view-switch { display: flex; align-items: center; justify-content: flex-end; padding: 12px 16px 0; gap: 8px; }
|
||||
.switch-btn { width: 36px; height: 36px; border: 1px solid #e8e8e8; background: #fff; border-radius: 8px; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: all 0.15s; }
|
||||
.switch-btn.active { background: #667eea; border-color: #667eea; }
|
||||
.switch-btn.active svg path, .switch-btn.active svg rect, .switch-btn.active svg line { stroke: #fff; }
|
||||
/* 统计卡片 */
|
||||
.stats-row { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; gap: 8px; padding: 12px 16px; }
|
||||
.stats-item { background: #fff; border-radius: 10px; padding: 12px 8px; text-align: center; }
|
||||
.stats-item__label { font-size: 11px; color: #999; margin-bottom: 4px; }
|
||||
.stats-item__value { font-size: 16px; font-weight: 700; color: #1a1a1a; }
|
||||
.stats-item__unit { font-size: 10px; color: #999; margin-left: 1px; }
|
||||
.stats-item--change .stats-item__value { color: #52c41a; }
|
||||
/* 趋势图区域 */
|
||||
.chart-area { margin: 0 16px 12px; background: #fff; border-radius: 16px; padding: 16px; }
|
||||
.chart-title { font-size: 14px; font-weight: 600; color: #1a1a1a; margin-bottom: 12px; }
|
||||
.chart-wrapper { position: relative; height: 200px; }
|
||||
.chart-y-axis { position: absolute; left: 0; top: 0; bottom: 20px; width: 36px; display: flex; flex-direction: column; justify-content: space-between; }
|
||||
.chart-y-label { font-size: 10px; color: #999; text-align: right; }
|
||||
.chart-grid { position: absolute; left: 40px; right: 0; top: 0; bottom: 20px; }
|
||||
.chart-grid-line { position: absolute; left: 0; right: 0; height: 1px; background: #f0f0f0; }
|
||||
.chart-line { position: absolute; left: 40px; right: 0; top: 0; bottom: 20px; }
|
||||
.chart-svg { width: 100%; height: 100%; }
|
||||
.chart-x-axis { position: absolute; left: 40px; right: 0; bottom: 0; height: 20px; display: flex; justify-content: space-between; }
|
||||
.chart-x-label { font-size: 10px; color: #999; text-align: center; }
|
||||
/* 趋势图节点 */
|
||||
.chart-dot { cursor: pointer; transition: r 0.15s; }
|
||||
.chart-dot:hover { r: 6; }
|
||||
/* Tip 弹窗 */
|
||||
.chart-tip { position: absolute; background: #fff; border-radius: 10px; padding: 12px; box-shadow: 0 4px 20px rgba(0,0,0,0.15); border: 1px solid #f0f0f0; z-index: 10; min-width: 150px; display: none; }
|
||||
.chart-tip.show { display: block; }
|
||||
.chart-tip__title { font-size: 12px; color: #999; margin-bottom: 8px; }
|
||||
.chart-tip__row { display: flex; justify-content: space-between; align-items: center; padding: 4px 0; }
|
||||
.chart-tip__label { font-size: 12px; color: #666; }
|
||||
.chart-tip__value { font-size: 13px; font-weight: 600; color: #1a1a1a; }
|
||||
.chart-tip__close { position: absolute; top: 6px; right: 8px; font-size: 14px; color: #ccc; cursor: pointer; line-height: 1; }
|
||||
/* 列表模式 */
|
||||
.list-area { margin: 0 16px 12px; }
|
||||
.list-item { background: #fff; border-radius: 12px; padding: 14px 16px; margin-bottom: 8px; display: flex; align-items: center; justify-content: space-between; cursor: pointer; transition: transform 0.15s; text-decoration: none; }
|
||||
.list-item:active { transform: scale(0.98); }
|
||||
.list-item__left { flex: 1; min-width: 0; }
|
||||
.list-item__time { font-size: 14px; font-weight: 500; color: #1a1a1a; margin-bottom: 4px; }
|
||||
.list-item__metrics { display: flex; gap: 12px; }
|
||||
.list-item__metric { font-size: 12px; color: #999; }
|
||||
.list-item__metric strong { color: #1a1a1a; font-weight: 600; }
|
||||
.list-item__top { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
|
||||
.list-item__time { margin-bottom: 0; }
|
||||
.device-tag { display: inline-flex; align-items: center; font-size: 10px; padding: 1px 6px; border-radius: 4px; font-weight: 500; flex-shrink: 0; }
|
||||
.device-tag--scale { background: #e6f7ff; color: #1890ff; border: 1px solid #91d5ff; }
|
||||
.device-tag--bluetooth { background: #f6ffed; color: #52c41a; border: 1px solid #b7eb8f; }
|
||||
.device-tag--fat { background: #fff7e6; color: #fa8c16; border: 1px solid #ffd591; }
|
||||
.list-item__arrow { width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
|
||||
/* 底部安全区 */
|
||||
.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="location.href='index.html'">
|
||||
<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>
|
||||
<!-- Tab -->
|
||||
<div class="tab-bar">
|
||||
<div class="tab-item active" onclick="switchTab(this)">近7天</div>
|
||||
<div class="tab-item" onclick="switchTab(this)">近30天</div>
|
||||
<div class="tab-item" onclick="switchTab(this)">近3个月</div>
|
||||
</div>
|
||||
<div class="scroll-content">
|
||||
<!-- 切换按钮 -->
|
||||
<div class="view-switch">
|
||||
<div class="switch-btn active" id="btnChart" onclick="switchView('chart')">
|
||||
<svg width="18" height="18" fill="none"><path d="M2 14l4-5 3 3 5-7" stroke="#666" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
</div>
|
||||
<div class="switch-btn" id="btnList" onclick="switchView('list')">
|
||||
<svg width="18" height="18" fill="none"><line x1="3" y1="5" x2="15" y2="5" stroke="#666" stroke-width="1.8" stroke-linecap="round"/><line x1="3" y1="9" x2="15" y2="9" stroke="#666" stroke-width="1.8" stroke-linecap="round"/><line x1="3" y1="13" x2="15" y2="13" stroke="#666" stroke-width="1.8" stroke-linecap="round"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 统计 -->
|
||||
<div class="stats-row">
|
||||
<div class="stats-item">
|
||||
<div class="stats-item__label">最高</div>
|
||||
<div class="stats-item__value">73.2<span class="stats-item__unit">kg</span></div>
|
||||
</div>
|
||||
<div class="stats-item">
|
||||
<div class="stats-item__label">最低</div>
|
||||
<div class="stats-item__value">71.8<span class="stats-item__unit">kg</span></div>
|
||||
</div>
|
||||
<div class="stats-item">
|
||||
<div class="stats-item__label">平均</div>
|
||||
<div class="stats-item__value">72.4<span class="stats-item__unit">kg</span></div>
|
||||
</div>
|
||||
<div class="stats-item stats-item--change">
|
||||
<div class="stats-item__label">变化</div>
|
||||
<div class="stats-item__value">-0.7<span class="stats-item__unit">kg</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 趋势图 -->
|
||||
<div class="chart-area" id="chartArea">
|
||||
<div class="chart-title">体重趋势</div>
|
||||
<div class="chart-wrapper" id="chartWrapper">
|
||||
<div class="chart-y-axis">
|
||||
<span class="chart-y-label">74</span>
|
||||
<span class="chart-y-label">73</span>
|
||||
<span class="chart-y-label">72</span>
|
||||
<span class="chart-y-label">71</span>
|
||||
</div>
|
||||
<div class="chart-grid">
|
||||
<div class="chart-grid-line" style="top:0%"></div>
|
||||
<div class="chart-grid-line" style="top:33.3%"></div>
|
||||
<div class="chart-grid-line" style="top:66.6%"></div>
|
||||
<div class="chart-grid-line" style="top:100%"></div>
|
||||
</div>
|
||||
<div class="chart-line">
|
||||
<svg class="chart-svg" viewBox="0 0 300 160" preserveAspectRatio="none">
|
||||
<defs>
|
||||
<linearGradient id="areaGrad" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#667eea" stop-opacity="0.3"/>
|
||||
<stop offset="100%" stop-color="#667eea" stop-opacity="0.02"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<!-- 面积 -->
|
||||
<polygon points="0,80 50,53 100,107 150,40 200,67 250,27 300,53 300,160 0,160" fill="url(#areaGrad)"/>
|
||||
<!-- 线条 -->
|
||||
<polyline points="0,80 50,53 100,107 150,40 200,67 250,27 300,53" fill="none" stroke="#667eea" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<!-- 节点 -->
|
||||
<circle class="chart-dot" cx="0" cy="80" r="4" fill="#667eea" stroke="#fff" stroke-width="2" onclick="showTip(event,0)"/>
|
||||
<circle class="chart-dot" cx="50" cy="53" r="4" fill="#667eea" stroke="#fff" stroke-width="2" onclick="showTip(event,1)"/>
|
||||
<circle class="chart-dot" cx="100" cy="107" r="4" fill="#667eea" stroke="#fff" stroke-width="2" onclick="showTip(event,2)"/>
|
||||
<circle class="chart-dot" cx="150" cy="40" r="4" fill="#667eea" stroke="#fff" stroke-width="2" onclick="showTip(event,3)"/>
|
||||
<circle class="chart-dot" cx="200" cy="67" r="4" fill="#667eea" stroke="#fff" stroke-width="2" onclick="showTip(event,4)"/>
|
||||
<circle class="chart-dot" cx="250" cy="27" r="4" fill="#667eea" stroke="#fff" stroke-width="2" onclick="showTip(event,5)"/>
|
||||
<circle class="chart-dot" cx="300" cy="53" r="4" fill="#667eea" stroke="#fff" stroke-width="2" onclick="showTip(event,6)"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="chart-x-axis">
|
||||
<span class="chart-x-label">5/8</span>
|
||||
<span class="chart-x-label">5/9</span>
|
||||
<span class="chart-x-label">5/10</span>
|
||||
<span class="chart-x-label">5/11</span>
|
||||
<span class="chart-x-label">5/12</span>
|
||||
<span class="chart-x-label">5/13</span>
|
||||
<span class="chart-x-label">5/14</span>
|
||||
</div>
|
||||
<!-- Tip -->
|
||||
<div class="chart-tip" id="chartTip">
|
||||
<span class="chart-tip__close" onclick="hideTip()">×</span>
|
||||
<div class="chart-tip__title" id="tipDate"></div>
|
||||
<div class="chart-tip__row"><span class="chart-tip__label">设备来源</span><span class="chart-tip__value" id="tipDevice"></span></div>
|
||||
<div class="chart-tip__row"><span class="chart-tip__label">体重</span><span class="chart-tip__value" id="tipWeight"></span></div>
|
||||
<div class="chart-tip__row"><span class="chart-tip__label">BMI</span><span class="chart-tip__value" id="tipBmi"></span></div>
|
||||
<div class="chart-tip__row"><span class="chart-tip__label">体脂率</span><span class="chart-tip__value" id="tipFat"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 列表模式 -->
|
||||
<div class="list-area" id="listArea" style="display:none">
|
||||
<a class="list-item" href="report-detail.html?device=fat">
|
||||
<div class="list-item__left">
|
||||
<div class="list-item__top">
|
||||
<div class="list-item__time">2026-05-14 08:30</div>
|
||||
<span class="device-tag device-tag--fat">体脂仪</span>
|
||||
</div>
|
||||
<div class="list-item__metrics">
|
||||
<span class="list-item__metric">体重 <strong>72.5kg</strong></span>
|
||||
<span class="list-item__metric">BMI <strong>23.7</strong></span>
|
||||
<span class="list-item__metric">体脂率 <strong>18.5%</strong></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-item__arrow"><svg width="7" height="12" fill="none"><path d="M1 1l5 5-5 5" stroke="#ccc" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
|
||||
</a>
|
||||
<a class="list-item" href="report-detail.html?device=bluetooth">
|
||||
<div class="list-item__left">
|
||||
<div class="list-item__top">
|
||||
<div class="list-item__time">2026-05-13 07:55</div>
|
||||
<span class="device-tag device-tag--bluetooth">蓝牙秤</span>
|
||||
</div>
|
||||
<div class="list-item__metrics">
|
||||
<span class="list-item__metric">体重 <strong>72.8kg</strong></span>
|
||||
<span class="list-item__metric">BMI <strong>23.8</strong></span>
|
||||
<span class="list-item__metric">体脂率 <strong>18.8%</strong></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-item__arrow"><svg width="7" height="12" fill="none"><path d="M1 1l5 5-5 5" stroke="#ccc" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
|
||||
</a>
|
||||
<a class="list-item" href="report-detail.html?device=scale">
|
||||
<div class="list-item__left">
|
||||
<div class="list-item__top">
|
||||
<div class="list-item__time">2026-05-12 08:10</div>
|
||||
<span class="device-tag device-tag--scale">体重秤</span>
|
||||
</div>
|
||||
<div class="list-item__metrics">
|
||||
<span class="list-item__metric">体重 <strong>71.8kg</strong></span>
|
||||
<span class="list-item__metric">BMI <strong>23.4</strong></span>
|
||||
<span class="list-item__metric">体脂率 <strong>17.9%</strong></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-item__arrow"><svg width="7" height="12" fill="none"><path d="M1 1l5 5-5 5" stroke="#ccc" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
|
||||
</a>
|
||||
<a class="list-item" href="report-detail.html?device=fat">
|
||||
<div class="list-item__left">
|
||||
<div class="list-item__top">
|
||||
<div class="list-item__time">2026-05-11 09:20</div>
|
||||
<span class="device-tag device-tag--fat">体脂仪</span>
|
||||
</div>
|
||||
<div class="list-item__metrics">
|
||||
<span class="list-item__metric">体重 <strong>73.2kg</strong></span>
|
||||
<span class="list-item__metric">BMI <strong>23.9</strong></span>
|
||||
<span class="list-item__metric">体脂率 <strong>19.1%</strong></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-item__arrow"><svg width="7" height="12" fill="none"><path d="M1 1l5 5-5 5" stroke="#ccc" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
|
||||
</a>
|
||||
<a class="list-item" href="report-detail.html?device=bluetooth">
|
||||
<div class="list-item__left">
|
||||
<div class="list-item__top">
|
||||
<div class="list-item__time">2026-05-10 08:40</div>
|
||||
<span class="device-tag device-tag--bluetooth">蓝牙秤</span>
|
||||
</div>
|
||||
<div class="list-item__metrics">
|
||||
<span class="list-item__metric">体重 <strong>72.3kg</strong></span>
|
||||
<span class="list-item__metric">BMI <strong>23.6</strong></span>
|
||||
<span class="list-item__metric">体脂率 <strong>18.3%</strong></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-item__arrow"><svg width="7" height="12" fill="none"><path d="M1 1l5 5-5 5" stroke="#ccc" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
|
||||
</a>
|
||||
<a class="list-item" href="report-detail.html?device=scale">
|
||||
<div class="list-item__left">
|
||||
<div class="list-item__top">
|
||||
<div class="list-item__time">2026-05-09 07:30</div>
|
||||
<span class="device-tag device-tag--scale">体重秤</span>
|
||||
</div>
|
||||
<div class="list-item__metrics">
|
||||
<span class="list-item__metric">体重 <strong>72.9kg</strong></span>
|
||||
<span class="list-item__metric">BMI <strong>23.8</strong></span>
|
||||
<span class="list-item__metric">体脂率 <strong>18.6%</strong></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-item__arrow"><svg width="7" height="12" fill="none"><path d="M1 1l5 5-5 5" stroke="#ccc" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
|
||||
</a>
|
||||
<a class="list-item" href="report-detail.html?device=fat">
|
||||
<div class="list-item__left">
|
||||
<div class="list-item__top">
|
||||
<div class="list-item__time">2026-05-08 08:15</div>
|
||||
<span class="device-tag device-tag--fat">体脂仪</span>
|
||||
</div>
|
||||
<div class="list-item__metrics">
|
||||
<span class="list-item__metric">体重 <strong>72.5kg</strong></span>
|
||||
<span class="list-item__metric">BMI <strong>23.7</strong></span>
|
||||
<span class="list-item__metric">体脂率 <strong>18.5%</strong></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-item__arrow"><svg width="7" height="12" fill="none"><path d="M1 1l5 5-5 5" stroke="#ccc" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="bottom-safe"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
/* Tab 切换 */
|
||||
function switchTab(el) {
|
||||
var tabs = el.parentElement.querySelectorAll('.tab-item');
|
||||
tabs.forEach(function(t) { t.classList.remove('active'); });
|
||||
el.classList.add('active');
|
||||
}
|
||||
/* 图表/列表切换 */
|
||||
function switchView(mode) {
|
||||
var chartArea = document.getElementById('chartArea');
|
||||
var listArea = document.getElementById('listArea');
|
||||
var btnChart = document.getElementById('btnChart');
|
||||
var btnList = document.getElementById('btnList');
|
||||
if (mode === 'chart') {
|
||||
chartArea.style.display = 'block';
|
||||
listArea.style.display = 'none';
|
||||
btnChart.classList.add('active');
|
||||
btnList.classList.remove('active');
|
||||
} else {
|
||||
chartArea.style.display = 'none';
|
||||
listArea.style.display = 'block';
|
||||
btnChart.classList.remove('active');
|
||||
btnList.classList.add('active');
|
||||
}
|
||||
hideTip();
|
||||
}
|
||||
/* Tip 数据 */
|
||||
var tipData = [
|
||||
{ date:'2026-05-08', device:'体脂仪', weight:'72.5kg', bmi:'23.7', fat:'18.5%' },
|
||||
{ date:'2026-05-09', device:'体重秤', weight:'72.9kg', bmi:'23.8', fat:'18.6%' },
|
||||
{ date:'2026-05-10', device:'蓝牙秤', weight:'71.8kg', bmi:'23.4', fat:'17.9%' },
|
||||
{ date:'2026-05-11', device:'体脂仪', weight:'73.2kg', bmi:'23.9', fat:'19.1%' },
|
||||
{ date:'2026-05-12', device:'体重秤', weight:'72.3kg', bmi:'23.6', fat:'18.3%' },
|
||||
{ date:'2026-05-13', device:'蓝牙秤', weight:'72.8kg', bmi:'23.8', fat:'18.8%' },
|
||||
{ date:'2026-05-14', device:'体脂仪', weight:'72.5kg', bmi:'23.7', fat:'18.5%' }
|
||||
];
|
||||
function showTip(e, idx) {
|
||||
e.stopPropagation();
|
||||
var tip = document.getElementById('chartTip');
|
||||
var d = tipData[idx];
|
||||
document.getElementById('tipDate').textContent = d.date;
|
||||
document.getElementById('tipDevice').textContent = d.device;
|
||||
document.getElementById('tipWeight').textContent = d.weight;
|
||||
document.getElementById('tipBmi').textContent = d.bmi;
|
||||
document.getElementById('tipFat').textContent = d.fat;
|
||||
/* 定位 */
|
||||
var wrapper = document.getElementById('chartWrapper');
|
||||
var rect = wrapper.getBoundingClientRect();
|
||||
var dotRect = e.target.getBoundingClientRect();
|
||||
var left = dotRect.left - rect.left - 60;
|
||||
var top = dotRect.top - rect.top + 16;
|
||||
if (left < 0) left = 4;
|
||||
if (left > rect.width - 160) left = rect.width - 164;
|
||||
tip.style.left = left + 'px';
|
||||
tip.style.top = top + 'px';
|
||||
tip.classList.add('show');
|
||||
}
|
||||
function hideTip() {
|
||||
document.getElementById('chartTip').classList.remove('show');
|
||||
}
|
||||
/* 点击空白关闭 */
|
||||
document.addEventListener('click', function(e) {
|
||||
if (!e.target.closest('.chart-tip') && !e.target.closest('.chart-dot')) {
|
||||
hideTip();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,192 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>体重监测 - 员工端 | 健康长庆原型</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; }
|
||||
/* 最近测量卡片 */
|
||||
.measure-card { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 16px; padding: 20px; color: #fff; position: relative; overflow: hidden; margin-bottom: 12px; }
|
||||
.measure-card::after { content: ''; position: absolute; top: -40px; right: -40px; width: 140px; height: 140px; background: rgba(255,255,255,0.08); border-radius: 50%; }
|
||||
.measure-card__label { font-size: 12px; opacity: 0.8; margin-bottom: 4px; }
|
||||
.measure-card__time { font-size: 13px; opacity: 0.9; margin-bottom: 16px; display: flex; align-items: center; gap: 6px; }
|
||||
.measure-card__time svg { opacity: 0.7; }
|
||||
.measure-card__main { display: flex; align-items: flex-end; gap: 16px; margin-bottom: 16px; }
|
||||
.measure-card__weight { display: flex; align-items: baseline; gap: 4px; }
|
||||
.measure-card__weight-num { font-size: 48px; font-weight: 800; line-height: 1; }
|
||||
.measure-card__weight-unit { font-size: 16px; opacity: 0.8; }
|
||||
.measure-card__change { display: flex; align-items: center; gap: 4px; font-size: 13px; padding: 4px 10px; border-radius: 20px; background: rgba(255,255,255,0.15); }
|
||||
.measure-card__change--down { color: #a5f3c4; }
|
||||
.measure-card__change--up { color: #fca5a5; }
|
||||
.measure-card__stats { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
|
||||
.stat-item { background: rgba(255,255,255,0.12); border-radius: 10px; padding: 12px; }
|
||||
.stat-item__label { font-size: 11px; opacity: 0.7; margin-bottom: 4px; }
|
||||
.stat-item__value { font-size: 18px; font-weight: 700; }
|
||||
.stat-item__unit { font-size: 11px; opacity: 0.7; margin-left: 2px; }
|
||||
/* 详细信息 */
|
||||
.detail-section { background: #fff; border-radius: 16px; padding: 16px; margin-bottom: 12px; }
|
||||
.detail-section__title { font-size: 15px; font-weight: 700; color: #1a1a1a; margin-bottom: 14px; display: flex; align-items: center; gap: 8px; }
|
||||
.detail-section__title::before { content: ''; width: 3px; height: 16px; background: linear-gradient(135deg, #667eea, #764ba2); border-radius: 2px; }
|
||||
.detail-grid { display: flex; flex-direction: column; gap: 0; }
|
||||
.detail-row { display: flex; align-items: center; justify-content: space-between; padding: 12px 0; border-bottom: 1px solid #f5f5f5; }
|
||||
.detail-row:last-child { border-bottom: none; }
|
||||
.detail-row__left { display: flex; align-items: center; gap: 10px; }
|
||||
.detail-row__icon { width: 36px; height: 36px; border-radius: 10px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
|
||||
.detail-row__icon--fat { background: #fff3e0; }
|
||||
.detail-row__icon--fat-mass { background: #fce4ec; }
|
||||
.detail-row__icon--bmr { background: #e8f5e9; }
|
||||
.detail-row__info { display: flex; flex-direction: column; }
|
||||
.detail-row__label { font-size: 14px; color: #1a1a1a; font-weight: 500; }
|
||||
.detail-row__sub { font-size: 11px; color: #999; margin-top: 2px; }
|
||||
.detail-row__right { display: flex; align-items: baseline; gap: 2px; }
|
||||
.detail-row__value { font-size: 18px; font-weight: 700; color: #1a1a1a; }
|
||||
.detail-row__unit { font-size: 12px; color: #999; }
|
||||
/* 查看历史按钮 */
|
||||
.btn-history { width: 100%; height: 48px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border: none; border-radius: 24px; font-size: 16px; font-weight: 600; color: #fff; cursor: pointer; display: flex; align-items: center; justify-content: center; gap: 8px; transition: transform 0.15s; margin-bottom: 12px; }
|
||||
.btn-history:active { transform: scale(0.97); }
|
||||
/* 健康建议 */
|
||||
.advice-card { background: #fff; border-radius: 16px; padding: 16px; margin-bottom: 12px; }
|
||||
.advice-card__title { font-size: 15px; font-weight: 700; color: #1a1a1a; margin-bottom: 12px; display: flex; align-items: center; gap: 8px; }
|
||||
.advice-card__title::before { content: ''; width: 3px; height: 16px; background: linear-gradient(135deg, #667eea, #764ba2); border-radius: 2px; }
|
||||
.advice-item { display: flex; gap: 10px; padding: 10px 0; border-bottom: 1px solid #f5f5f5; }
|
||||
.advice-item:last-child { border-bottom: none; }
|
||||
.advice-item__icon { font-size: 20px; flex-shrink: 0; line-height: 1.4; }
|
||||
.advice-item__text { font-size: 13px; color: #666; line-height: 1.6; }
|
||||
.advice-item__text strong { color: #1a1a1a; font-weight: 600; }
|
||||
/* 底部安全区 */
|
||||
.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="location.href='../index.html'">
|
||||
<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="measure-card">
|
||||
<div class="measure-card__label">最近一次测量</div>
|
||||
<div class="measure-card__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>
|
||||
2026-05-14 08:30
|
||||
</div>
|
||||
<div class="measure-card__main">
|
||||
<div class="measure-card__weight">
|
||||
<span class="measure-card__weight-num">72.5</span>
|
||||
<span class="measure-card__weight-unit">kg</span>
|
||||
</div>
|
||||
<div class="measure-card__change measure-card__change--down">
|
||||
<svg width="12" height="12" fill="none"><path d="M6 2v8M3 7l3 3 3-3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
较上次 -0.3kg
|
||||
</div>
|
||||
</div>
|
||||
<div class="measure-card__stats">
|
||||
<div class="stat-item">
|
||||
<div class="stat-item__label">身高</div>
|
||||
<div class="stat-item__value">175<span class="stat-item__unit">cm</span></div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-item__label">BMI</div>
|
||||
<div class="stat-item__value">23.7<span class="stat-item__unit">正常</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 详细信息 -->
|
||||
<div class="detail-section">
|
||||
<!-- <div class="detail-section__title">详细信息</div>-->
|
||||
<div class="detail-grid">
|
||||
<div class="detail-row">
|
||||
<div class="detail-row__left">
|
||||
<div class="detail-row__icon detail-row__icon--fat">
|
||||
<svg width="20" height="20" fill="none"><circle cx="10" cy="10" r="8" stroke="#f57c00" stroke-width="2"/><path d="M10 6v4M10 12.5v.5" stroke="#f57c00" stroke-width="2" stroke-linecap="round"/></svg>
|
||||
</div>
|
||||
<div class="detail-row__info">
|
||||
<div class="detail-row__label">体脂率</div>
|
||||
<div class="detail-row__sub">正常范围 10-20%</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-row__right">
|
||||
<span class="detail-row__value">18.5</span>
|
||||
<span class="detail-row__unit">%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<div class="detail-row__left">
|
||||
<div class="detail-row__icon detail-row__icon--fat-mass">
|
||||
<svg width="20" height="20" fill="none"><rect x="3" y="6" width="14" height="10" rx="2" stroke="#e91e63" stroke-width="1.8"/><path d="M7 6V4a3 3 0 0 1 6 0v2" stroke="#e91e63" stroke-width="1.8" stroke-linecap="round"/></svg>
|
||||
</div>
|
||||
<div class="detail-row__info">
|
||||
<div class="detail-row__label">体脂肪量</div>
|
||||
<div class="detail-row__sub">正常范围 8-15kg</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-row__right">
|
||||
<span class="detail-row__value">13.4</span>
|
||||
<span class="detail-row__unit">kg</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<div class="detail-row__left">
|
||||
<div class="detail-row__icon detail-row__icon--bmr">
|
||||
<svg width="20" height="20" fill="none"><path d="M4 14l3-4 3 2 3-5 3 3" stroke="#4caf50" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
</div>
|
||||
<div class="detail-row__info">
|
||||
<div class="detail-row__label">基础代谢</div>
|
||||
<div class="detail-row__sub">每日静息消耗</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-row__right">
|
||||
<span class="detail-row__value">1,685</span>
|
||||
<span class="detail-row__unit">kcal</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 查看历史 -->
|
||||
<button class="btn-history" onclick="location.href='history.html'">
|
||||
<svg width="18" height="18" fill="none"><path d="M9 1a8 8 0 1 0 0 16A8 8 0 0 0 9 1z" stroke="#fff" stroke-width="1.8"/><path d="M9 4.5V9l3 2" stroke="#fff" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
查看历史数据
|
||||
</button>
|
||||
<!-- 健康建议 -->
|
||||
<div class="advice-card">
|
||||
<div class="advice-card__title">健康建议</div>
|
||||
<div class="advice-item">
|
||||
<span class="advice-item__icon">💪</span>
|
||||
<span class="advice-item__text"><strong>BMI 正常</strong>,您的体重在健康范围内,继续保持规律运动和均衡饮食。</span>
|
||||
</div>
|
||||
<div class="advice-item">
|
||||
<span class="advice-item__icon">🥗</span>
|
||||
<span class="advice-item__text"><strong>体脂率达标</strong>,建议每周进行3-5次有氧运动,每次30分钟以上。</span>
|
||||
</div>
|
||||
<div class="advice-item">
|
||||
<span class="advice-item__icon">💧</span>
|
||||
<span class="advice-item__text">每日饮水量建议 <strong>2000-2500ml</strong>,有助于维持基础代谢水平。</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom-safe"></div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,285 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>详细报告 - 员工端 | 健康长庆原型</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, #667eea 0%, #764ba2 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; gap: 8px; margin-bottom: 12px; }
|
||||
.report-header__time { font-size: 13px; opacity: 0.8; 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--scale { background: rgba(24,144,255,0.2); color: #91d5ff; }
|
||||
.device-tag--bluetooth { background: rgba(82,196,26,0.2); color: #b7eb8f; }
|
||||
.device-tag--fat { background: rgba(250,140,22,0.2); color: #ffd591; }
|
||||
.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.8; }
|
||||
.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.2); color: #a5f3c4; }
|
||||
.report-tag--change { background: rgba(255,255,255,0.15); }
|
||||
/* 数据分类 */
|
||||
.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: 14px; display: flex; align-items: center; gap: 8px; }
|
||||
.data-section__title::before { content: ''; width: 3px; height: 16px; background: linear-gradient(135deg, #667eea, #764ba2); border-radius: 2px; }
|
||||
.data-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0; }
|
||||
.data-cell { padding: 12px; border-bottom: 1px solid #f5f5f5; }
|
||||
.data-cell:nth-child(odd) { border-right: 1px solid #f5f5f5; }
|
||||
.data-cell:nth-last-child(-n+2) { border-bottom: none; }
|
||||
.data-cell__label { font-size: 12px; color: #999; margin-bottom: 4px; }
|
||||
.data-cell__value { font-size: 18px; font-weight: 700; color: #1a1a1a; }
|
||||
.data-cell__unit { font-size: 11px; color: #999; margin-left: 2px; }
|
||||
.data-cell__status { display: inline-block; font-size: 10px; padding: 1px 6px; border-radius: 4px; margin-left: 4px; }
|
||||
.data-cell__status--normal { background: #f6ffed; color: #52c41a; border: 1px solid #b7eb8f; }
|
||||
.data-cell__status--high { background: #fff2f0; color: #ff4d4f; border: 1px solid #ffccc7; }
|
||||
.data-row { display: flex; justify-content: space-between; align-items: center; padding: 12px 0; border-bottom: 1px solid #f5f5f5; }
|
||||
.data-row:last-child { border-bottom: none; }
|
||||
.data-row__label { font-size: 14px; color: #666; }
|
||||
.data-row__right { display: flex; align-items: center; gap: 6px; }
|
||||
.data-row__value { font-size: 16px; font-weight: 700; color: #1a1a1a; }
|
||||
.data-row__unit { font-size: 12px; color: #999; }
|
||||
/* BMI 指示条 */
|
||||
.bmi-bar { margin-top: 12px; }
|
||||
.bmi-bar__track { height: 8px; border-radius: 4px; background: linear-gradient(90deg, #52c41a 0%, #52c41a 35%, #fadb14 35%, #fadb14 55%, #fa8c16 55%, #fa8c16 75%, #ff4d4f 75%, #ff4d4f 100%); position: relative; }
|
||||
.bmi-bar__pointer { position: absolute; top: -4px; width: 16px; height: 16px; background: #fff; border: 3px solid #667eea; 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; }
|
||||
/* 节段数据表格 */
|
||||
.seg-table { width: 100%; border-collapse: collapse; font-size: 13px; }
|
||||
.seg-table th { font-weight: 500; color: #999; text-align: center; padding: 8px 4px; border-bottom: 1px solid #f0f0f0; }
|
||||
.seg-table td { text-align: center; padding: 8px 4px; border-bottom: 1px solid #f5f5f5; color: #1a1a1a; font-weight: 600; }
|
||||
.seg-table tr:last-child td { border-bottom: none; }
|
||||
.seg-table td:first-child { text-align: left; color: #666; font-weight: 400; }
|
||||
.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="location.href='history.html'">
|
||||
<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">
|
||||
<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>
|
||||
2026-05-14 08:30
|
||||
</div>
|
||||
<span class="device-tag" id="headerDeviceTag"></span>
|
||||
</div>
|
||||
<div class="report-header__main">
|
||||
<div class="report-header__weight">
|
||||
<span class="report-header__weight-num">72.5</span>
|
||||
<span class="report-header__weight-unit">kg</span>
|
||||
</div>
|
||||
<div class="report-header__tags">
|
||||
<span class="report-tag report-tag--normal">BMI 正常</span>
|
||||
<span class="report-tag report-tag--change">较上次 -0.3kg</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 动态内容区域 -->
|
||||
<div id="reportContent"></div>
|
||||
<div class="bottom-safe"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var device = new URLSearchParams(location.search).get('device') || 'fat';
|
||||
|
||||
/* 头部设备标签 */
|
||||
var tagEl = document.getElementById('headerDeviceTag');
|
||||
var tagMap = { scale:['体重秤','device-tag--scale'], bluetooth:['蓝牙秤','device-tag--bluetooth'], fat:['体脂仪','device-tag--fat'] };
|
||||
var t = tagMap[device] || tagMap.fat;
|
||||
tagEl.textContent = t[0];
|
||||
tagEl.classList.add(t[1]);
|
||||
|
||||
/* 各设备的数据配置 */
|
||||
var deviceData = {
|
||||
/* ========== 体重秤 ========== */
|
||||
scale: [
|
||||
{ title: '基础指标', type: 'grid', fields: [
|
||||
{ label:'身高', value:'175', unit:'cm' },
|
||||
{ label:'体重', value:'72.5', unit:'kg' },
|
||||
{ label:'BMI', value:'23.7', status:'正常' },
|
||||
{ label:'基础代谢', value:'1,680', unit:'kcal' },
|
||||
{ label:'体脂肪量', value:'15.2', unit:'kg' },
|
||||
{ label:'体脂肪率', value:'21.0', unit:'%', status:'正常' }
|
||||
], bmi: true },
|
||||
{ title: '水分与蛋白质', type: 'rows', fields: [
|
||||
{ label:'体水分量', value:'38.6', unit:'kg' },
|
||||
{ label:'体水分率', value:'53.2', unit:'%' },
|
||||
{ label:'蛋白质量', value:'8.5', unit:'kg' },
|
||||
{ label:'蛋白质率', value:'11.7', unit:'%' }
|
||||
]},
|
||||
{ title: '肌肉与骨骼', type: 'rows', fields: [
|
||||
{ label:'肌肉率', value:'42.6', unit:'%' },
|
||||
{ label:'肌肉量', value:'30.9', unit:'kg' },
|
||||
{ label:'体骨骼量/骨量', value:'3.1', unit:'kg' }
|
||||
]},
|
||||
{ title: '脂肪分析', type: 'rows', fields: [
|
||||
{ label:'皮下脂肪率', value:'16.8', unit:'%' },
|
||||
{ label:'内脏脂肪等级', value:'6', status:'正常' },
|
||||
{ label:'去脂体重', value:'57.3', unit:'kg' }
|
||||
]},
|
||||
{ title: '其他', type: 'rows', fields: [
|
||||
{ label:'无机盐量/矿物质量', value:'3.52', unit:'kg' },
|
||||
{ label:'细胞内液', value:'24.1', unit:'kg' },
|
||||
{ label:'细胞外液', value:'14.5', unit:'kg' },
|
||||
{ label:'健康评分', value:'82', unit:'分' }
|
||||
]}
|
||||
],
|
||||
/* ========== 蓝牙秤 ========== */
|
||||
bluetooth: [
|
||||
{ title: '基础指标', type: 'grid', fields: [
|
||||
{ label:'身高', value:'175', unit:'cm' },
|
||||
{ label:'体重', value:'72.5', unit:'kg' },
|
||||
{ label:'BMI', value:'23.7', status:'正常' },
|
||||
{ label:'基础代谢', value:'1,680', unit:'kcal' },
|
||||
{ label:'体脂肪量', value:'15.2', unit:'kg' },
|
||||
{ label:'体脂肪率', value:'21.0', unit:'%', status:'正常' }
|
||||
], bmi: true },
|
||||
{ title: '水分与蛋白质', type: 'rows', fields: [
|
||||
{ label:'体水分量', value:'37.8', unit:'kg' },
|
||||
{ label:'体水分率', value:'52.1', unit:'%' },
|
||||
{ label:'蛋白质量', value:'8.2', unit:'kg' },
|
||||
{ label:'蛋白质率', value:'11.3', unit:'%' }
|
||||
]},
|
||||
{ title: '肌肉与骨骼', type: 'rows', fields: [
|
||||
{ label:'体肌肉量', value:'30.5', unit:'kg' },
|
||||
{ label:'体肌肉率', value:'42.1', unit:'%' },
|
||||
{ label:'体骨骼量', value:'3.0', unit:'kg' }
|
||||
]},
|
||||
{ title: '脂肪分析', type: 'rows', fields: [
|
||||
{ label:'皮下脂肪量', value:'12.8', unit:'kg' },
|
||||
{ label:'皮下脂肪率', value:'17.7', unit:'%' },
|
||||
{ label:'除脂肪量', value:'57.3', unit:'kg' }
|
||||
]},
|
||||
{ title: '细胞液', type: 'rows', fields: [
|
||||
{ label:'细胞外液量', value:'14.2', unit:'L' },
|
||||
{ label:'细胞外液率', value:'37.6', unit:'%' },
|
||||
{ label:'细胞内液量', value:'23.6', unit:'L' },
|
||||
{ label:'细胞内液率', value:'62.4', unit:'%' }
|
||||
]},
|
||||
{ title: '其他', type: 'rows', fields: [
|
||||
{ label:'矿物质量', value:'3.48', unit:'kg' }
|
||||
]}
|
||||
],
|
||||
/* ========== 体脂仪 ========== */
|
||||
fat: [
|
||||
{ title: '基础指标', type: 'grid', fields: [
|
||||
{ label:'身高', value:'175', unit:'cm' },
|
||||
{ label:'体重', value:'72.5', unit:'kg' },
|
||||
{ label:'BMI', value:'23.7', status:'正常' },
|
||||
{ label:'基础代谢', value:'1,680', unit:'kcal' },
|
||||
{ label:'InBody评分', value:'62', unit:'分' }
|
||||
], bmi: true },
|
||||
{ title: '体脂分析', type: 'rows', fields: [
|
||||
{ label:'体脂肪量', value:'15.2', unit:'kg' },
|
||||
{ label:'体脂肪率', value:'21.0', unit:'%', status:'正常' },
|
||||
{ label:'内脏脂肪等级', value:'6', status:'正常' },
|
||||
{ label:'肥胖度', value:'147', unit:'%' },
|
||||
{ label:'去脂体重', value:'59.6', unit:'kg' }
|
||||
]},
|
||||
{ title: '体成分', type: 'rows', fields: [
|
||||
{ label:'体水分', value:'43.7', unit:'L' },
|
||||
{ label:'蛋白质', value:'11.8', unit:'kg' },
|
||||
{ label:'无机盐', value:'4.11', unit:'kg' },
|
||||
{ label:'骨骼肌量', value:'33.6', unit:'kg' },
|
||||
{ label:'骨骼肌指数', value:'8.8', unit:'kg/m²' }
|
||||
]},
|
||||
{ title: '体重管理', type: 'rows', fields: [
|
||||
{ label:'目标体重', value:'70.2', unit:'kg' },
|
||||
{ label:'体重控制', value:'-2.3', unit:'kg' },
|
||||
{ label:'脂肪控制', value:'-3.1', unit:'kg' },
|
||||
{ label:'肌肉控制', value:'+0.8', unit:'kg' },
|
||||
{ label:'腰臀比', value:'0.88' }
|
||||
]},
|
||||
{ title: '节段脂肪', type: 'segment', cols:['部位','测量值(kg)'],
|
||||
rows: [
|
||||
['左上肢','2.7'], ['右上肢','2.6'],
|
||||
['左下肢','4.7'], ['右下肢','4.8'],
|
||||
['躯干','17.5']
|
||||
]
|
||||
},
|
||||
{ title: '节段肌肉', type: 'segment', cols:['部位','测量值(kg)'],
|
||||
rows: [
|
||||
['左上肢','3.35'], ['右上肢','3.50'],
|
||||
['左下肢','9.11'], ['右下肢','9.40'],
|
||||
['躯干','26.9']
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
/* 渲染 */
|
||||
var sections = deviceData[device] || deviceData.fat;
|
||||
var html = '';
|
||||
sections.forEach(function(sec) {
|
||||
html += '<div class="data-section">';
|
||||
html += '<div class="data-section__title">' + sec.title + '</div>';
|
||||
if (sec.type === 'grid') {
|
||||
html += '<div class="data-grid">';
|
||||
sec.fields.forEach(function(f) {
|
||||
html += '<div class="data-cell"><div class="data-cell__label">' + f.label + '</div>';
|
||||
html += '<div class="data-cell__value">' + f.value;
|
||||
if (f.unit) html += '<span class="data-cell__unit">' + f.unit + '</span>';
|
||||
if (f.status) html += '<span class="data-cell__status data-cell__status--normal">' + f.status + '</span>';
|
||||
html += '</div></div>';
|
||||
});
|
||||
html += '</div>';
|
||||
if (sec.bmi) {
|
||||
html += '<div class="bmi-bar"><div class="bmi-bar__track"><div class="bmi-bar__pointer" style="left:48%"></div></div>';
|
||||
html += '<div class="bmi-bar__labels"><span>偏瘦 <18.5</span><span>正常 18.5-24</span><span>偏胖 24-28</span><span>肥胖 ≥28</span></div></div>';
|
||||
}
|
||||
} else if (sec.type === 'rows') {
|
||||
sec.fields.forEach(function(f, i) {
|
||||
html += '<div class="data-row' + (i === sec.fields.length - 1 ? '' : '') + '">';
|
||||
html += '<span class="data-row__label">' + f.label + '</span>';
|
||||
html += '<div class="data-row__right"><span class="data-row__value">' + f.value + '</span>';
|
||||
if (f.unit) html += '<span class="data-row__unit">' + f.unit + '</span>';
|
||||
if (f.status) html += '<span class="data-cell__status data-cell__status--normal">' + f.status + '</span>';
|
||||
html += '</div></div>';
|
||||
});
|
||||
} else if (sec.type === 'segment') {
|
||||
html += '<table class="seg-table"><thead><tr>';
|
||||
sec.cols.forEach(function(c) { html += '<th>' + c + '</th>'; });
|
||||
html += '</tr></thead><tbody>';
|
||||
sec.rows.forEach(function(r) {
|
||||
html += '<tr>';
|
||||
r.forEach(function(v, i) { html += '<td>' + v + '</td>'; });
|
||||
html += '</tr>';
|
||||
});
|
||||
html += '</tbody></table>';
|
||||
}
|
||||
html += '</div>';
|
||||
});
|
||||
document.getElementById('reportContent').innerHTML = html;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user