feat: 新增体重管理v2相关页面(饮食建议、打卡、扫码、详情、主页)
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,915 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>饮食记录 - 员工端 | 健康CQ原型 v2</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; 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; height: 28px; }
|
||||
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f5f7fa; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
|
||||
/* ===== 周日历 ===== */
|
||||
.calendar-card { background: #fff; border-radius: 16px; margin: 12px 12px 0; padding: 14px 12px 10px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); position: relative; }
|
||||
.calendar-card__header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
|
||||
.calendar-card__arrow { width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: #999; border-radius: 50%; transition: background .2s; user-select: none; }
|
||||
.calendar-card__arrow:hover { background: #f0f0f0; color: #333; }
|
||||
.calendar-card__range { font-size: 13px; font-weight: 600; color: #333; display: inline-flex; align-items: center; gap: 4px; cursor: pointer; user-select: none; }
|
||||
.calendar-card__range svg { flex-shrink: 0; }
|
||||
.calendar-card__date-arrow { transition: transform .2s; }
|
||||
.calendar-card__date-arrow.open { transform: rotate(180deg); }
|
||||
|
||||
/* ===== 月历弹窗 ===== */
|
||||
.month-picker { position: absolute; top: 46px; left: 12px; right: 12px; z-index: 20; background: #fff; border-radius: 14px; padding: 12px 14px; box-shadow: 0 8px 30px rgba(0,0,0,0.15); display: none; }
|
||||
.month-picker.show { display: block; }
|
||||
.month-picker__header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
|
||||
.month-picker__title { font-size: 14px; font-weight: 700; color: #1a1a1a; }
|
||||
.month-picker__nav { width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: #999; border-radius: 50%; font-size: 13px; }
|
||||
.month-picker__nav:hover { background: #f0f0f0; }
|
||||
.month-picker__weekdays { display: grid; grid-template-columns: repeat(7, 1fr); text-align: center; font-size: 11px; color: #bbb; margin-bottom: 6px; }
|
||||
.month-picker__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; text-align: center; }
|
||||
.month-picker__day { padding: 6px 0; font-size: 13px; color: #333; border-radius: 8px; cursor: pointer; font-weight: 500; position: relative; }
|
||||
.month-picker__day:hover { background: #f5f5f5; }
|
||||
.month-picker__day--other { color: #ddd; }
|
||||
.month-picker__day--today { background: #e8fbfa; color: #36cfc9; font-weight: 700; }
|
||||
.month-picker__day--selected { background: #36cfc9; color: #fff; font-weight: 700; }
|
||||
/* 月历日期数字 + 来源圆环 */
|
||||
.month-picker__date-wrap { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; }
|
||||
.month-picker__ring { position: absolute; inset: 0; border-radius: 50%; border: 2px solid transparent; }
|
||||
.month-picker__ring--auto { border-color: #1890ff; }
|
||||
.month-picker__ring--manual { border-color: #fa8c16; }
|
||||
.month-picker__ring--mixed { border-color: #722ed1; }
|
||||
.cal-week { display: flex; gap: 4px; }
|
||||
.cal-day { flex: 1; text-align: center; padding: 8px 0 8px; border-radius: 12px; cursor: pointer; background: #f7f8fa; transition: background .2s; }
|
||||
.cal-day.active { background: #e8fbfa; }
|
||||
.cal-day.today .cal-day__num { color: #1a1a1a; font-weight: 800; }
|
||||
.cal-day.active .cal-day__num { color: #36cfc9; font-weight: 800; }
|
||||
.cal-day.active .cal-day__wd { color: #36cfc9; font-weight: 600; }
|
||||
.cal-day__wd { font-size: 10px; color: #999; margin-bottom: 4px; }
|
||||
/* 日期数字 + 来源圆环 */
|
||||
.cal-day__date-wrap { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 30px; height: 30px; margin: 0 auto; }
|
||||
.cal-day__num { font-size: 15px; font-weight: 700; color: #333; position: relative; z-index: 2; }
|
||||
.cal-day__ring { position: absolute; inset: 0; border-radius: 50%; border: 2.5px solid transparent; z-index: 1; }
|
||||
.cal-day__ring--auto { border-color: #1890ff; }
|
||||
.cal-day__ring--manual { border-color: #fa8c16; }
|
||||
.cal-day__ring--mixed { border-color: #722ed1; }
|
||||
|
||||
/* ===== 图例:三种来源 ===== */
|
||||
.month-picker__legend { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 14px; margin-top: 8px; padding-top: 8px; font-size: 11px; color: #666; }
|
||||
.month-picker__legend-item { display: inline-flex; align-items: center; gap: 4px; }
|
||||
.month-picker__legend-ring { width: 12px; height: 12px; border-radius: 50%; border: 2.5px solid; }
|
||||
.month-picker__legend-ring--auto { border-color: #1890ff; }
|
||||
.month-picker__legend-ring--manual { border-color: #fa8c16; }
|
||||
.month-picker__legend-ring--mixed { border-color: #722ed1; }
|
||||
|
||||
/* ===== 热量缺口标尺卡片 ===== */
|
||||
.gap-card { background: #fff; border-radius: 16px; margin: 12px 12px 0; padding: 16px 16px 14px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
|
||||
.gap-card__header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 2px; }
|
||||
.gap-card__title { font-size: 16px; font-weight: 800; color: #1a1a1a; }
|
||||
.gap-card__target { font-size: 12px; font-weight: 600; color: #36cfc9; }
|
||||
|
||||
/* ===== 标尺 SVG ===== */
|
||||
.gauge-wrap { width: 100%; margin-top: -30px; position: relative; }
|
||||
.gauge-wrap svg { width: 100%; height: auto; display: block; }
|
||||
.recipe-btn { position: absolute; top: 44px; right: 8px; padding: 5px 12px; border-radius: 14px; border: none; background: linear-gradient(160deg, #36cfc9, #2db8b0); color: #fff; font-size: 11px; font-weight: 600; cursor: pointer; z-index: 5; box-shadow: 0 2px 6px rgba(54,207,201,0.3); }
|
||||
|
||||
/* ===== 营养素三列 ===== */
|
||||
.macros-row { display: flex; gap: 10px; padding: 0 4px 8px; }
|
||||
.macros-row.hidden { display: none; }
|
||||
.macro-col { flex: 1; padding: 8px 10px; background: #f7f8fa; border-radius: 10px; text-align: center; }
|
||||
.macro-col__name { font-size: 11px; color: #999; margin-bottom: 4px; }
|
||||
.macro-col__val { font-size: 16px; font-weight: 800; color: #333; }
|
||||
.macro-col__unit { font-size: 10px; font-weight: 400; color: #999; }
|
||||
.macro-col__bar { height: 4px; border-radius: 2px; background: #e8e8e8; overflow: hidden; margin-top: 6px; }
|
||||
.macro-col__fill { height: 100%; border-radius: 2px; }
|
||||
.macro-col__fill--carb { background: #5470c6; }
|
||||
.macro-col__fill--protein { background: #ee6666; }
|
||||
.macro-col__fill--fat { background: #fac858; }
|
||||
|
||||
/* ===== 餐食卡片通用 ===== */
|
||||
.meal-card { background: #fff; border-radius: 16px; margin: 12px 12px 0; padding: 14px 16px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
|
||||
.meal-card__header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; cursor: pointer; }
|
||||
.meal-card__left { display: flex; align-items: center; gap: 8px; }
|
||||
.meal-card__icon { width: 28px; height: 28px; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 14px; }
|
||||
.meal-card__icon--breakfast { background: #fff3e0; color: #fa8c16; }
|
||||
.meal-card__icon--lunch { background: #fff1f0; color: #ee6666; }
|
||||
.meal-card__icon--dinner { background: #f0f0ff; color: #5470c6; }
|
||||
.meal-card__icon--snack { background: #fffbe6; color: #fac858; }
|
||||
.meal-card__icon--exercise { background: #f0fff0; color: #52c41a; }
|
||||
.meal-card__name { font-size: 15px; font-weight: 700; color: #1a1a1a; }
|
||||
.meal-card__kcal { font-size: 13px; font-weight: 600; }
|
||||
.meal-card__kcal span { font-size: 17px; font-weight: 800; }
|
||||
.meal-card__kcal--in { color: #fa8c16; }
|
||||
.meal-card__kcal--in span { color: #fa8c16; }
|
||||
.meal-card__kcal--out { color: #52c41a; }
|
||||
.meal-card__kcal--out span { color: #52c41a; }
|
||||
.meal-card__expand { width: 22px; height: 22px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: #bbb; transition: transform .25s; }
|
||||
.meal-card__expand.open { transform: rotate(180deg); }
|
||||
|
||||
/* 食物列表 */
|
||||
.meal-items { display: flex; flex-direction: column; gap: 6px; }
|
||||
.meal-item { display: flex; align-items: center; padding: 6px 10px; background: #f7f8fa; border-radius: 8px; gap: 8px; }
|
||||
.meal-item__emoji { font-size: 18px; width: 24px; text-align: center; flex-shrink: 0; }
|
||||
.meal-item__info { flex: 1; min-width: 0; }
|
||||
.meal-item__name { font-size: 13px; color: #333; font-weight: 500; display: flex; align-items: center; gap: 6px; }
|
||||
.meal-item__src { font-size: 9px; font-weight: 600; padding: 1px 6px; border-radius: 6px; white-space: nowrap; line-height: 1.5; }
|
||||
.meal-item__src--auto { color: #1890ff; background: #e6f7ff; }
|
||||
.meal-item__src--manual { color: #fa8c16; background: #fff7e6; }
|
||||
.meal-item__meta { font-size: 11px; color: #bbb; margin-top: 1px; }
|
||||
.meal-item__kcal { font-size: 13px; font-weight: 700; color: #fa8c16; white-space: nowrap; flex-shrink: 0; }
|
||||
.meal-item--exercise .meal-item__kcal { color: #52c41a; }
|
||||
.meal-empty { text-align: center; padding: 16px 0; color: #ccc; font-size: 13px; }
|
||||
|
||||
/* ===== 底部工具栏 ===== */
|
||||
.toolbar { height: 56px; background: #fff; border-top: 1px solid #f0f0f0; display: flex; align-items: center; padding: 0 8px; flex-shrink: 0; gap: 6px; }
|
||||
.toolbar__btn { flex: 1; height: 38px; border-radius: 19px; border: none; font-size: 12px; font-weight: 600; cursor: pointer; display: flex; align-items: center; justify-content: center; gap: 3px; transition: transform .15s, box-shadow .15s; color: #fff; }
|
||||
.toolbar__btn:active { transform: scale(0.96); }
|
||||
.toolbar__btn--breakfast { background: linear-gradient(160deg, #ffc069, #fa8c16); box-shadow: 0 2px 8px rgba(250,140,22,0.25); }
|
||||
.toolbar__btn--lunch { background: linear-gradient(160deg, #ff7875, #ee6666); box-shadow: 0 2px 8px rgba(238,102,102,0.25); }
|
||||
.toolbar__btn--dinner { background: linear-gradient(160deg, #7b8ce6, #5470c6); box-shadow: 0 2px 8px rgba(84,112,198,0.25); }
|
||||
.toolbar__btn--snack { background: linear-gradient(160deg, #ffe07a, #fac858); box-shadow: 0 2px 8px rgba(250,200,88,0.25); }
|
||||
.toolbar__btn--exercise { background: linear-gradient(160deg, #7ee87e, #52c41a); box-shadow: 0 2px 8px rgba(82,196,26,0.25); }
|
||||
.toolbar__btn svg { width: 13px; height: 13px; }
|
||||
</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-v2.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">
|
||||
|
||||
<!-- ====== 本周7日日历 ====== -->
|
||||
<div class="calendar-card">
|
||||
<div class="calendar-card__header">
|
||||
<div class="calendar-card__arrow" id="calPrev" onclick="prevWeek()">
|
||||
<svg width="16" height="16" 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>
|
||||
<span class="calendar-card__range" onclick="toggleMonthPicker()">
|
||||
<span id="calRange">2026年7月23日</span>
|
||||
<svg class="calendar-card__date-arrow" id="dateArrow" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#999" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
|
||||
</span>
|
||||
<div class="calendar-card__arrow" id="calNext" onclick="nextWeek()">
|
||||
<svg width="16" height="16" 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>
|
||||
|
||||
<!-- 月历弹窗 -->
|
||||
<div class="month-picker" id="monthPicker">
|
||||
<div class="month-picker__header">
|
||||
<div class="month-picker__nav" onclick="event.stopPropagation();prevMonth()">◀</div>
|
||||
<span class="month-picker__title" id="monthPickerTitle">2026年7月</span>
|
||||
<div class="month-picker__nav" onclick="event.stopPropagation();nextMonth()">▶</div>
|
||||
</div>
|
||||
<div class="month-picker__weekdays">
|
||||
<span>日</span><span>一</span><span>二</span><span>三</span><span>四</span><span>五</span><span>六</span>
|
||||
</div>
|
||||
<div class="month-picker__grid" id="monthGrid"></div>
|
||||
<!-- 图例:来源颜色 -->
|
||||
<div class="month-picker__legend">
|
||||
<span class="month-picker__legend-item"><span class="month-picker__legend-ring month-picker__legend-ring--auto"></span>智记餐</span>
|
||||
<span class="month-picker__legend-item"><span class="month-picker__legend-ring month-picker__legend-ring--manual"></span>自记餐</span>
|
||||
<span class="month-picker__legend-item"><span class="month-picker__legend-ring month-picker__legend-ring--mixed"></span>智记+自记餐</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cal-week" id="calWeek"></div>
|
||||
|
||||
<div class="gauge-wrap">
|
||||
<button class="recipe-btn" onclick="location.href='diet-advice-v2.html'">今日饮食建议</button>
|
||||
<svg viewBox="0 0 340 170" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<linearGradient id="gapGrad" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||
<stop offset="0%" stop-color="#ffc069"/>
|
||||
<stop offset="35%" stop-color="#fa8c16"/>
|
||||
<stop offset="100%" stop-color="#52c41a"/>
|
||||
</linearGradient>
|
||||
<radialGradient id="glowGrad" cx="50%" cy="70%" r="55%">
|
||||
<stop offset="0%" stop-color="#e8fbfa" stop-opacity="0.3"/>
|
||||
<stop offset="100%" stop-color="#fff" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
|
||||
<rect x="0" y="0" width="340" height="170" fill="url(#glowGrad)"/>
|
||||
|
||||
<!-- 灰色底轨 -->
|
||||
<path d="M 90 135 A 80 80 0 0 1 250 135"
|
||||
fill="none" stroke="#ebeef0" stroke-width="14" stroke-linecap="round"/>
|
||||
|
||||
<!-- 进度弧 -->
|
||||
<path id="gapArc" d="M 90 135 A 80 80 0 0 1 222 75"
|
||||
fill="none" stroke="url(#gapGrad)" stroke-width="14" stroke-linecap="round"/>
|
||||
|
||||
<!-- 刻度圆点 -->
|
||||
<circle cx="98" cy="103" r="2.5" fill="#cfcfcf"/>
|
||||
<circle cx="120" cy="75" r="2.5" fill="#cfcfcf"/>
|
||||
<circle cx="152" cy="60" r="2.5" fill="#cfcfcf"/>
|
||||
<circle cx="188" cy="60" r="2.5" fill="#cfcfcf"/>
|
||||
<circle cx="220" cy="75" r="2.5" fill="#cfcfcf"/>
|
||||
<circle cx="242" cy="103" r="2.5" fill="#cfcfcf"/>
|
||||
|
||||
<!-- 端点 -->
|
||||
<circle cx="90" cy="135" r="5" fill="#bbb" stroke="#fff" stroke-width="2.5"/>
|
||||
<circle cx="250" cy="135" r="5" fill="#52c41a" stroke="#fff" stroke-width="2.5"/>
|
||||
|
||||
<!-- 左侧端点下方:饮食摄入 -->
|
||||
<text x="90" y="150" font-size="12" fill="#999" text-anchor="middle">饮食摄入</text>
|
||||
<text x="90" y="165" font-size="18" fill="#fa8c16" text-anchor="middle" font-weight="800"><tspan id="intakeText">1086</tspan><tspan font-size="10" font-weight="400" fill="#bbb">/1950 千卡</tspan></text>
|
||||
|
||||
<!-- 右侧端点下方:运动消耗 -->
|
||||
<text x="250" y="150" font-size="12" fill="#999" text-anchor="middle">运动消耗</text>
|
||||
<text x="250" y="165" font-size="18" fill="#52c41a" text-anchor="middle" font-weight="800"><tspan id="consumeText">820</tspan><tspan font-size="10" font-weight="400" fill="#bbb">/1000 千卡</tspan></text>
|
||||
|
||||
<!-- 中心 -->
|
||||
<text x="170" y="88" font-size="12" fill="#999" text-anchor="middle">吃动热量差</text>
|
||||
<text id="gapCenterVal" x="170" y="120" font-size="28" fill="#fa8c16" text-anchor="middle" font-weight="800">-364</text>
|
||||
<text x="170" y="137" font-size="11" fill="#bbb" text-anchor="middle">/ -500 千卡</text>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<!-- 营养素三列 -->
|
||||
<div class="macros-row" id="macrosRow">
|
||||
<div class="macro-col">
|
||||
<div class="macro-col__name">碳水</div>
|
||||
<div><span class="macro-col__val" id="macroCarb">155</span><span class="macro-col__unit">/260 g</span></div>
|
||||
<div class="macro-col__bar"><div class="macro-col__fill macro-col__fill--carb" id="macroCarbBar" style="width:58%"></div></div>
|
||||
</div>
|
||||
<div class="macro-col">
|
||||
<div class="macro-col__name">蛋白质</div>
|
||||
<div><span class="macro-col__val" id="macroProtein">47</span><span class="macro-col__unit">/82 g</span></div>
|
||||
<div class="macro-col__bar"><div class="macro-col__fill macro-col__fill--protein" id="macroProteinBar" style="width:57%"></div></div>
|
||||
</div>
|
||||
<div class="macro-col">
|
||||
<div class="macro-col__name">脂肪</div>
|
||||
<div><span class="macro-col__val" id="macroFat">31</span><span class="macro-col__unit">/60 g</span></div>
|
||||
<div class="macro-col__bar"><div class="macro-col__fill macro-col__fill--fat" id="macroFatBar" style="width:52%"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ====== 早餐卡片 ====== -->
|
||||
<div class="meal-card" id="cardBreakfast">
|
||||
<div class="meal-card__header" onclick="toggleMeal('breakfast', this)">
|
||||
<div class="meal-card__left">
|
||||
<div class="meal-card__icon meal-card__icon--breakfast">☀</div>
|
||||
<span class="meal-card__name">早餐</span>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;gap:8px;">
|
||||
<span class="meal-card__kcal meal-card__kcal--in"><span id="kcalBreakfast">320</span> kcal</span>
|
||||
<div class="meal-card__expand">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="meal-items" id="groupBreakfast">
|
||||
<div class="meal-item">
|
||||
<div class="meal-item__emoji">🥚</div>
|
||||
<div class="meal-item__info">
|
||||
<div class="meal-item__name">水煮鸡蛋<span class="meal-item__src meal-item__src--auto">智记</span></div>
|
||||
<div class="meal-item__meta">×1 · 约50g</div>
|
||||
</div>
|
||||
<div class="meal-item__kcal">80 kcal</div>
|
||||
</div>
|
||||
<div class="meal-item">
|
||||
<div class="meal-item__emoji">🥛</div>
|
||||
<div class="meal-item__info">
|
||||
<div class="meal-item__name">纯牛奶<span class="meal-item__src meal-item__src--auto">智记</span></div>
|
||||
<div class="meal-item__meta">×1 · 250ml</div>
|
||||
</div>
|
||||
<div class="meal-item__kcal">120 kcal</div>
|
||||
</div>
|
||||
<div class="meal-item">
|
||||
<div class="meal-item__emoji">🍞</div>
|
||||
<div class="meal-item__info">
|
||||
<div class="meal-item__name">全麦面包<span class="meal-item__src meal-item__src--auto">智记</span></div>
|
||||
<div class="meal-item__meta">×2 · 约80g</div>
|
||||
</div>
|
||||
<div class="meal-item__kcal">120 kcal</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ====== 午餐卡片 ====== -->
|
||||
<div class="meal-card" id="cardLunch">
|
||||
<div class="meal-card__header" onclick="toggleMeal('lunch', this)">
|
||||
<div class="meal-card__left">
|
||||
<div class="meal-card__icon meal-card__icon--lunch">☀</div>
|
||||
<span class="meal-card__name">午餐</span>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;gap:8px;">
|
||||
<span class="meal-card__kcal meal-card__kcal--in"><span id="kcalLunch">480</span> kcal</span>
|
||||
<div class="meal-card__expand">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="meal-items" id="groupLunch">
|
||||
<div class="meal-item">
|
||||
<div class="meal-item__emoji">🍚</div>
|
||||
<div class="meal-item__info">
|
||||
<div class="meal-item__name">白米饭<span class="meal-item__src meal-item__src--auto">智记</span></div>
|
||||
<div class="meal-item__meta">×1 · 约200g</div>
|
||||
</div>
|
||||
<div class="meal-item__kcal">232 kcal</div>
|
||||
</div>
|
||||
<div class="meal-item">
|
||||
<div class="meal-item__emoji">🐔</div>
|
||||
<div class="meal-item__info">
|
||||
<div class="meal-item__name">宫保鸡丁<span class="meal-item__src meal-item__src--manual">自记</span></div>
|
||||
<div class="meal-item__meta">×1 · 约150g</div>
|
||||
</div>
|
||||
<div class="meal-item__kcal">148 kcal</div>
|
||||
</div>
|
||||
<div class="meal-item">
|
||||
<div class="meal-item__emoji">🥬</div>
|
||||
<div class="meal-item__info">
|
||||
<div class="meal-item__name">清炒时蔬<span class="meal-item__src meal-item__src--manual">自记</span></div>
|
||||
<div class="meal-item__meta">×1 · 约200g</div>
|
||||
</div>
|
||||
<div class="meal-item__kcal">100 kcal</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ====== 晚餐卡片 ====== -->
|
||||
<div class="meal-card" id="cardDinner">
|
||||
<div class="meal-card__header" onclick="toggleMeal('dinner', this)">
|
||||
<div class="meal-card__left">
|
||||
<div class="meal-card__icon meal-card__icon--dinner">🌙</div>
|
||||
<span class="meal-card__name">晚餐</span>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;gap:8px;">
|
||||
<span class="meal-card__kcal meal-card__kcal--in"><span id="kcalDinner">220</span> kcal</span>
|
||||
<div class="meal-card__expand">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="meal-items" id="groupDinner">
|
||||
<div class="meal-item">
|
||||
<div class="meal-item__emoji">🥗</div>
|
||||
<div class="meal-item__info">
|
||||
<div class="meal-item__name">鸡胸肉沙拉<span class="meal-item__src meal-item__src--auto">智记</span></div>
|
||||
<div class="meal-item__meta">×1 · 约250g</div>
|
||||
</div>
|
||||
<div class="meal-item__kcal">180 kcal</div>
|
||||
</div>
|
||||
<div class="meal-item">
|
||||
<div class="meal-item__emoji">🍠</div>
|
||||
<div class="meal-item__info">
|
||||
<div class="meal-item__name">蒸红薯<span class="meal-item__src meal-item__src--auto">智记</span></div>
|
||||
<div class="meal-item__meta">×1 · 约100g</div>
|
||||
</div>
|
||||
<div class="meal-item__kcal">40 kcal</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ====== 加餐卡片 ====== -->
|
||||
<div class="meal-card" id="cardSnack">
|
||||
<div class="meal-card__header" onclick="toggleMeal('snack', this)">
|
||||
<div class="meal-card__left">
|
||||
<div class="meal-card__icon meal-card__icon--snack">🍎</div>
|
||||
<span class="meal-card__name">加餐</span>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;gap:8px;">
|
||||
<span class="meal-card__kcal meal-card__kcal--in"><span id="kcalSnack">66</span> kcal</span>
|
||||
<div class="meal-card__expand">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="meal-items" id="groupSnack">
|
||||
<div class="meal-item">
|
||||
<div class="meal-item__emoji">🍎</div>
|
||||
<div class="meal-item__info">
|
||||
<div class="meal-item__name">苹果<span class="meal-item__src meal-item__src--manual">自记</span></div>
|
||||
<div class="meal-item__meta">×1 · 约200g</div>
|
||||
</div>
|
||||
<div class="meal-item__kcal">66 kcal</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ====== 运动卡片 ====== -->
|
||||
<div class="meal-card" id="cardExercise">
|
||||
<div class="meal-card__header" onclick="toggleMeal('exercise', this)">
|
||||
<div class="meal-card__left">
|
||||
<div class="meal-card__icon meal-card__icon--exercise">🏃</div>
|
||||
<span class="meal-card__name">运动</span>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;gap:8px;">
|
||||
<span class="meal-card__kcal meal-card__kcal--out"><span id="kcalExercise">-320</span> kcal</span>
|
||||
<div class="meal-card__expand">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="meal-items" id="groupExercise">
|
||||
<div class="meal-item meal-item--exercise">
|
||||
<div class="meal-item__emoji">🏃</div>
|
||||
<div class="meal-item__info">
|
||||
<div class="meal-item__name">户外跑步</div>
|
||||
<div class="meal-item__meta">5.2km · 32分钟</div>
|
||||
</div>
|
||||
<div class="meal-item__kcal">-260 kcal</div>
|
||||
</div>
|
||||
<div class="meal-item meal-item--exercise">
|
||||
<div class="meal-item__emoji">🚶</div>
|
||||
<div class="meal-item__info">
|
||||
<div class="meal-item__name">步行</div>
|
||||
<div class="meal-item__meta">6800步 · 今日累计</div>
|
||||
</div>
|
||||
<div class="meal-item__kcal">-60 kcal</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 饮食未记录缺省卡片 -->
|
||||
<div class="meal-card" id="cardEmptyDiet" style="display:none;">
|
||||
<div style="text-align:center;padding:24px 0;color:#ccc;">
|
||||
<div style="font-size:36px;margin-bottom:8px;">🍽️</div>
|
||||
<div style="font-size:14px;">暂无饮食记录</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="height: 8px; flex-shrink: 0;"></div>
|
||||
</div>
|
||||
|
||||
<!-- ====== 底部工具栏 ====== -->
|
||||
<div class="toolbar">
|
||||
<button class="toolbar__btn toolbar__btn--breakfast" onclick="addMeal('breakfast')">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
|
||||
早餐
|
||||
</button>
|
||||
<button class="toolbar__btn toolbar__btn--lunch" onclick="addMeal('lunch')">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
|
||||
午餐
|
||||
</button>
|
||||
<button class="toolbar__btn toolbar__btn--dinner" onclick="addMeal('dinner')">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
|
||||
晚餐
|
||||
</button>
|
||||
<button class="toolbar__btn toolbar__btn--snack" onclick="addMeal('snack')">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
|
||||
加餐
|
||||
</button>
|
||||
<button class="toolbar__btn toolbar__btn--exercise" onclick="addMeal('exercise')">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
|
||||
运动
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* ===== 日历数据(按日期存储) ===== */
|
||||
var dayData = {
|
||||
'2026-07-20': { intake: 1050, consume: 780, gap: -380, macros: {carb:140,carbT:260,protein:52,proteinT:82,fat:28,fatT:60}, meals: {
|
||||
breakfast: { source:'manual', kcal: 280, items: [{e:'🥚',n:'水煮鸡蛋',m:'×1',k:80},{e:'🥛',n:'纯牛奶',m:'×1 · 250ml',k:120},{e:'🍞',n:'全麦面包',m:'×1',k:80}] },
|
||||
lunch: { source:'auto', kcal: 450, items: [{e:'🍚',n:'白米饭',m:'×1 · 约200g',k:232},{e:'🐔',n:'红烧鸡块',m:'×1 · 约150g',k:140},{e:'🥬',n:'炒青菜',m:'×1',k:78}] },
|
||||
dinner: { source:'auto', kcal: 260, items: [{e:'🥗',n:'蔬菜沙拉',m:'×1 · 约200g',k:160},{e:'🍠',n:'蒸红薯',m:'×1',k:100}] },
|
||||
snack: { source:'manual', kcal: 60, items: [{e:'🍌',n:'香蕉',m:'×1',k:60}] },
|
||||
exercise: { kcal: -280, items: [{e:'🏃',n:'户外跑步',m:'4.5km · 28分钟',k:-200},{e:'🚶',n:'步行',m:'5500步',k:-80}] }
|
||||
}},
|
||||
'2026-07-21': { intake: 1120, consume: 790, gap: -330, macros: {carb:165,carbT:260,protein:44,proteinT:82,fat:34,fatT:60}, meals: {
|
||||
breakfast: { source:'manual', kcal: 350, items: [{e:'🥛',n:'豆浆',m:'×1 · 300ml',k:90},{e:'🥮',n:'肉包',m:'×2',k:180},{e:'🥚',n:'茶叶蛋',m:'×1',k:80}] },
|
||||
lunch: { source:'manual', kcal: 480, items: [{e:'🍜',n:'牛肉面',m:'×1 · 约400g',k:380},{e:'🥒',n:'凉拌黄瓜',m:'×1',k:100}] },
|
||||
dinner: { source:'manual', kcal: 210, items: [{e:'🐟',n:'清蒸鱼',m:'×1 · 约150g',k:130},{e:'🥦',n:'西兰花',m:'×1',k:80}] },
|
||||
snack: { source:'manual', kcal: 80, items: [{e:'🥜',n:'坚果',m:'×1把 · 约20g',k:80}] },
|
||||
exercise: { kcal: -250, items: [{e:'🚴',n:'骑行',m:'8km · 35分钟',k:-250}] }
|
||||
}},
|
||||
'2026-07-22': { intake: 980, consume: 740, gap: -412, macros: {carb:120,carbT:260,protein:58,proteinT:82,fat:22,fatT:60}, meals: {
|
||||
breakfast: { source:'auto', kcal: 220, items: [{e:'🥚',n:'水煮蛋',m:'×2',k:160},{e:'☕',n:'黑咖啡',m:'×1',k:5},{e:'🍞',n:'全麦吐司',m:'×1',k:55}] },
|
||||
lunch: { source:'auto', kcal: 420, items: [{e:'🍚',n:'杂粮饭',m:'×1 · 约180g',k:200},{e:'🐔',n:'鸡胸肉',m:'×1 · 约120g',k:120},{e:'🥬',n:'蒜蓉菠菜',m:'×1',k:100}] },
|
||||
dinner: { source:'auto', kcal: 280, items: [{e:'🥗',n:'凯撒沙拉',m:'×1 · 约250g',k:220},{e:'🍎',n:'苹果',m:'×1',k:60}] },
|
||||
snack: { source:'auto', kcal: 60, items: [{e:'🥒',n:'黄瓜',m:'×1根',k:15},{e:'🍅',n:'小番茄',m:'×5颗',k:45}] },
|
||||
exercise: { kcal: -320, items: [{e:'🏊',n:'游泳',m:'40分钟',k:-260},{e:'🚶',n:'步行',m:'5000步',k:-60}] }
|
||||
}},
|
||||
'2026-07-23': { intake: 1086, consume: 820, gap: -364, macros: {carb:155,carbT:260,protein:47,proteinT:82,fat:31,fatT:60}, meals: {
|
||||
breakfast: { source:'auto', kcal: 320, items: [{e:'🥚',n:'水煮鸡蛋',m:'×1 · 约50g',k:80},{e:'🥛',n:'纯牛奶',m:'×1 · 250ml',k:120},{e:'🍞',n:'全麦面包',m:'×2 · 约80g',k:120}] },
|
||||
lunch: { source:'manual', kcal: 480, items: [{e:'🍚',n:'白米饭',m:'×1 · 约200g',k:232,src:'auto'},{e:'🐔',n:'宫保鸡丁',m:'×1 · 约150g',k:148},{e:'🥬',n:'清炒时蔬',m:'×1 · 约200g',k:100}] },
|
||||
dinner: { source:'auto', kcal: 220, items: [{e:'🥗',n:'鸡胸肉沙拉',m:'×1 · 约250g',k:180},{e:'🍠',n:'蒸红薯',m:'×1 · 约100g',k:40}] },
|
||||
snack: { source:'manual', kcal: 66, items: [{e:'🍎',n:'苹果',m:'×1 · 约200g',k:66}] },
|
||||
exercise: { kcal: -320, items: [{e:'🏃',n:'户外跑步',m:'5.2km · 32分钟',k:-260},{e:'🚶',n:'步行',m:'6800步 · 今日累计',k:-60}] }
|
||||
}},
|
||||
'2026-07-24': { intake: 0, consume: 0, gap: 0 },
|
||||
'2026-07-25': { intake: 0, consume: 0, gap: 0 },
|
||||
'2026-07-26': { intake: 0, consume: 0, gap: 0 }
|
||||
};
|
||||
|
||||
/* ===== 周导航 ===== */
|
||||
var WEEK_MS = 7 * 24 * 60 * 60 * 1000;
|
||||
var today = new Date(2026, 6, 23); // 2026-07-23
|
||||
var currentWeekStart = getMonday(today);
|
||||
|
||||
/* 获取某日期所在周的周一 */
|
||||
function getMonday(d) {
|
||||
var m = new Date(d);
|
||||
var day = m.getDay(); // 0=Sun, 1=Mon, ...
|
||||
var diff = day === 0 ? -6 : 1 - day;
|
||||
m.setDate(m.getDate() + diff);
|
||||
m.setHours(0, 0, 0, 0);
|
||||
return m;
|
||||
}
|
||||
|
||||
/* 格式化日期:YYYY-MM-DD */
|
||||
function fmtDate(d) {
|
||||
var y = d.getFullYear();
|
||||
var m = ('0' + (d.getMonth() + 1)).slice(-2);
|
||||
var day = ('0' + d.getDate()).slice(-2);
|
||||
return y + '-' + m + '-' + day;
|
||||
}
|
||||
|
||||
/* 格式化中文日期 */
|
||||
function fmtDateCN(d) {
|
||||
return d.getFullYear() + '年' + (d.getMonth() + 1) + '月' + d.getDate() + '日';
|
||||
}
|
||||
|
||||
/* 判断两个日期是否同一天 */
|
||||
function isSameDay(a, b) {
|
||||
return a.getFullYear() === b.getFullYear() &&
|
||||
a.getMonth() === b.getMonth() &&
|
||||
a.getDate() === b.getDate();
|
||||
}
|
||||
|
||||
/* 计算某日的来源类型:汇总所有餐别,全 auto→auto / 全 manual→manual / 混合→mixed */
|
||||
function getDaySource(dateStr) {
|
||||
var data = dayData[dateStr];
|
||||
if (!data || !data.meals) return null;
|
||||
var mealTypes = ['breakfast', 'lunch', 'dinner', 'snack'];
|
||||
var hasAuto = false, hasManual = false;
|
||||
mealTypes.forEach(function(t) {
|
||||
var m = data.meals[t];
|
||||
if (m && m.items && m.items.length > 0) {
|
||||
if (m.source === 'auto') hasAuto = true;
|
||||
else hasManual = true;
|
||||
}
|
||||
});
|
||||
if (!hasAuto && !hasManual) return null;
|
||||
if (hasAuto && hasManual) return 'mixed';
|
||||
return hasAuto ? 'auto' : 'manual';
|
||||
}
|
||||
|
||||
/* 渲染一周日历 */
|
||||
function renderWeek() {
|
||||
var container = document.getElementById('calWeek');
|
||||
container.innerHTML = '';
|
||||
|
||||
var weekDayChars = ['日', '一', '二', '三', '四', '五', '六'];
|
||||
|
||||
for (var i = 0; i < 7; i++) {
|
||||
var d = new Date(currentWeekStart);
|
||||
d.setDate(d.getDate() + i);
|
||||
var dateStr = fmtDate(d);
|
||||
var wd = weekDayChars[d.getDay()];
|
||||
var dayNum = d.getDate();
|
||||
var isToday = isSameDay(d, today);
|
||||
|
||||
var dayEl = document.createElement('div');
|
||||
dayEl.className = 'cal-day' + (isToday ? ' today' : '');
|
||||
dayEl.setAttribute('data-date', dateStr);
|
||||
dayEl.setAttribute('data-wd', wd);
|
||||
dayEl.onclick = function() { selectDay(this); };
|
||||
|
||||
var data = dayData[dateStr];
|
||||
var hasData = data && data.intake !== 0;
|
||||
var daySource = hasData ? getDaySource(dateStr) : null;
|
||||
|
||||
dayEl.innerHTML =
|
||||
'<div class="cal-day__wd">' + wd + '</div>' +
|
||||
'<div class="cal-day__date-wrap">' +
|
||||
(daySource ? '<div class="cal-day__ring cal-day__ring--' + daySource + '"></div>' : '') +
|
||||
'<span class="cal-day__num">' + dayNum + '</span>' +
|
||||
'</div>';
|
||||
|
||||
container.appendChild(dayEl);
|
||||
}
|
||||
|
||||
// 自动选中今天(如果在当前周),否则选中周一
|
||||
var firstDay = container.querySelector('.cal-day.today');
|
||||
if (!firstDay) firstDay = container.querySelector('.cal-day');
|
||||
if (firstDay) selectDay(firstDay);
|
||||
|
||||
// 箭头状态:未来周灰显右箭头
|
||||
var mondayOfThisWeek = getMonday(today);
|
||||
var nextArrow = document.getElementById('calNext');
|
||||
if (currentWeekStart.getTime() >= mondayOfThisWeek.getTime()) {
|
||||
nextArrow.style.opacity = '0.3';
|
||||
nextArrow.style.pointerEvents = 'none';
|
||||
} else {
|
||||
nextArrow.style.opacity = '1';
|
||||
nextArrow.style.pointerEvents = '';
|
||||
}
|
||||
}
|
||||
|
||||
function prevWeek() {
|
||||
currentWeekStart = new Date(currentWeekStart.getTime() - WEEK_MS);
|
||||
renderWeek();
|
||||
}
|
||||
|
||||
function nextWeek() {
|
||||
var mondayOfThisWeek = getMonday(today);
|
||||
if (currentWeekStart.getTime() >= mondayOfThisWeek.getTime()) return;
|
||||
currentWeekStart = new Date(currentWeekStart.getTime() + WEEK_MS);
|
||||
renderWeek();
|
||||
}
|
||||
|
||||
/* ===== 月历弹窗 ===== */
|
||||
var pickerYear = 2026;
|
||||
var pickerMonth = 6; // 0-based (July)
|
||||
|
||||
function toggleMonthPicker() {
|
||||
var picker = document.getElementById('monthPicker');
|
||||
var arrow = document.getElementById('dateArrow');
|
||||
var show = !picker.classList.contains('show');
|
||||
picker.classList.toggle('show', show);
|
||||
arrow.classList.toggle('open', show);
|
||||
if (show) {
|
||||
// 同步到当前选中日期所在月份
|
||||
var selDay = document.querySelector('.cal-day.active');
|
||||
if (selDay) {
|
||||
var d = selDay.getAttribute('data-date').split('-');
|
||||
pickerYear = parseInt(d[0]);
|
||||
pickerMonth = parseInt(d[1]) - 1;
|
||||
}
|
||||
renderMonthGrid();
|
||||
}
|
||||
}
|
||||
|
||||
function prevMonth() {
|
||||
if (pickerMonth === 0) { pickerMonth = 11; pickerYear--; }
|
||||
else { pickerMonth--; }
|
||||
renderMonthGrid();
|
||||
}
|
||||
|
||||
function nextMonth() {
|
||||
if (pickerMonth === 11) { pickerMonth = 0; pickerYear++; }
|
||||
else { pickerMonth++; }
|
||||
renderMonthGrid();
|
||||
}
|
||||
|
||||
function renderMonthGrid() {
|
||||
document.getElementById('monthPickerTitle').textContent = pickerYear + '年' + (pickerMonth + 1) + '月';
|
||||
var grid = document.getElementById('monthGrid');
|
||||
grid.innerHTML = '';
|
||||
|
||||
var firstDay = new Date(pickerYear, pickerMonth, 1).getDay(); // 0=Sun
|
||||
var daysInMonth = new Date(pickerYear, pickerMonth + 1, 0).getDate();
|
||||
|
||||
// 填充上月尾巴
|
||||
var prevDays = new Date(pickerYear, pickerMonth, 0).getDate();
|
||||
for (var i = firstDay - 1; i >= 0; i--) {
|
||||
var el = document.createElement('div');
|
||||
el.className = 'month-picker__day month-picker__day--other';
|
||||
el.textContent = prevDays - i;
|
||||
grid.appendChild(el);
|
||||
}
|
||||
|
||||
// 当月日期
|
||||
var todayStr = fmtDate(today);
|
||||
var selDay = document.querySelector('.cal-day.active');
|
||||
var selStr = selDay ? selDay.getAttribute('data-date') : '';
|
||||
|
||||
for (var d = 1; d <= daysInMonth; d++) {
|
||||
var dateStr = pickerYear + '-' + ('0' + (pickerMonth + 1)).slice(-2) + '-' + ('0' + d).slice(-2);
|
||||
var el = document.createElement('div');
|
||||
var cls = 'month-picker__day';
|
||||
if (dateStr === todayStr) cls += ' month-picker__day--today';
|
||||
if (dateStr === selStr) cls += ' month-picker__day--selected';
|
||||
el.className = cls;
|
||||
// 有记录:日期数字外包来源色圆环
|
||||
var daySource = (dayData[dateStr] && dayData[dateStr].intake !== 0) ? getDaySource(dateStr) : null;
|
||||
if (daySource) {
|
||||
el.innerHTML = '<span class="month-picker__date-wrap">' +
|
||||
'<span class="month-picker__ring month-picker__ring--' + daySource + '"></span>' +
|
||||
d + '</span>';
|
||||
} else {
|
||||
el.textContent = d;
|
||||
}
|
||||
el.onclick = (function(ds) { return function(e) { e.stopPropagation(); pickDay(ds); }; })(dateStr);
|
||||
grid.appendChild(el);
|
||||
}
|
||||
}
|
||||
|
||||
function pickDay(dateStr) {
|
||||
// 关闭弹窗
|
||||
document.getElementById('monthPicker').classList.remove('show');
|
||||
document.getElementById('dateArrow').classList.remove('open');
|
||||
|
||||
// 切换到该日期所在的周
|
||||
var parts = dateStr.split('-');
|
||||
var d = new Date(parseInt(parts[0]), parseInt(parts[1]) - 1, parseInt(parts[2]));
|
||||
currentWeekStart = getMonday(d);
|
||||
renderWeek();
|
||||
|
||||
// 选中该日
|
||||
var target = document.querySelector('.cal-day[data-date="' + dateStr + '"]');
|
||||
if (target) selectDay(target);
|
||||
}
|
||||
|
||||
// 点击外部关闭月历
|
||||
document.addEventListener('click', function(e) {
|
||||
var picker = document.getElementById('monthPicker');
|
||||
if (!picker.classList.contains('show')) return;
|
||||
if (!e.target.closest('.calendar-card__range') && !e.target.closest('#monthPicker')) {
|
||||
picker.classList.remove('show');
|
||||
document.getElementById('dateArrow').classList.remove('open');
|
||||
}
|
||||
});
|
||||
|
||||
/* ===== 计算弧线终点 ===== */
|
||||
// 半圆弧: cx=170, cy=135, r=80。左端点(90,135)角度π,右端点(250,135)角度0。
|
||||
// sweep=1 在 y-down SVG 中从左向右经顶部走。
|
||||
// 进度 progress: 0~1,对应角度 θ = π * (1 - progress)
|
||||
// x = 170 + 80 * cos(π*(1-p)), y = 135 - 80 * sin(π*(1-p))
|
||||
function arcPoint(progress) {
|
||||
var angle = Math.PI * (1 - progress);
|
||||
var x = 170 + 80 * Math.cos(angle);
|
||||
var y = 135 - 80 * Math.sin(angle);
|
||||
return { x: Math.round(x * 10) / 10, y: Math.round(y * 10) / 10 };
|
||||
}
|
||||
|
||||
/* ===== 选中日历天 ===== */
|
||||
function selectDay(el) {
|
||||
document.querySelectorAll('.cal-day').forEach(function(d) { d.classList.remove('active'); });
|
||||
el.classList.add('active');
|
||||
|
||||
var dateStr = el.getAttribute('data-date');
|
||||
|
||||
// 更新顶部日期显示为选中日期
|
||||
var parts = dateStr.split('-');
|
||||
document.getElementById('calRange').textContent = parts[0] + '年' + parseInt(parts[1]) + '月' + parseInt(parts[2]) + '日';
|
||||
|
||||
var data = dayData[dateStr];
|
||||
if (!data) {
|
||||
// 无数据日,清空显示
|
||||
data = { intake: 0, consume: 0, gap: 0 };
|
||||
}
|
||||
|
||||
var gapAbs = Math.abs(data.gap);
|
||||
var maxGap = 500;
|
||||
var progress = data.gap === 0 ? 0 : Math.min(gapAbs / maxGap, 1);
|
||||
|
||||
var pt = arcPoint(progress);
|
||||
var arcD = 'M 90 135 A 80 80 0 0 1 ' + pt.x + ' ' + pt.y;
|
||||
|
||||
var gapArc = document.getElementById('gapArc');
|
||||
gapArc.setAttribute('d', arcD);
|
||||
|
||||
document.getElementById('intakeText').textContent = data.intake === 0 ? '--' : data.intake;
|
||||
document.getElementById('consumeText').textContent = data.consume === 0 ? '--' : data.consume;
|
||||
|
||||
var gapCenter = document.getElementById('gapCenterVal');
|
||||
gapCenter.textContent = data.gap === 0 ? '--' : ('-' + Math.abs(data.gap));
|
||||
|
||||
var colorIntake = data.intake === 0 ? '#bbb' : '#fa8c16';
|
||||
var colorConsume = data.consume === 0 ? '#bbb' : '#52c41a';
|
||||
var colorGap = data.gap === 0 ? '#bbb' : '#fa8c16';
|
||||
document.getElementById('intakeText').setAttribute('fill', colorIntake);
|
||||
document.getElementById('consumeText').setAttribute('fill', colorConsume);
|
||||
gapCenter.setAttribute('fill', colorGap);
|
||||
|
||||
var rightDot = document.querySelector('.gauge-wrap svg circle[cy="135"][cx="250"]');
|
||||
rightDot.setAttribute('fill', data.gap === 0 ? '#bbb' : '#52c41a');
|
||||
|
||||
// 更新餐食卡片
|
||||
renderMeals(dateStr);
|
||||
}
|
||||
|
||||
/* ===== 渲染餐食卡片 ===== */
|
||||
function renderMeals(dateStr) {
|
||||
var data = dayData[dateStr];
|
||||
var meals = data && data.meals;
|
||||
var dietTypes = ['breakfast', 'lunch', 'dinner', 'snack'];
|
||||
|
||||
// 检查是否有任何饮食记录
|
||||
var hasAnyDiet = false;
|
||||
dietTypes.forEach(function(type) {
|
||||
var md = meals ? meals[type] : null;
|
||||
if (md && md.items && md.items.length > 0) hasAnyDiet = true;
|
||||
});
|
||||
|
||||
if (hasAnyDiet) {
|
||||
// 有饮食记录:逐卡片显示/隐藏
|
||||
document.getElementById('cardEmptyDiet').style.display = 'none';
|
||||
dietTypes.forEach(function(type) {
|
||||
var cap = type.charAt(0).toUpperCase() + type.slice(1);
|
||||
var card = document.getElementById('card' + cap);
|
||||
var container = document.getElementById('group' + cap);
|
||||
var kcalEl = document.getElementById('kcal' + cap);
|
||||
var md = meals ? meals[type] : null;
|
||||
|
||||
if (md && md.items && md.items.length > 0) {
|
||||
card.style.display = '';
|
||||
var html = '';
|
||||
md.items.forEach(function(item) {
|
||||
// 来源:item 自带 src 优先,否则回退到餐别 source
|
||||
var src = item.src || md.source || 'manual';
|
||||
var srcLabel = src === 'auto' ? '智记' : '自记';
|
||||
html += '<div class="meal-item">' +
|
||||
'<div class="meal-item__emoji">' + item.e + '</div>' +
|
||||
'<div class="meal-item__info"><div class="meal-item__name">' + item.n + '<span class="meal-item__src meal-item__src--' + src + '">' + srcLabel + '</span></div><div class="meal-item__meta">' + item.m + '</div></div>' +
|
||||
'<div class="meal-item__kcal">' + item.k + ' kcal</div></div>';
|
||||
});
|
||||
container.innerHTML = html;
|
||||
container.style.display = '';
|
||||
kcalEl.textContent = md.kcal;
|
||||
kcalEl.parentElement.style.display = '';
|
||||
} else {
|
||||
card.style.display = 'none';
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 无任何饮食记录:隐藏4张卡片,显示缺省卡片
|
||||
dietTypes.forEach(function(type) {
|
||||
document.getElementById('card' + type.charAt(0).toUpperCase() + type.slice(1)).style.display = 'none';
|
||||
});
|
||||
document.getElementById('cardEmptyDiet').style.display = '';
|
||||
}
|
||||
|
||||
// 运动卡片独立处理
|
||||
var exCard = document.getElementById('cardExercise');
|
||||
var exContainer = document.getElementById('groupExercise');
|
||||
var exKcalEl = document.getElementById('kcalExercise');
|
||||
var exMd = meals ? meals['exercise'] : null;
|
||||
if (exMd && exMd.items && exMd.items.length > 0) {
|
||||
exCard.style.display = '';
|
||||
var html = '';
|
||||
exMd.items.forEach(function(item) {
|
||||
html += '<div class="meal-item meal-item--exercise">' +
|
||||
'<div class="meal-item__emoji">' + item.e + '</div>' +
|
||||
'<div class="meal-item__info"><div class="meal-item__name">' + item.n + '</div><div class="meal-item__meta">' + item.m + '</div></div>' +
|
||||
'<div class="meal-item__kcal">' + item.k + ' kcal</div></div>';
|
||||
});
|
||||
exContainer.innerHTML = html;
|
||||
exContainer.style.display = '';
|
||||
exKcalEl.textContent = exMd.kcal;
|
||||
exKcalEl.parentElement.style.display = '';
|
||||
} else {
|
||||
exCard.style.display = 'none';
|
||||
}
|
||||
|
||||
// 更新营养素三列
|
||||
var macrosRow = document.getElementById('macrosRow');
|
||||
var macros = data && data.macros;
|
||||
if (macros && data.intake !== 0) {
|
||||
macrosRow.classList.remove('hidden');
|
||||
document.getElementById('macroCarb').textContent = macros.carb;
|
||||
document.getElementById('macroCarbBar').style.width = Math.round(macros.carb / macros.carbT * 100) + '%';
|
||||
document.getElementById('macroProtein').textContent = macros.protein;
|
||||
document.getElementById('macroProteinBar').style.width = Math.round(macros.protein / macros.proteinT * 100) + '%';
|
||||
document.getElementById('macroFat').textContent = macros.fat;
|
||||
document.getElementById('macroFatBar').style.width = Math.round(macros.fat / macros.fatT * 100) + '%';
|
||||
} else {
|
||||
macrosRow.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
function toggleMeal(type, headerEl) {
|
||||
var items = document.getElementById('group' + type.charAt(0).toUpperCase() + type.slice(1));
|
||||
var expand = headerEl.querySelector('.meal-card__expand');
|
||||
if (items.style.display === 'none') {
|
||||
items.style.display = '';
|
||||
expand.classList.remove('open');
|
||||
} else {
|
||||
items.style.display = 'none';
|
||||
expand.classList.add('open');
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== 工具栏按钮 ===== */
|
||||
function addMeal(type) {
|
||||
location.href = 'eat-checkin-v2.html?meal=' + type;
|
||||
}
|
||||
|
||||
/* ===== 初始化 ===== */
|
||||
renderWeek();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,357 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>拍照录入 - 员工端 | 健康CQ原型 v2</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: #000; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; display: flex; flex-direction: column; position: relative; }
|
||||
|
||||
/* ===== 头栏 ===== */
|
||||
.scan-header { height: 50px; display: flex; align-items: center; justify-content: space-between; padding: 0 12px; flex-shrink: 0; }
|
||||
.scan-close { width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; color: #fff; cursor: pointer; font-size: 20px; }
|
||||
.scan-title { font-size: 16px; font-weight: 600; color: #fff; }
|
||||
.scan-flash { width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; color: #fff; cursor: pointer; }
|
||||
|
||||
/* ===== 内容区 ===== */
|
||||
.scan-body { flex: 1; display: flex; flex-direction: column; overflow: hidden; }
|
||||
|
||||
/* —— 拍照入口 —— */
|
||||
.camera-area { display: flex; flex-direction: column; align-items: center; justify-content: center; flex: 1; padding: 0; }
|
||||
.camera-area.hidden { display: none; }
|
||||
.camera-frame { width: 320px; height: 360px; border-radius: 20px; background: #1a1a2e; display: flex; align-items: center; justify-content: center; overflow: hidden; border: 2px dashed rgba(255,255,255,0.15); }
|
||||
.camera-placeholder { text-align: center; color: rgba(255,255,255,0.4); }
|
||||
.camera-placeholder svg { width: 64px; height: 64px; margin-bottom: 12px; display: block; margin-left: auto; margin-right: auto; }
|
||||
.camera-placeholder span { font-size: 14px; display: block; }
|
||||
.camera-hint { color: rgba(255,255,255,0.45); font-size: 13px; margin-top: 24px; text-align: center; }
|
||||
.camera-footer { padding: 0 16px 36px; display: flex; align-items: center; justify-content: center; gap: 48px; flex-shrink: 0; }
|
||||
.camera-footer.hidden { display: none; }
|
||||
.camera-btn-gallery { width: 44px; height: 44px; border-radius: 12px; background: rgba(255,255,255,0.12); border: 1.5px solid rgba(255,255,255,0.25); color: #fff; cursor: pointer; display: flex; align-items: center; justify-content: center; }
|
||||
.camera-btn-gallery svg { width: 24px; height: 24px; }
|
||||
.camera-btn-gallery:active { background: rgba(255,255,255,0.22); }
|
||||
.camera-btn-capture { width: 64px; height: 64px; border-radius: 50%; border: 4px solid #fff; background: transparent; cursor: pointer; position: relative; }
|
||||
.camera-btn-capture::after { content: ''; position: absolute; inset: 6px; border-radius: 50%; background: #fff; }
|
||||
.camera-btn-capture:active::after { background: #ddd; }
|
||||
|
||||
/* —— 分析中 —— */
|
||||
.analyzing-area { display: none; flex-direction: column; flex: 1; }
|
||||
.analyzing-area.show { display: flex; }
|
||||
.analyzing-photo { width: 100%; height: 360px; object-fit: cover; flex-shrink: 0; }
|
||||
.analyzing-info { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 24px 32px; }
|
||||
.analyzing-icon { width: 56px; height: 56px; border-radius: 50%; background: linear-gradient(160deg, #6ee16e, #3ec46a); display: flex; align-items: center; justify-content: center; margin-bottom: 18px; animation: pulse 1.5s ease-in-out infinite; }
|
||||
@keyframes pulse { 0%,100% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.1); opacity: 0.8; } }
|
||||
.analyzing-icon svg { width: 26px; height: 26px; color: #fff; }
|
||||
.analyzing-text { font-size: 15px; font-weight: 600; color: #fff; margin-bottom: 18px; }
|
||||
.analyzing-bar-wrap { width: 100%; height: 5px; border-radius: 3px; background: rgba(255,255,255,0.12); overflow: hidden; }
|
||||
.analyzing-bar { height: 100%; border-radius: 3px; background: linear-gradient(90deg, #6ee16e, #36cfc9); width: 0%; transition: width .25s ease; }
|
||||
.analyzing-sub { font-size: 12px; color: rgba(255,255,255,0.35); margin-top: 10px; }
|
||||
.analyzing-cancel { margin-top: 24px; padding: 8px 24px; border-radius: 16px; border: 1px solid rgba(255,255,255,0.25); background: transparent; color: rgba(255,255,255,0.5); font-size: 12px; cursor: pointer; }
|
||||
.analyzing-cancel:active { background: rgba(255,255,255,0.08); }
|
||||
|
||||
/* ===== 底部结果弹窗 ===== */
|
||||
.result-mask { display: none; position: absolute; inset: 0; background: rgba(0,0,0,0.6); z-index: 50; }
|
||||
.result-mask.show { display: block; }
|
||||
.result-panel { position: absolute; bottom: 0; left: 0; right: 0; background: #141420; border-radius: 20px 20px 0 0; padding: 20px 18px 30px; z-index: 51; transform: translateY(100%); transition: transform .3s ease; }
|
||||
.result-mask.show .result-panel { transform: translateY(0); }
|
||||
.result-handle { width: 36px; height: 4px; background: rgba(255,255,255,0.2); border-radius: 2px; margin: 0 auto 16px; }
|
||||
.result-food-row { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 14px; }
|
||||
.result-food-thumb { width: 52px; height: 52px; border-radius: 12px; background: rgba(255,255,255,0.06); display: flex; align-items: center; justify-content: center; font-size: 30px; flex-shrink: 0; }
|
||||
.result-food-info { flex: 1; min-width: 0; }
|
||||
.result-food-name { font-size: 17px; font-weight: 700; color: #fff; margin-bottom: 3px; }
|
||||
.result-food-meta { font-size: 12px; color: rgba(255,255,255,0.4); }
|
||||
.result-food-meta em { font-style: normal; color: #fa8c16; font-weight: 700; }
|
||||
.result-meal-select { flex-shrink: 0; position: relative; }
|
||||
.result-meal-select select { height: 30px; padding: 0 24px 0 8px; border: 1px solid rgba(255,255,255,0.2); border-radius: 8px; background: rgba(255,255,255,0.06); color: #fff; font-size: 12px; font-weight: 600; cursor: pointer; appearance: none; outline: none; }
|
||||
.result-meal-select::after { content: '▾'; position: absolute; right: 8px; top: 50%; transform: translateY(-50%); color: rgba(255,255,255,0.4); font-size: 10px; pointer-events: none; }
|
||||
.result-advice { margin-bottom: 14px; padding: 10px 12px; background: rgba(54,207,201,0.06); border-radius: 10px; border-left: 3px solid #36cfc9; }
|
||||
.result-advice__title { font-size: 12px; font-weight: 700; color: #36cfc9; margin-bottom: 4px; }
|
||||
.result-advice__text { font-size: 12px; color: rgba(255,255,255,0.55); line-height: 1.5; }
|
||||
.result-divider { height: 1px; background: rgba(255,255,255,0.06); margin-bottom: 14px; }
|
||||
.result-label { font-size: 13px; font-weight: 600; color: rgba(255,255,255,0.5); margin-bottom: 10px; }
|
||||
.result-gram-row { display: flex; align-items: center; gap: 0; margin-bottom: 14px; }
|
||||
.result-gram-btn { width: 44px; height: 44px; border: 1.5px solid rgba(255,255,255,0.15); background: rgba(255,255,255,0.04); color: #fff; font-size: 22px; cursor: pointer; display: flex; align-items: center; justify-content: center; }
|
||||
.result-gram-btn:first-child { border-radius: 10px 0 0 10px; }
|
||||
.result-gram-btn:last-child { border-radius: 0 10px 10px 0; }
|
||||
.result-gram-btn:active { background: rgba(255,255,255,0.1); }
|
||||
.result-gram-input { width: 90px; height: 44px; border: 1.5px solid rgba(255,255,255,0.15); border-left: none; border-right: none; background: transparent; text-align: center; font-size: 22px; font-weight: 700; color: #fff; outline: none; }
|
||||
.result-gram-unit { font-size: 14px; color: rgba(255,255,255,0.3); margin-left: 10px; }
|
||||
.result-kcal-box { text-align: center; padding: 12px; background: rgba(255,255,255,0.04); border-radius: 10px; margin-bottom: 18px; }
|
||||
.result-kcal-box span { font-size: 13px; color: rgba(255,255,255,0.4); }
|
||||
.result-kcal-box em { font-style: normal; font-weight: 800; color: #fa8c16; font-size: 22px; }
|
||||
.result-submit { width: 100%; height: 46px; border: none; border-radius: 23px; background: linear-gradient(160deg, #6ee16e, #3ec46a); color: #fff; font-size: 16px; font-weight: 700; cursor: pointer; }
|
||||
.result-submit: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: 100; pointer-events: none; opacity: 0; transition: all .25s ease; white-space: nowrap; }
|
||||
.toast.show { opacity: 1; transform: translate(-50%, -50%) scale(1); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
|
||||
<div class="scan-header">
|
||||
<div class="scan-close" onclick="history.back()">✕</div>
|
||||
<div class="scan-title">拍照识别</div>
|
||||
<div class="scan-flash" onclick="showToast('闪光灯')">⚡</div>
|
||||
</div>
|
||||
|
||||
<div class="scan-body">
|
||||
|
||||
<!-- 拍照入口 -->
|
||||
<div class="camera-area" id="cameraArea">
|
||||
<div class="camera-frame">
|
||||
<div class="camera-placeholder" id="camPlaceholder">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/><circle cx="12" cy="13" r="4"/></svg>
|
||||
<span>将餐品对准框内</span>
|
||||
</div>
|
||||
<input type="file" id="camFileInput" accept="image/*" style="display:none;" onchange="handleFilePicked(event)">
|
||||
</div>
|
||||
<div class="camera-hint">点击拍照或从相册选择</div>
|
||||
</div>
|
||||
|
||||
<!-- 拍照入口底部按钮 -->
|
||||
<div class="camera-footer" id="cameraFooter">
|
||||
<div class="camera-btn-gallery" onclick="pickFromGallery()">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
|
||||
</div>
|
||||
<button class="camera-btn-capture" onclick="takePhoto()"></button>
|
||||
<div style="width:44px;"></div>
|
||||
</div>
|
||||
|
||||
<!-- 分析中 -->
|
||||
<div class="analyzing-area" id="analyzingArea">
|
||||
<img class="analyzing-photo" id="analyzingPhoto" alt="">
|
||||
<div class="analyzing-info">
|
||||
<div class="analyzing-icon">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||
</div>
|
||||
<div class="analyzing-text">AI 正在识别餐品...</div>
|
||||
<div class="analyzing-bar-wrap">
|
||||
<div class="analyzing-bar" id="analyzingBar"></div>
|
||||
</div>
|
||||
<div class="analyzing-sub" id="analyzingSub">正在分析图像特征...</div>
|
||||
<button class="analyzing-cancel" onclick="cancelAnalyze()">取消</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 底部结果弹窗 -->
|
||||
<div class="result-mask" id="resultMask">
|
||||
<div class="result-panel" id="resultPanel" onclick="event.stopPropagation()">
|
||||
<div class="result-handle"></div>
|
||||
<div class="result-food-row">
|
||||
<div class="result-food-thumb" id="resultEmoji">🍚</div>
|
||||
<div class="result-food-info">
|
||||
<div class="result-food-name" id="resultName">白米饭</div>
|
||||
<div class="result-food-meta">每100g 约 <em id="resultKcalRef">116</em> 千卡</div>
|
||||
</div>
|
||||
<div class="result-meal-select">
|
||||
<select id="resultMeal" onchange="onMealChange()">
|
||||
<option value="breakfast">早餐</option>
|
||||
<option value="lunch">午餐</option>
|
||||
<option value="dinner">晚餐</option>
|
||||
<option value="snack">加餐</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="result-advice">
|
||||
<div class="result-advice__title">💡 饮食建议</div>
|
||||
<div class="result-advice__text" id="resultAdvice">建议搭配蔬菜和优质蛋白质一起食用,控制总热量摄入。</div>
|
||||
</div>
|
||||
<div class="result-divider"></div>
|
||||
<div class="result-label">录入克数</div>
|
||||
<div class="result-gram-row">
|
||||
<button class="result-gram-btn" onclick="adjustGram(-10)">−</button>
|
||||
<input class="result-gram-input" type="number" id="gramInput" value="150" min="1" max="5000" oninput="updateCalorie()">
|
||||
<button class="result-gram-btn" onclick="adjustGram(10)">+</button>
|
||||
<span class="result-gram-unit">克</span>
|
||||
</div>
|
||||
<div class="result-kcal-box">
|
||||
<span>预估热量 </span><em id="resultCalorie">174</em><span> 千卡</span>
|
||||
</div>
|
||||
<button class="result-submit" onclick="confirmAdd()">一键录入</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Toast -->
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* ===== 餐品数据 ===== */
|
||||
var foodData = {
|
||||
common: { name:'常用', items:[
|
||||
{id:'c1',name:'白米饭',kcal:116,weight:'100g',emoji:'🍚'},{id:'c2',name:'水煮鸡蛋',kcal:80,weight:'约50g/个',emoji:'🥚'},{id:'c3',name:'纯牛奶',kcal:120,weight:'250ml',emoji:'🥛'},{id:'c4',name:'全麦面包',kcal:60,weight:'约40g/片',emoji:'🍞'},{id:'c5',name:'苹果',kcal:66,weight:'约200g/个',emoji:'🍎'},{id:'c6',name:'鸡胸肉',kcal:133,weight:'100g',emoji:'🐔'},{id:'c7',name:'清炒时蔬',kcal:50,weight:'约200g',emoji:'🥬'},{id:'c8',name:'豆浆',kcal:90,weight:'300ml',emoji:'🥤'}
|
||||
]},
|
||||
staple: { name:'主食', items:[
|
||||
{id:'s1',name:'白米饭',kcal:116,weight:'100g',emoji:'🍚'},{id:'s2',name:'杂粮饭',kcal:110,weight:'100g',emoji:'🍚'},{id:'s3',name:'全麦面包',kcal:60,weight:'约40g/片',emoji:'🍞'},{id:'s4',name:'白馒头',kcal:120,weight:'约80g/个',emoji:'🥟'},{id:'s5',name:'面条',kcal:140,weight:'约200g',emoji:'🍜'},{id:'s6',name:'蒸红薯',kcal:40,weight:'约100g',emoji:'🍠'},{id:'s7',name:'玉米',kcal:112,weight:'约200g/根',emoji:'🌽'},{id:'s8',name:'小米粥',kcal:46,weight:'约250g',emoji:'🥣'},{id:'s9',name:'燕麦片',kcal:130,weight:'约35g/份',emoji:'🥣'},{id:'s10',name:'包子(肉)',kcal:180,weight:'约100g/个',emoji:'🥟'}
|
||||
]},
|
||||
meat: { name:'肉蛋奶', items:[
|
||||
{id:'m1',name:'鸡胸肉',kcal:133,weight:'100g',emoji:'🐔'},{id:'m2',name:'水煮鸡蛋',kcal:80,weight:'约50g/个',emoji:'🥚'},{id:'m3',name:'纯牛奶',kcal:120,weight:'250ml',emoji:'🥛'},{id:'m4',name:'牛肉(瘦)',kcal:125,weight:'100g',emoji:'🥩'},{id:'m5',name:'猪瘦肉',kcal:143,weight:'100g',emoji:'🥩'},{id:'m6',name:'宫保鸡丁',kcal:148,weight:'约150g',emoji:'🐔'},{id:'m7',name:'清蒸鱼',kcal:130,weight:'约150g',emoji:'🐟'},{id:'m8',name:'虾仁',kcal:48,weight:'100g',emoji:'🦐'},{id:'m9',name:'豆浆',kcal:90,weight:'300ml',emoji:'🥤'},{id:'m10',name:'酸奶',kcal:72,weight:'100g',emoji:'🥛'}
|
||||
]},
|
||||
vegetable: { name:'蔬菜', items:[
|
||||
{id:'v1',name:'清炒时蔬',kcal:50,weight:'约200g',emoji:'🥬'},{id:'v2',name:'西兰花',kcal:36,weight:'100g',emoji:'🥦'},{id:'v3',name:'番茄炒蛋',kcal:85,weight:'约150g',emoji:'🍅'},{id:'v4',name:'凉拌黄瓜',kcal:100,weight:'约200g',emoji:'🥒'},{id:'v5',name:'蒜蓉菠菜',kcal:100,weight:'约200g',emoji:'🥬'},{id:'v6',name:'炒青菜',kcal:78,weight:'约200g',emoji:'🥬'},{id:'v7',name:'鸡胸肉沙拉',kcal:180,weight:'约250g',emoji:'🥗'},{id:'v8',name:'凯撒沙拉',kcal:220,weight:'约250g',emoji:'🥗'},{id:'v9',name:'酸辣土豆丝',kcal:120,weight:'约150g',emoji:'🥔'},{id:'v10',name:'蒸茄子',kcal:35,weight:'约150g',emoji:'🍆'}
|
||||
]},
|
||||
fruit: { name:'水果', items:[
|
||||
{id:'f1',name:'苹果',kcal:66,weight:'约200g/个',emoji:'🍎'},{id:'f2',name:'香蕉',kcal:60,weight:'约120g/根',emoji:'🍌'},{id:'f3',name:'橙子',kcal:48,weight:'约200g/个',emoji:'🍊'},{id:'f4',name:'小番茄',kcal:9,weight:'约20g/颗',emoji:'🍅'},{id:'f5',name:'葡萄',kcal:36,weight:'约100g',emoji:'🍇'},{id:'f6',name:'西瓜',kcal:31,weight:'100g',emoji:'🍉'},{id:'f7',name:'草莓',kcal:32,weight:'100g',emoji:'🍓'},{id:'f8',name:'蓝莓',kcal:57,weight:'100g',emoji:'🫐'}
|
||||
]},
|
||||
drink: { name:'饮品', items:[
|
||||
{id:'d1',name:'纯牛奶',kcal:120,weight:'250ml',emoji:'🥛'},{id:'d2',name:'豆浆',kcal:90,weight:'300ml',emoji:'🥤'},{id:'d3',name:'酸奶',kcal:72,weight:'100g',emoji:'🥛'},{id:'d4',name:'黑咖啡',kcal:5,weight:'约250ml',emoji:'☕'},{id:'d5',name:'拿铁',kcal:150,weight:'约350ml',emoji:'☕'},{id:'d6',name:'橙汁',kcal:112,weight:'约300ml',emoji:'🧃'},{id:'d7',name:'绿茶',kcal:0,weight:'约300ml',emoji:'🍵'},{id:'d8',name:'运动饮料',kcal:80,weight:'约500ml',emoji:'🧃'}
|
||||
]},
|
||||
snack: { name:'零食', items:[
|
||||
{id:'sk1',name:'坚果',kcal:80,weight:'约20g/把',emoji:'🥜'},{id:'sk2',name:'香蕉',kcal:60,weight:'约120g/根',emoji:'🍌'},{id:'sk3',name:'苹果',kcal:66,weight:'约200g/个',emoji:'🍎'},{id:'sk4',name:'黄瓜',kcal:15,weight:'约200g/根',emoji:'🥒'},{id:'sk5',name:'小番茄',kcal:45,weight:'约100g',emoji:'🍅'},{id:'sk6',name:'全麦饼干',kcal:120,weight:'约30g/包',emoji:'🍪'},{id:'sk7',name:'蒸红薯',kcal:40,weight:'约100g',emoji:'🍠'},{id:'sk8',name:'酸奶',kcal:72,weight:'100g',emoji:'🥛'}
|
||||
]}
|
||||
};
|
||||
|
||||
var scanResultDish = null;
|
||||
var analyzeTimer = null;
|
||||
var resultMeal = 'breakfast';
|
||||
|
||||
/* ===== 拍照 ===== */
|
||||
function takePhoto() {
|
||||
var colors = ['#e8f5e9','#fff3e0','#e3f2fd','#fce4ec','#f3e5f5','#fff8e1','#e0f2f1','#fbe9e7'];
|
||||
var color = colors[Math.floor(Math.random()*colors.length)];
|
||||
var c = document.createElement('canvas');
|
||||
c.width = 320; c.height = 360;
|
||||
var ctx = c.getContext('2d');
|
||||
ctx.fillStyle = color; ctx.fillRect(0,0,320,360);
|
||||
ctx.fillStyle = 'rgba(255,255,255,0.5)';
|
||||
ctx.beginPath(); ctx.arc(160,170,90,0,Math.PI*2); ctx.fill();
|
||||
ctx.fillStyle = 'rgba(0,0,0,0.05)';
|
||||
ctx.beginPath(); ctx.arc(160,170,65,0,Math.PI*2); ctx.fill();
|
||||
ctx.fillStyle = 'rgba(0,0,0,0.12)'; ctx.font = '20px sans-serif'; ctx.textAlign = 'center';
|
||||
ctx.fillText('🍽️', 160, 178);
|
||||
|
||||
startAnalyze(c.toDataURL('image/png'));
|
||||
}
|
||||
|
||||
function pickFromGallery() { document.getElementById('camFileInput').click(); }
|
||||
|
||||
function handleFilePicked(e) {
|
||||
var f = e.target.files[0]; if (!f) return;
|
||||
var r = new FileReader();
|
||||
r.onload = function(ev) { startAnalyze(ev.target.result); };
|
||||
r.readAsDataURL(f);
|
||||
}
|
||||
|
||||
/* ===== 开始分析 ===== */
|
||||
function startAnalyze(imgSrc) {
|
||||
// 隐藏拍照入口,显示分析区
|
||||
document.getElementById('cameraArea').classList.add('hidden');
|
||||
document.getElementById('cameraFooter').classList.add('hidden');
|
||||
document.getElementById('analyzingArea').classList.add('show');
|
||||
|
||||
document.getElementById('analyzingPhoto').src = imgSrc;
|
||||
var bar = document.getElementById('analyzingBar');
|
||||
var sub = document.getElementById('analyzingSub');
|
||||
var phases = ['正在分析图像特征...', '正在匹配食物数据库...', '正在计算营养信息...'];
|
||||
bar.style.width = '0%';
|
||||
sub.textContent = phases[0];
|
||||
|
||||
var progress = 0, phaseIdx = 0;
|
||||
analyzeTimer = setInterval(function() {
|
||||
progress += Math.random()*18 + 8;
|
||||
if (progress >= 100) {
|
||||
progress = 100; clearInterval(analyzeTimer); analyzeTimer = null;
|
||||
bar.style.width = '100%';
|
||||
sub.textContent = '识别完成';
|
||||
setTimeout(function() { showResult(); }, 400);
|
||||
} else {
|
||||
bar.style.width = progress + '%';
|
||||
var newPhase = progress > 60 ? 2 : (progress > 30 ? 1 : 0);
|
||||
if (newPhase !== phaseIdx) { phaseIdx = newPhase; sub.textContent = phases[phaseIdx]; }
|
||||
}
|
||||
}, 350);
|
||||
}
|
||||
|
||||
function cancelAnalyze() {
|
||||
if (analyzeTimer) { clearInterval(analyzeTimer); analyzeTimer = null; }
|
||||
resetToCamera();
|
||||
}
|
||||
|
||||
function resetToCamera() {
|
||||
document.getElementById('analyzingArea').classList.remove('show');
|
||||
document.getElementById('cameraArea').classList.remove('hidden');
|
||||
document.getElementById('cameraFooter').classList.remove('hidden');
|
||||
document.getElementById('resultMask').classList.remove('show');
|
||||
document.getElementById('camFileInput').value = '';
|
||||
scanResultDish = null;
|
||||
}
|
||||
|
||||
/* ===== 显示结果(底部弹窗) ===== */
|
||||
function showResult() {
|
||||
// 固定可识别餐品池,每项有专属建议
|
||||
var pool = [
|
||||
{ name:'肉夹馍', kcal:228, emoji:'🥙', advice:'肉夹馍热量较高,约228千卡/100g,作为减重期早餐建议控制在半个(约120g)。搭配无糖豆浆补充优质蛋白,再配一份凉拌黄瓜增加膳食纤维,更有饱腹感。' },
|
||||
{ name:'白米饭', kcal:116, emoji:'🍚', advice:'白米饭升糖指数较高,建议减重期每餐控制在150g以内。可搭配鸡胸肉和清炒时蔬,先吃菜再吃饭,有助于延缓血糖上升、减少脂肪堆积。' },
|
||||
{ name:'宫保鸡丁', kcal:148, emoji:'🐔', advice:'宫保鸡丁含油量偏高,建议要求少油烹饪。搭配杂粮饭和一份白灼青菜,平衡油脂摄入。午餐食用为宜,晚餐尽量避免油炸类菜肴。' },
|
||||
{ name:'全麦面包', kcal:60, emoji:'🍞', advice:'全麦面包富含膳食纤维,是优质的减脂主食。早餐搭配水煮蛋和纯牛奶,营养均衡又能延长饱腹感。建议选择无糖无油的全麦配方。' },
|
||||
{ name:'鸡胸肉沙拉', kcal:180, emoji:'🥗', advice:'鸡胸肉沙拉高蛋白低脂肪,是减重期理想的午餐选择。注意沙拉酱热量较高,建议用油醋汁替代,或只用少量调味。搭配一片全麦面包更饱腹。' },
|
||||
{ name:'香蕉', kcal:60, emoji:'🍌', advice:'香蕉富含钾和碳水化合物,适合运动前后补充能量。减重期建议上午或运动前食用,每次一根即可,避免晚餐后食用以免糖分堆积。' },
|
||||
{ name:'牛肉面', kcal:190, emoji:'🍜', advice:'牛肉面热量中等但钠含量较高,建议喝汤适量。搭配一份清炒蔬菜平衡营养,面条控制在200g以内。减重期建议中午食用,晚餐尽量清淡。' },
|
||||
{ name:'蒸红薯', kcal:40, emoji:'🍠', advice:'红薯是优质粗粮,低热量高纤维,饱腹感强。适合替代精米白面作为主食,但一次不超过200g。搭配鸡蛋或牛奶补充蛋白质,营养更全面。' },
|
||||
{ name:'坚果', kcal:80, emoji:'🥜', advice:'坚果虽小热量密度高,每日建议不超过20g(约一小把)。作为加餐能提供优质脂肪和饱腹感,但需控制总量。推荐原味坚果,避免盐焗或糖渍品种。' },
|
||||
{ name:'苹果', kcal:66, emoji:'🍎', advice:'苹果富含果胶和膳食纤维,是理想的两餐之间加餐。一个中等苹果约200g,热量仅66千卡,能有效缓解饥饿感。建议连皮食用,营养更丰富。' }
|
||||
];
|
||||
var pick = pool[Math.floor(Math.random()*pool.length)];
|
||||
scanResultDish = pick;
|
||||
|
||||
document.getElementById('resultEmoji').textContent = pick.emoji;
|
||||
document.getElementById('resultName').textContent = pick.name;
|
||||
document.getElementById('resultKcalRef').textContent = pick.kcal;
|
||||
document.getElementById('resultMeal').value = 'breakfast';
|
||||
resultMeal = 'breakfast';
|
||||
document.getElementById('gramInput').value = 150;
|
||||
document.getElementById('resultAdvice').textContent = pick.advice;
|
||||
document.getElementById('resultMask').classList.add('show');
|
||||
updateCalorie();
|
||||
}
|
||||
|
||||
/* ===== 饮食建议已内嵌在餐品池中,无需单独函数 ===== */
|
||||
function onMealChange() {
|
||||
resultMeal = document.getElementById('resultMeal').value;
|
||||
}
|
||||
|
||||
/* ===== 关闭结果弹窗 → 回到相机 ===== */
|
||||
function closeResult() {
|
||||
document.getElementById('resultMask').classList.remove('show');
|
||||
}
|
||||
|
||||
/* ===== 克数调整 ===== */
|
||||
function adjustGram(delta) {
|
||||
var inp = document.getElementById('gramInput');
|
||||
var v = parseInt(inp.value)||150; v += delta;
|
||||
if (v<1) v=1; if (v>5000) v=5000;
|
||||
inp.value = v; updateCalorie();
|
||||
}
|
||||
|
||||
function updateCalorie() {
|
||||
if (!scanResultDish) return;
|
||||
var g = parseInt(document.getElementById('gramInput').value)||0;
|
||||
document.getElementById('resultCalorie').textContent = Math.round(scanResultDish.kcal*g/100);
|
||||
}
|
||||
|
||||
/* ===== 一键录入 → 返回来源页 ===== */
|
||||
function confirmAdd() {
|
||||
if (!scanResultDish) return;
|
||||
var grams = parseInt(document.getElementById('gramInput').value)||150;
|
||||
var kcal = Math.round(scanResultDish.kcal*grams/100);
|
||||
showToast('已录入「' + scanResultDish.name + '」' + grams + 'g,' + kcal + ' 千卡');
|
||||
setTimeout(function() { history.go(-2); }, 1000);
|
||||
}
|
||||
|
||||
/* Toast */
|
||||
var toastTimer;
|
||||
function showToast(msg) {
|
||||
var t = document.getElementById('toast');
|
||||
t.textContent = msg; t.classList.add('show');
|
||||
clearTimeout(toastTimer);
|
||||
toastTimer = setTimeout(function() { t.classList.remove('show'); }, 1800);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -97,7 +97,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
.weight-chart svg { width: 100%; height: auto; display: block; }
|
||||
|
||||
/* ===== 运动记录卡片 ===== */
|
||||
.move-card { background: #fff; border-radius: 16px; margin: 12px 12px 0; padding: 16px 16px 14px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
|
||||
.move-card { background: #fff; border-radius: 16px; margin: 12px 12px 0; padding: 16px 16px 14px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); cursor: pointer; }
|
||||
.move-card__header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
|
||||
.move-card__title { font-size: 16px; font-weight: 800; color: #1a1a1a; }
|
||||
.move-card__add { width: 30px; height: 30px; border-radius: 50%; background: linear-gradient(160deg, #ffb066, #ff8a3d); display: flex; align-items: center; justify-content: center; cursor: pointer; border: none; box-shadow: 0 2px 8px rgba(255,138,61,0.3); }
|
||||
@@ -278,8 +278,8 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
</div>
|
||||
|
||||
<!-- ====== 热量缺口卡片 ====== -->
|
||||
<div class="gap-card" onclick="location.href='eat-checkin-v2.html'">
|
||||
<div class="gap-card__title"><span>热量缺口</span><span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></span></div>
|
||||
<div class="gap-card" onclick="location.href='eat-detail-v2.html'">
|
||||
<div class="gap-card__title"><span>吃动平衡</span><span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></span></div>
|
||||
|
||||
<!-- 本周日历 -->
|
||||
<div class="gap-week" id="gapWeek">
|
||||
@@ -323,7 +323,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
<!-- 当日热量统计 -->
|
||||
<div class="gap-stats">
|
||||
<div class="gap-stat">
|
||||
<span class="gap-stat__label">当前缺口</span>
|
||||
<span class="gap-stat__label">吃动热量差</span>
|
||||
<span class="gap-stat__val gap-stat__val--good">-364<span class="gap-stat__unit"> / -500 千卡</span></span>
|
||||
</div>
|
||||
<div style="display:flex;gap:8px;">
|
||||
@@ -340,7 +340,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
</div>
|
||||
|
||||
<!-- ====== 吃记录卡片 ====== -->
|
||||
<div class="eat-card" onclick="location.href='eat-checkin-v2.html'">
|
||||
<div class="eat-card" onclick="location.href='eat-detail-v2.html'">
|
||||
<div class="eat-card__header">
|
||||
<span class="eat-card__title">吃记录</span>
|
||||
<div style="display:flex;align-items:center;gap:8px;">
|
||||
@@ -397,10 +397,10 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
</div>
|
||||
|
||||
<!-- ====== 运动记录卡片 ====== -->
|
||||
<div class="move-card">
|
||||
<div class="move-card" onclick="location.href='exercise-detail-v2.html'">
|
||||
<div class="move-card__header">
|
||||
<span class="move-card__title">动记录</span>
|
||||
<button class="move-card__add" onclick="location.href='exercise-checkin.html'">
|
||||
<button class="move-card__add" onclick="event.stopPropagation();location.href='exercise-checkin.html'">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
@@ -441,15 +441,15 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
</div>
|
||||
|
||||
<!-- ====== 体重记录卡片 ====== -->
|
||||
<div class="weight-card">
|
||||
<div class="weight-card" style="cursor:pointer;" onclick="location.href='weight-detail-v2.html'">
|
||||
<div class="weight-card__header">
|
||||
<span class="weight-card__title">体重记录</span>
|
||||
<div style="display:flex;align-items:center;gap:8px;">
|
||||
<button style="padding:5px 12px;border-radius:14px;border:none;background:linear-gradient(160deg,#b08cff,#8b6cff);color:#fff;font-size:12px;font-weight:600;cursor:pointer;box-shadow:0 2px 8px rgba(139,108,255,0.3);display:flex;align-items:center;gap:4px;" onclick="location.href='../bluetooth-scale-miniprogram/main.html'">
|
||||
<button style="padding:5px 12px;border-radius:14px;border:none;background:linear-gradient(160deg,#b08cff,#8b6cff);color:#fff;font-size:12px;font-weight:600;cursor:pointer;box-shadow:0 2px 8px rgba(139,108,255,0.3);display:flex;align-items:center;gap:4px;" onclick="event.stopPropagation();location.href='../bluetooth-scale-miniprogram/main.html'">
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><path d="M14.24 12.01l2.32 2.32c.28-.72.44-1.51.44-2.33 0-.82-.16-1.59-.43-2.31l-2.33 2.32zm5.29-5.3l-1.26 1.26c.63 1.21.98 2.57.98 4.02s-.36 2.82-.98 4.02l1.2 1.2c.97-1.54 1.54-3.36 1.54-5.31-.01-1.89-.55-3.67-1.48-5.19zm-3.82 1L10 2H9v7.59L4.41 5 3 6.41 8.59 12 3 17.59 4.41 19 9 14.41V22h1l5.71-5.71-4.3-4.29 4.3-4.29zM11 5.83l1.88 1.88L11 9.59V5.83zm1.88 10.46L11 18.17v-3.76l1.88 1.88z"/></svg>
|
||||
蓝牙称
|
||||
</button>
|
||||
<button class="weight-card__add" onclick="location.href='weight-checkin.html'">
|
||||
<button class="weight-card__add" onclick="event.stopPropagation();location.href='weight-checkin.html'">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user