feat: 体重管理子页面补充—饮食/运动/体重打卡与记录、建议页、排行榜、报告页

- weight-main.html: 右上角三点菜单支持三种页面类型切换(已参加活动/已设置个人目标/未参加未设置),各类型卡片显隐控制
- 每日打卡三卡片(吃/动/体重)添加点击跳转至对应打卡页
- 膳食建议/运动建议/体重报告卡片添加跳转,报告卡片携带当前类型参数
- 排行榜新增缺省占位状态(未参加活动时显示空态提示)
- 新增10个子页面: diet-advice/eat-checkin/eat-history/exercise-advice/exercise-checkin/exercise-history/weight-checkin/weight-history/weight-ranking/weight-report
- employee-app/home/index.html 每日打卡卡片同步添加点击跳转
- index.html SITE_MAP 体重管理模块新增10个页面条目

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
liuyunqin
2026-06-12 18:08:29 +08:00
co-authored by Claude Opus 4.8
parent 2373704945
commit 00f2ef7e73
14 changed files with 6239 additions and 17 deletions
+7 -4
View File
@@ -70,7 +70,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
.daily-date { font-size: 14px; color: #1f1f1f; text-align: center; margin-bottom: 14px; font-weight: 700; display: flex; align-items: center; justify-content: center; gap: 12px; }
.daily-date::before, .daily-date::after { content: ''; flex: 1; height: 1px; background: linear-gradient(90deg, transparent, #ff7a6b, transparent); max-width: 90px; }
.daily-checkin { display: flex; gap: 10px; }
.checkin-card { flex: 1; border-radius: 14px; padding: 14px 8px 12px; text-align: center; color: #fff; position: relative; }
.checkin-card { flex: 1; border-radius: 14px; padding: 14px 8px 12px; text-align: center; color: #fff; position: relative; cursor: pointer; }
.checkin-card--eat { background: linear-gradient(160deg, #6ee16e 0%, #3ec46a 100%); }
.checkin-card--move { background: linear-gradient(160deg, #ffb066 0%, #ff8a3d 100%); }
.checkin-card--weight { background: linear-gradient(160deg, #b08cff 0%, #8b6cff 100%); }
@@ -253,19 +253,22 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<div class="daily-card">
<div class="daily-date">2025年08月12日</div>
<div class="daily-checkin">
<div class="checkin-card checkin-card--eat">
<!-- [交互] 点击跳转至: eat-checkin.html -->
<div class="checkin-card checkin-card--eat" onclick="location.href='../weight-management/eat-checkin.html'">
<div class="checkin-card__label"></div>
<div class="checkin-card__val">1086<span class="checkin-card__unit">kcal</span></div>
<div class="checkin-card__recommend">推荐 1950千卡</div>
<div class="checkin-card__days">累计行动52天</div>
</div>
<div class="checkin-card checkin-card--move">
<!-- [交互] 点击跳转至: exercise-checkin.html -->
<div class="checkin-card checkin-card--move" onclick="location.href='../weight-management/exercise-checkin.html'">
<div class="checkin-card__label"></div>
<div class="checkin-card__val">12586<span class="checkin-card__unit"></span></div>
<div class="checkin-card__recommend">推荐 12000步</div>
<div class="checkin-card__days">累计行动362天</div>
</div>
<div class="checkin-card checkin-card--weight">
<!-- [交互] 点击跳转至: weight-checkin.html -->
<div class="checkin-card checkin-card--weight" onclick="location.href='../weight-management/weight-checkin.html'">
<div class="checkin-card__label">体重</div>
<div class="checkin-card__val">62.60<span class="checkin-card__unit">kg</span></div>
<div class="checkin-card__recommend">推荐 75-80公斤</div>
@@ -0,0 +1,408 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>膳食建议 - 员工端 | 健康CQ原型</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
.phone-shell { width: 390px; height: 844px; background: #f5f7fa; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; }
.status-bar { height: 44px; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; background: #fff; }
.status-bar .time { font-size: 15px; font-weight: 700; color: #333; }
.status-bar .icons { display: flex; gap: 6px; align-items: center; }
.nav-bar { height: 44px; background: #fff; display: flex; align-items: center; padding: 0 16px; flex-shrink: 0; border-bottom: 1px solid #f0f0f0; }
.nav-back { width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: #1a1a1a; }
.nav-title { flex: 1; text-align: center; font-size: 17px; font-weight: 600; color: #1a1a1a; }
.nav-placeholder { width: 28px; flex-shrink: 0; }
.scroll-content { flex: 1; overflow-y: auto; background: #f5f7fa; }
.scroll-content::-webkit-scrollbar { display: none; }
/* ===== 热量目标卡片 ===== */
.calorie-goal { background: linear-gradient(135deg, #6ee16e 0%, #3ec46a 100%); margin: 12px 12px 0; border-radius: 16px; padding: 18px; color: #fff; position: relative; overflow: hidden; box-shadow: 0 4px 14px rgba(62,196,106,0.25); }
.calorie-goal::after { content: ''; position: absolute; bottom: -30px; right: -20px; width: 100px; height: 100px; border-radius: 50%; background: rgba(255,255,255,0.08); pointer-events: none; }
.calorie-goal__header { display: flex; align-items: center; justify-content: space-between; position: relative; z-index: 1; }
.calorie-goal__label { font-size: 13px; opacity: 0.85; }
.calorie-goal__val { font-size: 42px; font-weight: 800; line-height: 1; margin: 6px 0 2px; position: relative; z-index: 1; }
.calorie-goal__unit { font-size: 16px; font-weight: 500; opacity: 0.8; }
.calorie-goal__sub { font-size: 12px; opacity: 0.7; position: relative; z-index: 1; }
.calorie-goal__bar-wrap { position: relative; z-index: 1; margin-top: 12px; background: rgba(255,255,255,0.2); border-radius: 6px; height: 8px; overflow: hidden; }
.calorie-goal__bar-fill { height: 100%; background: rgba(255,255,255,0.9); border-radius: 6px; transition: width .3s; }
.calorie-goal__bar-label { display: flex; justify-content: space-between; font-size: 11px; margin-top: 4px; opacity: 0.75; position: relative; z-index: 1; }
/* ===== 营养素卡片 ===== */
.nutri-card { background: #fff; border-radius: 16px; margin: 12px 12px 0; padding: 16px 14px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
.nutri-card__title { font-size: 15px; font-weight: 800; color: #1a1a1a; margin-bottom: 12px; }
.nutri-row { display: flex; gap: 10px; }
.nutri-item { flex: 1; text-align: center; }
.nutri-item__ring { position: relative; width: 72px; height: 72px; margin: 0 auto 6px; }
.nutri-item__ring svg { width: 100%; height: 100%; transform: rotate(-90deg); }
.nutri-item__center { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; }
.nutri-item__center-val { font-size: 16px; font-weight: 800; color: #1a1a1a; line-height: 1; }
.nutri-item__center-unit { font-size: 10px; color: #999; margin-top: 1px; }
.nutri-item__name { font-size: 12px; font-weight: 600; color: #333; margin-top: 4px; }
.nutri-item__detail { display: flex; justify-content: center; gap: 6px; font-size: 10px; color: #999; margin-top: 2px; }
.nutri-item__detail span { font-weight: 600; color: #666; }
/* 营养素详情条 */
.nutri-bars { margin-top: 14px; display: flex; flex-direction: column; gap: 8px; }
.nutri-bar { display: flex; align-items: center; gap: 8px; }
.nutri-bar__label { width: 40px; font-size: 12px; color: #666; font-weight: 600; text-align: right; flex-shrink: 0; }
.nutri-bar__track { flex: 1; height: 10px; border-radius: 5px; background: #f0f0f0; overflow: hidden; }
.nutri-bar__fill { height: 100%; border-radius: 5px; }
.nutri-bar__fill--protein { background: linear-gradient(90deg, #5470c6, #7367f0); }
.nutri-bar__fill--carbs { background: linear-gradient(90deg, #fac858, #ffc53d); }
.nutri-bar__fill--fat { background: linear-gradient(90deg, #ee6666, #ff7875); }
.nutri-bar__val { width: 60px; font-size: 12px; color: #333; font-weight: 600; text-align: left; flex-shrink: 0; }
/* ===== 今日三餐卡片 ===== */
.meal-card { background: #fff; border-radius: 16px; margin: 12px 12px 0; padding: 16px 14px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
.meal-card__title { font-size: 15px; font-weight: 800; color: #1a1a1a; margin-bottom: 12px; }
.meal-card__tabs { display: flex; gap: 6px; margin-bottom: 10px; }
.meal-tab { flex: 1; text-align: center; padding: 8px 0; border-radius: 8px; font-size: 13px; font-weight: 600; color: #999; background: #f7f8fa; cursor: pointer; }
.meal-tab.active { background: #6ee16e; color: #fff; }
.meal-list { display: flex; flex-direction: column; gap: 8px; }
.meal-item { display: flex; align-items: center; gap: 10px; padding: 8px 10px; background: #f9fafb; border-radius: 10px; }
.meal-item__icon { width: 36px; height: 36px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 18px; flex-shrink: 0; }
.meal-item__icon--staple { background: #fff7e6; }
.meal-item__icon--vege { background: #f6ffed; }
.meal-item__icon--meat { background: #fff1f0; }
.meal-item__icon--soup { background: #e6f7ff; }
.meal-item__info { flex: 1; min-width: 0; }
.meal-item__name { font-size: 13px; font-weight: 600; color: #333; }
.meal-item__desc { font-size: 11px; color: #999; margin-top: 2px; }
.meal-item__kcal { font-size: 12px; font-weight: 700; color: #6ee16e; flex-shrink: 0; }
/* ===== 一周食谱卡片 ===== */
.week-meal-card { background: #fff; border-radius: 16px; margin: 12px 12px 0; padding: 16px 14px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
.week-meal-card__header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
.week-meal-card__title { font-size: 15px; font-weight: 800; color: #1a1a1a; }
.week-meal-card__tip { font-size: 11px; color: #bbb; }
.week-day-row { display: flex; gap: 4px; margin-bottom: 8px; }
.week-day { flex: 1; text-align: center; padding: 6px 0; border-radius: 8px; cursor: pointer; font-size: 11px; font-weight: 600; color: #999; background: #f7f8fa; transition: all .2s; }
.week-day.active { background: #6ee16e; color: #fff; }
.week-day__label { display: block; font-size: 10px; opacity: 0.7; }
.week-detail { padding: 10px 0 0; }
.week-detail__meals { display: flex; flex-direction: column; gap: 8px; }
.week-detail__header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
.week-detail__total { font-size: 14px; font-weight: 800; color: #1a1a1a; }
.week-detail__total span { font-size: 11px; color: #6ee16e; margin-left: 4px; }
/* ===== 注意事项卡片 ===== */
.tips-card { background: #fff; border-radius: 16px; margin: 12px 12px 0; padding: 16px 14px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
.tips-card__title { font-size: 15px; font-weight: 800; color: #1a1a1a; margin-bottom: 10px; }
.tips-list { display: flex; flex-direction: column; gap: 8px; }
.tips-item { display: flex; align-items: flex-start; gap: 8px; padding: 10px; background: #f9fafb; border-radius: 10px; }
.tips-item__icon { width: 20px; height: 20px; border-radius: 50%; display: flex; align-items: center; justify-content: center; flex-shrink: 0; font-size: 10px; font-weight: 800; color: #fff; }
.tips-item__icon--warn { background: #faad14; }
.tips-item__icon--good { background: #52c41a; }
.tips-item__icon--info { background: #1677ff; }
.tips-item__text { font-size: 12px; color: #555; line-height: 1.6; flex: 1; }
.tips-item__text strong { color: #333; }
.bottom-safe { height: 20px; flex-shrink: 0; }
</style>
</head>
<body>
<div class="phone-shell">
<div class="status-bar">
<span class="time">09:40</span>
<div 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>
</div>
</div>
<div class="nav-bar">
<div class="nav-back" onclick="location.href='weight-main.html'">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
</div>
<div class="nav-title">膳食建议</div>
<div class="nav-placeholder"></div>
</div>
<div class="scroll-content">
<!-- 日热量目标 -->
<div class="calorie-goal">
<div class="calorie-goal__header">
<span class="calorie-goal__label">每日推荐摄入</span>
</div>
<div class="calorie-goal__val">1950<span class="calorie-goal__unit">千卡</span></div>
<div class="calorie-goal__sub">今日已摄入 1086 千卡,还可摄入 864 千卡</div>
<div class="calorie-goal__bar-wrap">
<div class="calorie-goal__bar-fill" style="width:55.7%"></div>
</div>
<div class="calorie-goal__bar-label"><span>已摄入55.7%</span><span>剩余44.3%</span></div>
</div>
<!-- 三大营养素 -->
<div class="nutri-card">
<div class="nutri-card__title">营养素分配建议</div>
<div class="nutri-row">
<!-- 蛋白质 -->
<div class="nutri-item">
<div class="nutri-item__ring">
<svg viewBox="0 0 80 80">
<circle cx="40" cy="40" r="32" fill="none" stroke="#f0f0f0" stroke-width="6"/>
<circle cx="40" cy="40" r="32" fill="none" stroke="#5470c6" stroke-width="6" stroke-dasharray="121 201" stroke-linecap="round"/>
</svg>
<div class="nutri-item__center">
<div class="nutri-item__center-val">73</div>
<div class="nutri-item__center-unit">g</div>
</div>
</div>
<div class="nutri-item__name">蛋白质</div>
<div class="nutri-item__detail"><span>15%</span>热量</div>
</div>
<!-- 碳水 -->
<div class="nutri-item">
<div class="nutri-item__ring">
<svg viewBox="0 0 80 80">
<circle cx="40" cy="40" r="32" fill="none" stroke="#f0f0f0" stroke-width="6"/>
<circle cx="40" cy="40" r="32" fill="none" stroke="#fac858" stroke-width="6" stroke-dasharray="155 201" stroke-linecap="round"/>
</svg>
<div class="nutri-item__center">
<div class="nutri-item__center-val">268</div>
<div class="nutri-item__center-unit">g</div>
</div>
</div>
<div class="nutri-item__name">碳水化合物</div>
<div class="nutri-item__detail"><span>55%</span>热量</div>
</div>
<!-- 脂肪 -->
<div class="nutri-item">
<div class="nutri-item__ring">
<svg viewBox="0 0 80 80">
<circle cx="40" cy="40" r="32" fill="none" stroke="#f0f0f0" stroke-width="6"/>
<circle cx="40" cy="40" r="32" fill="none" stroke="#ee6666" stroke-width="6" stroke-dasharray="65 201" stroke-linecap="round"/>
</svg>
<div class="nutri-item__center">
<div class="nutri-item__center-val">65</div>
<div class="nutri-item__center-unit">g</div>
</div>
</div>
<div class="nutri-item__name">脂肪</div>
<div class="nutri-item__detail"><span>30%</span>热量</div>
</div>
</div>
<!-- 今日摄入进度条 -->
<div class="nutri-bars">
<div class="nutri-bar">
<span class="nutri-bar__label">蛋白质</span>
<div class="nutri-bar__track"><div class="nutri-bar__fill nutri-bar__fill--protein" style="width:60%"></div></div>
<span class="nutri-bar__val">44 / 73g</span>
</div>
<div class="nutri-bar">
<span class="nutri-bar__label">碳水</span>
<div class="nutri-bar__track"><div class="nutri-bar__fill nutri-bar__fill--carbs" style="width:52%"></div></div>
<span class="nutri-bar__val">139 / 268g</span>
</div>
<div class="nutri-bar">
<span class="nutri-bar__label">脂肪</span>
<div class="nutri-bar__track"><div class="nutri-bar__fill nutri-bar__fill--fat" style="width:43%"></div></div>
<span class="nutri-bar__val">28 / 65g</span>
</div>
</div>
</div>
<!-- 今日三餐推荐 -->
<div class="meal-card" id="mealCard">
<div class="meal-card__title">今日三餐推荐</div>
<div class="meal-card__tabs">
<div class="meal-tab active" onclick="switchMealTab('breakfast', this)">早餐</div>
<div class="meal-tab" onclick="switchMealTab('lunch', this)">午餐</div>
<div class="meal-tab" onclick="switchMealTab('dinner', this)">晚餐</div>
</div>
<div id="mealContent"></div>
</div>
<!-- 一周食谱 -->
<div class="week-meal-card">
<div class="week-meal-card__header">
<div class="week-meal-card__title">一周食谱概览</div>
<div class="week-meal-card__tip">科学搭配 均衡营养</div>
</div>
<div class="week-day-row" id="weekDayRow">
<div class="week-day active" data-day="0" onclick="switchWeekDay(0, this)"><span class="week-day__label">周一</span>08-10</div>
<div class="week-day" data-day="1" onclick="switchWeekDay(1, this)"><span class="week-day__label">周二</span>08-11</div>
<div class="week-day" data-day="2" onclick="switchWeekDay(2, this)"><span class="week-day__label">周三</span>08-12</div>
<div class="week-day" data-day="3" onclick="switchWeekDay(3, this)"><span class="week-day__label">周四</span>08-13</div>
<div class="week-day" data-day="4" onclick="switchWeekDay(4, this)"><span class="week-day__label">周五</span>08-14</div>
<div class="week-day" data-day="5" onclick="switchWeekDay(5, this)"><span class="week-day__label">周六</span>08-15</div>
<div class="week-day" data-day="6" onclick="switchWeekDay(6, this)"><span class="week-day__label">周日</span>08-16</div>
</div>
<div class="week-detail" id="weekDetail"></div>
</div>
<!-- 注意事项 -->
<div class="tips-card">
<div class="tips-card__title">膳食注意事项</div>
<div class="tips-list">
<div class="tips-item">
<div class="tips-item__icon tips-item__icon--good"></div>
<div class="tips-item__text"><strong>少食多餐:</strong>建议每日4-5餐,控制单餐摄入量,避免暴饮暴食。</div>
</div>
<div class="tips-item">
<div class="tips-item__icon tips-item__icon--warn">!</div>
<div class="tips-item__text"><strong>低盐低油:</strong>每日食盐摄入不超过6g,烹调油控制在25g以内。</div>
</div>
<div class="tips-item">
<div class="tips-item__icon tips-item__icon--info">i</div>
<div class="tips-item__text"><strong>饮水充足:</strong>每日饮水量建议1500-2000ml,少量多次饮用。</div>
</div>
<div class="tips-item">
<div class="tips-item__icon tips-item__icon--good"></div>
<div class="tips-item__text"><strong>粗细搭配:</strong>主食中粗粮占比不低于1/3,增加膳食纤维摄入。</div>
</div>
<div class="tips-item">
<div class="tips-item__icon tips-item__icon--warn">!</div>
<div class="tips-item__text"><strong>控糖限酒:</strong>减少含糖饮料摄入,男性每日酒精不超过25g。</div>
</div>
<div class="tips-item">
<div class="tips-item__icon tips-item__icon--info">i</div>
<div class="tips-item__text"><strong>食材多样:</strong>每日摄入食物种类不少于12种,每周不少于25种。</div>
</div>
</div>
</div>
<div class="bottom-safe"></div>
</div>
</div>
<script>
/* ===== 三餐数据 ===== */
var MEALS = {
breakfast: [
{ icon:'🥣', cls:'staple', name:'燕麦粥', desc:'燕麦50g + 牛奶200ml', kcal:'245千卡' },
{ icon:'🥚', cls:'meat', name:'水煮蛋', desc:'鸡蛋1个(约50g', kcal:'72千卡' },
{ icon:'🍎', cls:'vege', name:'时令水果', desc:'苹果半个(约100g', kcal:'52千卡' },
{ icon:'🥜', cls:'staple', name:'混合坚果', desc:'核桃杏仁各5g', kcal:'58千卡' }
],
lunch: [
{ icon:'🍚', cls:'staple', name:'杂粮饭', desc:'大米80g + 小米20g', kcal:'280千卡' },
{ icon:'🐟', cls:'meat', name:'清蒸鲈鱼', desc:'鲈鱼120g,少油清蒸', kcal:'165千卡' },
{ icon:'🥬', cls:'vege', name:'蒜蓉西兰花', desc:'西兰花150g', kcal:'68千卡' },
{ icon:'🍄', cls:'soup', name:'菌菇豆腐汤', desc:'豆腐80g + 菌菇50g', kcal:'85千卡' }
],
dinner: [
{ icon:'🍠', cls:'staple', name:'蒸紫薯', desc:'紫薯150g', kcal:'123千卡' },
{ icon:'🍗', cls:'meat', name:'鸡胸肉沙拉', desc:'鸡胸肉100g + 生菜50g', kcal:'156千卡' },
{ icon:'🥒', cls:'vege', name:'凉拌黄瓜', desc:'黄瓜150g,少许醋调味', kcal:'28千卡' },
{ icon:'🍵', cls:'soup', name:'番茄蛋花汤', desc:'番茄100g + 鸡蛋半个', kcal:'55千卡' }
]
};
/* ===== 一周食谱数据 ===== */
var WEEK_PLANS = [
{ day:'周一', date:'08-10', total:'1880千卡', items:[
{ meal:'早餐', name:'燕麦牛奶粥、水煮蛋、苹果', kcal:'427' },
{ meal:'午餐', name:'杂粮饭、清蒸鲈鱼、西兰花、菌菇汤', kcal:'598' },
{ meal:'晚餐', name:'蒸紫薯、鸡胸肉沙拉、凉拌黄瓜', kcal:'362' },
{ meal:'加餐', name:'混合坚果、低脂酸奶', kcal:'185' },
{ meal:'全天', name:'', kcal:'1880' }
]},
{ day:'周二', date:'08-11', total:'1920千卡', items:[
{ meal:'早餐', name:'全麦面包2片、煎蛋、牛奶', kcal:'438' },
{ meal:'午餐', name:'糙米饭、红烧牛肉、炒菠菜、紫菜汤', kcal:'612' },
{ meal:'晚餐', name:'小米粥、虾仁豆腐、清炒苦瓜', kcal:'388' },
{ meal:'加餐', name:'香蕉1根、核桃仁', kcal:'195' },
{ meal:'全天', name:'', kcal:'1920' }
]},
{ day:'周三', date:'08-12', total:'1950千卡', items:[
{ meal:'早餐', name:'燕麦粥、水煮蛋、水果沙拉', kcal:'445' },
{ meal:'午餐', name:'荞麦面、鸡胸肉、凉拌木耳、冬瓜汤', kcal:'580' },
{ meal:'晚餐', name:'玉米、清蒸鱼块、蒜蓉生菜', kcal:'395' },
{ meal:'加餐', name:'无糖豆浆、杏仁', kcal:'178' },
{ meal:'全天', name:'', kcal:'1950' }
]},
{ day:'周四', date:'08-13', total:'1890千卡', items:[
{ meal:'早餐', name:'杂粮馒头、豆浆、煮鸡蛋', kcal:'410' },
{ meal:'午餐', name:'二米饭、蒜蓉虾、炒豆芽、番茄汤', kcal:'595' },
{ meal:'晚餐', name:'南瓜粥、瘦牛肉片、凉拌秋葵', kcal:'370' },
{ meal:'加餐', name:'酸奶、腰果', kcal:'192' },
{ meal:'全天', name:'', kcal:'1890' }
]},
{ day:'周五', date:'08-14', total:'1930千卡', items:[
{ meal:'早餐', name:'蔬菜鸡蛋饼、小米粥', kcal:'432' },
{ meal:'午餐', name:'紫米饭、红烧鱼块、炒芦笋、海带汤', kcal:'608' },
{ meal:'晚餐', name:'荞麦面、鸡丝凉拌、蚝油生菜', kcal:'385' },
{ meal:'加餐', name:'猕猴桃、南瓜籽', kcal:'165' },
{ meal:'全天', name:'', kcal:'1930' }
]},
{ day:'周六', date:'08-15', total:'1850千卡', items:[
{ meal:'早餐', name:'全麦三明治、牛奶、圣女果', kcal:'445' },
{ meal:'午餐', name:'糙米饭、红烧排骨、炒空心菜', kcal:'590' },
{ meal:'晚餐', name:'蒸山药、白灼虾、凉拌海带', kcal:'340' },
{ meal:'加餐', name:'苹果、开心果', kcal:'180' },
{ meal:'全天', name:'', kcal:'1850' }
]},
{ day:'周日', date:'08-16', total:'1870千卡', items:[
{ meal:'早餐', name:'鸡蛋羹、蒸玉米、牛奶', kcal:'420' },
{ meal:'午餐', name:'杂粮饭、蒸鳕鱼、炒四季豆', kcal:'575' },
{ meal:'晚餐', name:'蔬菜汤面、卤牛肉片、拍黄瓜', kcal:'398' },
{ meal:'加餐', name:'葡萄、松子', kcal:'172' },
{ meal:'全天', name:'', kcal:'1870' }
]}
];
/* ===== 渲染三餐 ===== */
var currentMealTab = 'breakfast';
function renderMeal(tab) {
var items = MEALS[tab];
var html = '<div class="meal-list">';
for (var i = 0; i < items.length; i++) {
var it = items[i];
html += '<div class="meal-item">';
html += '<div class="meal-item__icon meal-item__icon--' + it.cls + '">' + it.icon + '</div>';
html += '<div class="meal-item__info"><div class="meal-item__name">' + it.name + '</div><div class="meal-item__desc">' + it.desc + '</div></div>';
html += '<div class="meal-item__kcal">' + it.kcal + '</div>';
html += '</div>';
}
html += '</div>';
document.getElementById('mealContent').innerHTML = html;
}
function switchMealTab(tab, el) {
currentMealTab = tab;
el.parentElement.querySelectorAll('.meal-tab').forEach(function(t) { t.classList.remove('active'); });
el.classList.add('active');
renderMeal(tab);
}
/* ===== 一周食谱 ===== */
var currentWeekDay = 0;
function renderWeekDetail(dayIdx) {
var plan = WEEK_PLANS[dayIdx];
var html = '<div class="week-detail__header"><span class="week-detail__total">' + plan.total + '</span></div>';
html += '<div class="week-detail__meals">';
for (var i = 0; i < plan.items.length - 1; i++) {
var item = plan.items[i];
html += '<div class="meal-item">';
html += '<div class="meal-item__icon meal-item__icon--staple" style="font-size:14px;font-weight:700;color:#faad14;">' + item.meal + '</div>';
html += '<div class="meal-item__info"><div class="meal-item__name">' + item.name + '</div></div>';
html += '<div class="meal-item__kcal">' + item.kcal + 'kcal</div>';
html += '</div>';
}
html += '</div>';
document.getElementById('weekDetail').innerHTML = html;
}
function switchWeekDay(dayIdx, el) {
currentWeekDay = dayIdx;
document.querySelectorAll('.week-day').forEach(function(d) { d.classList.remove('active'); });
el.classList.add('active');
renderWeekDetail(dayIdx);
}
/* ===== 初始化 ===== */
function init() {
renderMeal('breakfast');
renderWeekDetail(0);
}
init();
</script>
</body>
</html>
@@ -4,6 +4,52 @@
---
## [2026-06-12] feat: 体重管理子页面补充—饮食/运动/体重打卡与记录、建议页、排行榜、报告页
**涉及文件(13个):**
- `employee-app/home/index.html`(修改)
- `employee-app/weight-management/weight-main.html`(修改)
- `employee-app/weight-management/diet-advice.html`(新增)
- `employee-app/weight-management/eat-checkin.html`(新增)
- `employee-app/weight-management/eat-history.html`(新增)
- `employee-app/weight-management/exercise-advice.html`(新增)
- `employee-app/weight-management/exercise-checkin.html`(新增)
- `employee-app/weight-management/exercise-history.html`(新增)
- `employee-app/weight-management/weight-checkin.html`(新增)
- `employee-app/weight-management/weight-history.html`(新增)
- `employee-app/weight-management/weight-ranking.html`(新增)
- `employee-app/weight-management/weight-report.html`(新增)
- `index.html`(修改)
**变更说明:**
**employee-app/home/index.html**
- 每日打卡三张卡片(吃/动/体重)添加 cursor:pointer 样式及点击跳转,分别导航至 `eat-checkin.html``exercise-checkin.html``weight-checkin.html`
**weight-main.html**
- 右上角新增三点菜单按钮,支持三种页面类型切换(已参加活动/已设置个人目标/未参加未设置),各类型对应不同的卡片显隐逻辑
- 排行榜卡片新增缺省占位状态(未参加活动时显示空态提示)
- 膳食建议/运动建议/体重报告三张卡片添加点击跳转至对应子页面
- 体重记录"查看历史"添加跳转至 `weight-history.html`
- 体重报告卡片跳转携带当前页面类型参数(`?type=`
**新增子页面(10个):**
- `diet-advice.html` — 膳食建议页
- `eat-checkin.html` — 饮食打卡页
- `eat-history.html` — 摄入记录历史页
- `exercise-advice.html` — 运动建议页
- `exercise-checkin.html` — 运动打卡页
- `exercise-history.html` — 消耗记录历史页
- `weight-checkin.html` — 体重打卡页
- `weight-history.html` — 体重记录历史页
- `weight-ranking.html` — 体重排行榜页
- `weight-report.html` — 体重报告页
**index.html**
- SITE_MAP 体重管理模块新增 10 个页面条目(weight-ranking、eat-checkin、eat-history、weight-history、weight-report、diet-advice、exercise-advice、exercise-checkin、exercise-history、weight-checkin
---
## [2026-06-12] feat: 体重管理模块交互完善—多状态卡片显隐、导航链路连通、SITE_MAP 补全
**涉及文件(7个):**
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,518 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>摄入记录 - 员工端 | 健康CQ原型</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
.phone-shell { width: 390px; height: 844px; background: #f5f7fa; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; }
.status-bar { height: 44px; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; background: #fff; }
.status-bar .time { font-size: 15px; font-weight: 700; color: #333; }
.status-bar .icons { display: flex; gap: 6px; align-items: center; }
.nav-bar { height: 44px; background: #fff; display: flex; align-items: center; padding: 0 16px; flex-shrink: 0; border-bottom: 1px solid #f0f0f0; }
.nav-back { width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: #1a1a1a; }
.nav-title { flex: 1; text-align: center; font-size: 17px; font-weight: 600; color: #1a1a1a; }
.nav-placeholder { width: 28px; flex-shrink: 0; }
.scroll-content { flex: 1; overflow-y: auto; background: #f5f7fa; }
.scroll-content::-webkit-scrollbar { display: none; }
/* ===== 日历月导航 ===== */
.cal-nav { display: flex; align-items: center; justify-content: space-between; padding: 8px 16px; background: #fff; }
.cal-nav__arrow { width: 30px; height: 30px; border-radius: 50%; background: #f5f7fa; display: flex; align-items: center; justify-content: center; cursor: pointer; border: none; flex-shrink: 0; }
.cal-nav__arrow svg { width: 14px; height: 14px; stroke: #333; }
.cal-nav__month { font-size: 15px; font-weight: 700; color: #1a1a1a; flex: 1; text-align: center; }
.cal-nav__toggle { font-size: 12px; color: #1890ff; cursor: pointer; font-weight: 600; padding: 4px 10px; border-radius: 12px; background: #e6f7ff; flex-shrink: 0; white-space: nowrap; }
/* ===== 周日历(默认视图) ===== */
.week-cal { background: #fff; padding: 0 10px 10px; margin: 0 12px; border-radius: 0 0 16px 16px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
.week-cal__row { display: flex; gap: 2px; }
.week-cal__cell { flex: 1; text-align: center; padding: 8px 0 6px; border-radius: 10px; position: relative; cursor: default; min-width: 0; }
.week-cal__cell.today { background: #e8f8f7; }
.week-cal__cell.selected { background: #e6f7ff; box-shadow: inset 0 0 0 2px #1890ff; }
.week-cal__wd { font-size: 10px; color: #999; margin-bottom: 4px; }
.week-cal__date-wrap { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; margin: 0 auto 4px; }
.week-cal__date { font-size: 14px; font-weight: 700; color: #333; position: relative; z-index: 2; }
.week-cal__cell.today .week-cal__date { color: #36cfc9; }
.week-cal__ring { position: absolute; inset: -2px; border-radius: 50%; border: 2.5px solid transparent; z-index: 1; }
.week-cal__ring--auto { border-color: #1890ff; }
.week-cal__ring--manual { border-color: #fa8c16; }
.week-cal__ring--mixed { border-color: #722ed1; }
.week-cal__dot-row { display: flex; justify-content: center; gap: 3px; margin-top: 2px; }
.week-cal__dot { width: 5px; height: 5px; border-radius: 50%; flex-shrink: 0; }
.week-cal__dot--auto { background: #1890ff; }
.week-cal__dot--manual { background: #fa8c16; }
.week-cal__dot--mixed { background: #722ed1; }
/* 日历摄入千卡数据 */
.week-cal__data { font-size: 10px; color: #666; line-height: 1.4; margin-top: 2px; }
.week-cal__data .w { font-weight: 700; color: #333; }
/* ===== 月日历(展开视图) ===== */
.month-cal { background: #fff; padding: 0 10px 10px; margin: 0 12px; border-radius: 0 0 16px 16px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
.month-cal__weekday { display: grid; grid-template-columns: repeat(7, 1fr); margin-bottom: 2px; }
.month-cal__weekday span { font-size: 10px; color: #999; text-align: center; padding: 4px 0; }
.month-cal__row { display: grid; grid-template-columns: repeat(7, 1fr); }
.month-cal__cell { text-align: center; padding: 2px 1px 4px; min-height: 46px; position: relative; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; border-radius: 8px; cursor: default; }
.month-cal__cell.today { background: #e8f8f7; }
.month-cal__cell.selected { background: #e6f7ff; box-shadow: inset 0 0 0 2px #1890ff; }
.month-cal__cell.other-month .month-cal__date { color: #ddd; }
.month-cal__date { font-size: 13px; font-weight: 600; color: #333; position: relative; z-index: 2; }
.month-cal__cell.today .month-cal__date { color: #36cfc9; font-weight: 800; }
.month-cal__ring { position: absolute; top: 2px; left: 50%; transform: translateX(-50%); width: 26px; height: 26px; border-radius: 50%; border: 2px solid transparent; }
.month-cal__ring--auto { border-color: #1890ff; }
.month-cal__ring--manual { border-color: #fa8c16; }
.month-cal__ring--mixed { border-color: #722ed1; }
.month-cal__dots { display: flex; justify-content: center; gap: 2px; margin-top: 1px; }
.month-cal__dot { width: 4px; height: 4px; border-radius: 50%; flex-shrink: 0; }
/* 月历摄入千卡数据 */
.month-cal__data { font-size: 9px; color: #666; line-height: 1.3; margin-top: 1px; }
.month-cal__data .mw { font-weight: 700; color: #333; }
.month-cal__dot--auto { background: #1890ff; }
.month-cal__dot--manual { background: #fa8c16; }
.month-cal__dot--mixed { background: #722ed1; }
/* ===== 图例 ===== */
.legend { display: flex; justify-content: center; gap: 14px; padding: 8px 16px; flex-wrap: wrap; background: #fff; margin: 8px 12px 0; border-radius: 12px; }
.legend__item { display: flex; align-items: center; gap: 4px; font-size: 11px; color: #666; }
.legend__dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.legend__dot--auto { background: #1890ff; }
.legend__dot--manual { background: #fa8c16; }
.legend__dot--mixed { background: #722ed1; }
/* ===== Tab 栏 ===== */
.record-tabs { display: flex; background: #fff; margin: 8px 12px 0; border-radius: 12px; overflow: hidden; }
.record-tab { flex: 1; text-align: center; padding: 10px 0; font-size: 13px; font-weight: 600; color: #999; cursor: pointer; position: relative; }
.record-tab.active { color: #1890ff; }
.record-tab.active::after { content: ''; position: absolute; bottom: 4px; left: 50%; transform: translateX(-50%); width: 20px; height: 3px; background: #1890ff; border-radius: 2px; }
/* ===== 列表区域 ===== */
.record-list { padding: 8px 12px 16px; display: flex; flex-direction: column; gap: 8px; }
.record-item { background: #fff; border-radius: 14px; padding: 14px; box-shadow: 0 2px 8px rgba(0,0,0,0.03); }
.record-item__header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.record-item__title { font-size: 14px; font-weight: 700; color: #1a1a1a; }
.record-item__time { font-size: 11px; color: #bbb; }
.record-item__body { display: flex; align-items: center; gap: 16px; }
.record-item__metric { text-align: center; min-width: 50px; }
.record-item__metric-label { font-size: 10px; color: #999; margin-bottom: 2px; }
.record-item__metric-val { font-size: 16px; font-weight: 700; color: #1a1a1a; }
.record-item__metric-unit { font-size: 10px; color: #999; font-weight: 400; margin-left: 1px; }
.record-item__source { margin-left: auto; }
.source-badge { display: inline-block; padding: 4px 10px; border-radius: 12px; font-size: 11px; font-weight: 600; }
.source-badge--auto { background: #e6f7ff; color: #1890ff; }
.source-badge--manual { background: #fff7e6; color: #fa8c16; }
.source-badge--mixed { background: #f9f0ff; color: #722ed1; }
.record-empty { text-align: center; padding: 40px 20px; color: #ccc; font-size: 14px; }
.bottom-safe { height: 20px; flex-shrink: 0; }
</style>
</head>
<body>
<div class="phone-shell">
<div class="status-bar">
<span class="time">09:40</span>
<div 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>
</div>
</div>
<div class="nav-bar">
<!-- [交互] 点击返回吃打卡页面 -->
<div class="nav-back" onclick="location.href='eat-checkin.html'">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
</div>
<div class="nav-title">摄入记录</div>
<div class="nav-placeholder"></div>
</div>
<div class="scroll-content">
<!-- 日历月导航 -->
<div class="cal-nav">
<div class="cal-nav__arrow" onclick="prevMonth()">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
</div>
<div class="cal-nav__month" id="calMonthLabel">2026年06月</div>
<div class="cal-nav__arrow" onclick="nextMonth()">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg>
</div>
<div class="cal-nav__toggle" id="calToggle" onclick="toggleCalView()">展开月历</div>
</div>
<!-- 周日历(默认) -->
<div class="week-cal" id="weekCal"></div>
<!-- 月日历(展开后显示) -->
<div class="month-cal" id="monthCal" style="display:none;"></div>
<!-- 图例 -->
<div class="legend">
<div class="legend__item"><span class="legend__dot legend__dot--auto"></span>智记餐</div>
<div class="legend__item"><span class="legend__dot legend__dot--manual"></span>自记餐</div>
<div class="legend__item"><span class="legend__dot legend__dot--mixed"></span>智记+自记餐</div>
</div>
<!-- Tab 栏 -->
<div class="record-tabs" id="recordTabs">
<div class="record-tab active" data-range="week" onclick="switchTab('week')"></div>
<div class="record-tab" data-range="month" onclick="switchTab('month')"></div>
<div class="record-tab" data-range="quarter" onclick="switchTab('quarter')"></div>
<div class="record-tab" data-range="activity" onclick="switchTab('activity')">活动期间</div>
<div class="record-tab" data-range="all" onclick="switchTab('all')">全部</div>
</div>
<!-- 记录列表 -->
<div class="record-list" id="recordList"></div>
<div class="bottom-safe"></div>
</div>
</div>
<script>
/* ===== 来源类型 ===== */
var SOURCE_TYPES = {
'auto': { label:'智记餐', css:'auto', ring:'week-cal__ring--auto', mring:'month-cal__ring--auto', dot:'week-cal__dot--auto', mdot:'month-cal__dot--auto', badge:'source-badge--auto' },
'manual': { label:'自记餐', css:'manual', ring:'week-cal__ring--manual', mring:'month-cal__ring--manual', dot:'week-cal__dot--manual', mdot:'month-cal__dot--manual', badge:'source-badge--manual' },
'mixed': { label:'智记+自记餐', css:'mixed', ring:'week-cal__ring--mixed', mring:'month-cal__ring--mixed', dot:'week-cal__dot--mixed', mdot:'month-cal__dot--mixed', badge:'source-badge--mixed' }
};
/* ===== 摄入记录数据 ===== */
var MEAL_NAMES = { breakfast:'早餐', lunch:'午餐', dinner:'晚餐', snack:'加餐' };
var RECORDS = [
{ date:'2026-06-13', meal:'breakfast', kcal:312, time:'07:45', source:'manual' },
{ date:'2026-06-13', meal:'lunch', kcal:480, time:'12:10', source:'auto' },
{ date:'2026-06-13', meal:'dinner', kcal:420, time:'18:30', source:'mixed' },
{ date:'2026-06-12', meal:'breakfast', kcal:300, time:'07:30', source:'manual' },
{ date:'2026-06-12', meal:'lunch', kcal:475, time:'12:05', source:'auto' },
{ date:'2026-06-12', meal:'dinner', kcal:306, time:'18:15', source:'manual' },
{ date:'2026-06-10', meal:'breakfast', kcal:280, time:'07:50', source:'mixed' },
{ date:'2026-06-10', meal:'lunch', kcal:520, time:'11:55', source:'auto' },
{ date:'2026-06-10', meal:'dinner', kcal:350, time:'18:40', source:'manual' },
{ date:'2026-06-08', meal:'breakfast', kcal:295, time:'07:20', source:'auto' },
{ date:'2026-06-08', meal:'lunch', kcal:488, time:'12:15', source:'auto' },
{ date:'2026-06-08', meal:'dinner', kcal:380, time:'18:20', source:'mixed' },
{ date:'2026-06-07', meal:'breakfast', kcal:260, time:'08:00', source:'manual' },
{ date:'2026-06-07', meal:'lunch', kcal:505, time:'12:00', source:'auto' },
{ date:'2026-06-05', meal:'dinner', kcal:400, time:'18:35', source:'manual' },
{ date:'2026-06-03', meal:'breakfast', kcal:310, time:'07:15', source:'mixed' },
{ date:'2026-06-03', meal:'lunch', kcal:460, time:'12:20', source:'auto' },
{ date:'2026-06-01', meal:'lunch', kcal:495, time:'12:08', source:'auto' },
{ date:'2026-06-01', meal:'dinner', kcal:370, time:'18:25', source:'manual' },
{ date:'2026-05-28', meal:'breakfast', kcal:275, time:'07:40', source:'auto' },
{ date:'2026-05-28', meal:'lunch', kcal:510, time:'12:03', source:'mixed' },
{ date:'2026-05-25', meal:'dinner', kcal:430, time:'18:30', source:'manual' },
{ date:'2026-05-20', meal:'breakfast', kcal:290, time:'07:35', source:'manual' },
{ date:'2026-05-20', meal:'lunch', kcal:485, time:'12:10', source:'auto' },
{ date:'2026-05-15', meal:'lunch', kcal:500, time:'11:50', source:'auto' },
{ date:'2026-05-15', meal:'dinner', kcal:360, time:'18:45', source:'mixed' },
{ date:'2026-05-10', meal:'breakfast', kcal:285, time:'07:25', source:'auto' },
{ date:'2026-05-10', meal:'dinner', kcal:410, time:'18:15', source:'manual' },
{ date:'2026-05-05', meal:'lunch', kcal:470, time:'12:05', source:'mixed' },
{ date:'2026-05-01', meal:'breakfast', kcal:305, time:'07:30', source:'manual' },
{ date:'2026-04-25', meal:'lunch', kcal:492, time:'12:12', source:'auto' },
{ date:'2026-04-20', meal:'dinner', kcal:385, time:'18:20', source:'mixed' },
];
/* ===== 状态 ===== */
var calYear = 2026;
var calMonth = 5; // 0-based, 5=June
var calExpanded = false;
var activeTab = 'week';
var selectedDate = null;
var TODAY = new Date(2026, 5, 12); // 2026-06-12
var ACTIVITY_START = new Date(2026, 4, 1); // 2026-05-01
var ACTIVITY_END = new Date(2026, 7, 1); // 2026-08-01
/* ===== 工具函数 ===== */
function fmt(n) { return n < 10 ? '0' + n : '' + n; }
function dateStr(y, m, d) { return y + '-' + fmt(m+1) + '-' + fmt(d); }
function parseDate(s) { var p = s.split('-'); return new Date(+p[0], +p[1]-1, +p[2]); }
function sameDay(a, b) { return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate(); }
/* 获取某天的记录列表,返回各来源类型集合 */
function getDaySources(y, m, d) {
var s = dateStr(y, m, d);
var sources = {};
for (var i = 0; i < RECORDS.length; i++) {
if (RECORDS[i].date === s) {
sources[RECORDS[i].source] = true;
}
}
return Object.keys(sources);
}
/* 获取某天的总摄入千卡 */
function getDayKcal(y, m, d) {
var s = dateStr(y, m, d);
var total = 0;
for (var i = 0; i < RECORDS.length; i++) {
if (RECORDS[i].date === s) {
total += RECORDS[i].kcal;
}
}
return total;
}
/* ===== 周日历 ===== */
var WEEKDAY_LABELS = ['一','二','三','四','五','六','日'];
function getWeekStart() {
var first = new Date(calYear, calMonth, 1);
var day = first.getDay();
var monday = new Date(first);
monday.setDate(1 - (day === 0 ? 6 : day - 1));
return monday;
}
function renderWeekCal() {
var container = document.getElementById('weekCal');
var now = new Date(2026, 5, 12);
var start;
if (calYear === now.getFullYear() && calMonth === now.getMonth()) {
var dow = now.getDay() || 7;
start = new Date(now);
start.setDate(now.getDate() - dow + 1);
} else {
start = getWeekStart();
}
var html = '<div class="week-cal__row">';
for (var i = 0; i < 7; i++) {
var d = new Date(start);
d.setDate(start.getDate() + i);
var sources = getDaySources(d.getFullYear(), d.getMonth(), d.getDate());
var hasRecord = sources.length > 0;
var isToday = sameDay(d, TODAY);
var isOtherMonth = d.getMonth() !== calMonth;
var dateKey = dateStr(d.getFullYear(), d.getMonth(), d.getDate());
var isSel = dateKey === selectedDate;
// 取第一个来源类型作为环色(有多个时显示第一个,并用点补充)
var primarySource = sources[0] || null;
html += '<div class="week-cal__cell' + (isToday ? ' today' : '') + (isSel ? ' selected' : '') + '"'
+ ' onclick="onDayClick(\'' + dateKey + '\')" style="cursor:' + (hasRecord ? 'pointer' : 'default') + '">';
html += '<div class="week-cal__wd">' + WEEKDAY_LABELS[i] + '</div>';
html += '<div class="week-cal__date-wrap">';
if (primarySource) {
html += '<div class="week-cal__ring ' + SOURCE_TYPES[primarySource].ring + '"></div>';
}
html += '<span class="week-cal__date" style="' + (isOtherMonth ? 'color:#ddd' : '') + '">' + (isToday ? '今' : d.getDate()) + '</span>';
html += '</div>';
var dayKcal = getDayKcal(d.getFullYear(), d.getMonth(), d.getDate());
if (dayKcal > 0) {
html += '<div class="week-cal__data"><span class="w">' + dayKcal + '</span>千卡</div>';
}
html += '</div>';
}
html += '</div>';
container.innerHTML = html;
}
/* ===== 月日历 ===== */
function renderMonthCal() {
var container = document.getElementById('monthCal');
var html = '<div class="month-cal__weekday">';
for (var w = 0; w < 7; w++) { html += '<span>' + WEEKDAY_LABELS[w] + '</span>'; }
html += '</div>';
var first = new Date(calYear, calMonth, 1);
var startDow = first.getDay() || 7;
var cursor = new Date(first);
cursor.setDate(1 - (startDow - 1));
var done = false;
for (var row = 0; row < 6 && !done; row++) {
html += '<div class="month-cal__row">';
for (var col = 0; col < 7; col++) {
var isOther = cursor.getMonth() !== calMonth;
var isToday = sameDay(cursor, TODAY);
var dateKey = dateStr(cursor.getFullYear(), cursor.getMonth(), cursor.getDate());
var isSel = dateKey === selectedDate;
var sources = getDaySources(cursor.getFullYear(), cursor.getMonth(), cursor.getDate());
var primarySource = sources[0] || null;
html += '<div class="month-cal__cell' + (isToday ? ' today' : '') + (isOther ? ' other-month' : '') + (isSel ? ' selected' : '') + '"'
+ ' onclick="onDayClick(\'' + dateKey + '\')" style="cursor:' + (sources.length ? 'pointer' : 'default') + '">';
html += '<div style="position:relative;width:26px;height:26px;">';
if (primarySource) {
html += '<div class="month-cal__ring ' + SOURCE_TYPES[primarySource].mring + '"></div>';
}
html += '<span class="month-cal__date">' + (isToday ? '今' : cursor.getDate()) + '</span>';
html += '</div>';
var mKcal = getDayKcal(cursor.getFullYear(), cursor.getMonth(), cursor.getDate());
if (mKcal > 0) {
html += '<div class="month-cal__data"><span class="mw">' + mKcal + '</span>千卡</div>';
}
html += '</div>';
cursor.setDate(cursor.getDate() + 1);
if (col === 6 && cursor.getDate() > 7 && cursor.getMonth() !== calMonth) { done = true; }
}
html += '</div>';
}
container.innerHTML = html;
}
/* ===== 日历展开/收起 ===== */
function toggleCalView() {
calExpanded = !calExpanded;
document.getElementById('weekCal').style.display = calExpanded ? 'none' : '';
document.getElementById('monthCal').style.display = calExpanded ? '' : 'none';
document.getElementById('calToggle').textContent = calExpanded ? '收起月历' : '展开月历';
if (calExpanded) renderMonthCal();
}
function prevMonth() {
if (calExpanded) {
calMonth--;
if (calMonth < 0) { calMonth = 11; calYear--; }
} else {
var now = new Date(2026, 5, 12);
var dow = now.getDay() || 7;
var curWeekStart;
if (calYear === now.getFullYear() && calMonth === now.getMonth()) {
curWeekStart = new Date(now);
curWeekStart.setDate(now.getDate() - dow + 1);
} else {
curWeekStart = getWeekStart();
}
curWeekStart.setDate(curWeekStart.getDate() - 7);
calYear = curWeekStart.getFullYear();
calMonth = curWeekStart.getMonth();
}
updateCal();
}
function nextMonth() {
if (calExpanded) {
calMonth++;
if (calMonth > 11) { calMonth = 0; calYear++; }
} else {
var now = new Date(2026, 5, 12);
var dow = now.getDay() || 7;
var curWeekStart;
if (calYear === now.getFullYear() && calMonth === now.getMonth()) {
curWeekStart = new Date(now);
curWeekStart.setDate(now.getDate() - dow + 1);
} else {
curWeekStart = getWeekStart();
}
curWeekStart.setDate(curWeekStart.getDate() + 7);
calYear = curWeekStart.getFullYear();
calMonth = curWeekStart.getMonth();
}
updateCal();
}
function updateCal() {
document.getElementById('calMonthLabel').textContent = calYear + '年' + fmt(calMonth + 1) + '月';
renderWeekCal();
if (calExpanded) renderMonthCal();
}
/* ===== Tab 切换 ===== */
function switchTab(range) {
activeTab = range;
selectedDate = null;
document.querySelectorAll('.record-tab').forEach(function(t) {
t.classList.toggle('active', t.dataset.range === range);
});
updateCal();
renderRecordList();
}
function getTabDateRange() {
var now = new Date(2026, 5, 12);
var start, end;
switch (activeTab) {
case 'week':
var dow = now.getDay() || 7;
start = new Date(now); start.setDate(now.getDate() - dow + 1);
end = new Date(start); end.setDate(start.getDate() + 6);
break;
case 'month':
start = new Date(now.getFullYear(), now.getMonth(), 1);
end = new Date(now.getFullYear(), now.getMonth() + 1, 0);
break;
case 'quarter':
var q = Math.floor(now.getMonth() / 3);
start = new Date(now.getFullYear(), q * 3, 1);
end = new Date(now.getFullYear(), (q + 1) * 3, 0);
break;
case 'activity':
start = ACTIVITY_START;
end = ACTIVITY_END;
break;
case 'all':
start = new Date(2000, 0, 1);
end = new Date(2099, 11, 31);
break;
}
return { start: start, end: end };
}
/* ===== 渲染记录列表 ===== */
function renderRecordList() {
var filtered;
if (selectedDate) {
filtered = RECORDS.filter(function(r) { return r.date === selectedDate; });
} else {
var range = getTabDateRange();
filtered = RECORDS.filter(function(r) {
var d = parseDate(r.date);
return d >= range.start && d <= range.end;
});
}
var container = document.getElementById('recordList');
if (filtered.length === 0) {
container.innerHTML = '<div class="record-empty">该时间段暂无记录</div>';
return;
}
var html = '';
for (var i = 0; i < filtered.length; i++) {
var r = filtered[i];
var src = SOURCE_TYPES[r.source];
html += '<div class="record-item">';
html += '<div class="record-item__header">';
html += '<span class="record-item__title">' + MEAL_NAMES[r.meal] + '记录</span>';
html += '<span class="record-item__time">' + r.date + ' ' + r.time + '</span>';
html += '</div>';
html += '<div class="record-item__body">';
html += '<div class="record-item__metric"><div class="record-item__metric-label">摄入热量</div><div class="record-item__metric-val">' + r.kcal + '<span class="record-item__metric-unit">千卡</span></div></div>';
html += '<div class="record-item__source"><span class="source-badge ' + src.badge + '">' + src.label + '</span></div>';
html += '</div>';
html += '</div>';
}
container.innerHTML = html;
}
/* ===== 点击日期 ===== */
function onDayClick(dateStr) {
if (selectedDate === dateStr) {
switchTab('week');
return;
}
selectedDate = dateStr;
activeTab = '';
document.querySelectorAll('.record-tab').forEach(function(t) { t.classList.remove('active'); });
updateCal();
renderRecordList();
document.querySelector('.scroll-content').scrollTop = document.getElementById('recordTabs').offsetTop - 100;
}
/* ===== 初始化 ===== */
function init() {
calYear = TODAY.getFullYear();
calMonth = TODAY.getMonth();
document.getElementById('calMonthLabel').textContent = calYear + '年' + fmt(calMonth + 1) + '月';
renderWeekCal();
renderRecordList();
}
init();
</script>
</body>
</html>
@@ -0,0 +1,302 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>运动建议 - 员工端 | 健康CQ原型</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
.phone-shell { width: 390px; height: 844px; background: #f5f7fa; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; }
.status-bar { height: 44px; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; background: #fff; }
.status-bar .time { font-size: 15px; font-weight: 700; color: #333; }
.status-bar .icons { display: flex; gap: 6px; align-items: center; }
.nav-bar { height: 44px; background: #fff; display: flex; align-items: center; padding: 0 16px; flex-shrink: 0; border-bottom: 1px solid #f0f0f0; }
.nav-back { width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: #1a1a1a; }
.nav-title { flex: 1; text-align: center; font-size: 17px; font-weight: 600; color: #1a1a1a; }
.nav-placeholder { width: 28px; flex-shrink: 0; }
.scroll-content { flex: 1; overflow-y: auto; background: #f5f7fa; }
.scroll-content::-webkit-scrollbar { display: none; }
/* ===== 步数目标卡片 ===== */
.step-goal { background: linear-gradient(135deg, #ffb066 0%, #ff8a3d 100%); margin: 12px 12px 0; border-radius: 16px; padding: 18px; color: #fff; position: relative; overflow: hidden; box-shadow: 0 4px 14px rgba(255,138,61,0.25); }
.step-goal::after { content: ''; position: absolute; bottom: -30px; right: -20px; width: 100px; height: 100px; border-radius: 50%; background: rgba(255,255,255,0.08); pointer-events: none; }
.step-goal__label { font-size: 13px; opacity: 0.85; position: relative; z-index: 1; }
.step-goal__val { font-size: 42px; font-weight: 800; line-height: 1; margin: 6px 0 2px; position: relative; z-index: 1; }
.step-goal__unit { font-size: 16px; font-weight: 500; opacity: 0.8; }
.step-goal__sub { font-size: 12px; opacity: 0.7; position: relative; z-index: 1; }
.step-goal__bar-wrap { position: relative; z-index: 1; margin-top: 12px; background: rgba(255,255,255,0.2); border-radius: 6px; height: 8px; overflow: hidden; }
.step-goal__bar-fill { height: 100%; background: rgba(255,255,255,0.9); border-radius: 6px; }
.step-goal__bar-label { display: flex; justify-content: space-between; font-size: 11px; margin-top: 4px; opacity: 0.75; position: relative; z-index: 1; }
/* ===== 运动消耗卡片 ===== */
.burn-card { background: #fff; border-radius: 16px; margin: 12px 12px 0; padding: 16px 14px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
.burn-card__title { font-size: 15px; font-weight: 800; color: #1a1a1a; margin-bottom: 12px; }
.burn-row { display: flex; gap: 10px; }
.burn-item { flex: 1; text-align: center; background: #f9fafb; border-radius: 12px; padding: 14px 8px; }
.burn-item__val { font-size: 24px; font-weight: 800; color: #ff8a3d; line-height: 1; }
.burn-item__unit { font-size: 12px; color: #999; font-weight: 400; margin-left: 2px; }
.burn-item__label { font-size: 11px; color: #999; margin-top: 4px; }
/* ===== 运动类型推荐 ===== */
.exer-type-card { background: #fff; border-radius: 16px; margin: 12px 12px 0; padding: 16px 14px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
.exer-type-card__title { font-size: 15px; font-weight: 800; color: #1a1a1a; margin-bottom: 12px; }
.exer-type-list { display: flex; flex-direction: column; gap: 8px; }
.exer-type-item { display: flex; align-items: center; gap: 10px; padding: 10px; background: #f9fafb; border-radius: 10px; }
.exer-type-item__icon { width: 44px; height: 44px; border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 22px; flex-shrink: 0; }
.exer-type-item__icon--aerobic { background: #fff2e8; }
.exer-type-item__icon--strength { background: #f0f5ff; }
.exer-type-item__icon--flex { background: #f6ffed; }
.exer-type-item__icon--balance { background: #f9f0ff; }
.exer-type-item__info { flex: 1; min-width: 0; }
.exer-type-item__name { font-size: 14px; font-weight: 700; color: #333; }
.exer-type-item__desc { font-size: 11px; color: #999; margin-top: 2px; line-height: 1.4; }
.exer-type-item__time { font-size: 12px; font-weight: 700; color: #ff8a3d; flex-shrink: 0; }
/* ===== 一周运动计划 ===== */
.week-plan-card { background: #fff; border-radius: 16px; margin: 12px 12px 0; padding: 16px 14px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
.week-plan-card__header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
.week-plan-card__title { font-size: 15px; font-weight: 800; color: #1a1a1a; }
.week-plan-card__tip { font-size: 11px; color: #bbb; }
.week-day-row { display: flex; gap: 4px; margin-bottom: 8px; }
.week-day { flex: 1; text-align: center; padding: 6px 0; border-radius: 8px; cursor: pointer; font-size: 11px; font-weight: 600; color: #999; background: #f7f8fa; transition: all .2s; }
.week-day.active { background: #ff8a3d; color: #fff; }
.week-day__label { display: block; font-size: 10px; opacity: 0.7; }
.week-detail { padding: 10px 0 0; }
.week-detail__total { font-size: 14px; font-weight: 800; color: #1a1a1a; margin-bottom: 8px; }
.week-detail__total span { font-size: 11px; color: #ff8a3d; margin-left: 4px; }
.plan-item { display: flex; align-items: center; gap: 10px; padding: 8px 10px; background: #f9fafb; border-radius: 10px; margin-bottom: 6px; }
.plan-item:last-child { margin-bottom: 0; }
.plan-item__icon { width: 36px; height: 36px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 18px; flex-shrink: 0; }
.plan-item__icon--aerobic { background: #fff2e8; }
.plan-item__icon--strength { background: #f0f5ff; }
.plan-item__icon--flex { background: #f6ffed; }
.plan-item__info { flex: 1; min-width: 0; }
.plan-item__name { font-size: 13px; font-weight: 600; color: #333; }
.plan-item__desc { font-size: 11px; color: #999; margin-top: 2px; }
.plan-item__kcal { font-size: 12px; font-weight: 700; color: #ff8a3d; flex-shrink: 0; }
/* ===== 注意事项卡片 ===== */
.tips-card { background: #fff; border-radius: 16px; margin: 12px 12px 0; padding: 16px 14px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
.tips-card__title { font-size: 15px; font-weight: 800; color: #1a1a1a; margin-bottom: 10px; }
.tips-list { display: flex; flex-direction: column; gap: 8px; }
.tips-item { display: flex; align-items: flex-start; gap: 8px; padding: 10px; background: #f9fafb; border-radius: 10px; }
.tips-item__icon { width: 20px; height: 20px; border-radius: 50%; display: flex; align-items: center; justify-content: center; flex-shrink: 0; font-size: 10px; font-weight: 800; color: #fff; }
.tips-item__icon--warn { background: #faad14; }
.tips-item__icon--good { background: #52c41a; }
.tips-item__icon--info { background: #1677ff; }
.tips-item__text { font-size: 12px; color: #555; line-height: 1.6; flex: 1; }
.tips-item__text strong { color: #333; }
.bottom-safe { height: 20px; flex-shrink: 0; }
</style>
</head>
<body>
<div class="phone-shell">
<div class="status-bar">
<span class="time">09:40</span>
<div 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>
</div>
</div>
<div class="nav-bar">
<div class="nav-back" onclick="location.href='weight-main.html'">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
</div>
<div class="nav-title">运动建议</div>
<div class="nav-placeholder"></div>
</div>
<div class="scroll-content">
<!-- 今日步数目标 -->
<div class="step-goal">
<div class="step-goal__label">今日运动目标</div>
<div class="step-goal__val">12586<span class="step-goal__unit"></span></div>
<div class="step-goal__sub">目标 12000 步 · 已超额完成 586 步</div>
<div class="step-goal__bar-wrap">
<div class="step-goal__bar-fill" style="width:100%"></div>
</div>
<div class="step-goal__bar-label"><span>已完成 104.9%</span><span>目标达成 ✓</span></div>
</div>
<!-- 运动消耗 -->
<div class="burn-card">
<div class="burn-card__title">运动消耗概览</div>
<div class="burn-row">
<div class="burn-item">
<div class="burn-item__val">586<span class="burn-item__unit">千卡</span></div>
<div class="burn-item__label">今日运动消耗</div>
</div>
<div class="burn-item">
<div class="burn-item__val">1000<span class="burn-item__unit">千卡</span></div>
<div class="burn-item__label">每日消耗目标</div>
</div>
</div>
</div>
<!-- 运动类型推荐 -->
<div class="exer-type-card">
<div class="exer-type-card__title">运动类型推荐</div>
<div class="exer-type-list">
<div class="exer-type-item">
<div class="exer-type-item__icon exer-type-item__icon--aerobic">🏃</div>
<div class="exer-type-item__info">
<div class="exer-type-item__name">有氧运动</div>
<div class="exer-type-item__desc">快走、慢跑、游泳、骑行,提升心肺功能</div>
</div>
<div class="exer-type-item__time">30-45分钟/天</div>
</div>
<div class="exer-type-item">
<div class="exer-type-item__icon exer-type-item__icon--strength">💪</div>
<div class="exer-type-item__info">
<div class="exer-type-item__name">力量训练</div>
<div class="exer-type-item__desc">深蹲、俯卧撑、哑铃推举,增肌提高代谢</div>
</div>
<div class="exer-type-item__time">20-30分钟/次</div>
</div>
<div class="exer-type-item">
<div class="exer-type-item__icon exer-type-item__icon--flex">🧘</div>
<div class="exer-type-item__info">
<div class="exer-type-item__name">柔韧拉伸</div>
<div class="exer-type-item__desc">瑜伽、动态拉伸、泡沫轴放松</div>
</div>
<div class="exer-type-item__time">10-15分钟/天</div>
</div>
<div class="exer-type-item">
<div class="exer-type-item__icon exer-type-item__icon--balance">🚶</div>
<div class="exer-type-item__info">
<div class="exer-type-item__name">日常活动</div>
<div class="exer-type-item__desc">步行通勤、爬楼梯、工间操,积少成多</div>
</div>
<div class="exer-type-item__time">全天累计</div>
</div>
</div>
</div>
<!-- 一周运动计划 -->
<div class="week-plan-card">
<div class="week-plan-card__header">
<div class="week-plan-card__title">一周运动计划</div>
<div class="week-plan-card__tip">循序渐进 科学运动</div>
</div>
<div class="week-day-row" id="weekDayRow">
<div class="week-day active" data-day="0" onclick="switchWeekDay(0, this)"><span class="week-day__label">周一</span>08-10</div>
<div class="week-day" data-day="1" onclick="switchWeekDay(1, this)"><span class="week-day__label">周二</span>08-11</div>
<div class="week-day" data-day="2" onclick="switchWeekDay(2, this)"><span class="week-day__label">周三</span>08-12</div>
<div class="week-day" data-day="3" onclick="switchWeekDay(3, this)"><span class="week-day__label">周四</span>08-13</div>
<div class="week-day" data-day="4" onclick="switchWeekDay(4, this)"><span class="week-day__label">周五</span>08-14</div>
<div class="week-day" data-day="5" onclick="switchWeekDay(5, this)"><span class="week-day__label">周六</span>08-15</div>
<div class="week-day" data-day="6" onclick="switchWeekDay(6, this)"><span class="week-day__label">周日</span>08-16</div>
</div>
<div class="week-detail" id="weekDetail"></div>
</div>
<!-- 注意事项 -->
<div class="tips-card">
<div class="tips-card__title">运动注意事项</div>
<div class="tips-list">
<div class="tips-item">
<div class="tips-item__icon tips-item__icon--good"></div>
<div class="tips-item__text"><strong>热身先行:</strong>运动前做5-10分钟动态热身,活动关节、提高心率,预防运动损伤。</div>
</div>
<div class="tips-item">
<div class="tips-item__icon tips-item__icon--warn">!</div>
<div class="tips-item__text"><strong>量力而行:</strong>根据自身身体状况选择运动强度,避免过度训练导致肌肉酸痛或损伤。</div>
</div>
<div class="tips-item">
<div class="tips-item__icon tips-item__icon--info">i</div>
<div class="tips-item__text"><strong>补水及时:</strong>运动前中后少量多次饮水,每15-20分钟补充150-200ml水分。</div>
</div>
<div class="tips-item">
<div class="tips-item__icon tips-item__icon--good"></div>
<div class="tips-item__text"><strong>循序渐进:</strong>运动强度和时间逐步增加,每周运动量增幅不超过10%。</div>
</div>
<div class="tips-item">
<div class="tips-item__icon tips-item__icon--warn">!</div>
<div class="tips-item__text"><strong>身体不适立即停止:</strong>运动中如出现胸闷、头晕、关节疼痛等不适,应立即停止并就医。</div>
</div>
<div class="tips-item">
<div class="tips-item__icon tips-item__icon--info">i</div>
<div class="tips-item__text"><strong>拉伸放松:</strong>运动后做5-10分钟静态拉伸,帮助肌肉恢复、减少酸痛。</div>
</div>
</div>
</div>
<div class="bottom-safe"></div>
</div>
</div>
<script>
/* ===== 一周运动计划数据 ===== */
var WEEK_PLANS = [
{ day:'周一', date:'08-10', total:'目标消耗 980千卡', items:[
{ icon:'🏃', cls:'aerobic', name:'户外慢跑', desc:'配速7-8min/km,时长30分钟', kcal:'320千卡' },
{ icon:'💪', cls:'strength', name:'上肢力量', desc:'俯卧撑3组×15 + 哑铃推举3组×12', kcal:'180千卡' },
{ icon:'🚶', cls:'flex', name:'全天步行', desc:'目标步数10000步以上', kcal:'480千卡' }
]},
{ day:'周二', date:'08-11', total:'目标消耗 850千卡', items:[
{ icon:'🏊', cls:'aerobic', name:'游泳', desc:'蛙泳/自由泳交替,时长40分钟', kcal:'380千卡' },
{ icon:'🧘', cls:'flex', name:'瑜伽拉伸', desc:'哈他瑜伽基础序列,时长20分钟', kcal:'120千卡' },
{ icon:'🚶', cls:'flex', name:'全天步行', desc:'目标步数8000步以上', kcal:'350千卡' }
]},
{ day:'周三', date:'08-12', total:'目标消耗 1000千卡', items:[
{ icon:'🚴', cls:'aerobic', name:'动感单车', desc:'中等阻力间歇骑行,时长35分钟', kcal:'400千卡' },
{ icon:'💪', cls:'strength', name:'下肢力量', desc:'深蹲4组×15 + 弓步蹲3组×12', kcal:'220千卡' },
{ icon:'🚶', cls:'flex', name:'全天步行', desc:'目标步数10000步以上', kcal:'380千卡' }
]},
{ day:'周四', date:'08-13', total:'目标消耗 780千卡', items:[
{ icon:'🏃', cls:'aerobic', name:'快走', desc:'配速10min/km,时长40分钟', kcal:'280千卡' },
{ icon:'🧘', cls:'flex', name:'核心训练', desc:'平板支撑+卷腹+仰卧举腿循环', kcal:'160千卡' },
{ icon:'🚶', cls:'flex', name:'全天步行', desc:'目标步数8000步以上', kcal:'340千卡' }
]},
{ day:'周五', date:'08-14', total:'目标消耗 950千卡', items:[
{ icon:'🏃', cls:'aerobic', name:'间歇跑', desc:'快跑2分钟+慢跑3分钟循环×6组', kcal:'380千卡' },
{ icon:'💪', cls:'strength', name:'全身力量', desc:'深蹲+俯卧撑+划船循环3组', kcal:'220千卡' },
{ icon:'🚶', cls:'flex', name:'全天步行', desc:'目标步数9000步以上', kcal:'350千卡' }
]},
{ day:'周六', date:'08-15', total:'目标消耗 1100千卡', items:[
{ icon:'🏸', cls:'aerobic', name:'羽毛球/球类运动', desc:'双打/单打,时长60分钟', kcal:'500千卡' },
{ icon:'🧘', cls:'flex', name:'运动后拉伸', desc:'全身静态拉伸,时长15分钟', kcal:'100千卡' },
{ icon:'🚶', cls:'flex', name:'全天步行', desc:'目标步数10000步以上', kcal:'500千卡' }
]},
{ day:'周日', date:'08-16', total:'目标消耗 600千卡', items:[
{ icon:'🚶', cls:'aerobic', name:'散步放松', desc:'悠闲步行,时长45分钟', kcal:'200千卡' },
{ icon:'🧘', cls:'flex', name:'恢复拉伸', desc:'阴瑜伽 + 泡沫轴放松,时长30分钟', kcal:'100千卡' },
{ icon:'🚶', cls:'flex', name:'全天步行', desc:'目标步数7000步以上', kcal:'300千卡' }
]}
];
/* ===== 渲染 ===== */
var currentWeekDay = 0;
function renderWeekDetail(dayIdx) {
var plan = WEEK_PLANS[dayIdx];
var html = '<div class="week-detail__total">' + plan.day + ' ' + plan.date + '<span>' + plan.total + '</span></div>';
for (var i = 0; i < plan.items.length; i++) {
var it = plan.items[i];
html += '<div class="plan-item">';
html += '<div class="plan-item__icon plan-item__icon--' + it.cls + '">' + it.icon + '</div>';
html += '<div class="plan-item__info"><div class="plan-item__name">' + it.name + '</div><div class="plan-item__desc">' + it.desc + '</div></div>';
html += '<div class="plan-item__kcal">' + it.kcal + '</div>';
html += '</div>';
}
document.getElementById('weekDetail').innerHTML = html;
}
function switchWeekDay(dayIdx, el) {
currentWeekDay = dayIdx;
document.querySelectorAll('.week-day').forEach(function(d) { d.classList.remove('active'); });
el.classList.add('active');
renderWeekDetail(dayIdx);
}
function init() {
renderWeekDetail(0);
}
init();
</script>
</body>
</html>
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,533 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>消耗记录 - 员工端 | 健康CQ原型</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
.phone-shell { width: 390px; height: 844px; background: #f5f7fa; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; }
.status-bar { height: 44px; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; background: #fff; }
.status-bar .time { font-size: 15px; font-weight: 700; color: #333; }
.status-bar .icons { display: flex; gap: 6px; align-items: center; }
.nav-bar { height: 44px; background: #fff; display: flex; align-items: center; padding: 0 16px; flex-shrink: 0; border-bottom: 1px solid #f0f0f0; }
.nav-back { width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: #1a1a1a; }
.nav-title { flex: 1; text-align: center; font-size: 17px; font-weight: 600; color: #1a1a1a; }
.nav-placeholder { width: 28px; flex-shrink: 0; }
.scroll-content { flex: 1; overflow-y: auto; background: #f5f7fa; }
.scroll-content::-webkit-scrollbar { display: none; }
/* ===== 日历月导航 ===== */
.cal-nav { display: flex; align-items: center; justify-content: space-between; padding: 8px 16px; background: #fff; }
.cal-nav__arrow { width: 30px; height: 30px; border-radius: 50%; background: #f5f7fa; display: flex; align-items: center; justify-content: center; cursor: pointer; border: none; flex-shrink: 0; }
.cal-nav__arrow svg { width: 14px; height: 14px; stroke: #333; }
.cal-nav__month { font-size: 15px; font-weight: 700; color: #1a1a1a; flex: 1; text-align: center; }
.cal-nav__toggle { font-size: 12px; color: #ff8a3d; cursor: pointer; font-weight: 600; padding: 4px 10px; border-radius: 12px; background: #fff7e6; flex-shrink: 0; white-space: nowrap; }
/* ===== 周日历(默认视图) ===== */
.week-cal { background: #fff; padding: 0 10px 10px; margin: 0 12px; border-radius: 0 0 16px 16px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
.week-cal__row { display: flex; gap: 2px; }
.week-cal__cell { flex: 1; text-align: center; padding: 8px 0 6px; border-radius: 10px; position: relative; cursor: default; min-width: 0; }
.week-cal__cell.today { background: #fff7e6; }
.week-cal__cell.selected { background: #fff7e6; box-shadow: inset 0 0 0 2px #ff8a3d; }
.week-cal__wd { font-size: 10px; color: #999; margin-bottom: 4px; }
.week-cal__date-wrap { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; margin: 0 auto 4px; }
.week-cal__date { font-size: 14px; font-weight: 700; color: #333; position: relative; z-index: 2; }
.week-cal__cell.today .week-cal__date { color: #ff8a3d; }
.week-cal__ring { position: absolute; inset: -2px; border-radius: 50%; border: 2.5px solid transparent; z-index: 1; }
.week-cal__ring--wearable { border-color: #1890ff; }
.week-cal__ring--equip { border-color: #52c41a; }
.week-cal__ring--wechat { border-color: #597ef7; }
.week-cal__ring--manual { border-color: #fa8c16; }
.week-cal__ring--mixed { border-color: #722ed1; }
.week-cal__dot-row { display: flex; justify-content: center; gap: 3px; margin-top: 2px; }
.week-cal__dot { width: 5px; height: 5px; border-radius: 50%; flex-shrink: 0; }
.week-cal__dot--wearable { background: #1890ff; }
.week-cal__dot--equip { background: #52c41a; }
.week-cal__dot--wechat { background: #597ef7; }
.week-cal__dot--manual { background: #fa8c16; }
.week-cal__dot--mixed { background: #722ed1; }
/* 日历消耗千卡数据 */
.week-cal__data { font-size: 10px; color: #666; line-height: 1.4; margin-top: 2px; }
.week-cal__data .w { font-weight: 700; color: #333; }
/* ===== 月日历(展开视图) ===== */
.month-cal { background: #fff; padding: 0 10px 10px; margin: 0 12px; border-radius: 0 0 16px 16px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
.month-cal__weekday { display: grid; grid-template-columns: repeat(7, 1fr); margin-bottom: 2px; }
.month-cal__weekday span { font-size: 10px; color: #999; text-align: center; padding: 4px 0; }
.month-cal__row { display: grid; grid-template-columns: repeat(7, 1fr); }
.month-cal__cell { text-align: center; padding: 2px 1px 4px; min-height: 46px; position: relative; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; border-radius: 8px; cursor: default; }
.month-cal__cell.today { background: #fff7e6; }
.month-cal__cell.selected { background: #fff7e6; box-shadow: inset 0 0 0 2px #ff8a3d; }
.month-cal__cell.other-month .month-cal__date { color: #ddd; }
.month-cal__date { font-size: 13px; font-weight: 600; color: #333; position: relative; z-index: 2; }
.month-cal__cell.today .month-cal__date { color: #ff8a3d; font-weight: 800; }
.month-cal__ring { position: absolute; top: 2px; left: 50%; transform: translateX(-50%); width: 26px; height: 26px; border-radius: 50%; border: 2px solid transparent; }
.month-cal__ring--wearable { border-color: #1890ff; }
.month-cal__ring--equip { border-color: #52c41a; }
.month-cal__ring--wechat { border-color: #597ef7; }
.month-cal__ring--manual { border-color: #fa8c16; }
.month-cal__ring--mixed { border-color: #722ed1; }
.month-cal__dots { display: flex; justify-content: center; gap: 2px; margin-top: 1px; }
.month-cal__dot { width: 4px; height: 4px; border-radius: 50%; flex-shrink: 0; }
/* 月历消耗千卡数据 */
.month-cal__data { font-size: 9px; color: #666; line-height: 1.3; margin-top: 1px; }
.month-cal__data .mw { font-weight: 700; color: #333; }
.month-cal__dot--wearable { background: #1890ff; }
.month-cal__dot--equip { background: #52c41a; }
.month-cal__dot--wechat { background: #597ef7; }
.month-cal__dot--manual { background: #fa8c16; }
.month-cal__dot--mixed { background: #722ed1; }
/* ===== 图例 ===== */
.legend { display: flex; justify-content: center; gap: 10px; padding: 8px 12px; flex-wrap: wrap; background: #fff; margin: 8px 12px 0; border-radius: 12px; }
.legend__item { display: flex; align-items: center; gap: 3px; font-size: 10px; color: #666; }
.legend__dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.legend__dot--wearable { background: #1890ff; }
.legend__dot--equip { background: #52c41a; }
.legend__dot--wechat { background: #597ef7; }
.legend__dot--manual { background: #fa8c16; }
.legend__dot--mixed { background: #722ed1; }
/* ===== Tab 栏 ===== */
.record-tabs { display: flex; background: #fff; margin: 8px 12px 0; border-radius: 12px; overflow: hidden; }
.record-tab { flex: 1; text-align: center; padding: 10px 0; font-size: 13px; font-weight: 600; color: #999; cursor: pointer; position: relative; }
.record-tab.active { color: #ff8a3d; }
.record-tab.active::after { content: ''; position: absolute; bottom: 4px; left: 50%; transform: translateX(-50%); width: 20px; height: 3px; background: #ff8a3d; border-radius: 2px; }
/* ===== 列表区域 ===== */
.record-list { padding: 8px 12px 16px; display: flex; flex-direction: column; gap: 8px; }
.record-item { background: #fff; border-radius: 14px; padding: 14px; box-shadow: 0 2px 8px rgba(0,0,0,0.03); }
.record-item__header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.record-item__title { font-size: 14px; font-weight: 700; color: #1a1a1a; }
.record-item__time { font-size: 11px; color: #bbb; }
.record-item__body { display: flex; align-items: center; gap: 16px; }
.record-item__metric { text-align: center; min-width: 50px; }
.record-item__metric-label { font-size: 10px; color: #999; margin-bottom: 2px; }
.record-item__metric-val { font-size: 16px; font-weight: 700; color: #1a1a1a; }
.record-item__metric-unit { font-size: 10px; color: #999; font-weight: 400; margin-left: 1px; }
.record-item__source { margin-left: auto; }
.source-badge { display: inline-block; padding: 4px 10px; border-radius: 12px; font-size: 11px; font-weight: 600; }
.source-badge--wearable { background: #e6f7ff; color: #1890ff; }
.source-badge--equip { background: #f6ffed; color: #52c41a; }
.source-badge--wechat { background: #f0f5ff; color: #597ef7; }
.source-badge--manual { background: #fff7e6; color: #fa8c16; }
.source-badge--mixed { background: #f9f0ff; color: #722ed1; }
.record-empty { text-align: center; padding: 40px 20px; color: #ccc; font-size: 14px; }
.bottom-safe { height: 20px; flex-shrink: 0; }
</style>
</head>
<body>
<div class="phone-shell">
<div class="status-bar">
<span class="time">09:40</span>
<div 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>
</div>
</div>
<div class="nav-bar">
<!-- [交互] 点击返回动打卡页面 -->
<div class="nav-back" onclick="location.href='exercise-checkin.html'">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
</div>
<div class="nav-title">消耗记录</div>
<div class="nav-placeholder"></div>
</div>
<div class="scroll-content">
<!-- 日历月导航 -->
<div class="cal-nav">
<div class="cal-nav__arrow" onclick="prevMonth()">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
</div>
<div class="cal-nav__month" id="calMonthLabel">2026年06月</div>
<div class="cal-nav__arrow" onclick="nextMonth()">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg>
</div>
<div class="cal-nav__toggle" id="calToggle" onclick="toggleCalView()">展开月历</div>
</div>
<!-- 周日历(默认) -->
<div class="week-cal" id="weekCal"></div>
<!-- 月日历(展开后显示) -->
<div class="month-cal" id="monthCal" style="display:none;"></div>
<!-- 图例 -->
<div class="legend">
<div class="legend__item"><span class="legend__dot legend__dot--wearable"></span>穿戴</div>
<div class="legend__item"><span class="legend__dot legend__dot--equip"></span>器械</div>
<div class="legend__item"><span class="legend__dot legend__dot--wechat"></span>微信</div>
<div class="legend__item"><span class="legend__dot legend__dot--manual"></span>自记</div>
<div class="legend__item"><span class="legend__dot legend__dot--mixed"></span>多途径</div>
</div>
<!-- Tab 栏 -->
<div class="record-tabs" id="recordTabs">
<div class="record-tab active" data-range="week" onclick="switchTab('week')"></div>
<div class="record-tab" data-range="month" onclick="switchTab('month')"></div>
<div class="record-tab" data-range="quarter" onclick="switchTab('quarter')"></div>
<div class="record-tab" data-range="activity" onclick="switchTab('activity')">活动期间</div>
<div class="record-tab" data-range="all" onclick="switchTab('all')">全部</div>
</div>
<!-- 记录列表 -->
<div class="record-list" id="recordList"></div>
<div class="bottom-safe"></div>
</div>
</div>
<script>
/* ===== 来源类型 ===== */
var SOURCE_TYPES = {
'wearable': { label:'穿戴', css:'wearable', ring:'week-cal__ring--wearable', mring:'month-cal__ring--wearable', dot:'week-cal__dot--wearable', mdot:'month-cal__dot--wearable', badge:'source-badge--wearable' },
'equip': { label:'器械', css:'equip', ring:'week-cal__ring--equip', mring:'month-cal__ring--equip', dot:'week-cal__dot--equip', mdot:'month-cal__dot--equip', badge:'source-badge--equip' },
'wechat': { label:'微信', css:'wechat', ring:'week-cal__ring--wechat', mring:'month-cal__ring--wechat', dot:'week-cal__dot--wechat', mdot:'month-cal__dot--wechat', badge:'source-badge--wechat' },
'manual': { label:'自记', css:'manual', ring:'week-cal__ring--manual', mring:'month-cal__ring--manual', dot:'week-cal__dot--manual', mdot:'month-cal__dot--manual', badge:'source-badge--manual' },
'mixed': { label:'多途径',css:'mixed', ring:'week-cal__ring--mixed', mring:'month-cal__ring--mixed', dot:'week-cal__dot--mixed', mdot:'month-cal__dot--mixed', badge:'source-badge--mixed' }
};
/* ===== 消耗记录数据 ===== */
var RECORDS = [
{ date:'2026-06-13', name:'跑步', duration:30, kcal:300, time:'07:15', source:'wearable' },
{ date:'2026-06-13', name:'快走', duration:45, kcal:234, time:'12:30', source:'wechat' },
{ date:'2026-06-13', name:'瑜伽', duration:25, kcal:125, time:'18:40', source:'manual' },
{ date:'2026-06-12', name:'快走', duration:40, kcal:208, time:'07:30', source:'wearable' },
{ date:'2026-06-12', name:'椭圆机', duration:30, kcal:270, time:'12:05', source:'equip' },
{ date:'2026-06-12', name:'哑铃训练', duration:20, kcal:120, time:'18:15', source:'manual' },
{ date:'2026-06-10', name:'骑行', duration:60, kcal:420, time:'06:50', source:'wearable' },
{ date:'2026-06-10', name:'深蹲', duration:15, kcal:100, time:'17:30', source:'equip' },
{ date:'2026-06-10', name:'散步', duration:35, kcal:117, time:'19:10', source:'mixed' },
{ date:'2026-06-08', name:'游泳', duration:45, kcal:495, time:'06:20', source:'wearable' },
{ date:'2026-06-08', name:'篮球', duration:60, kcal:500, time:'16:00', source:'wechat' },
{ date:'2026-06-08', name:'拉伸', duration:20, kcal:80, time:'20:15', source:'mixed' },
{ date:'2026-06-07', name:'慢跑', duration:35, kcal:280, time:'07:00', source:'wearable' },
{ date:'2026-06-07', name:'器械训练', duration:40, kcal:293, time:'12:15', source:'equip' },
{ date:'2026-06-05', name:'跳绳', duration:20, kcal:240, time:'18:30', source:'manual' },
{ date:'2026-06-03', name:'快走', duration:50, kcal:260, time:'07:20', source:'wechat' },
{ date:'2026-06-03', name:'羽毛球', duration:45, kcal:330, time:'17:10', source:'mixed' },
{ date:'2026-06-01', name:'跑步', duration:30, kcal:300, time:'06:40', source:'wearable' },
{ date:'2026-06-01', name:'俯卧撑', duration:15, kcal:105, time:'19:30', source:'manual' },
{ date:'2026-05-28', name:'骑行', duration:50, kcal:350, time:'07:10', source:'wearable' },
{ date:'2026-05-28', name:'普拉提', duration:30, kcal:165, time:'18:00', source:'mixed' },
{ date:'2026-05-25', name:'徒步', duration:90, kcal:600, time:'08:00', source:'wechat' },
{ date:'2026-05-20', name:'太极拳', duration:30, kcal:140, time:'06:30', source:'manual' },
{ date:'2026-05-20', name:'引体向上', duration:20, kcal:160, time:'17:00', source:'equip' },
{ date:'2026-05-15', name:'游泳', duration:40, kcal:440, time:'06:15', source:'wearable' },
{ date:'2026-05-15', name:'广场舞', duration:45, kcal:255, time:'19:00', source:'mixed' },
{ date:'2026-05-10', name:'跑步', duration:25, kcal:250, time:'07:00', source:'wechat' },
{ date:'2026-05-10', name:'家务劳动', duration:40, kcal:173, time:'15:30', source:'manual' },
{ date:'2026-05-05', name:'慢跑', duration:30, kcal:240, time:'06:50', source:'wearable' },
{ date:'2026-05-01', name:'卧推', duration:25, kcal:163, time:'17:20', source:'equip' },
{ date:'2026-04-25', name:'椭圆机', duration:35, kcal:315, time:'12:00', source:'mixed' },
{ date:'2026-04-20', name:'骑行', duration:55, kcal:385, time:'07:30', source:'wechat' },
];
/* ===== 状态 ===== */
var calYear = 2026;
var calMonth = 5; // 0-based, 5=June
var calExpanded = false;
var activeTab = 'week';
var selectedDate = null;
var TODAY = new Date(2026, 5, 12); // 2026-06-12
var ACTIVITY_START = new Date(2026, 4, 1); // 2026-05-01
var ACTIVITY_END = new Date(2026, 7, 1); // 2026-08-01
/* ===== 工具函数 ===== */
function fmt(n) { return n < 10 ? '0' + n : '' + n; }
function dateStr(y, m, d) { return y + '-' + fmt(m+1) + '-' + fmt(d); }
function parseDate(s) { var p = s.split('-'); return new Date(+p[0], +p[1]-1, +p[2]); }
function sameDay(a, b) { return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate(); }
/* 获取某天的记录列表,返回各来源类型集合 */
function getDaySources(y, m, d) {
var s = dateStr(y, m, d);
var sources = {};
for (var i = 0; i < RECORDS.length; i++) {
if (RECORDS[i].date === s) {
sources[RECORDS[i].source] = true;
}
}
return Object.keys(sources);
}
/* 获取某天的总消耗千卡 */
function getDayKcal(y, m, d) {
var s = dateStr(y, m, d);
var total = 0;
for (var i = 0; i < RECORDS.length; i++) {
if (RECORDS[i].date === s) {
total += RECORDS[i].kcal;
}
}
return total;
}
/* ===== 周日历 ===== */
var WEEKDAY_LABELS = ['一','二','三','四','五','六','日'];
function getWeekStart() {
var first = new Date(calYear, calMonth, 1);
var day = first.getDay();
var monday = new Date(first);
monday.setDate(1 - (day === 0 ? 6 : day - 1));
return monday;
}
function renderWeekCal() {
var container = document.getElementById('weekCal');
var now = new Date(2026, 5, 12);
var start;
if (calYear === now.getFullYear() && calMonth === now.getMonth()) {
var dow = now.getDay() || 7;
start = new Date(now);
start.setDate(now.getDate() - dow + 1);
} else {
start = getWeekStart();
}
var html = '<div class="week-cal__row">';
for (var i = 0; i < 7; i++) {
var d = new Date(start);
d.setDate(start.getDate() + i);
var sources = getDaySources(d.getFullYear(), d.getMonth(), d.getDate());
var hasRecord = sources.length > 0;
var isToday = sameDay(d, TODAY);
var isOtherMonth = d.getMonth() !== calMonth;
var dateKey = dateStr(d.getFullYear(), d.getMonth(), d.getDate());
var isSel = dateKey === selectedDate;
var primarySource = sources[0] || null;
html += '<div class="week-cal__cell' + (isToday ? ' today' : '') + (isSel ? ' selected' : '') + '"'
+ ' onclick="onDayClick(\'' + dateKey + '\')" style="cursor:' + (hasRecord ? 'pointer' : 'default') + '">';
html += '<div class="week-cal__wd">' + WEEKDAY_LABELS[i] + '</div>';
html += '<div class="week-cal__date-wrap">';
if (primarySource) {
html += '<div class="week-cal__ring ' + SOURCE_TYPES[primarySource].ring + '"></div>';
}
html += '<span class="week-cal__date" style="' + (isOtherMonth ? 'color:#ddd' : '') + '">' + (isToday ? '今' : d.getDate()) + '</span>';
html += '</div>';
var dayKcal = getDayKcal(d.getFullYear(), d.getMonth(), d.getDate());
if (dayKcal > 0) {
html += '<div class="week-cal__data"><span class="w">' + dayKcal + '</span>千卡</div>';
}
html += '</div>';
}
html += '</div>';
container.innerHTML = html;
}
/* ===== 月日历 ===== */
function renderMonthCal() {
var container = document.getElementById('monthCal');
var html = '<div class="month-cal__weekday">';
for (var w = 0; w < 7; w++) { html += '<span>' + WEEKDAY_LABELS[w] + '</span>'; }
html += '</div>';
var first = new Date(calYear, calMonth, 1);
var startDow = first.getDay() || 7;
var cursor = new Date(first);
cursor.setDate(1 - (startDow - 1));
var done = false;
for (var row = 0; row < 6 && !done; row++) {
html += '<div class="month-cal__row">';
for (var col = 0; col < 7; col++) {
var isOther = cursor.getMonth() !== calMonth;
var isToday = sameDay(cursor, TODAY);
var dateKey = dateStr(cursor.getFullYear(), cursor.getMonth(), cursor.getDate());
var isSel = dateKey === selectedDate;
var sources = getDaySources(cursor.getFullYear(), cursor.getMonth(), cursor.getDate());
var primarySource = sources[0] || null;
html += '<div class="month-cal__cell' + (isToday ? ' today' : '') + (isOther ? ' other-month' : '') + (isSel ? ' selected' : '') + '"'
+ ' onclick="onDayClick(\'' + dateKey + '\')" style="cursor:' + (sources.length ? 'pointer' : 'default') + '">';
html += '<div style="position:relative;width:26px;height:26px;">';
if (primarySource) {
html += '<div class="month-cal__ring ' + SOURCE_TYPES[primarySource].mring + '"></div>';
}
html += '<span class="month-cal__date">' + (isToday ? '今' : cursor.getDate()) + '</span>';
html += '</div>';
var mKcal = getDayKcal(cursor.getFullYear(), cursor.getMonth(), cursor.getDate());
if (mKcal > 0) {
html += '<div class="month-cal__data"><span class="mw">' + mKcal + '</span>千卡</div>';
}
html += '</div>';
cursor.setDate(cursor.getDate() + 1);
if (col === 6 && cursor.getDate() > 7 && cursor.getMonth() !== calMonth) { done = true; }
}
html += '</div>';
}
container.innerHTML = html;
}
/* ===== 日历展开/收起 ===== */
function toggleCalView() {
calExpanded = !calExpanded;
document.getElementById('weekCal').style.display = calExpanded ? 'none' : '';
document.getElementById('monthCal').style.display = calExpanded ? '' : 'none';
document.getElementById('calToggle').textContent = calExpanded ? '收起月历' : '展开月历';
if (calExpanded) renderMonthCal();
}
function prevMonth() {
if (calExpanded) {
calMonth--;
if (calMonth < 0) { calMonth = 11; calYear--; }
} else {
var now = new Date(2026, 5, 12);
var dow = now.getDay() || 7;
var curWeekStart;
if (calYear === now.getFullYear() && calMonth === now.getMonth()) {
curWeekStart = new Date(now);
curWeekStart.setDate(now.getDate() - dow + 1);
} else {
curWeekStart = getWeekStart();
}
curWeekStart.setDate(curWeekStart.getDate() - 7);
calYear = curWeekStart.getFullYear();
calMonth = curWeekStart.getMonth();
}
updateCal();
}
function nextMonth() {
if (calExpanded) {
calMonth++;
if (calMonth > 11) { calMonth = 0; calYear++; }
} else {
var now = new Date(2026, 5, 12);
var dow = now.getDay() || 7;
var curWeekStart;
if (calYear === now.getFullYear() && calMonth === now.getMonth()) {
curWeekStart = new Date(now);
curWeekStart.setDate(now.getDate() - dow + 1);
} else {
curWeekStart = getWeekStart();
}
curWeekStart.setDate(curWeekStart.getDate() + 7);
calYear = curWeekStart.getFullYear();
calMonth = curWeekStart.getMonth();
}
updateCal();
}
function updateCal() {
document.getElementById('calMonthLabel').textContent = calYear + '年' + fmt(calMonth + 1) + '月';
renderWeekCal();
if (calExpanded) renderMonthCal();
}
/* ===== Tab 切换 ===== */
function switchTab(range) {
activeTab = range;
selectedDate = null;
document.querySelectorAll('.record-tab').forEach(function(t) {
t.classList.toggle('active', t.dataset.range === range);
});
updateCal();
renderRecordList();
}
function getTabDateRange() {
var now = new Date(2026, 5, 12);
var start, end;
switch (activeTab) {
case 'week':
var dow = now.getDay() || 7;
start = new Date(now); start.setDate(now.getDate() - dow + 1);
end = new Date(start); end.setDate(start.getDate() + 6);
break;
case 'month':
start = new Date(now.getFullYear(), now.getMonth(), 1);
end = new Date(now.getFullYear(), now.getMonth() + 1, 0);
break;
case 'quarter':
var q = Math.floor(now.getMonth() / 3);
start = new Date(now.getFullYear(), q * 3, 1);
end = new Date(now.getFullYear(), (q + 1) * 3, 0);
break;
case 'activity':
start = ACTIVITY_START;
end = ACTIVITY_END;
break;
case 'all':
start = new Date(2000, 0, 1);
end = new Date(2099, 11, 31);
break;
}
return { start: start, end: end };
}
/* ===== 渲染记录列表 ===== */
function renderRecordList() {
var filtered;
if (selectedDate) {
filtered = RECORDS.filter(function(r) { return r.date === selectedDate; });
} else {
var range = getTabDateRange();
filtered = RECORDS.filter(function(r) {
var d = parseDate(r.date);
return d >= range.start && d <= range.end;
});
}
var container = document.getElementById('recordList');
if (filtered.length === 0) {
container.innerHTML = '<div class="record-empty">该时间段暂无记录</div>';
return;
}
var html = '';
for (var i = 0; i < filtered.length; i++) {
var r = filtered[i];
var src = SOURCE_TYPES[r.source];
html += '<div class="record-item">';
html += '<div class="record-item__header">';
html += '<span class="record-item__title">' + r.name + '</span>';
html += '<span class="record-item__time">' + r.date + ' ' + r.time + '</span>';
html += '</div>';
html += '<div class="record-item__body">';
html += '<div class="record-item__metric"><div class="record-item__metric-label">消耗热量</div><div class="record-item__metric-val">' + r.kcal + '<span class="record-item__metric-unit">千卡</span></div></div>';
html += '<div class="record-item__metric"><div class="record-item__metric-label">运动时长</div><div class="record-item__metric-val">' + r.duration + '<span class="record-item__metric-unit">分钟</span></div></div>';
html += '<div class="record-item__source"><span class="source-badge ' + src.badge + '">' + src.label + '</span></div>';
html += '</div>';
html += '</div>';
}
container.innerHTML = html;
}
/* ===== 点击日期 ===== */
function onDayClick(dateStr) {
if (selectedDate === dateStr) {
switchTab('week');
return;
}
selectedDate = dateStr;
activeTab = '';
document.querySelectorAll('.record-tab').forEach(function(t) { t.classList.remove('active'); });
updateCal();
renderRecordList();
document.querySelector('.scroll-content').scrollTop = document.getElementById('recordTabs').offsetTop - 100;
}
/* ===== 初始化 ===== */
function init() {
calYear = TODAY.getFullYear();
calMonth = TODAY.getMonth();
document.getElementById('calMonthLabel').textContent = calYear + '年' + fmt(calMonth + 1) + '月';
renderWeekCal();
renderRecordList();
}
init();
</script>
</body>
</html>
@@ -0,0 +1,923 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>重打卡 - 体重管理 | 健康CQ原型</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
/* ===== 手机壳 ===== */
.phone-shell { width: 390px; height: 844px; background: #f5f7fa; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; }
/* ===== 状态栏 & 导航栏 ===== */
.status-bar { height: 44px; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; background: #fff; }
.status-bar .time { font-size: 15px; font-weight: 700; color: #333; }
.status-bar .icons { display: flex; gap: 6px; align-items: center; }
.nav-bar { height: 44px; background: #fff; display: flex; align-items: center; padding: 0 16px; flex-shrink: 0; border-bottom: 1px solid #f0f0f0; }
.nav-back { width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: #1a1a1a; }
.nav-title { flex: 1; text-align: center; font-size: 17px; font-weight: 600; color: #1a1a1a; }
.nav-placeholder { width: 28px; flex-shrink: 0; }
/* ===== 滚动内容区 ===== */
.scroll-content { flex: 1; overflow-y: auto; background: #f5f7fa; padding-bottom: 80px; }
.scroll-content::-webkit-scrollbar { display: none; }
/* ===== 今日摘要栏 ===== */
.summary-bar { display: flex; align-items: center; justify-content: space-between; background: #fff; margin: 12px 12px 0; padding: 12px 14px; border-radius: 12px; }
.summary-bar__info { flex: 1; }
.summary-bar__text { font-size: 14px; font-weight: 600; color: #1a1a1a; }
.summary-bar__text em { font-style: normal; color: #8b6cff; font-weight: 800; }
.summary-bar__history { font-size: 12px; color: #8b6cff; font-weight: 600; cursor: pointer; display: flex; align-items: center; gap: 2px; flex-shrink: 0; white-space: nowrap; }
.summary-bar__history svg { width: 14px; height: 14px; }
/* ===== 一周日期卡片(2行:4+3 ===== */
.day-grid { display: flex; flex-wrap: wrap; gap: 6px; margin: 12px; }
.day-card { flex: 0 0 calc(25% - 4.5px); background: #fff; border-radius: 12px; padding: 10px 4px 8px; text-align: center; box-shadow: 0 2px 8px rgba(0,0,0,0.04); display: flex; flex-direction: column; align-items: center; cursor: pointer; border: 2px solid transparent; transition: all .2s; }
.day-card--selected { border-color: #8b6cff; box-shadow: 0 2px 12px rgba(139,108,255,0.18); }
.day-card--today { border-color: #b08cff; }
.day-card__name { font-size: 12px; font-weight: 700; color: #1a1a1a; margin-bottom: 2px; }
.day-card__date { font-size: 9px; color: #bbb; margin-bottom: 6px; }
/* 已记录状态 */
.day-card__weight { font-size: 16px; font-weight: 800; color: #1a1a1a; line-height: 1.1; margin-bottom: 2px; }
.day-card__weight-unit { font-size: 10px; font-weight: 500; color: #999; }
.day-card__recommend { font-size: 10px; color: #bbb; margin-bottom: 6px; line-height: 1.3; }
.day-card__recommend em { font-style: normal; color: #999; font-weight: 600; }
.day-card__badge { display: inline-block; font-size: 9px; padding: 1px 6px; border-radius: 3px; font-weight: 600; }
.day-card__badge--height { background: #e6f7ff; color: #1890ff; }
.day-card__badge--bluetooth { background: #f6ffed; color: #52c41a; }
.day-card__badge--fat { background: #fff0f6; color: #eb2f96; }
.day-card__badge--manual { background: #fff7e6; color: #fa8c16; }
/* 未记录状态 */
.day-card--empty .day-card__name { color: #bbb; }
.day-card--empty .day-card__date { color: #ddd; }
.day-card__empty-rec { font-size: 10px; color: #bbb; line-height: 1.3; }
.day-card__empty-rec em { font-style: normal; color: #999; font-weight: 600; }
.day-card__empty-hint { font-size: 10px; color: #ccc; margin-top: 2px; }
/* ===== 类型卡片(身高秤/蓝牙称/体脂仪/自记)同一行 ===== */
.type-cards { margin: 0 12px 12px; display: flex; gap: 6px; }
.type-card { flex: 1; background: #fff; border-radius: 12px; padding: 10px 4px 8px; display: flex; flex-direction: column; align-items: center; text-align: center; box-shadow: 0 2px 8px rgba(0,0,0,0.04); cursor: pointer; position: relative; }
.type-card__icon-wrap { width: 28px; height: 28px; border-radius: 8px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; margin-bottom: 4px; }
.type-card__icon-wrap--height { background: #e6f7ff; }
.type-card__icon-wrap--bluetooth { background: #f6ffed; }
.type-card__icon-wrap--fat { background: #fff0f6; }
.type-card__icon-wrap--manual { background: #fff7e6; }
.type-card__icon-wrap svg { width: 16px; height: 16px; }
.type-card__info { min-width: 0; }
.type-card__label { font-size: 11px; font-weight: 700; color: #1a1a1a; margin-bottom: 1px; }
.type-card__val { font-size: 10px; color: #666; line-height: 1.3; }
.type-card__val em { font-style: normal; font-weight: 700; color: #1a1a1a; }
.type-card__empty { font-size: 10px; color: #bbb; }
/* ===== 自记测量选择区 ===== */
.self-record { margin: 0 12px 12px; }
.self-record__title { font-size: 15px; font-weight: 700; color: #1a1a1a; margin-bottom: 10px; padding-left: 2px; }
/* 测量项列表 */
.measure-list { background: #fff; border-radius: 12px; overflow: hidden; }
.measure-item { display: flex; align-items: center; padding: 14px 12px; border-bottom: 1px solid #f5f5f5; gap: 10px; }
.measure-item:last-child { border-bottom: none; }
.measure-item__icon { width: 44px; height: 44px; border-radius: 10px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; font-size: 22px; }
.measure-item__icon--weight { background: #f0e6ff; }
.measure-item__icon--fat { background: #fff0f6; }
.measure-item__icon--waist { background: #e6f7ff; }
.measure-item__info { flex: 1; min-width: 0; }
.measure-item__name { font-size: 14px; font-weight: 700; color: #1a1a1a; margin-bottom: 4px; }
.measure-item__last { font-size: 12px; color: #999; line-height: 1.4; }
.measure-item__last em { font-style: normal; font-weight: 700; color: #333; }
.measure-item__range { font-size: 11px; color: #bbb; margin-top: 2px; }
.measure-item__range em { font-style: normal; color: #8b6cff; font-weight: 600; }
.measure-item__btn { width: 32px; height: 32px; border-radius: 50%; border: 1.5px solid #8b6cff; background: #fff; display: flex; align-items: center; justify-content: center; cursor: pointer; color: #8b6cff; flex-shrink: 0; transition: all .15s; }
.measure-item__btn svg { width: 16px; height: 16px; }
.measure-item__btn:active { background: #f0e6ff; }
/* 底部已选栏 */
.bottom-bar { position: absolute; bottom: 0; left: 0; right: 0; background: #fff; border-top: 1px solid #f0f0f0; padding: 10px 16px 24px; display: flex; align-items: center; justify-content: space-between; z-index: 10; }
.bottom-bar__info { font-size: 13px; color: #666; display: flex; align-items: center; gap: 6px; }
.bottom-bar__info em { font-style: normal; font-weight: 800; color: #1a1a1a; }
.bottom-bar__list { width: 32px; height: 32px; border-radius: 8px; background: #f0e6ff; display: flex; align-items: center; justify-content: center; cursor: pointer; flex-shrink: 0; position: relative; }
.bottom-bar__list svg { width: 18px; height: 18px; color: #8b6cff; }
.bottom-bar__list-dot { display: none; position: absolute; top: -2px; right: -2px; width: 16px; height: 16px; border-radius: 50%; background: #ff4d4f; color: #fff; font-size: 10px; font-weight: 700; align-items: center; justify-content: center; line-height: 1; }
.bottom-bar__list-dot.show { display: flex; }
.bottom-bar__submit { background: linear-gradient(135deg, #8b6cff, #b08cff); color: #fff; border: none; border-radius: 20px; padding: 10px 28px; font-size: 14px; font-weight: 700; cursor: pointer; }
.bottom-bar__submit:active { opacity: 0.85; }
/* ===== 数值录入弹窗 ===== */
.value-mask { display: none; position: absolute; inset: 0; background: rgba(0,0,0,0.45); z-index: 50; }
.value-mask.show { display: block; }
.value-panel { position: absolute; bottom: 0; left: 0; right: 0; background: #fff; border-radius: 20px 20px 0 0; padding: 20px 16px 30px; z-index: 51; transform: translateY(100%); transition: transform .25s ease; }
.value-mask.show .value-panel { transform: translateY(0); }
.value-panel__handle { width: 36px; height: 4px; background: #ddd; border-radius: 2px; margin: 0 auto 16px; }
.value-panel__header { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; }
.value-panel__icon { width: 52px; height: 52px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 28px; flex-shrink: 0; }
.value-panel__icon--weight { background: #f0e6ff; }
.value-panel__icon--fat { background: #fff0f6; }
.value-panel__icon--waist { background: #e6f7ff; }
.value-panel__info { flex: 1; }
.value-panel__name { font-size: 16px; font-weight: 700; color: #1a1a1a; margin-bottom: 2px; }
.value-panel__ref { font-size: 12px; color: #999; }
.value-panel__ref em { font-style: normal; color: #8b6cff; font-weight: 600; }
.value-panel__label { font-size: 13px; font-weight: 600; color: #666; margin-bottom: 8px; }
.value-input-row { display: flex; align-items: center; gap: 0; margin-bottom: 12px; }
.value-input-row__btn { width: 40px; height: 40px; border: 1.5px solid #e8e8e8; background: #fafafa; font-size: 20px; color: #666; cursor: pointer; display: flex; align-items: center; justify-content: center; }
.value-input-row__btn:first-child { border-radius: 10px 0 0 10px; }
.value-input-row__btn:last-child { border-radius: 0 10px 10px 0; }
.value-input-row__btn:active { background: #f0f0f0; }
.value-input-row__input { width: 80px; height: 40px; border: 1.5px solid #e8e8e8; border-left: none; border-right: none; text-align: center; font-size: 20px; font-weight: 700; color: #1a1a1a; outline: none; }
.value-input-row__input:focus { border-color: #8b6cff; }
.value-input-row__unit { font-size: 13px; color: #999; margin-left: 8px; }
.value-panel__hint { text-align: center; font-size: 13px; color: #666; margin-bottom: 16px; padding: 10px; background: #f7f8fa; border-radius: 10px; }
.value-panel__hint em { font-style: normal; font-weight: 800; color: #8b6cff; font-size: 18px; }
.value-panel__confirm { width: 100%; height: 46px; border: none; border-radius: 23px; background: linear-gradient(135deg, #8b6cff, #b08cff); color: #fff; font-size: 16px; font-weight: 700; cursor: pointer; }
.value-panel__confirm:active { opacity: 0.85; }
/* ===== Toast 提示 ===== */
.toast { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) scale(0.9); background: rgba(0,0,0,0.78); color: #fff; font-size: 14px; padding: 10px 22px; border-radius: 20px; z-index: 60; pointer-events: none; opacity: 0; transition: all .25s ease; white-space: nowrap; }
.toast.show { opacity: 1; transform: translate(-50%, -50%) scale(1); }
/* ===== 已选测量汇总面板 ===== */
.summary-mask { display: none; position: absolute; inset: 0; background: rgba(0,0,0,0.45); z-index: 50; }
.summary-mask.show { display: block; }
.summary-panel { position: absolute; bottom: 0; left: 0; right: 0; background: #fff; border-radius: 20px 20px 0 0; max-height: 70%; display: flex; flex-direction: column; z-index: 51; transform: translateY(100%); transition: transform .25s ease; }
.summary-mask.show .summary-panel { transform: translateY(0); }
.summary-panel__head { padding: 16px 16px 12px; flex-shrink: 0; }
.summary-panel__handle { width: 36px; height: 4px; background: #ddd; border-radius: 2px; margin: 0 auto 12px; }
.summary-panel__meta { display: flex; align-items: center; justify-content: space-between; }
.summary-panel__date-day { font-size: 14px; font-weight: 700; color: #1a1a1a; }
.summary-panel__date-day em { font-style: normal; color: #8b6cff; }
.summary-panel__list { flex: 1; overflow-y: auto; padding: 0 16px; }
.summary-panel__list::-webkit-scrollbar { display: none; }
.summary-item { display: flex; align-items: center; padding: 10px 0; border-bottom: 1px solid #f5f5f5; gap: 8px; }
.summary-item:last-child { border-bottom: none; }
.summary-item__thumb { width: 40px; height: 40px; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 20px; flex-shrink: 0; }
.summary-item__thumb--weight { background: #f0e6ff; }
.summary-item__thumb--fat { background: #fff0f6; }
.summary-item__thumb--waist { background: #e6f7ff; }
.summary-item__info { flex: 1; min-width: 0; }
.summary-item__name { font-size: 13px; font-weight: 600; color: #1a1a1a; margin-bottom: 2px; }
.summary-item__meta { font-size: 10px; color: #999; display: flex; gap: 6px; flex-wrap: wrap; }
.summary-item__val { font-weight: 700; color: #8b6cff; }
.summary-item__remove { width: 24px; height: 24px; border-radius: 50%; border: none; background: #fff1f0; color: #ff4d4f; cursor: pointer; display: flex; align-items: center; justify-content: center; flex-shrink: 0; font-size: 12px; line-height: 1; }
.summary-item__remove:active { background: #ffccc7; }
.summary-panel__footer { padding: 12px 16px 24px; flex-shrink: 0; }
.summary-panel__submit { width: 100%; height: 46px; border: none; border-radius: 23px; background: linear-gradient(135deg, #8b6cff, #b08cff); color: #fff; font-size: 16px; font-weight: 700; cursor: pointer; }
.summary-panel__submit:active { opacity: 0.85; }
/* ===== 确认提交弹窗 ===== */
.confirm-mask { display: none; position: absolute; inset: 0; background: rgba(0,0,0,0.5); z-index: 60; align-items: center; justify-content: center; }
.confirm-mask.show { display: flex; }
.confirm-dialog { background: #fff; border-radius: 16px; width: 290px; padding: 24px 20px 20px; text-align: center; }
.confirm-dialog__icon { width: 52px; height: 52px; border-radius: 50%; background: linear-gradient(135deg, #f0e6ff, #fff1f0); display: flex; align-items: center; justify-content: center; margin: 0 auto 12px; font-size: 28px; }
.confirm-dialog__title { font-size: 17px; font-weight: 800; color: #1a1a1a; margin-bottom: 8px; }
.confirm-dialog__text { font-size: 13px; color: #666; line-height: 1.6; margin-bottom: 20px; }
.confirm-dialog__text em { font-style: normal; font-weight: 800; color: #8b6cff; font-size: 16px; }
.confirm-dialog__actions { display: flex; gap: 12px; }
.confirm-dialog__btn { flex: 1; height: 42px; border-radius: 21px; border: none; font-size: 15px; font-weight: 600; cursor: pointer; }
.confirm-dialog__btn--cancel { background: #f5f5f5; color: #666; }
.confirm-dialog__btn--confirm { background: linear-gradient(135deg, #8b6cff, #b08cff); color: #fff; }
.confirm-dialog__btn:active { opacity: 0.85; }
/* ===== 提示弹窗(单按钮) ===== */
.tip-mask { display: none; position: absolute; inset: 0; background: rgba(0,0,0,0.5); z-index: 60; align-items: center; justify-content: center; }
.tip-mask.show { display: flex; }
.tip-dialog { background: #fff; border-radius: 16px; width: 270px; padding: 24px 20px 20px; text-align: center; }
.tip-dialog__icon { font-size: 40px; margin-bottom: 12px; }
.tip-dialog__text { font-size: 14px; color: #666; line-height: 1.6; margin-bottom: 20px; }
.tip-dialog__btn { width: 100%; height: 42px; border-radius: 21px; border: none; font-size: 15px; font-weight: 600; cursor: pointer; background: linear-gradient(135deg, #8b6cff, #b08cff); color: #fff; }
.tip-dialog__btn:active { opacity: 0.85; }
</style>
</head>
<body>
<div class="phone-shell">
<!-- 状态栏 -->
<div class="status-bar">
<span class="time">09:40</span>
<div 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>
</div>
</div>
<!-- 导航栏 -->
<div class="nav-bar">
<!-- [交互] 点击返回体重管理主页 -->
<div class="nav-back" onclick="location.href='weight-main.html'">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
</div>
<div class="nav-title">08-10 ~ 08-16</div>
<div class="nav-placeholder"></div>
</div>
<!-- 滚动内容区 -->
<div class="scroll-content">
<!-- 今日摘要栏 -->
<!-- [交互] 点击"历史记录"跳转至: weight-history.html -->
<div class="summary-bar">
<div class="summary-bar__info">
<span class="summary-bar__text" id="summaryText">08月12日 周三 · 今日体重 <em>62.6</em> 公斤</span>
</div>
<div class="summary-bar__history" onclick="location.href='weight-history.html'">
历史记录
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
<polyline points="9 18 15 12 9 6"/>
</svg>
</div>
</div>
<!-- 一周日期卡片(2行:4+3 -->
<div class="day-grid" id="dayGrid">
<!-- 周一 - 已记录(蓝牙称) -->
<!-- [交互] 点击选中该日,下方显示记录详情(非当日仅查看) -->
<!-- [状态] 已记录 - 蓝牙称 -->
<div class="day-card" data-day="mon" onclick="selectDay('mon')">
<div class="day-card__name">周一</div>
<div class="day-card__date">08-10</div>
<div class="day-card__weight">62.8<span class="day-card__weight-unit">kg</span></div>
<div class="day-card__recommend">推荐<em>56-68</em>kg</div>
<span class="day-card__badge day-card__badge--bluetooth">蓝牙</span>
</div>
<!-- 周二 - 已记录(体脂仪) -->
<!-- [交互] 点击选中该日,下方显示记录详情(非当日仅查看) -->
<!-- [状态] 已记录 - 体脂仪 -->
<div class="day-card" data-day="tue" onclick="selectDay('tue')">
<div class="day-card__name">周二</div>
<div class="day-card__date">08-11</div>
<div class="day-card__weight">62.7<span class="day-card__weight-unit">kg</span></div>
<div class="day-card__recommend">推荐<em>56-68</em>kg</div>
<span class="day-card__badge day-card__badge--fat">体脂仪</span>
</div>
<!-- 周三(今天)- 已记录(身高秤) -->
<!-- [交互] 默认选中当天,下方显示记录详情 -->
<!-- [状态] 已记录 - 身高秤 -->
<div class="day-card day-card--today" data-day="wed" onclick="selectDay('wed')">
<div class="day-card__name">周三</div>
<div class="day-card__date">今天</div>
<div class="day-card__weight">62.6<span class="day-card__weight-unit">kg</span></div>
<div class="day-card__recommend">推荐<em>56-68</em>kg</div>
<span class="day-card__badge day-card__badge--height">身高秤</span>
</div>
<!-- 周四 - 未记录 -->
<!-- [交互] 不可点击,灰色显示 -->
<!-- [状态] 未记录 -->
<div class="day-card day-card--empty" data-day="thu" onclick="selectDay('thu')">
<div class="day-card__name">周四</div>
<div class="day-card__date">08-13</div>
<div class="day-card__empty-rec">推荐<em>56-68</em>kg</div>
<div class="day-card__empty-hint">请记录</div>
</div>
<!-- 周五 - 未记录 -->
<!-- [交互] 不可点击,灰色显示 -->
<!-- [状态] 未记录 -->
<div class="day-card day-card--empty" data-day="fri" onclick="selectDay('fri')">
<div class="day-card__name">周五</div>
<div class="day-card__date">08-14</div>
<div class="day-card__empty-rec">推荐<em>56-68</em>kg</div>
<div class="day-card__empty-hint">请记录</div>
</div>
<!-- 周六 - 未记录 -->
<!-- [交互] 不可点击,灰色显示 -->
<!-- [状态] 未记录 -->
<div class="day-card day-card--empty" data-day="sat" onclick="selectDay('sat')">
<div class="day-card__name">周六</div>
<div class="day-card__date">08-15</div>
<div class="day-card__empty-rec">推荐<em>56-68</em>kg</div>
<div class="day-card__empty-hint">请记录</div>
</div>
<!-- 周日 - 未记录 -->
<!-- [交互] 不可点击,灰色显示 -->
<!-- [状态] 未记录 -->
<div class="day-card day-card--empty" data-day="sun" onclick="selectDay('sun')">
<div class="day-card__name">周日</div>
<div class="day-card__date">08-16</div>
<div class="day-card__empty-rec">推荐<em>56-68</em>kg</div>
<div class="day-card__empty-hint">请记录</div>
</div>
</div>
<!-- 类型卡片(身高秤/蓝牙称/体脂仪/自记)2x2 布局 -->
<div class="type-cards">
<!-- 身高秤 - 已记录 -->
<div class="type-card" onclick="showHeightScaleTip()">
<div class="type-card__icon-wrap type-card__icon-wrap--height">
<svg viewBox="0 0 24 24" fill="none" stroke="#1890ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="4" y="2" width="16" height="20" rx="2"/>
<line x1="8" y1="6" x2="16" y2="6"/>
<line x1="8" y1="10" x2="16" y2="10"/>
<line x1="8" y1="14" x2="12" y2="14"/>
<line x1="12" y1="18" x2="12" y2="22"/>
</svg>
</div>
<div class="type-card__info">
<div class="type-card__label">身高秤</div>
<div class="type-card__val">已记录 <em>62.6</em> kg</div>
</div>
</div>
<!-- 蓝牙称 - 已记录 -->
<div class="type-card" onclick="showBluetoothTip()">
<div class="type-card__icon-wrap type-card__icon-wrap--bluetooth">
<svg viewBox="0 0 24 24" fill="none" stroke="#52c41a" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="6.5 6.5 17.5 17.5 12 22 12 2 17.5 6.5 6.5 17.5"/>
</svg>
</div>
<div class="type-card__info">
<div class="type-card__label">蓝牙称</div>
<div class="type-card__val">已记录 <em>62.8</em> kg</div>
</div>
</div>
<!-- 体脂仪 - 未记录 -->
<div class="type-card" onclick="showFatAnalyzerTip()">
<div class="type-card__icon-wrap type-card__icon-wrap--fat">
<svg viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="8" r="5"/>
<path d="M3 21c0-5 4-9 9-9s9 4 9 9"/>
<line x1="12" y1="13" x2="12" y2="22"/>
</svg>
</div>
<div class="type-card__info">
<div class="type-card__label">体脂仪</div>
<div class="type-card__empty">尚未记录</div>
</div>
</div>
<!-- 自记 - 已记录 -->
<!-- [交互] 点击滚动到自记区域 -->
<div class="type-card" onclick="scrollToSelfRecord()">
<div class="type-card__icon-wrap type-card__icon-wrap--manual">
<svg viewBox="0 0 24 24" fill="none" stroke="#fa8c16" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/>
<path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/>
</svg>
</div>
<div class="type-card__info">
<div class="type-card__label">自记</div>
<div class="type-card__val">已记录 <em>62.6</em> kg</div>
</div>
</div>
</div>
<!-- 自记测量选择区 -->
<div class="self-record" id="selfRecordSection">
<div class="self-record__title">选择指标进行自记</div>
<div class="measure-list" id="measureList">
<!-- 体重 -->
<div class="measure-item">
<div class="measure-item__icon measure-item__icon--weight">⚖️</div>
<div class="measure-item__info">
<div class="measure-item__name">体重</div>
<div class="measure-item__last">最近一次:<em id="lastWeight">62.6</em> kg08-12</div>
<div class="measure-item__range">参考范围:<em>56-68</em> kg</div>
</div>
<!-- [交互] 点击+号弹出录入弹窗 -->
<div class="measure-item__btn" onclick="openValuePanel('weight')">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">
<line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/>
</svg>
</div>
</div>
<!-- 体脂 -->
<div class="measure-item">
<div class="measure-item__icon measure-item__icon--fat">🧬</div>
<div class="measure-item__info">
<div class="measure-item__name">体脂</div>
<div class="measure-item__last">最近一次:<em id="lastFat">20.0</em> %08-12</div>
<div class="measure-item__range">参考范围:<em>15-25</em> %</div>
</div>
<!-- [交互] 点击+号弹出录入弹窗 -->
<div class="measure-item__btn" onclick="openValuePanel('fat')">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">
<line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/>
</svg>
</div>
</div>
<!-- 腰围 -->
<div class="measure-item">
<div class="measure-item__icon measure-item__icon--waist">📏</div>
<div class="measure-item__info">
<div class="measure-item__name">腰围</div>
<div class="measure-item__last">最近一次:<em id="lastWaist">76.5</em> cm08-12</div>
<div class="measure-item__range">参考范围:<em>75-85</em> cm</div>
</div>
<!-- [交互] 点击+号弹出录入弹窗 -->
<div class="measure-item__btn" onclick="openValuePanel('waist')">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">
<line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/>
</svg>
</div>
</div>
</div>
</div>
</div>
<!-- 底部已选栏 -->
<!-- [交互] 点击列表图标查看已选指标;点击"提交"记录所选指标 -->
<div class="bottom-bar" id="bottomBar">
<div class="bottom-bar__info">
<div class="bottom-bar__list" id="listIcon" onclick="openSummary()">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/>
<polyline points="14 2 14 8 20 8"/>
<line x1="16" y1="13" x2="8" y2="13"/>
<line x1="16" y1="17" x2="8" y2="17"/>
</svg>
<div class="bottom-bar__list-dot" id="listDot"></div>
</div>
<span>已选 <em id="selCount">0</em></span>
</div>
<button class="bottom-bar__submit" id="submitBtn" onclick="submitRecord()">提交</button>
</div>
<!-- Toast 提示 -->
<div class="toast" id="toast"></div>
<!-- 已选测量汇总面板 -->
<!-- [交互] 点击列表图标弹出,可查看/移除已选指标 -->
<div class="summary-mask" id="summaryMask" onclick="closeSummary()">
<div class="summary-panel" onclick="event.stopPropagation()">
<div class="summary-panel__head">
<div class="summary-panel__handle"></div>
<div class="summary-panel__meta">
<span class="summary-panel__date-day" id="summaryDateDay"></span>
</div>
</div>
<div class="summary-panel__list" id="summaryList"></div>
<div class="summary-panel__footer">
<button class="summary-panel__submit" onclick="openConfirm()">提交记录</button>
</div>
</div>
</div>
<!-- 确认提交弹窗 -->
<!-- [交互] 二次确认后提交记录 -->
<div class="confirm-mask" id="confirmMask" onclick="closeConfirm()">
<div class="confirm-dialog" onclick="event.stopPropagation()">
<div class="confirm-dialog__icon">⚖️</div>
<div class="confirm-dialog__title">体重记录确认</div>
<div class="confirm-dialog__text" id="confirmText"></div>
<div class="confirm-dialog__actions">
<button class="confirm-dialog__btn confirm-dialog__btn--cancel" onclick="closeConfirm()">取消</button>
<button class="confirm-dialog__btn confirm-dialog__btn--confirm" onclick="confirmSubmit()">确定</button>
</div>
</div>
</div>
<!-- 提示弹窗 -->
<div class="tip-mask" id="tipMask" onclick="closeTip()">
<div class="tip-dialog" onclick="event.stopPropagation()">
<div class="tip-dialog__icon">💡</div>
<div class="tip-dialog__text" id="tipText"></div>
<button class="tip-dialog__btn" onclick="closeTip()">知道了</button>
</div>
</div>
<!-- 数值录入弹窗 -->
<!-- [交互] 点击+号弹出,输入数值后确认添加 -->
<div class="value-mask" id="valueMask" onclick="closeValuePanel()">
<div class="value-panel" onclick="event.stopPropagation()">
<div class="value-panel__handle"></div>
<div class="value-panel__header">
<div class="value-panel__icon" id="valueIcon"></div>
<div class="value-panel__info">
<div class="value-panel__name" id="valueName"></div>
<div class="value-panel__ref">参考范围:<em id="valueRef"></em></div>
</div>
</div>
<div class="value-panel__label">输入测量值</div>
<div class="value-input-row">
<button class="value-input-row__btn" id="valueMinusBtn" onclick="adjustValue(-0.1)"></button>
<input class="value-input-row__input" type="number" id="valueInput" value="62.6" step="0.1" min="0" oninput="updateValuePreview()">
<button class="value-input-row__btn" id="valuePlusBtn" onclick="adjustValue(0.1)">+</button>
<span class="value-input-row__unit" id="valueUnit">kg</span>
</div>
<div class="value-panel__hint" id="valueHint">
记录值 <em id="valuePreview">62.6</em> <span id="valueHintUnit">kg</span>
</div>
<button class="value-panel__confirm" onclick="confirmAddValue()">确认添加</button>
</div>
</div>
</div>
<script>
/* ===== 日期数据 ===== */
var dayNames = { mon:'周一', tue:'周二', wed:'周三', thu:'周四', fri:'周五', sat:'周六', sun:'周日' };
var dayDates = { mon:'08-10', tue:'08-11', wed:'08-12', thu:'08-13', fri:'08-14', sat:'08-15', sun:'08-16' };
var TODAY = 'wed';
/* 各天已记录数据 */
var dayRecords = {
mon: { weight: { val: 62.8, type: 'bluetooth' } },
tue: { weight: { val: 62.7, type: 'fat', fatVal: 20.2, waistVal: 77.0 } },
wed: { weight: { val: 62.6, type: 'height', fatVal: 20.0, waistVal: 76.5 } },
thu: {},
fri: {},
sat: {},
sun: {}
};
var selectedDay = null;
/* 自记暂存 */
var cart = {};
var measureConfig = {
weight: { name: '体重', icon: '⚖️', unit: 'kg', ref: '56-68', step: 0.1, defaultVal: 62.6, iconClass: 'value-panel__icon--weight' },
fat: { name: '体脂', icon: '🧬', unit: '%', ref: '15-25', step: 0.1, defaultVal: 20.0, iconClass: 'value-panel__icon--fat' },
waist: { name: '腰围', icon: '📏', unit: 'cm', ref: '75-85', step: 0.5, defaultVal: 76.5, iconClass: 'value-panel__icon--waist' }
};
var currentMeasureKey = null;
var CURRENT_STEP = 0.1;
/* ===== 日期选择 ===== */
/* 选中/取消选中日期 */
/* [规则] 只有当天可以操作(选中+自记),非当天只能查看,不可点击切换 */
function selectDay(day) {
// 仅当天可交互,其他日期无任何响应
if (day !== TODAY) return;
if (selectedDay === day) {
selectedDay = null;
} else {
selectedDay = day;
}
// 更新卡片选中态(仅当天卡片可选中)
document.querySelectorAll('.day-card').forEach(function(card) {
card.classList.toggle('day-card--selected', card.dataset.day === selectedDay);
});
// 根据是否选中切换操作区显隐
toggleSelfRecordBody();
}
/* 切换底部栏和操作区:仅当日可自记 */
function toggleSelfRecordBody() {
var isToday = selectedDay === TODAY;
var bottomBar = document.getElementById('bottomBar');
if (isToday) {
bottomBar.style.display = '';
} else {
bottomBar.style.display = 'none';
}
}
/* ===== 数值录入弹窗 ===== */
/* 打开弹窗 */
function openValuePanel(measureKey) {
if (!selectedDay) {
showToast('请先选择日期');
return;
}
if (selectedDay !== TODAY) {
showToast('仅可对当日进行自记操作');
return;
}
currentMeasureKey = measureKey;
var cfg = measureConfig[measureKey];
CURRENT_STEP = cfg.step;
var iconEl = document.getElementById('valueIcon');
iconEl.textContent = cfg.icon;
iconEl.className = 'value-panel__icon ' + cfg.iconClass;
document.getElementById('valueName').textContent = cfg.name;
document.getElementById('valueRef').textContent = cfg.ref;
document.getElementById('valueUnit').textContent = cfg.unit;
document.getElementById('valueHintUnit').textContent = cfg.unit;
var currentVal = cfg.defaultVal;
// 如果已有暂存值,使用暂存值
if (cart[measureKey]) {
currentVal = cart[measureKey];
}
document.getElementById('valueInput').value = currentVal;
document.getElementById('valueInput').step = cfg.step;
// 调整步进按钮的文本
var stepText = cfg.step === 0.5 ? '0.5' : '0.1';
document.getElementById('valueMinusBtn').textContent = '' + stepText;
document.getElementById('valuePlusBtn').textContent = '+' + stepText;
document.getElementById('valueMask').classList.add('show');
updateValuePreview();
}
/* 关闭弹窗 */
function closeValuePanel() {
document.getElementById('valueMask').classList.remove('show');
currentMeasureKey = null;
}
/* 调整数值 */
function adjustValue(delta) {
var input = document.getElementById('valueInput');
var cfg = measureConfig[currentMeasureKey];
var val = parseFloat(input.value) || cfg.defaultVal;
val = Math.round((val + delta) * 10) / 10; // 保留一位小数
if (val < 0) val = 0;
input.value = val;
updateValuePreview();
}
/* 实时更新预览 */
function updateValuePreview() {
var val = parseFloat(document.getElementById('valueInput').value) || 0;
document.getElementById('valuePreview').textContent = val.toFixed(1);
}
/* 确认添加 */
function confirmAddValue() {
if (!currentMeasureKey) return;
var val = parseFloat(document.getElementById('valueInput').value);
if (isNaN(val) || val <= 0) {
showToast('请输入有效数值');
return;
}
cart[currentMeasureKey] = val;
closeValuePanel();
updateBottomBar();
}
/* ===== 底部栏操作 ===== */
/* 更新底部栏 */
function updateBottomBar() {
var totalItems = Object.keys(cart).length;
document.getElementById('selCount').textContent = totalItems;
var listDot = document.getElementById('listDot');
if (totalItems > 0) {
listDot.textContent = totalItems;
listDot.classList.add('show');
} else {
listDot.classList.remove('show');
}
var submitBtn = document.getElementById('submitBtn');
if (totalItems === 0) {
submitBtn.style.opacity = '0.4';
submitBtn.style.pointerEvents = 'none';
} else {
submitBtn.style.opacity = '1';
submitBtn.style.pointerEvents = 'auto';
}
}
/* 提交记录 */
function submitRecord() {
if (!selectedDay) {
showToast('请先选择日期');
return;
}
if (selectedDay !== TODAY) {
showToast('仅可对当日进行自记操作');
return;
}
if (Object.keys(cart).length === 0) {
showToast('请先添加测量指标');
return;
}
openConfirm();
}
/* ===== 已选汇总面板 ===== */
function openSummary() {
renderSummary();
document.getElementById('summaryMask').classList.add('show');
}
function closeSummary() {
document.getElementById('summaryMask').classList.remove('show');
}
function renderSummary() {
document.getElementById('summaryDateDay').innerHTML = '2026年08月' + dayDates[selectedDay] + '日 · <em>' + dayNames[selectedDay] + '</em>';
var html = '';
var thumbClasses = { weight: 'summary-item__thumb--weight', fat: 'summary-item__thumb--fat', waist: 'summary-item__thumb--waist' };
Object.keys(cart).forEach(function(key) {
var cfg = measureConfig[key];
var val = cart[key];
html += '<div class="summary-item">';
html += ' <div class="summary-item__thumb ' + (thumbClasses[key] || '') + '">' + cfg.icon + '</div>';
html += ' <div class="summary-item__info">';
html += ' <div class="summary-item__name">' + cfg.name + '</div>';
html += ' <div class="summary-item__meta">';
html += ' <span class="summary-item__val">' + val.toFixed(1) + ' ' + cfg.unit + '</span>';
html += ' <span>参考范围 ' + cfg.ref + ' ' + cfg.unit + '</span>';
html += ' </div>';
html += ' </div>';
html += ' <button class="summary-item__remove" onclick="removeSummaryItem(\'' + key + '\')"></button>';
html += '</div>';
});
if (Object.keys(cart).length === 0) {
html = '<div style="padding:20px;text-align:center;color:#bbb;font-size:13px;">暂无已选指标</div>';
}
document.getElementById('summaryList').innerHTML = html;
}
function removeSummaryItem(key) {
delete cart[key];
updateBottomBar();
if (Object.keys(cart).length === 0) {
closeSummary();
} else {
renderSummary();
}
}
/* ===== 二次确认弹窗 ===== */
function openConfirm() {
var lines = [];
Object.keys(cart).forEach(function(key) {
var cfg = measureConfig[key];
var val = cart[key];
lines.push(cfg.name + ' <em>' + val.toFixed(1) + ' ' + cfg.unit + '</em>');
});
document.getElementById('confirmText').innerHTML = lines.join('<br>') + '<br>是否确认记录?';
document.getElementById('confirmMask').classList.add('show');
}
function closeConfirm() {
document.getElementById('confirmMask').classList.remove('show');
}
/* 确认提交 */
function confirmSubmit() {
if (!dayRecords[selectedDay]) dayRecords[selectedDay] = {};
Object.keys(cart).forEach(function(key) {
var cfg = measureConfig[key];
var val = cart[key];
if (key === 'weight') {
dayRecords[selectedDay].weight = { val: val, type: 'manual' };
} else if (key === 'fat') {
dayRecords[selectedDay].fatVal = val;
} else if (key === 'waist') {
dayRecords[selectedDay].waistVal = val;
}
});
// 确保有 weight 记录
if (!dayRecords[selectedDay].weight) {
dayRecords[selectedDay].weight = { val: cart['weight'] || 62.6, type: 'manual' };
}
updateDayCard(selectedDay);
updateSummaryBar();
updateLastValues();
closeConfirm();
closeSummary();
cart = {};
updateBottomBar();
showToast('记录成功!');
}
/* 更新日期卡片显示 */
function updateDayCard(day) {
var card = document.querySelector('.day-card[data-day="' + day + '"]');
if (!card) return;
var rec = dayRecords[day] || {};
var weightData = rec.weight;
card.classList.remove('day-card--empty');
// 更新体重显示
var weightEl = card.querySelector('.day-card__weight');
if (!weightEl) {
weightEl = document.createElement('div');
weightEl.className = 'day-card__weight';
var recEl = card.querySelector('.day-card__recommend, .day-card__empty-rec');
if (recEl) {
card.insertBefore(weightEl, recEl);
} else {
card.appendChild(weightEl);
}
}
if (weightData) {
weightEl.innerHTML = weightData.val + '<span class="day-card__weight-unit">kg</span>';
} else {
weightEl.innerHTML = '--<span class="day-card__weight-unit">kg</span>';
}
// 移除空状态提示
var emptyHint = card.querySelector('.day-card__empty-hint');
if (emptyHint) emptyHint.remove();
// 更新标签
var oldBadge = card.querySelector('.day-card__badge');
if (oldBadge) oldBadge.remove();
if (weightData) {
var badge = document.createElement('span');
var typeMap = { height: 'day-card__badge--height', bluetooth: 'day-card__badge--bluetooth', fat: 'day-card__badge--fat', manual: 'day-card__badge--manual' };
var labelMap = { height: '身高秤', bluetooth: '蓝牙', fat: '体脂仪', manual: '自记' };
badge.className = 'day-card__badge ' + (typeMap[weightData.type] || 'day-card__badge--manual');
badge.textContent = labelMap[weightData.type] || '自记';
card.appendChild(badge);
}
updateSummaryBar();
}
/* 更新摘要栏 */
function updateSummaryBar() {
var todayRec = dayRecords[TODAY] || {};
var weightVal = todayRec.weight ? todayRec.weight.val : '--';
var bar = document.getElementById('summaryText');
if (bar) {
bar.innerHTML = '08月12日 周三 · 今日体重 <em>' + weightVal + '</em> 公斤';
}
}
/* 更新自记区域最近一次数据 */
function updateLastValues() {
var todayRec = dayRecords[TODAY] || {};
if (todayRec.weight) {
document.getElementById('lastWeight').textContent = todayRec.weight.val;
}
if (todayRec.fatVal !== undefined) {
document.getElementById('lastFat').textContent = todayRec.fatVal;
}
if (todayRec.waistVal !== undefined) {
document.getElementById('lastWaist').textContent = todayRec.waistVal;
}
// 同步更新默认值
if (todayRec.weight) measureConfig.weight.defaultVal = todayRec.weight.val;
if (todayRec.fatVal !== undefined) measureConfig.fat.defaultVal = todayRec.fatVal;
if (todayRec.waistVal !== undefined) measureConfig.waist.defaultVal = todayRec.waistVal;
}
/* ===== 提示弹窗 ===== */
function showHeightScaleTip() {
document.getElementById('tipText').textContent = '来自身高体重一体秤设备自动同步数据';
document.getElementById('tipMask').classList.add('show');
}
function showBluetoothTip() {
document.getElementById('tipText').textContent = '来自蓝牙体重秤设备自动同步数据';
document.getElementById('tipMask').classList.add('show');
}
function showFatAnalyzerTip() {
document.getElementById('tipText').textContent = '来自inBody体脂分析设备自动同步数据';
document.getElementById('tipMask').classList.add('show');
}
function closeTip() {
document.getElementById('tipMask').classList.remove('show');
}
/* ===== Toast 提示 ===== */
var toastTimer = null;
function showToast(msg) {
var t = document.getElementById('toast');
t.textContent = msg;
t.classList.add('show');
if (toastTimer) clearTimeout(toastTimer);
toastTimer = setTimeout(function() {
t.classList.remove('show');
}, 1800);
}
/* 滚动到自记区域 */
function scrollToSelfRecord() {
document.getElementById('selfRecordSection').scrollIntoView({ behavior: 'smooth' });
}
/* 初始化 */
selectDay(TODAY);
updateBottomBar();
</script>
</body>
</html>
@@ -0,0 +1,520 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>体重记录 - 员工端 | 健康CQ原型</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
.phone-shell { width: 390px; height: 844px; background: #f5f7fa; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; }
.status-bar { height: 44px; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; background: #fff; }
.status-bar .time { font-size: 15px; font-weight: 700; color: #333; }
.status-bar .icons { display: flex; gap: 6px; align-items: center; }
.nav-bar { height: 44px; background: #fff; display: flex; align-items: center; padding: 0 16px; flex-shrink: 0; border-bottom: 1px solid #f0f0f0; }
.nav-back { width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: #1a1a1a; }
.nav-title { flex: 1; text-align: center; font-size: 17px; font-weight: 600; color: #1a1a1a; }
.nav-placeholder { width: 28px; flex-shrink: 0; }
.scroll-content { flex: 1; overflow-y: auto; background: #f5f7fa; }
.scroll-content::-webkit-scrollbar { display: none; }
/* ===== 日历月导航 ===== */
.cal-nav { display: flex; align-items: center; justify-content: space-between; padding: 8px 16px; background: #fff; }
.cal-nav__arrow { width: 30px; height: 30px; border-radius: 50%; background: #f5f7fa; display: flex; align-items: center; justify-content: center; cursor: pointer; border: none; flex-shrink: 0; }
.cal-nav__arrow svg { width: 14px; height: 14px; stroke: #333; }
.cal-nav__month { font-size: 15px; font-weight: 700; color: #1a1a1a; flex: 1; text-align: center; }
.cal-nav__toggle { font-size: 12px; color: #36cfc9; cursor: pointer; font-weight: 600; padding: 4px 10px; border-radius: 12px; background: #e8f8f7; flex-shrink: 0; white-space: nowrap; }
/* ===== 周日历(默认视图) ===== */
.week-cal { background: #fff; padding: 0 10px 10px; margin: 0 12px; border-radius: 0 0 16px 16px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
.week-cal__row { display: flex; gap: 2px; }
.week-cal__cell { flex: 1; text-align: center; padding: 8px 0 6px; border-radius: 10px; position: relative; cursor: default; min-width: 0; }
.week-cal__cell.today { background: #e8f8f7; }
.week-cal__cell.selected { background: #e6f7ff; box-shadow: inset 0 0 0 2px #36cfc9; }
.week-cal__wd { font-size: 10px; color: #999; margin-bottom: 4px; }
.week-cal__date-wrap { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; margin: 0 auto 4px; }
.week-cal__date { font-size: 14px; font-weight: 700; color: #333; position: relative; z-index: 2; }
.week-cal__cell.today .week-cal__date { color: #36cfc9; }
/* 记录圆圈 */
.week-cal__ring { position: absolute; inset: -2px; border-radius: 50%; border: 2.5px solid transparent; z-index: 1; }
.week-cal__ring--scale { border-color: #5470c6; } /* 身高秤 蓝色 */
.week-cal__ring--bt { border-color: #8b5cf6; } /* 蓝牙秤 紫色 */
.week-cal__ring--self { border-color: #c4b5fd; } /* 自记 浅紫色 */
.week-cal__ring--fat { border-color: #1e3a5f; } /* 体脂仪 深蓝色 */
/* 记录数据 */
.week-cal__data { font-size: 10px; color: #666; line-height: 1.4; }
.week-cal__data .w { font-weight: 700; color: #333; }
.week-cal__data .bf { color: #999; display: block; }
/* ===== 月日历(展开视图) ===== */
.month-cal { background: #fff; padding: 0 10px 10px; margin: 0 12px; border-radius: 0 0 16px 16px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
.month-cal__weekday { display: grid; grid-template-columns: repeat(7, 1fr); margin-bottom: 2px; }
.month-cal__weekday span { font-size: 10px; color: #999; text-align: center; padding: 4px 0; }
.month-cal__row { display: grid; grid-template-columns: repeat(7, 1fr); }
.month-cal__cell { text-align: center; padding: 2px 1px 4px; min-height: 48px; position: relative; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; border-radius: 8px; cursor: default; }
.month-cal__cell.today { background: #e8f8f7; }
.month-cal__cell.selected { background: #e6f7ff; box-shadow: inset 0 0 0 2px #36cfc9; }
.month-cal__cell.other-month .month-cal__date { color: #ddd; }
.month-cal__date-wrap { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; }
.month-cal__date { font-size: 13px; font-weight: 600; color: #333; position: relative; z-index: 2; }
.month-cal__cell.today .month-cal__date { color: #36cfc9; font-weight: 800; }
.month-cal__ring { position: absolute; inset: -2px; border-radius: 50%; border: 2px solid transparent; z-index: 1; }
.month-cal__ring--scale { border-color: #5470c6; }
.month-cal__ring--bt { border-color: #8b5cf6; }
.month-cal__ring--self { border-color: #c4b5fd; }
.month-cal__ring--fat { border-color: #1e3a5f; }
/* 月历记录数据 */
.month-cal__data { font-size: 9px; color: #666; line-height: 1.3; margin-top: 1px; }
.month-cal__data .mw { font-weight: 700; color: #333; }
.month-cal__data .mbf { color: #999; display: block; }
.month-cal__dot { width: 5px; height: 5px; border-radius: 50%; margin-top: 1px; flex-shrink: 0; }
.month-cal__dot--scale { background: #5470c6; }
.month-cal__dot--bt { background: #8b5cf6; }
.month-cal__dot--self { background: #c4b5fd; }
.month-cal__dot--fat { background: #1e3a5f; }
/* ===== 图例 ===== */
.legend { display: flex; justify-content: center; gap: 14px; padding: 8px 16px; flex-wrap: wrap; background: #fff; margin: 8px 12px 0; border-radius: 12px; }
.legend__item { display: flex; align-items: center; gap: 4px; font-size: 11px; color: #666; }
.legend__dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.legend__dot--scale { background: #5470c6; }
.legend__dot--bt { background: #8b5cf6; }
.legend__dot--self { background: #c4b5fd; }
.legend__dot--fat { background: #1e3a5f; }
/* ===== Tab 栏 ===== */
.record-tabs { display: flex; background: #fff; margin: 8px 12px 0; border-radius: 12px; overflow: hidden; }
.record-tab { flex: 1; text-align: center; padding: 10px 0; font-size: 13px; font-weight: 600; color: #999; cursor: pointer; position: relative; }
.record-tab.active { color: #36cfc9; }
.record-tab.active::after { content: ''; position: absolute; bottom: 4px; left: 50%; transform: translateX(-50%); width: 20px; height: 3px; background: #36cfc9; border-radius: 2px; }
/* ===== 列表区域 ===== */
.record-list { padding: 8px 12px 16px; display: flex; flex-direction: column; gap: 8px; }
.record-item { background: #fff; border-radius: 14px; padding: 14px; box-shadow: 0 2px 8px rgba(0,0,0,0.03); }
.record-item__header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.record-item__title { font-size: 14px; font-weight: 700; color: #1a1a1a; }
.record-item__time { font-size: 11px; color: #bbb; }
.record-item__body { display: flex; align-items: center; gap: 16px; }
.record-item__metric { text-align: center; min-width: 50px; }
.record-item__metric-label { font-size: 10px; color: #999; margin-bottom: 2px; }
.record-item__metric-val { font-size: 16px; font-weight: 700; color: #1a1a1a; }
.record-item__metric-unit { font-size: 10px; color: #999; font-weight: 400; margin-left: 1px; }
.record-item__source { margin-left: auto; }
.source-badge { display: inline-block; padding: 4px 10px; border-radius: 12px; font-size: 11px; font-weight: 600; }
.source-badge--scale { background: #e8effa; color: #5470c6; }
.source-badge--bt { background: #f3efff; color: #8b5cf6; }
.source-badge--self { background: #f5f0ff; color: #a78bfa; }
.source-badge--fat { background: #e6edf5; color: #1e3a5f; }
.record-empty { text-align: center; padding: 40px 20px; color: #ccc; font-size: 14px; }
.bottom-safe { height: 20px; flex-shrink: 0; }
</style>
</head>
<body>
<div class="phone-shell">
<div class="status-bar">
<span class="time">09:40</span>
<div 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>
</div>
</div>
<div class="nav-bar">
<div class="nav-back" onclick="location.href='weight-main.html'">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
</div>
<div class="nav-title">体重记录</div>
<div class="nav-placeholder"></div>
</div>
<div class="scroll-content">
<!-- 日历月导航 -->
<div class="cal-nav">
<div class="cal-nav__arrow" onclick="prevMonth()">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
</div>
<div class="cal-nav__month" id="calMonthLabel">2026年06月</div>
<div class="cal-nav__arrow" onclick="nextMonth()">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg>
</div>
<div class="cal-nav__toggle" id="calToggle" onclick="toggleCalView()">展开月历</div>
</div>
<!-- 周日历(默认) -->
<div class="week-cal" id="weekCal"></div>
<!-- 月日历(展开后显示) -->
<div class="month-cal" id="monthCal" style="display:none;"></div>
<!-- 图例 -->
<div class="legend">
<div class="legend__item"><span class="legend__dot legend__dot--scale"></span>身高秤</div>
<div class="legend__item"><span class="legend__dot legend__dot--bt"></span>蓝牙秤</div>
<div class="legend__item"><span class="legend__dot legend__dot--self"></span>自记</div>
<div class="legend__item"><span class="legend__dot legend__dot--fat"></span>体脂仪</div>
</div>
<!-- Tab 栏 -->
<div class="record-tabs" id="recordTabs">
<div class="record-tab active" data-range="week" onclick="switchTab('week')"></div>
<div class="record-tab" data-range="month" onclick="switchTab('month')"></div>
<div class="record-tab" data-range="quarter" onclick="switchTab('quarter')"></div>
<div class="record-tab" data-range="activity" onclick="switchTab('activity')">活动期间</div>
<div class="record-tab" data-range="all" onclick="switchTab('all')">全部</div>
</div>
<!-- 记录列表 -->
<div class="record-list" id="recordList"></div>
<div class="bottom-safe"></div>
</div>
</div>
<script>
/* ===== 数据 ===== */
// 来源类型及其颜色映射
var SOURCE_TYPES = {
'scale': { label:'身高秤', css:'scale', ring:'week-cal__ring--scale', mring:'month-cal__ring--scale', dot:'month-cal__dot--scale', badge:'source-badge--scale' },
'bt': { label:'蓝牙秤', css:'bt', ring:'week-cal__ring--bt', mring:'month-cal__ring--bt', dot:'month-cal__dot--bt', badge:'source-badge--bt' },
'self': { label:'自记', css:'self', ring:'week-cal__ring--self', mring:'month-cal__ring--self', dot:'month-cal__dot--self', badge:'source-badge--self' },
'fat': { label:'体脂仪', css:'fat', ring:'week-cal__ring--fat', mring:'month-cal__ring--fat', dot:'month-cal__dot--fat', badge:'source-badge--fat' }
};
// 模拟体重记录数据
var RECORDS = [
{ date:'2026-06-13', title:'晨起空腹测量', weight:66.3, bodyFat:23.3, waist:81.5, time:'07:30', source:'bt' },
{ date:'2026-06-12', title:'晨起空腹测量', weight:66.5, bodyFat:23.5, waist:81.5, time:'06:45', source:'scale' },
{ date:'2026-06-10', title:'运动后测量', weight:66.8, bodyFat:23.7, waist:null, time:'19:20', source:'bt' },
{ date:'2026-06-08', title:'晨起空腹测量', weight:67.0, bodyFat:23.9, waist:null, time:'07:15', source:'scale' },
{ date:'2026-06-07', title:'健身房测量', weight:67.2, bodyFat:24.1, waist:82.0, time:'18:00', source:'fat' },
{ date:'2026-06-05', title:'手动录入', weight:67.5, bodyFat:null, waist:null, time:'08:30', source:'self' },
{ date:'2026-06-03', title:'晨起空腹测量', weight:67.8, bodyFat:24.5, waist:null, time:'07:00', source:'bt' },
{ date:'2026-06-01', title:'晨起空腹测量', weight:68.2, bodyFat:24.8, waist:82.5, time:'07:20', source:'scale' },
{ date:'2026-05-28', title:'晨起空腹测量', weight:68.5, bodyFat:25.0, waist:83.0, time:'07:10', source:'scale' },
{ date:'2026-05-25', title:'午间测量', weight:68.9, bodyFat:25.2, waist:null, time:'12:30', source:'bt' },
{ date:'2026-05-20', title:'晨起空腹测量', weight:69.5, bodyFat:25.5, waist:83.5, time:'06:50', source:'fat' },
{ date:'2026-05-15', title:'手动录入', weight:70.0, bodyFat:null, waist:null, time:'09:00', source:'self' },
{ date:'2026-05-10', title:'晨起空腹测量', weight:70.5, bodyFat:26.0, waist:84.0, time:'07:05', source:'scale' },
{ date:'2026-05-05', title:'晨起空腹测量', weight:71.2, bodyFat:26.5, waist:84.5, time:'07:30', source:'bt' },
{ date:'2026-05-01', title:'晨起空腹测量', weight:71.8, bodyFat:27.0, waist:85.0, time:'08:00', source:'scale' },
{ date:'2026-04-25', title:'晨起空腹测量', weight:72.5, bodyFat:27.5, waist:85.5, time:'07:00', source:'fat' },
{ date:'2026-04-20', title:'晨起空腹测量', weight:73.0, bodyFat:28.0, waist:86.0, time:'07:15', source:'scale' },
{ date:'2026-04-10', title:'晨起空腹测量', weight:73.3, bodyFat:28.3, waist:86.5, time:'07:20', source:'bt' },
];
// 活动期间范围
var ACTIVITY_START = new Date(2026, 4, 1); // 2026-05-01
var ACTIVITY_END = new Date(2026, 7, 1); // 2026-08-01
/* ===== 状态 ===== */
var calYear = 2026;
var calMonth = 6; // 0-based
var calExpanded = false; // 月历是否展开
var activeTab = 'week';
var selectedDate = null; // 当前选中的日期('YYYY-MM-DD'),null 时按tab范围过滤
// 今天
var TODAY = new Date(2026, 5, 12); // 2026-06-12
/* ===== 工具函数 ===== */
function fmt(n) { return n < 10 ? '0' + n : '' + n; }
function dateStr(y, m, d) { return y + '-' + fmt(m+1) + '-' + fmt(d); }
function parseDate(s) { var p = s.split('-'); return new Date(+p[0], +p[1]-1, +p[2]); }
function sameDay(a, b) { return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate(); }
// 获取某天的记录
function getRecord(y, m, d) {
var s = dateStr(y, m, d);
for (var i = 0; i < RECORDS.length; i++) {
if (RECORDS[i].date === s) return RECORDS[i];
}
return null;
}
/* ===== 渲染周日历 ===== */
var WEEKDAY_LABELS = ['一','二','三','四','五','六','日'];
function getWeekStart() {
// 返回当前显示月份中第一个周一(可能在上一月)
var first = new Date(calYear, calMonth, 1);
var day = first.getDay(); // 0=周日
var monday = new Date(first);
monday.setDate(1 - (day === 0 ? 6 : day - 1));
return monday;
}
function renderWeekCal() {
var container = document.getElementById('weekCal');
// 找到当月包含本周的周一。简单起见:如果当前日期的月份与显示月份相同,从当前周一开始;否则从该月第一天所在周一开始
var now = new Date(2026, 5, 12); // 固定"今天" = 2026-06-12
var start;
if (calYear === now.getFullYear() && calMonth === now.getMonth()) {
// 当前月:从今天所在的周一开始
var dow = now.getDay() || 7;
start = new Date(now);
start.setDate(now.getDate() - dow + 1);
} else {
start = getWeekStart();
}
var html = '<div class="week-cal__row">';
for (var i = 0; i < 7; i++) {
var d = new Date(start);
d.setDate(start.getDate() + i);
var rec = getRecord(d.getFullYear(), d.getMonth(), d.getDate());
var isToday = sameDay(d, TODAY);
var isoOtherMonth = d.getMonth() !== calMonth;
var dateKey = dateStr(d.getFullYear(), d.getMonth(), d.getDate());
var isSel = dateKey === selectedDate;
html += '<div class="week-cal__cell' + (isToday ? ' today' : '') + (isSel ? ' selected' : '') + '"'
+ ' onclick="onDayClick(\'' + dateStr(d.getFullYear(), d.getMonth(), d.getDate()) + '\')" style="cursor:' + (rec ? 'pointer' : 'default') + '">';
html += '<div class="week-cal__wd">' + WEEKDAY_LABELS[i] + '</div>';
html += '<div class="week-cal__date-wrap">';
if (rec) {
html += '<div class="week-cal__ring ' + SOURCE_TYPES[rec.source].ring + '"></div>';
}
html += '<span class="week-cal__date" style="' + (isoOtherMonth ? 'color:#ddd' : '') + '">' + (isToday ? '今' : d.getDate()) + '</span>';
html += '</div>';
html += '<div class="week-cal__data">';
if (rec) {
html += '<span class="w">' + rec.weight.toFixed(1) + 'kg</span>';
if (rec.bodyFat !== null) {
html += '<span class="bf">' + rec.bodyFat.toFixed(1) + '%</span>';
}
}
html += '</div>';
html += '</div>';
}
html += '</div>';
container.innerHTML = html;
}
/* ===== 渲染月日历 ===== */
function renderMonthCal() {
var container = document.getElementById('monthCal');
// 周日历抬头
var html = '<div class="month-cal__weekday">';
for (var w = 0; w < 7; w++) { html += '<span>' + WEEKDAY_LABELS[w] + '</span>'; }
html += '</div>';
var first = new Date(calYear, calMonth, 1);
var startDow = first.getDay() || 7; // 1=周一 … 7=周日
var cursor = new Date(first);
cursor.setDate(1 - (startDow - 1)); // 回退到该行周一
var done = false;
for (var row = 0; row < 6 && !done; row++) {
html += '<div class="month-cal__row">';
for (var col = 0; col < 7; col++) {
var isOther = cursor.getMonth() !== calMonth;
var isToday = sameDay(cursor, TODAY);
var dateKey = dateStr(cursor.getFullYear(), cursor.getMonth(), cursor.getDate());
var isSel = dateKey === selectedDate;
var rec = getRecord(cursor.getFullYear(), cursor.getMonth(), cursor.getDate());
html += '<div class="month-cal__cell' + (isToday ? ' today' : '') + (isOther ? ' other-month' : '') + (isSel ? ' selected' : '') + '"'
+ ' onclick="onDayClick(\'' + dateStr(cursor.getFullYear(), cursor.getMonth(), cursor.getDate()) + '\')" style="cursor:' + (rec ? 'pointer' : 'default') + '">';
html += '<div class="month-cal__date-wrap">';
if (rec) {
html += '<div class="month-cal__ring ' + SOURCE_TYPES[rec.source].mring + '"></div>';
}
html += '<span class="month-cal__date">' + (isToday ? '今' : cursor.getDate()) + '</span>';
html += '</div>';
html += '<div class="month-cal__data">';
if (rec) {
html += '<span class="mw">' + rec.weight.toFixed(1) + 'kg</span>';
if (rec.bodyFat !== null) {
html += '<span class="mbf">' + rec.bodyFat.toFixed(1) + '%</span>';
}
}
html += '</div>';
html += '</div>';
cursor.setDate(cursor.getDate() + 1);
if (col === 6 && cursor.getDate() > 7 && cursor.getMonth() !== calMonth) { done = true; }
}
html += '</div>';
}
container.innerHTML = html;
}
/* ===== 日历展开/收起 ===== */
function toggleCalView() {
calExpanded = !calExpanded;
document.getElementById('weekCal').style.display = calExpanded ? 'none' : '';
document.getElementById('monthCal').style.display = calExpanded ? '' : 'none';
document.getElementById('calToggle').textContent = calExpanded ? '收起月历' : '展开月历';
if (calExpanded) renderMonthCal();
}
/* ===== 月份切换 ===== */
function prevMonth() {
if (calExpanded) {
// 月视图:按整月切换
calMonth--;
if (calMonth < 0) { calMonth = 11; calYear--; }
} else {
// 周视图:按周切换(切换到上一周,可能跨月)
var now = new Date(2026, 5, 12);
var dow = now.getDay() || 7;
var curWeekStart;
if (calYear === now.getFullYear() && calMonth === now.getMonth()) {
curWeekStart = new Date(now);
curWeekStart.setDate(now.getDate() - dow + 1);
} else {
curWeekStart = getWeekStart();
}
// 上一周
curWeekStart.setDate(curWeekStart.getDate() - 7);
calYear = curWeekStart.getFullYear();
calMonth = curWeekStart.getMonth();
}
updateCal();
}
function nextMonth() {
if (calExpanded) {
calMonth++;
if (calMonth > 11) { calMonth = 0; calYear++; }
} else {
var now = new Date(2026, 5, 12);
var dow = now.getDay() || 7;
var curWeekStart;
if (calYear === now.getFullYear() && calMonth === now.getMonth()) {
curWeekStart = new Date(now);
curWeekStart.setDate(now.getDate() - dow + 1);
} else {
curWeekStart = getWeekStart();
}
curWeekStart.setDate(curWeekStart.getDate() + 7);
calYear = curWeekStart.getFullYear();
calMonth = curWeekStart.getMonth();
}
updateCal();
}
function updateCal() {
document.getElementById('calMonthLabel').textContent = calYear + '年' + fmt(calMonth + 1) + '月';
renderWeekCal();
if (calExpanded) renderMonthCal();
}
/* ===== Tab 切换 ===== */
function switchTab(range) {
activeTab = range;
selectedDate = null; // 清除日期选中
document.querySelectorAll('.record-tab').forEach(function(t) {
t.classList.toggle('active', t.dataset.range === range);
});
updateCal(); // 刷新日历高亮
renderRecordList();
}
/* ===== 日期范围计算 ===== */
function getTabDateRange() {
// 以"今天" 2026-06-12 为基准
var now = new Date(2026, 5, 12);
var start, end;
switch (activeTab) {
case 'week':
// 本周:周一到周日
var dow = now.getDay() || 7;
start = new Date(now); start.setDate(now.getDate() - dow + 1);
end = new Date(start); end.setDate(start.getDate() + 6);
break;
case 'month':
start = new Date(now.getFullYear(), now.getMonth(), 1);
end = new Date(now.getFullYear(), now.getMonth() + 1, 0);
break;
case 'quarter':
var q = Math.floor(now.getMonth() / 3);
start = new Date(now.getFullYear(), q * 3, 1);
end = new Date(now.getFullYear(), (q + 1) * 3, 0);
break;
case 'activity':
start = ACTIVITY_START;
end = ACTIVITY_END;
break;
case 'all':
start = new Date(2000, 0, 1);
end = new Date(2099, 11, 31);
break;
}
return { start: start, end: end };
}
/* ===== 渲染记录列表 ===== */
function renderRecordList() {
var filtered;
if (selectedDate) {
// 按选中日期过滤
filtered = RECORDS.filter(function(r) { return r.date === selectedDate; });
} else {
var range = getTabDateRange();
filtered = RECORDS.filter(function(r) {
var d = parseDate(r.date);
return d >= range.start && d <= range.end;
});
}
var container = document.getElementById('recordList');
if (filtered.length === 0) {
container.innerHTML = '<div class="record-empty">该时间段暂无记录</div>';
return;
}
var html = '';
for (var i = 0; i < filtered.length; i++) {
var r = filtered[i];
var src = SOURCE_TYPES[r.source];
html += '<div class="record-item">';
html += '<div class="record-item__header">';
html += '<span class="record-item__title">体重记录</span>';
html += '<span class="record-item__time">' + r.date + ' ' + r.time + '</span>';
html += '</div>';
html += '<div class="record-item__body">';
html += '<div class="record-item__metric"><div class="record-item__metric-label">体重</div><div class="record-item__metric-val">' + r.weight.toFixed(1) + '<span class="record-item__metric-unit">kg</span></div></div>';
if (r.bodyFat !== null) {
html += '<div class="record-item__metric"><div class="record-item__metric-label">体脂率</div><div class="record-item__metric-val">' + r.bodyFat.toFixed(1) + '<span class="record-item__metric-unit">%</span></div></div>';
}
if (r.waist !== null) {
html += '<div class="record-item__metric"><div class="record-item__metric-label">腰围</div><div class="record-item__metric-val">' + r.waist.toFixed(1) + '<span class="record-item__metric-unit">cm</span></div></div>';
}
html += '<div class="record-item__source"><span class="source-badge ' + src.badge + '">' + src.label + '</span></div>';
html += '</div>';
html += '</div>';
}
container.innerHTML = html;
}
/* ===== 点击日期 ===== */
function onDayClick(dateStr) {
// 再次点击已选中的日期 → 取消选中,回到周tab
if (selectedDate === dateStr) {
switchTab('week');
return;
}
// 选中日期,取消所有tab高亮
selectedDate = dateStr;
activeTab = '';
document.querySelectorAll('.record-tab').forEach(function(t) { t.classList.remove('active'); });
updateCal();
renderRecordList();
document.querySelector('.scroll-content').scrollTop = document.getElementById('recordTabs').offsetTop - 100;
}
/* ===== 初始化 ===== */
function init() {
calYear = TODAY.getFullYear();
calMonth = TODAY.getMonth();
document.getElementById('calMonthLabel').textContent = calYear + '年' + fmt(calMonth + 1) + '月';
renderWeekCal();
renderRecordList();
}
init();
</script>
</body>
</html>
+122 -12
View File
@@ -13,7 +13,26 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
.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; color: #1a1a1a; }
.nav-title { flex: 1; text-align: center; font-size: 17px; font-weight: 600; color: #1a1a1a; margin-right: 28px; }
.nav-title { flex: 1; text-align: center; font-size: 17px; font-weight: 600; color: #1a1a1a; }
.nav-more { width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: #1a1a1a; position: relative; flex-shrink: 0; }
.nav-more__dots { display: flex; flex-direction: column; gap: 3px; align-items: center; }
.nav-more__dots span { display: block; width: 4px; height: 4px; border-radius: 50%; background: #333; }
/* 类型切换下拉菜单 */
.type-menu { display: none; position: absolute; top: 34px; right: 8px; background: #fff; border-radius: 12px; box-shadow: 0 6px 24px rgba(0,0,0,0.12); z-index: 100; min-width: 170px; overflow: hidden; }
.type-menu.show { display: block; }
.type-menu__item { padding: 13px 16px; font-size: 14px; color: #333; cursor: pointer; display: flex; align-items: center; justify-content: space-between; white-space: nowrap; border-bottom: 1px solid #f5f5f5; }
.type-menu__item:last-child { border-bottom: none; }
.type-menu__item:hover { background: #f7f8fa; }
.type-menu__item.active { color: #36cfc9; font-weight: 700; }
.type-menu__item.active::after { content: '✓'; font-size: 12px; color: #36cfc9; }
/* 排行榜缺省占位 */
.rank-card--empty { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 28px 16px; text-align: center; min-height: 180px; }
.rank-card--empty__icon { width: 56px; height: 56px; border-radius: 50%; background: #f0f2f5; display: flex; align-items: center; justify-content: center; margin-bottom: 12px; }
.rank-card--empty__icon svg { width: 28px; height: 28px; color: #ccc; }
.rank-card--empty__text { font-size: 13px; color: #bbb; line-height: 1.6; }
/* 遮罩层 */
.type-mask { display: none; position: fixed; inset: 0; z-index: 50; }
.type-mask.show { display: block; }
/* 排名副标题栏 */
.rank-sub-bar { background: #fff; padding: 8px 16px 10px; border-bottom: 1px solid #f0f0f0; }
.rank-sub-bar__text { font-size: 13px; color: #666; text-align: center; line-height: 1.5; }
@@ -82,7 +101,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
.daily-date { font-size: 14px; color: #1f1f1f; text-align: center; margin-bottom: 14px; font-weight: 700; display: flex; align-items: center; justify-content: center; gap: 12px; }
.daily-date::before, .daily-date::after { content: ''; flex: 1; height: 1px; background: linear-gradient(90deg, transparent, #ff7a6b, transparent); max-width: 90px; }
.daily-checkin { display: flex; gap: 10px; }
.checkin-card { flex: 1; border-radius: 14px; padding: 14px 8px 12px; text-align: center; color: #fff; position: relative; }
.checkin-card { flex: 1; border-radius: 14px; padding: 14px 8px 12px; text-align: center; color: #fff; position: relative; cursor: pointer; }
.checkin-card--eat { background: linear-gradient(160deg, #6ee16e 0%, #3ec46a 100%); }
.checkin-card--move { background: linear-gradient(160deg, #ffb066 0%, #ff8a3d 100%); }
.checkin-card--weight { background: linear-gradient(160deg, #b08cff 0%, #8b6cff 100%); }
@@ -251,7 +270,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
.dash-grid__left { flex: 1.5; }
.dash-grid__right { flex: 1; display: flex; flex-direction: column; gap: 8px; }
.rank-card { background: #fff; border-radius: 16px; padding: 14px 12px 10px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
.rank-card { background: #fff; border-radius: 16px; padding: 14px 12px 10px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); cursor: pointer; }
.rank-card__title { font-size: 11px; font-weight: 700; color: #36cfc9; margin-bottom: 10px; text-align: center; white-space: nowrap; }
.rank-card__my { display: flex; align-items: center; justify-content: center; gap: 12px; margin-bottom: 10px; padding-bottom: 10px; border-bottom: 1px solid #f0f0f0; }
.rank-card__my-label { font-size: 12px; color: #666; white-space: nowrap; }
@@ -322,7 +341,20 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
</div>
<div class="nav-title">体重管理</div>
<div class="nav-more" id="navMore" onclick="toggleTypeMenu(event)">
<div class="nav-more__dots">
<span></span><span></span><span></span>
</div>
<!-- 类型切换下拉菜单 -->
<div class="type-menu" id="typeMenu">
<div class="type-menu__item active" data-type="hasact" onclick="setPageType('hasact')">已参加活动</div>
<div class="type-menu__item" data-type="personal" onclick="setPageType('personal')">已设置个人目标</div>
<div class="type-menu__item" data-type="none" onclick="setPageType('none')">未参加未设置</div>
</div>
</div>
</div>
<!-- 点击空白区域关闭菜单的遮罩 -->
<div class="type-mask" id="typeMask" onclick="closeTypeMenu()"></div>
<!-- 排名副标题 -->
<div class="rank-sub-bar">
<div class="rank-sub-bar__text">公司机关020411体重管理计划 第<span class="rank-sub-bar__num">8</span>名(共8626人)</div>
@@ -406,19 +438,22 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<div class="daily-card">
<div class="daily-date">2026年08月12日</div>
<div class="daily-checkin">
<div class="checkin-card checkin-card--eat">
<!-- [交互] 点击跳转至: eat-checkin.html -->
<div class="checkin-card checkin-card--eat" onclick="location.href='eat-checkin.html'">
<div class="checkin-card__label"></div>
<div class="checkin-card__val">1086<span class="checkin-card__unit">kcal</span></div>
<div class="checkin-card__recommend">推荐 1950千卡</div>
<div class="checkin-card__days">累计行动52天</div>
</div>
<div class="checkin-card checkin-card--move">
<!-- [交互] 点击跳转至: exercise-checkin.html -->
<div class="checkin-card checkin-card--move" onclick="location.href='exercise-checkin.html'">
<div class="checkin-card__label"></div>
<div class="checkin-card__val">12586<span class="checkin-card__unit"></span></div>
<div class="checkin-card__recommend">推荐 12000步</div>
<div class="checkin-card__days">累计行动362天</div>
</div>
<div class="checkin-card checkin-card--weight">
<!-- [交互] 点击跳转至: weight-checkin.html -->
<div class="checkin-card checkin-card--weight" onclick="location.href='weight-checkin.html'">
<div class="checkin-card__label">体重</div>
<div class="checkin-card__val">62.60<span class="checkin-card__unit">kg</span></div>
<div class="checkin-card__recommend">推荐 75-80公斤</div>
@@ -658,7 +693,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<div class="record-card">
<div class="record-card__header">
<div class="record-card__title">体重记录</div>
<div class="record-card__history">
<div class="record-card__history" onclick="location.href='weight-history.html'" style="cursor:pointer;">
查看历史
<svg viewBox="0 0 24 24" fill="none" stroke="#36cfc9" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
<polyline points="9 18 15 12 9 6"/>
@@ -1028,10 +1063,12 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
</div>
<!-- 排行榜 & 建议入口 -->
<div class="dash-grid">
<div class="dash-grid" id="dashGrid">
<!-- 左侧:排行榜 -->
<div class="dash-grid__left">
<div class="rank-card">
<!-- 正常排行榜(已参加活动) -->
<!-- [交互] 点击跳转至: weight-ranking.html -->
<div class="rank-card" id="rankCardNormal" onclick="location.href='weight-ranking.html'">
<div class="rank-card__title">2026年二季度体重管理活动</div>
<div class="rank-card__my">
<span class="rank-card__my-label">减重排名</span>
@@ -1086,21 +1123,28 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
</div>
</div>
</div>
<!-- 排行榜缺省占位(已设置个人目标 / 未参加未设置) -->
<div class="rank-card rank-card--empty" id="rankCardEmpty" style="display:none;">
<div class="rank-card--empty__icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20V10"/><path d="M18 20V4"/><path d="M6 20v-4"/></svg>
</div>
<div class="rank-card--empty__text">暂未参加活动<br>暂无排行榜数据</div>
</div>
</div>
<!-- 右侧:建议 & 报告入口 -->
<div class="dash-grid__right">
<div class="sug-card sug-card--diet">
<div class="sug-card sug-card--diet" onclick="location.href='diet-advice.html'" style="cursor:pointer;">
<div class="sug-card__label">膳食建议</div>
<div class="sug-card__val">1950<span class="sug-card__unit">千卡</span></div>
<div class="sug-card__sub">今日推荐摄入</div>
</div>
<div class="sug-card sug-card--move">
<div class="sug-card sug-card--move" onclick="location.href='exercise-advice.html'" style="cursor:pointer;">
<div class="sug-card__label">运动建议</div>
<div class="sug-card__val">12000<span class="sug-card__unit"></span></div>
<div class="sug-card__sub">今日推荐运动量</div>
</div>
<div class="sug-card sug-card--report">
<div class="sug-card sug-card--report" onclick="location.href='weight-report.html?type=' + currentPageType" style="cursor:pointer;">
<div class="sug-card__label">体重报告</div>
<div class="sug-card__sub">健康,从今天开始</div>
</div>
@@ -1167,6 +1211,72 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
</div>
<script>
/* ===== 类型切换:右上角三点菜单 ===== */
function getQueryParam(key) {
var m = location.search.match(new RegExp('[?&]' + key + '=([^&]*)'));
return m ? decodeURIComponent(m[1]) : '';
}
var currentPageType = getQueryParam('type') || 'hasact';
/* 下拉菜单开关 */
function toggleTypeMenu(e) {
e.stopPropagation();
var menu = document.getElementById('typeMenu');
var mask = document.getElementById('typeMask');
var show = !menu.classList.contains('show');
menu.classList.toggle('show', show);
mask.classList.toggle('show', show);
}
/* 关闭下拉菜单 */
function closeTypeMenu() {
document.getElementById('typeMenu').classList.remove('show');
document.getElementById('typeMask').classList.remove('show');
}
document.addEventListener('click', function(e) {
if (!e.target.closest('.nav-more')) closeTypeMenu();
});
/* 切换页面类型 */
function setPageType(type) {
if (type === currentPageType) { closeTypeMenu(); return; }
location.href = 'weight-main.html?type=' + type;
}
/* 根据类型初始化页面显隐 */
function applyPageType(type) {
var rankSubBar = document.querySelector('.rank-sub-bar');
var progressCard = document.querySelector('.progress-card');
var rankCardNormal = document.getElementById('rankCardNormal');
var rankCardEmpty = document.getElementById('rankCardEmpty');
// 菜单项高亮
document.querySelectorAll('.type-menu__item').forEach(function(item) {
item.classList.toggle('active', item.dataset.type === type);
});
if (type === 'hasact') {
// 已参加活动:全部显示
if (rankSubBar) rankSubBar.style.display = '';
if (progressCard) progressCard.style.display = '';
if (rankCardNormal) rankCardNormal.style.display = '';
if (rankCardEmpty) rankCardEmpty.style.display = 'none';
} else if (type === 'personal') {
// 已设置个人目标:隐藏排名副标题,排行榜改为缺省样式
if (rankSubBar) rankSubBar.style.display = 'none';
if (progressCard) progressCard.style.display = '';
if (rankCardNormal) rankCardNormal.style.display = 'none';
if (rankCardEmpty) rankCardEmpty.style.display = '';
} else if (type === 'none') {
// 未参加未设置:隐藏排名副标题,隐藏减重进度卡片,排行榜改为缺省样式
if (rankSubBar) rankSubBar.style.display = 'none';
if (progressCard) progressCard.style.display = 'none';
if (rankCardNormal) rankCardNormal.style.display = 'none';
if (rankCardEmpty) rankCardEmpty.style.display = '';
}
}
applyPageType(currentPageType);
function switchBalanceTab(el, tab) {
el.parentElement.querySelectorAll('.balance-tab').forEach(t => t.classList.remove('active'));
el.classList.add('active');
@@ -0,0 +1,322 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>排行榜 - 体重管理 | 健康CQ原型</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
.phone-shell { width: 390px; height: 844px; background: #f5f7fa; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; }
.status-bar { height: 44px; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; background: #fff; }
.status-bar .time { font-size: 15px; font-weight: 700; color: #333; }
.status-bar .icons { display: flex; gap: 6px; align-items: center; }
.nav-bar { height: 44px; background: #fff; display: flex; align-items: center; padding: 0 16px; flex-shrink: 0; border-bottom: 1px solid #f0f0f0; }
.nav-back { width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: #1a1a1a; }
.nav-title { flex: 1; text-align: center; font-size: 17px; font-weight: 600; color: #1a1a1a; }
.nav-placeholder { width: 28px; flex-shrink: 0; }
.scroll-content { flex: 1; overflow-y: auto; background: #f5f7fa; }
.scroll-content::-webkit-scrollbar { display: none; }
/* ===== 活动标题 ===== */
.activity-header { background: linear-gradient(135deg, #36cfc9, #2ec4b6); padding: 20px 16px 18px; text-align: center; color: #fff; }
.activity-header__title { font-size: 18px; font-weight: 800; margin-bottom: 6px; line-height: 1.3; }
.activity-header__sub { font-size: 12px; opacity: 0.85; }
/* ===== 排行榜容器 ===== */
.rank-container { margin: 0 12px 12px; background: #fff; border-radius: 16px; overflow: hidden; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
/* Tab 栏 */
.rank-tabs { display: flex; border-bottom: 1px solid #f0f0f0; }
.rank-tab { flex: 1; text-align: center; padding: 12px 0 10px; font-size: 13px; font-weight: 600; color: #bbb; cursor: pointer; position: relative; white-space: nowrap; }
.rank-tab.active { color: #36cfc9; }
.rank-tab.active::after { content: ''; position: absolute; bottom: -1px; left: 50%; transform: translateX(-50%); width: 36px; height: 3px; background: #36cfc9; border-radius: 2px; }
/* ===== 个人排名卡片 ===== */
.my-rank-card { margin: 12px; padding: 14px 16px; background: linear-gradient(135deg, #e8fbfa, #f0fffe); border-radius: 12px; border: 1.5px solid #b6f0eb; display: flex; align-items: center; gap: 14px; }
.my-rank-card__rank-wrap { width: 52px; height: 52px; border-radius: 50%; background: #fff; display: flex; flex-direction: column; align-items: center; justify-content: center; flex-shrink: 0; box-shadow: 0 2px 8px rgba(54,207,201,0.15); }
.my-rank-card__rank-num { font-size: 22px; font-weight: 800; color: #36cfc9; line-height: 1; }
.my-rank-card__rank-label { font-size: 9px; color: #999; margin-top: 1px; }
.my-rank-card__info { flex: 1; min-width: 0; }
.my-rank-card__name { font-size: 15px; font-weight: 700; color: #1a1a1a; margin-bottom: 2px; }
.my-rank-card__dept { font-size: 11px; color: #999; }
.my-rank-card__score { text-align: right; flex-shrink: 0; }
.my-rank-card__score-val { font-size: 22px; font-weight: 800; color: #1a1a1a; line-height: 1; }
.my-rank-card__score-unit { font-size: 11px; color: #999; margin-left: 1px; }
.my-rank-card__score-sub { font-size: 10px; color: #bbb; margin-top: 2px; }
/* ===== 排行榜列表头 ===== */
.rank-list-header { display: flex; align-items: center; padding: 8px 16px 8px; margin: 0 12px; border-bottom: 1px solid #f0f0f0; }
.rank-list-header span { font-size: 11px; color: #999; white-space: nowrap; }
.rank-list-header__rank { width: 36px; flex-shrink: 0; text-align: center; }
.rank-list-header__user { flex: 1; padding-left: 4px; }
.rank-list-header__score { width: 56px; text-align: right; flex-shrink: 0; }
/* ===== 排行榜列表 ===== */
.rank-list { padding: 4px 12px 12px; display: flex; flex-direction: column; }
.rank-item { display: flex; align-items: center; padding: 10px 4px; border-bottom: 1px solid #f8f8f8; gap: 4px; }
.rank-item:last-child { border-bottom: none; }
.rank-item--my { background: #f5fffe; border-radius: 10px; margin: 2px -4px; padding: 10px 8px; border-bottom: none; }
/* 排名数字/勋章 */
.rank-item__num { width: 36px; height: 30px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; }
.rank-item__num-text { font-size: 14px; font-weight: 700; color: #666; }
.rank-item__num--gold { width: 28px; height: 28px; border-radius: 50%; background: linear-gradient(135deg, #ffd700, #ffb300); display: flex; align-items: center; justify-content: center; margin: 0 auto; }
.rank-item__num--silver { width: 28px; height: 28px; border-radius: 50%; background: linear-gradient(135deg, #b0bec5, #90a4ae); display: flex; align-items: center; justify-content: center; margin: 0 auto; }
.rank-item__num--bronze { width: 28px; height: 28px; border-radius: 50%; background: linear-gradient(135deg, #cd7f32, #a0522d); display: flex; align-items: center; justify-content: center; margin: 0 auto; }
.rank-item__medal-icon { width: 16px; height: 16px; }
/* 用户信息 */
.rank-item__user { flex: 1; min-width: 0; padding-left: 2px; }
.rank-item__name { font-size: 14px; font-weight: 600; color: #1a1a1a; white-space: nowrap; }
.rank-item__name span { font-size: 11px; color: #bbb; margin: 0 2px; }
.rank-item__dept { font-size: 11px; color: #999; margin-top: 1px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* 分数 */
.rank-item__score { width: 56px; text-align: right; flex-shrink: 0; }
.rank-item__score-val { font-size: 14px; font-weight: 700; color: #1a1a1a; }
.rank-item__score-unit { font-size: 10px; color: #999; margin-left: 1px; }
.rank-item__score-sub { font-size: 10px; color: #bbb; }
/* 减重量 tab 的额外数据列 */
.rank-item__extra { width: 42px; text-align: right; flex-shrink: 0; font-size: 12px; color: #999; }
.bottom-safe { height: 20px; flex-shrink: 0; }
</style>
</head>
<body>
<div class="phone-shell">
<!-- 状态栏 -->
<div class="status-bar">
<span class="time">09:40</span>
<div 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>
</div>
</div>
<!-- 导航栏 -->
<div class="nav-bar">
<!-- [交互] 点击返回体重管理主页 -->
<div class="nav-back" onclick="location.href='weight-main.html'">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
</div>
<div class="nav-title">排行榜</div>
<div class="nav-placeholder"></div>
</div>
<div class="scroll-content">
<!-- 活动标题 -->
<div class="activity-header">
<div class="activity-header__title">2026年二季度体重管理活动</div>
<div class="activity-header__sub">排行榜(共8626人参加)</div>
</div>
<!-- 排行榜卡片 -->
<div class="rank-container">
<!-- Tab 栏 -->
<!-- [交互] 点击切换四个排行榜维度 -->
<div class="rank-tabs" id="rankTabs">
<div class="rank-tab active" data-tab="weight" onclick="switchRankTab('weight')">减重量</div>
<div class="rank-tab" data-tab="rate" onclick="switchRankTab('rate')">减重率</div>
<div class="rank-tab" data-tab="score" onclick="switchRankTab('score')">综合分</div>
<div class="rank-tab" data-tab="action" onclick="switchRankTab('action')">行动积分</div>
</div>
<!-- 个人排名卡片 -->
<div class="my-rank-card" id="myRankCard">
<div class="my-rank-card__rank-wrap">
<div class="my-rank-card__rank-label">我的排名</div>
<div class="my-rank-card__rank-num" id="myRankNum">8</div>
</div>
<div class="my-rank-card__info">
<div class="my-rank-card__name" id="myRankName">李**</div>
<div class="my-rank-card__dept" id="myRankDept">办公室</div>
</div>
<div class="my-rank-card__score">
<div class="my-rank-card__score-val" id="myRankVal">10.9<span class="my-rank-card__score-unit" id="myRankUnit">kg</span></div>
<div class="my-rank-card__score-sub" id="myRankSub">共减重</div>
</div>
</div>
<!-- 排行榜列表头 -->
<div class="rank-list-header">
<span class="rank-list-header__rank">排名</span>
<span class="rank-list-header__user">用户</span>
<span class="rank-list-header__score" id="rankListHeaderScore">减重量</span>
</div>
<!-- 排行榜列表 -->
<!-- [交互] 列表可滚动查看全部排名 -->
<div class="rank-list" id="rankList">
<!-- JS 动态渲染 -->
</div>
</div>
<div class="bottom-safe"></div>
</div>
</div>
<script>
/* ===== 排行榜数据 ===== */
var TOTAL_PARTICIPANTS = 8626;
/* 减重量排行数据 */
var weightRankData = [
{ rank:1, name:'张', org:'公司机关', dept:'办公室', val:'15.2', unit:'kg', sub:'共减重', trend:'up' },
{ rank:2, name:'刘', org:'信息技术中心', dept:'技术部', val:'14.8', unit:'kg', sub:'共减重', trend:'up' },
{ rank:3, name:'王', org:'公司机关', dept:'人力部', val:'13.5', unit:'kg', sub:'共减重', trend:'up' },
{ rank:4, name:'赵', org:'安全环保部', dept:'安环部', val:'12.9', unit:'kg', sub:'共减重', trend:'same' },
{ rank:5, name:'陈', org:'公司机关', dept:'财务部', val:'12.1', unit:'kg', sub:'共减重', trend:'up' },
{ rank:6, name:'孙', org:'信息技术中心', dept:'技术部', val:'11.6', unit:'kg', sub:'共减重', trend:'down' },
{ rank:7, name:'周', org:'公司机关', dept:'办公室', val:'11.2', unit:'kg', sub:'共减重', trend:'up' },
{ rank:8, name:'李', org:'公司机关', dept:'办公室', val:'10.9', unit:'kg', sub:'共减重', trend:'same', isMe:true },
{ rank:9, name:'吴', org:'信息技术中心', dept:'技术部', val:'10.3', unit:'kg', sub:'共减重', trend:'up' },
{ rank:10, name:'郑', org:'公司机关', dept:'人力部', val:'9.8', unit:'kg', sub:'共减重', trend:'down' },
{ rank:11, name:'黄', org:'安全环保部', dept:'安环部', val:'9.2', unit:'kg', sub:'共减重', trend:'up' },
{ rank:12, name:'杨', org:'公司机关', dept:'办公室', val:'8.7', unit:'kg', sub:'共减重', trend:'up' },
{ rank:13, name:'林', org:'公司机关', dept:'财务部', val:'8.1', unit:'kg', sub:'共减重', trend:'same' },
{ rank:14, name:'何', org:'信息技术中心', dept:'技术部', val:'7.5', unit:'kg', sub:'共减重', trend:'down' },
{ rank:15, name:'马', org:'公司机关', dept:'人力部', val:'7.0', unit:'kg', sub:'共减重', trend:'up' }
];
/* 减重率排行数据 */
var rateRankData = [
{ rank:1, name:'刘', org:'信息技术中心', dept:'技术部', val:'18.6', unit:'%', sub:'减重率', trend:'up' },
{ rank:2, name:'张', org:'公司机关', dept:'办公室', val:'17.9', unit:'%', sub:'减重率', trend:'up' },
{ rank:3, name:'赵', org:'安全环保部', dept:'安环部', val:'17.2', unit:'%', sub:'减重率', trend:'up' },
{ rank:4, name:'王', org:'公司机关', dept:'人力部', val:'16.5', unit:'%', sub:'减重率', trend:'same' },
{ rank:5, name:'陈', org:'公司机关', dept:'财务部', val:'16.0', unit:'%', sub:'减重率', trend:'up' },
{ rank:6, name:'孙', org:'信息技术中心', dept:'技术部', val:'15.3', unit:'%', sub:'减重率', trend:'down' },
{ rank:7, name:'周', org:'公司机关', dept:'办公室', val:'15.1', unit:'%', sub:'减重率', trend:'up' },
{ rank:8, name:'吴', org:'信息技术中心', dept:'技术部', val:'14.8', unit:'%', sub:'减重率', trend:'up' },
{ rank:9, name:'黄', org:'安全环保部', dept:'安环部', val:'14.2', unit:'%', sub:'减重率', trend:'up' },
{ rank:10, name:'郑', org:'公司机关', dept:'人力部', val:'13.6', unit:'%', sub:'减重率', trend:'down' },
{ rank:11, name:'杨', org:'公司机关', dept:'办公室', val:'13.0', unit:'%', sub:'减重率', trend:'up' },
{ rank:12, name:'李', org:'公司机关', dept:'办公室', val:'12.5', unit:'%', sub:'减重率', trend:'same', isMe:true },
{ rank:13, name:'林', org:'公司机关', dept:'财务部', val:'12.0', unit:'%', sub:'减重率', trend:'same' },
{ rank:14, name:'马', org:'公司机关', dept:'人力部', val:'11.3', unit:'%', sub:'减重率', trend:'up' },
{ rank:15, name:'何', org:'信息技术中心', dept:'技术部', val:'10.8', unit:'%', sub:'减重率', trend:'down' }
];
/* 综合分排行数据 */
var scoreRankData = [
{ rank:1, name:'张', org:'公司机关', dept:'办公室', val:'96.6', unit:'分', sub:'综合分', trend:'up' },
{ rank:2, name:'刘', org:'信息技术中心', dept:'技术部', val:'95.3', unit:'分', sub:'综合分', trend:'up' },
{ rank:3, name:'王', org:'公司机关', dept:'人力部', val:'92.9', unit:'分', sub:'综合分', trend:'same' },
{ rank:4, name:'赵', org:'安全环保部', dept:'安环部', val:'90.2', unit:'分', sub:'综合分', trend:'up' },
{ rank:5, name:'陈', org:'公司机关', dept:'财务部', val:'88.5', unit:'分', sub:'综合分', trend:'down' },
{ rank:6, name:'孙', org:'信息技术中心', dept:'技术部', val:'87.3', unit:'分', sub:'综合分', trend:'up' },
{ rank:7, name:'周', org:'公司机关', dept:'办公室', val:'87.0', unit:'分', sub:'综合分', trend:'up' },
{ rank:8, name:'李', org:'公司机关', dept:'办公室', val:'86.6', unit:'分', sub:'综合分', trend:'same', isMe:true },
{ rank:9, name:'吴', org:'信息技术中心', dept:'技术部', val:'84.1', unit:'分', sub:'综合分', trend:'up' },
{ rank:10, name:'郑', org:'公司机关', dept:'人力部', val:'82.8', unit:'分', sub:'综合分', trend:'down' },
{ rank:11, name:'黄', org:'安全环保部', dept:'安环部', val:'80.5', unit:'分', sub:'综合分', trend:'same' },
{ rank:12, name:'杨', org:'公司机关', dept:'办公室', val:'78.2', unit:'分', sub:'综合分', trend:'up' },
{ rank:13, name:'林', org:'公司机关', dept:'财务部', val:'76.0', unit:'分', sub:'综合分', trend:'down' },
{ rank:14, name:'何', org:'信息技术中心', dept:'技术部', val:'73.5', unit:'分', sub:'综合分', trend:'same' },
{ rank:15, name:'马', org:'公司机关', dept:'人力部', val:'70.8', unit:'分', sub:'综合分', trend:'up' }
];
/* 行动积分排行数据 */
var actionRankData = [
{ rank:1, name:'陈', org:'公司机关', dept:'财务部', val:'1580', unit:'分', sub:'行动积分', trend:'up' },
{ rank:2, name:'周', org:'公司机关', dept:'办公室', val:'1520', unit:'分', sub:'行动积分', trend:'up' },
{ rank:3, name:'吴', org:'信息技术中心', dept:'技术部', val:'1460', unit:'分', sub:'行动积分', trend:'same' },
{ rank:4, name:'孙', org:'信息技术中心', dept:'技术部', val:'1380', unit:'分', sub:'行动积分', trend:'up' },
{ rank:5, name:'李', org:'公司机关', dept:'办公室', val:'1250', unit:'分', sub:'行动积分', trend:'up', isMe:true },
{ rank:6, name:'张', org:'公司机关', dept:'办公室', val:'1180', unit:'分', sub:'行动积分', trend:'down' },
{ rank:7, name:'黄', org:'安全环保部', dept:'安环部', val:'1100', unit:'分', sub:'行动积分', trend:'up' },
{ rank:8, name:'刘', org:'信息技术中心', dept:'技术部', val:'1060', unit:'分', sub:'行动积分', trend:'same' },
{ rank:9, name:'杨', org:'公司机关', dept:'办公室', val:'1020', unit:'分', sub:'行动积分', trend:'down' },
{ rank:10, name:'王', org:'公司机关', dept:'人力部', val:'980', unit:'分', sub:'行动积分', trend:'up' },
{ rank:11, name:'林', org:'公司机关', dept:'财务部', val:'920', unit:'分', sub:'行动积分', trend:'up' },
{ rank:12, name:'赵', org:'安全环保部', dept:'安环部', val:'860', unit:'分', sub:'行动积分', trend:'down' },
{ rank:13, name:'郑', org:'公司机关', dept:'人力部', val:'800', unit:'分', sub:'行动积分', trend:'same' },
{ rank:14, name:'马', org:'公司机关', dept:'人力部', val:'750', unit:'分', sub:'行动积分', trend:'up' },
{ rank:15, name:'何', org:'信息技术中心', dept:'技术部', val:'680', unit:'分', sub:'行动积分', trend:'down' }
];
var rankDataMap = {
weight: weightRankData,
rate: rateRankData,
score: scoreRankData,
action: actionRankData
};
var rankHeaderLabels = {
weight: '减重量',
rate: '减重率',
score: '综合分',
action: '行动积分'
};
var myInfoMap = {
weight: { rank:8, name:'李**', org:'公司机关', dept:'办公室', val:'10.9', unit:'kg', sub:'共减重' },
rate: { rank:12, name:'李**', org:'公司机关', dept:'办公室', val:'12.5', unit:'%', sub:'减重率' },
score: { rank:8, name:'李**', org:'公司机关', dept:'办公室', val:'86.6', unit:'分', sub:'综合分' },
action: { rank:5, name:'李**', org:'公司机关', dept:'办公室', val:'1250', unit:'分', sub:'行动积分' }
};
/* ===== Tab 切换 ===== */
function switchRankTab(tab) {
// 更新 tab 高亮
document.querySelectorAll('#rankTabs .rank-tab').forEach(function(t) {
t.classList.toggle('active', t.dataset.tab === tab);
});
// 更新列表头
document.getElementById('rankListHeaderScore').textContent = rankHeaderLabels[tab];
// 更新个人排名卡片
var my = myInfoMap[tab];
document.getElementById('myRankNum').textContent = my.rank;
document.getElementById('myRankName').textContent = my.name;
document.getElementById('myRankDept').textContent = my.org + ' · ' + my.dept;
document.getElementById('myRankVal').innerHTML = my.val + '<span class="my-rank-card__score-unit">' + my.unit + '</span>';
document.getElementById('myRankSub').textContent = my.sub;
// 渲染列表
renderRankList(rankDataMap[tab]);
}
/* ===== 渲染排行榜列表 ===== */
function renderRankList(data) {
var html = '';
data.forEach(function(item, idx) {
var numHtml = '';
if (item.rank === 1) {
numHtml = '<div class="rank-item__num rank-item__num--gold"><svg class="rank-item__medal-icon" viewBox="0 0 16 16" fill="none"><polygon points="8,1 10.5,5.5 15.5,6 11.5,9.5 12.5,14 8,11.5 3.5,14 4.5,9.5 .5,6 5.5,5.5" fill="#fff" opacity="0.9"/></svg></div>';
} else if (item.rank === 2) {
numHtml = '<div class="rank-item__num rank-item__num--silver"><svg class="rank-item__medal-icon" viewBox="0 0 16 16" fill="none"><polygon points="8,1 10.5,5.5 15.5,6 11.5,9.5 12.5,14 8,11.5 3.5,14 4.5,9.5 .5,6 5.5,5.5" fill="#fff" opacity="0.9"/></svg></div>';
} else if (item.rank === 3) {
numHtml = '<div class="rank-item__num rank-item__num--bronze"><svg class="rank-item__medal-icon" viewBox="0 0 16 16" fill="none"><polygon points="8,1 10.5,5.5 15.5,6 11.5,9.5 12.5,14 8,11.5 3.5,14 4.5,9.5 .5,6 5.5,5.5" fill="#fff" opacity="0.9"/></svg></div>';
} else {
numHtml = '<span class="rank-item__num-text">' + item.rank + '</span>';
}
var rowCls = item.isMe ? 'rank-item rank-item--my' : 'rank-item';
html += '<div class="' + rowCls + '">';
html += ' <div class="rank-item__num">' + numHtml + '</div>';
html += ' <div class="rank-item__user">';
html += ' <div class="rank-item__name">' + item.name + '<span>·</span>**</div>';
html += ' <div class="rank-item__dept">' + item.org + ' · ' + item.dept + '</div>';
html += ' </div>';
html += ' <div class="rank-item__score">';
html += ' <div class="rank-item__score-val">' + item.val + '<span class="rank-item__score-unit">' + item.unit + '</span></div>';
html += ' <div class="rank-item__score-sub">' + item.sub + '</div>';
html += ' </div>';
html += '</div>';
});
document.getElementById('rankList').innerHTML = html;
}
/* 初始化:默认显示减重量 tab */
switchRankTab('weight');
</script>
</body>
</html>
@@ -0,0 +1,373 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>体重报告 - 员工端 | 健康CQ原型</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
.phone-shell { width: 390px; height: 844px; background: #f5f7fa; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; }
.status-bar { height: 44px; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; background: #fff; }
.status-bar .time { font-size: 15px; font-weight: 700; color: #333; }
.status-bar .icons { display: flex; gap: 6px; align-items: center; }
.nav-bar { height: 44px; background: #fff; display: flex; align-items: center; padding: 0 16px; flex-shrink: 0; border-bottom: 1px solid #f0f0f0; }
.nav-back { width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: #1a1a1a; }
.nav-title { flex: 1; text-align: center; font-size: 17px; font-weight: 600; color: #1a1a1a; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 0 4px; }
.nav-more { width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: #1a1a1a; position: relative; flex-shrink: 0; }
.nav-more__dots { display: flex; flex-direction: column; gap: 3px; align-items: center; }
.nav-more__dots span { display: block; width: 4px; height: 4px; border-radius: 50%; background: #333; }
/* 类型切换下拉菜单 */
.type-menu { display: none; position: absolute; top: 34px; right: 8px; background: #fff; border-radius: 12px; box-shadow: 0 6px 24px rgba(0,0,0,0.12); z-index: 100; min-width: 170px; overflow: hidden; }
.type-menu.show { display: block; }
.type-menu__item { padding: 13px 16px; font-size: 14px; color: #333; cursor: pointer; display: flex; align-items: center; justify-content: space-between; white-space: nowrap; border-bottom: 1px solid #f5f5f5; }
.type-menu__item:last-child { border-bottom: none; }
.type-menu__item:hover { background: #f7f8fa; }
.type-menu__item.active { color: #36cfc9; font-weight: 700; }
.type-menu__item.active::after { content: '✓'; font-size: 12px; color: #36cfc9; }
/* 遮罩层 */
.type-mask { display: none; position: fixed; inset: 0; z-index: 50; }
.type-mask.show { display: block; }
.scroll-content { flex: 1; overflow-y: auto; background: #f5f7fa; }
.scroll-content::-webkit-scrollbar { display: none; }
/* ===== 总览卡片 ===== */
.overview-card { background: linear-gradient(135deg, #36cfc9 0%, #2ec4b6 100%); margin: 12px 12px 0; border-radius: 16px; padding: 20px 18px; color: #fff; position: relative; overflow: hidden; box-shadow: 0 4px 14px rgba(54,207,201,0.25); }
.overview-card::before { content: ''; position: absolute; top: -30px; right: -30px; width: 100px; height: 100px; border-radius: 50%; background: rgba(255,255,255,0.08); pointer-events: none; }
.overview-card::after { content: ''; position: absolute; bottom: -40px; left: -20px; width: 120px; height: 120px; border-radius: 50%; background: rgba(255,255,255,0.05); pointer-events: none; }
.overview-card__title { font-size: 18px; font-weight: 800; margin-bottom: 14px; position: relative; z-index: 1; letter-spacing: 1px; }
.overview-card__info { display: flex; flex-direction: column; gap: 6px; position: relative; z-index: 1; }
.overview-card__row { display: flex; align-items: center; justify-content: space-between; }
.overview-card__label { font-size: 13px; opacity: 0.85; }
.overview-card__val { font-size: 13px; font-weight: 700; }
.overview-card__metrics { display: flex; gap: 12px; margin-top: 14px; position: relative; z-index: 1; }
.overview-card__metric { flex: 1; background: rgba(255,255,255,0.15); border-radius: 10px; padding: 8px 10px; text-align: center; backdrop-filter: blur(4px); }
.overview-card__metric-val { font-size: 22px; font-weight: 800; }
.overview-card__metric-unit { font-size: 12px; font-weight: 500; opacity: 0.8; margin-left: 2px; }
.overview-card__metric-label { font-size: 11px; opacity: 0.75; margin-right: 4px; }
/* ===== 状态缺省(非活动类型) ===== */
.overview-empty { background: #fff; margin: 12px 12px 0; border-radius: 16px; padding: 32px 18px; text-align: center; color: #ccc; box-shadow: 0 2px 8px rgba(0,0,0,0.03); }
.overview-empty__icon { margin-bottom: 12px; }
.overview-empty__text { font-size: 14px; line-height: 1.6; }
/* ===== Tab 栏 ===== */
.report-tabs { display: flex; background: #fff; margin: 12px 12px 0; border-radius: 12px; overflow: hidden; box-shadow: 0 2px 8px rgba(0,0,0,0.03); }
.report-tab { flex: 1; text-align: center; padding: 12px 0; font-size: 13px; font-weight: 600; color: #999; cursor: pointer; position: relative; transition: color .2s; }
.report-tab.active { color: #36cfc9; }
.report-tab.active::after { content: ''; position: absolute; bottom: 4px; left: 50%; transform: translateX(-50%); width: 24px; height: 3px; background: #36cfc9; border-radius: 2px; }
/* ===== 记录列表 ===== */
.record-list { padding: 8px 12px 16px; display: flex; flex-direction: column; gap: 10px; }
.record-item { background: #fff; border-radius: 14px; padding: 14px; box-shadow: 0 2px 8px rgba(0,0,0,0.03); }
.record-item__date { font-size: 14px; font-weight: 700; color: #1a1a1a; margin-bottom: 10px; padding-bottom: 8px; border-bottom: 1px solid #f5f5f5; }
.record-item__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px 4px; }
.record-item__cell { text-align: center; }
.record-item__label { font-size: 11px; color: #999; margin-right: 2px; }
.record-item__val { font-size: 13px; font-weight: 700; color: #1a1a1a; }
.record-item__unit { font-size: 10px; color: #bbb; font-weight: 400; margin-left: 1px; }
.record-empty { text-align: center; padding: 40px 20px; color: #ccc; font-size: 14px; }
.bottom-safe { height: 20px; flex-shrink: 0; }
</style>
</head>
<body>
<div class="phone-shell">
<div class="status-bar">
<span class="time">09:40</span>
<div 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>
</div>
</div>
<div class="nav-bar">
<div class="nav-back" id="navBack" onclick="location.href='weight-main.html' + (currentPageType ? '?type=' + currentPageType : '')">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
</div>
<div class="nav-title" id="navTitle">体重报告</div>
<div class="nav-more" id="navMore" onclick="toggleTypeMenu(event)">
<div class="nav-more__dots">
<span></span><span></span><span></span>
</div>
<div class="type-menu" id="typeMenu">
<div class="type-menu__item active" data-type="hasact" onclick="setPageType('hasact')">已参加活动</div>
<div class="type-menu__item" data-type="personal" onclick="setPageType('personal')">已设置个人目标</div>
<div class="type-menu__item" data-type="none" onclick="setPageType('none')">未参加未设置</div>
</div>
</div>
</div>
<!-- 点击空白区域关闭菜单的遮罩 -->
<div class="type-mask" id="typeMask" onclick="closeTypeMenu()"></div>
<div class="scroll-content">
<!-- 总览卡片(已参加活动) -->
<div class="overview-card" id="overviewCard">
<div class="overview-card__title">您的体重报告</div>
<div class="overview-card__info">
<div class="overview-card__row" id="ovInfoRow">
<span class="overview-card__label">截止至 <span id="ovCutoff">2026年08月12日</span></span>
<span class="overview-card__label"><span id="ovDay">52</span> 天(共 <span id="ovTotal">180</span> 天)</span>
</div>
</div>
<div class="overview-card__metrics">
<div class="overview-card__metric">
<span class="overview-card__metric-label">已减重</span>
<span class="overview-card__metric-val" id="ovLoss">10.9<span class="overview-card__metric-unit">kg</span></span>
</div>
<div class="overview-card__metric">
<span class="overview-card__metric-label">减重率</span>
<span class="overview-card__metric-val" id="ovRate">14.8<span class="overview-card__metric-unit">%</span></span>
</div>
</div>
</div>
<!-- 非活动类型缺省 -->
<div class="overview-empty" id="overviewEmpty" style="display:none;">
<div class="overview-empty__icon">
<svg width="48" height="48" viewBox="0 0 48 48" fill="none"><rect x="8" y="6" width="32" height="36" rx="4" stroke="#ddd" stroke-width="2"/><line x1="16" y1="18" x2="32" y2="18" stroke="#ddd" stroke-width="2" stroke-linecap="round"/><line x1="16" y1="24" x2="28" y2="24" stroke="#ddd" stroke-width="2" stroke-linecap="round"/><line x1="16" y1="30" x2="24" y2="30" stroke="#ddd" stroke-width="2" stroke-linecap="round"/></svg>
</div>
<div class="overview-empty__text">暂未参加体重管理活动<br>暂无体重报告数据</div>
</div>
<!-- Tab 栏 -->
<div class="report-tabs" id="reportTabs">
<div class="report-tab active" data-range="week" onclick="switchTab('week')"></div>
<div class="report-tab" data-range="month" onclick="switchTab('month')"></div>
<div class="report-tab" data-range="quarter" onclick="switchTab('quarter')"></div>
<div class="report-tab" data-range="all" onclick="switchTab('all')">全部</div>
<div class="report-tab" data-range="activity" id="tabActivity" onclick="switchTab('activity')">活动期间</div>
</div>
<!-- 记录列表 -->
<div class="record-list" id="recordList"></div>
<div class="bottom-safe"></div>
</div>
</div>
<script>
/* ===== 获取 URL 参数 ===== */
function getQueryParam(key) {
var m = location.search.match(new RegExp('[?&]' + key + '=([^&]*)'));
return m ? decodeURIComponent(m[1]) : '';
}
var currentPageType = getQueryParam('type') || 'hasact';
/* ===== 模拟数据 ===== */
// 身高假设 1.63mBMI = 体重/(1.63*1.63) = 体重/2.6569
function calcBMI(weight) { return weight / 2.6569; }
var RECORDS = [
{ date:'2026-08-12', intake:1086, consume:1450, weight:62.6, bmi:calcBMI(62.6), bodyFat:20.0, waist:76.5 },
{ date:'2026-08-09', intake:1520, consume:1680, weight:62.8, bmi:calcBMI(62.8), bodyFat:20.3, waist:76.8 },
{ date:'2026-08-07', intake:1380, consume:1520, weight:63.1, bmi:calcBMI(63.1), bodyFat:20.5, waist:77.0 },
{ date:'2026-08-05', intake:1620, consume:1400, weight:63.5, bmi:calcBMI(63.5), bodyFat:20.8, waist:77.5 },
{ date:'2026-08-02', intake:1280, consume:1560, weight:63.8, bmi:calcBMI(63.8), bodyFat:21.1, waist:78.0 },
{ date:'2026-07-30', intake:1750, consume:1350, weight:64.2, bmi:calcBMI(64.2), bodyFat:21.4, waist:78.5 },
{ date:'2026-07-27', intake:1420, consume:1480, weight:64.5, bmi:calcBMI(64.5), bodyFat:21.6, waist:79.0 },
{ date:'2026-07-24', intake:1560, consume:1420, weight:64.9, bmi:calcBMI(64.9), bodyFat:21.9, waist:79.5 },
{ date:'2026-07-20', intake:1330, consume:1500, weight:65.2, bmi:calcBMI(65.2), bodyFat:22.2, waist:80.0 },
{ date:'2026-07-15', intake:1680, consume:1380, weight:65.8, bmi:calcBMI(65.8), bodyFat:22.6, waist:80.5 },
{ date:'2026-07-10', intake:1450, consume:1400, weight:66.5, bmi:calcBMI(66.5), bodyFat:23.0, waist:81.0 },
{ date:'2026-07-05', intake:1520, consume:1350, weight:67.2, bmi:calcBMI(67.2), bodyFat:23.5, waist:81.5 },
{ date:'2026-06-30', intake:1600, consume:1300, weight:68.0, bmi:calcBMI(68.0), bodyFat:24.0, waist:82.0 },
{ date:'2026-06-25', intake:1480, consume:1280, weight:68.8, bmi:calcBMI(68.8), bodyFat:24.5, waist:83.0 },
{ date:'2026-06-22', intake:1550, consume:1200, weight:69.5, bmi:calcBMI(69.5), bodyFat:25.0, waist:83.5 },
{ date:'2026-06-20', intake:1420, consume:1250, weight:70.0, bmi:calcBMI(70.0), bodyFat:25.5, waist:84.0 },
{ date:'2026-06-18', intake:1580, consume:1180, weight:70.5, bmi:calcBMI(70.5), bodyFat:26.0, waist:84.5 },
{ date:'2026-06-16', intake:1650, consume:1100, weight:71.0, bmi:calcBMI(71.0), bodyFat:26.5, waist:85.5 },
{ date:'2026-06-14', intake:1720, consume:1050, weight:71.5, bmi:calcBMI(71.5), bodyFat:27.0, waist:86.0 },
{ date:'2026-06-12', intake:1800, consume:1000, weight:72.0, bmi:calcBMI(72.0), bodyFat:27.3, waist:86.5 },
{ date:'2026-06-10', intake:1750, consume:980, weight:72.5, bmi:calcBMI(72.5), bodyFat:27.8, waist:87.5 },
{ date:'2026-06-08', intake:1680, consume:1020, weight:72.8, bmi:calcBMI(72.8), bodyFat:28.0, waist:88.0 },
{ date:'2026-06-05', intake:1720, consume:950, weight:73.0, bmi:calcBMI(73.0), bodyFat:28.2, waist:88.5 },
{ date:'2026-06-02', intake:1850, consume:900, weight:73.3, bmi:calcBMI(73.3), bodyFat:28.4, waist:89.0 },
{ date:'2026-06-01', intake:1900, consume:880, weight:73.5, bmi:calcBMI(73.5), bodyFat:28.5, waist:89.5 }
];
/* ===== 活动期间 ===== */
var ACTIVITY_START = new Date(2026, 5, 1); // 2026-06-01
var ACTIVITY_END = new Date(2026, 10, 28); // 2026-11-28 (180 days)
/* ===== 今天 ===== */
var TODAY = new Date(2026, 7, 12); // 2026-08-12
/* ===== 工具函数 ===== */
function fmt(n) { return n < 10 ? '0' + n : '' + n; }
function parseDate(s) { var p = s.split('-'); return new Date(+p[0], +p[1]-1, +p[2]); }
/* ===== 类型切换:右上角三点菜单 ===== */
/* 下拉菜单开关 */
function toggleTypeMenu(e) {
e.stopPropagation();
var menu = document.getElementById('typeMenu');
var mask = document.getElementById('typeMask');
var show = !menu.classList.contains('show');
menu.classList.toggle('show', show);
mask.classList.toggle('show', show);
}
/* 关闭下拉菜单 */
function closeTypeMenu() {
document.getElementById('typeMenu').classList.remove('show');
document.getElementById('typeMask').classList.remove('show');
}
document.addEventListener('click', function(e) {
if (!e.target.closest('.nav-more')) closeTypeMenu();
});
/* 切换页面类型 */
function setPageType(type) {
if (type === currentPageType) { closeTypeMenu(); return; }
location.href = 'weight-report.html?type=' + type;
}
/* ===== 根据页面类型初始化 ===== */
function applyPageType(type) {
var overviewCard = document.getElementById('overviewCard');
var overviewEmpty = document.getElementById('overviewEmpty');
var navTitle = document.getElementById('navTitle');
var ovInfoRow = document.getElementById('ovInfoRow');
// 菜单项高亮
document.querySelectorAll('.type-menu__item').forEach(function(item) {
item.classList.toggle('active', item.dataset.type === type);
});
if (type === 'hasact') {
// 已参加活动:显示活动名称标题和完整总览卡片
navTitle.textContent = '2026年二季度体重管理活动';
overviewCard.style.display = '';
overviewEmpty.style.display = 'none';
if (ovInfoRow) ovInfoRow.style.display = '';
document.getElementById('tabActivity').style.display = '';
updateOverview();
} else if (type === 'personal') {
// 已设置个人目标:标题改为个人目标名,显示完整总览卡片
navTitle.textContent = '个人减重目标标题';
overviewCard.style.display = '';
overviewEmpty.style.display = 'none';
if (ovInfoRow) ovInfoRow.style.display = '';
document.getElementById('tabActivity').style.display = '';
updateOverview();
} else {
// 未参加未设置:隐藏标题,显示总览卡片但隐藏截止至/活动进度,隐藏"活动期间"tab
navTitle.textContent = '';
overviewCard.style.display = '';
overviewEmpty.style.display = 'none';
if (ovInfoRow) ovInfoRow.style.display = 'none';
document.getElementById('tabActivity').style.display = 'none';
updateOverview();
}
}
/* ===== 更新总览数据 ===== */
function updateOverview() {
var firstRecord = RECORDS[RECORDS.length - 1]; // 最早的记录
var latestRecord = RECORDS[0]; // 最新的记录
var startWeight = firstRecord.weight; // 73.5
var currentWeight = latestRecord.weight; // 62.6
var loss = startWeight - currentWeight; // 10.9
var rate = (loss / startWeight) * 100; // 14.83
// 计算活动天数
var startDate = ACTIVITY_START;
var todayDate = TODAY;
var elapsedDays = Math.floor((todayDate - startDate) / (1000 * 60 * 60 * 24)) + 1;
var totalDays = Math.floor((ACTIVITY_END - ACTIVITY_START) / (1000 * 60 * 60 * 24)) + 1;
document.getElementById('ovDay').textContent = elapsedDays;
document.getElementById('ovTotal').textContent = totalDays;
document.getElementById('ovLoss').innerHTML = loss.toFixed(1) + '<span class="overview-card__metric-unit">kg</span>';
document.getElementById('ovRate').innerHTML = rate.toFixed(1) + '<span class="overview-card__metric-unit">%</span>';
}
/* ===== Tab 切换 ===== */
var activeTab = 'week';
function switchTab(range) {
activeTab = range;
document.querySelectorAll('.report-tab').forEach(function(t) {
t.classList.toggle('active', t.dataset.range === range);
});
renderRecordList();
}
/* ===== 日期范围计算 ===== */
function getTabDateRange() {
var now = TODAY;
var start, end;
switch (activeTab) {
case 'week':
var dow = now.getDay() || 7;
start = new Date(now); start.setDate(now.getDate() - dow + 1);
end = new Date(start); end.setDate(start.getDate() + 6);
break;
case 'month':
start = new Date(now.getFullYear(), now.getMonth(), 1);
end = new Date(now.getFullYear(), now.getMonth() + 1, 0);
break;
case 'quarter':
var q = Math.floor(now.getMonth() / 3);
start = new Date(now.getFullYear(), q * 3, 1);
end = new Date(now.getFullYear(), (q + 1) * 3, 0);
break;
case 'activity':
start = ACTIVITY_START;
end = ACTIVITY_END;
break;
case 'all':
start = new Date(2000, 0, 1);
end = new Date(2099, 11, 31);
break;
}
return { start: start, end: end };
}
/* ===== 渲染记录列表 ===== */
function renderRecordList() {
var range = getTabDateRange();
var filtered = RECORDS.filter(function(r) {
var d = parseDate(r.date);
return d >= range.start && d <= range.end;
});
var container = document.getElementById('recordList');
if (filtered.length === 0) {
container.innerHTML = '<div class="record-empty">该时间段暂无记录</div>';
return;
}
var html = '';
for (var i = 0; i < filtered.length; i++) {
var r = filtered[i];
html += '<div class="record-item">';
// 日期行
html += '<div class="record-item__date">' + r.date + '</div>';
// 3×2 网格:身体指标优先
html += '<div class="record-item__grid">';
// 第一行:体重 | BMI | 体脂率
html += '<div class="record-item__cell"><span class="record-item__label">体重</span><span class="record-item__val">' + r.weight.toFixed(1) + '<span class="record-item__unit">kg</span></span></div>';
html += '<div class="record-item__cell"><span class="record-item__label">BMI</span><span class="record-item__val">' + r.bmi.toFixed(1) + '</span></div>';
html += '<div class="record-item__cell"><span class="record-item__label">体脂率</span><span class="record-item__val">' + r.bodyFat.toFixed(1) + '<span class="record-item__unit">%</span></span></div>';
// 第二行:腰围 | 摄入 | 消耗
html += '<div class="record-item__cell"><span class="record-item__label">腰围</span><span class="record-item__val">' + (r.waist !== null ? r.waist.toFixed(1) + '<span class="record-item__unit">cm</span>' : '-') + '</span></div>';
html += '<div class="record-item__cell"><span class="record-item__label">摄入</span><span class="record-item__val">' + r.intake + '<span class="record-item__unit">kcal</span></span></div>';
html += '<div class="record-item__cell"><span class="record-item__label">消耗</span><span class="record-item__val">' + r.consume + '<span class="record-item__unit">kcal</span></span></div>';
html += '</div>';
html += '</div>';
}
container.innerHTML = html;
}
/* ===== 初始化 ===== */
function init() {
applyPageType(currentPageType);
renderRecordList();
}
init();
</script>
</body>
</html>
+11 -1
View File
@@ -565,6 +565,9 @@ const SITE_MAP = [
] },
{ name:'体重管理', dir:'employee-app/weight-management', entry:'weight-main.html', pages:[
{ file:'weight-main.html', label:'体重管理主页' },
{ file:'weight-ranking.html', label:'排行榜' },
{ file:'eat-checkin.html', label:'吃打卡' },
{ file:'eat-history.html', label:'摄入记录历史' },
{ file:'goal-commitment.html', label:'目标承诺' },
{ file:'basic-info.html', label:'基本信息' },
{ file:'indicators-diseases.html', label:'指标慢病' },
@@ -573,7 +576,14 @@ const SITE_MAP = [
{ file:'contraindications.html', label:'禁忌证' },
{ file:'promise-signing.html', label:'承诺签订' },
{ file:'my-promise.html', label:'我的承诺书' },
{ file:'balance-history.html', label:'吃动平衡历史' }
{ file:'balance-history.html', label:'吃动平衡历史' },
{ file:'weight-history.html', label:'体重记录历史' },
{ file:'weight-report.html', label:'体重报告' },
{ file:'diet-advice.html', label:'膳食建议' },
{ file:'exercise-advice.html', label:'运动建议' },
{ file:'exercise-checkin.html', label:'动打卡' },
{ file:'exercise-history.html', label:'消耗记录' },
{ file:'weight-checkin.html', label:'重打卡' }
] },
{ name:'营养管理', dir:'employee-app/nutrition', pages:[] },
{ name:'运动管理', dir:'employee-app/exercise', pages:[] },