356 lines
15 KiB
HTML
356 lines
15 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>运动日志 | Fitness Diary</title>
|
||
<link rel="stylesheet" href="style.css">
|
||
</head>
|
||
<body>
|
||
|
||
<div class="container">
|
||
<div class="tool-tabs">
|
||
<button class="tab-btn active" data-tab="records">记录</button>
|
||
<button class="tab-btn" data-tab="weekly">本周剩余</button>
|
||
<button class="tab-btn" data-tab="calendar">日历</button>
|
||
<button class="tab-btn" data-tab="stats">统计</button>
|
||
<button class="tab-btn" data-tab="screen">运动大屏</button>
|
||
<button class="tab-btn" data-tab="settings">设置</button>
|
||
</div>
|
||
|
||
<section id="section-records" class="tab-content active">
|
||
<div class="stats-cards">
|
||
<div class="stat-card" style="background: linear-gradient(135deg, #00a8ff 0%, #4cdfff 100%);">
|
||
<div class="stat-label">本周总千卡</div>
|
||
<div class="stat-value" id="stat-calories">0</div>
|
||
<div class="stat-icon">🔥 运动能量</div>
|
||
</div>
|
||
<div class="stat-card" style="background: linear-gradient(135deg, #00d8a7 0%, #00e6b8 100%);">
|
||
<div class="stat-label">运动时长</div>
|
||
<div class="stat-value" id="stat-duration">0<span style="font-size: 16px;">分钟</span></div>
|
||
<div class="stat-icon">⏱️ 坚持时间</div>
|
||
</div>
|
||
<div class="stat-card" style="background: linear-gradient(135deg, #ff9f43 0%, #ffb74d 100%);">
|
||
<div class="stat-label">站立次数</div>
|
||
<div class="stat-value" id="stat-stand">0</div>
|
||
<div class="stat-icon">🔄 活动频率</div>
|
||
</div>
|
||
</div>
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<h3>🏃♀️ 已记录数据</h3>
|
||
<div class="controls" style="display: flex; gap: 10px;">
|
||
<button id="btn-add-modal" class="primary">📝 记一笔</button>
|
||
</div>
|
||
</div>
|
||
<div class="filter-bar filter-wrap">
|
||
<div class="filter-group">
|
||
<label class="mobile-label">📅 按日期筛选</label>
|
||
<div class="filter-row">
|
||
<input type="date" id="filter-start" class="mobile-input">
|
||
<span class="range-sep">至</span>
|
||
<input type="date" id="filter-end" class="mobile-input">
|
||
<button id="btn-filter" class="secondary btn-sm">筛选</button>
|
||
</div>
|
||
</div>
|
||
<div class="filter-actions-right">
|
||
<button id="btn-prev-week" class="secondary btn-sm">◀ 上周</button>
|
||
<button id="btn-this-week" class="primary btn-sm">本周</button>
|
||
<button id="btn-next-week" class="secondary btn-sm">下周 ▶</button>
|
||
</div>
|
||
</div>
|
||
<div class="table-responsive">
|
||
<table class="data-table">
|
||
<thead>
|
||
<tr>
|
||
<th>日期</th>
|
||
<th>每日计划</th>
|
||
<th>活动千卡</th>
|
||
<th>时长(分)</th>
|
||
<th>站立</th>
|
||
<th>运动项目明细</th>
|
||
<th>操作</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="record-list"></tbody>
|
||
</table>
|
||
</div>
|
||
<div id="weekly-must-warning" class="weekly-warning" style="display:none"></div>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="section-weekly" class="tab-content">
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<h3>本周达标剩余</h3>
|
||
<div class="muted" id="weekly-range"></div>
|
||
</div>
|
||
<div class="grid-2" id="weekly-progress"></div>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="section-calendar" class="tab-content">
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<h3>📅 运动日历</h3>
|
||
<div class="controls" style="display:flex;gap:8px;">
|
||
<button id="btn-prev-month" class="secondary">◀ 上一月</button>
|
||
<button id="btn-next-month" class="secondary">下一月 ▶</button>
|
||
</div>
|
||
</div>
|
||
<div class="calendar-wrapper">
|
||
<div class="calendar-header" id="calendar-title"></div>
|
||
<table class="calendar">
|
||
<thead><tr><th>一</th><th>二</th><th>三</th><th>四</th><th>五</th><th>六</th><th>日</th></tr></thead>
|
||
<tbody id="calendar-body"></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="section-stats" class="tab-content">
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<h3>查询统计</h3>
|
||
</div>
|
||
<div class="filter-bar">
|
||
<div class="stats-filter-grid">
|
||
<label class="mobile-label">起始日期</label>
|
||
<input type="date" id="stats-start" class="mobile-input">
|
||
<label class="mobile-label">结束日期</label>
|
||
<input type="date" id="stats-end" class="mobile-input">
|
||
<button id="btn-stats" class="primary btn-sm">统计</button>
|
||
<button id="btn-export" class="secondary btn-sm">导出Excel</button>
|
||
</div>
|
||
<div class="quick-range">
|
||
<button type="button" id="s-prev-week" class="range-btn">上周</button>
|
||
<button type="button" id="s-this-week" class="range-btn">本周</button>
|
||
<button type="button" id="s-next-week" class="range-btn">下周</button>
|
||
<span style="opacity:.6;margin:0 8px;">|</span>
|
||
<button type="button" id="s-prev-month" class="range-btn">上月</button>
|
||
<button type="button" id="s-this-month" class="range-btn">本月</button>
|
||
<button type="button" id="s-next-month" class="range-btn">下月</button>
|
||
</div>
|
||
</div>
|
||
<div class="stats-cards">
|
||
<div class="stat-card" style="background: linear-gradient(135deg, #00a8ff 0%, #4cdfff 100%);">
|
||
<div class="stat-label">总千卡</div>
|
||
<div class="stat-value" id="stats-total-cal">0</div>
|
||
<div class="stat-icon">🔥 运动能量</div>
|
||
</div>
|
||
<div class="stat-card" style="background: linear-gradient(135deg, #00d8a7 0%, #00e6b8 100%);">
|
||
<div class="stat-label">总时长(分钟)</div>
|
||
<div class="stat-value" id="stats-total-dur">0</div>
|
||
<div class="stat-icon">⏱️ 坚持时间</div>
|
||
</div>
|
||
<div class="stat-card" style="background: linear-gradient(135deg, #ff9f43 0%, #ffb74d 100%);">
|
||
<div class="stat-label">总站立次数</div>
|
||
<div class="stat-value" id="stats-total-stand">0</div>
|
||
<div class="stat-icon">🔄 活动频率</div>
|
||
</div>
|
||
</div>
|
||
<div class="grid-2">
|
||
<div class="chart-container">
|
||
<h3>记录频率</h3>
|
||
<canvas id="pieDays" height="200"></canvas>
|
||
</div>
|
||
<div class="chart-container">
|
||
<h3>每周汇总</h3>
|
||
<canvas id="barWeekly" height="200"></canvas>
|
||
</div>
|
||
</div>
|
||
<div class="chart-container">
|
||
<h3>记录明细(所选范围)</h3>
|
||
<div class="table-responsive">
|
||
<table class="data-table">
|
||
<thead><tr><th>日期</th><th>计划</th><th>千卡</th><th>时长</th><th>站立</th><th>项目数</th></tr></thead>
|
||
<tbody id="stats-records"></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="section-screen" class="tab-content">
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<h3>🏃♂️ 运动大屏</h3>
|
||
</div>
|
||
<div class="grid-3">
|
||
<div style="display:flex;flex-direction:column;gap:16px;">
|
||
<div class="screen-card">
|
||
<div class="label">📈 本周千卡趋势</div>
|
||
<canvas id="lineCal" height="160"></canvas>
|
||
</div>
|
||
<div class="screen-card">
|
||
<div class="label">⏰ 本周时长趋势</div>
|
||
<canvas id="lineDur" height="160"></canvas>
|
||
</div>
|
||
<div class="screen-card">
|
||
<div class="label">🚶♀️ 本周站立趋势</div>
|
||
<canvas id="lineStand" height="160"></canvas>
|
||
</div>
|
||
</div>
|
||
<div style="display:flex;flex-direction:column;gap:16px;">
|
||
<div class="screen-card">
|
||
<div class="label">🎯 项目构成(本周数量)</div>
|
||
<canvas id="pieComp" height="300"></canvas>
|
||
</div>
|
||
<div class="screen-card">
|
||
<div class="label">📅 月度趋势</div>
|
||
<canvas id="barMonthly" height="220"></canvas>
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<div class="screen-card">
|
||
<div class="label">🎯 每周目标进度</div>
|
||
<div class="progress-list" id="weekly-progress-list"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="section-settings" class="tab-content">
|
||
<div class="card">
|
||
<div class="card-header"><h3>运动项目管理与每周达标设置</h3></div>
|
||
<div class="table-responsive">
|
||
<table class="data-table">
|
||
<thead><tr><th>项目</th><th>单位</th><th>每周目标</th><th>排序</th><th>操作</th></tr></thead>
|
||
<tbody id="settings-types"></tbody>
|
||
</table>
|
||
</div>
|
||
<div style="display:flex;justify-content:flex-end;margin-top:12px;">
|
||
<button id="btn-save-types" class="primary">保存设置</button>
|
||
</div>
|
||
<h3 style="margin-top:20px;">新增运动项目</h3>
|
||
<div class="grid-3">
|
||
<div><label>项目名称</label><input type="text" id="add-type-name"></div>
|
||
<div><label>单位</label><input type="text" id="add-type-unit"></div>
|
||
<div><label>每周目标</label><input type="number" id="add-type-goal" value="0"></div>
|
||
<div style="display:flex;align-items:flex-end;"><button id="btn-add-type" class="secondary">新增项目</button></div>
|
||
</div>
|
||
</div>
|
||
<div class="card">
|
||
<div class="card-header"><h3>本日计划管理</h3></div>
|
||
<div class="table-responsive">
|
||
<table class="data-table">
|
||
<thead><tr><th>计划名称</th><th>操作</th></tr></thead>
|
||
<tbody id="settings-plans"></tbody>
|
||
</table>
|
||
</div>
|
||
<div style="display:flex;justify-content:flex-end;margin-top:12px;">
|
||
<button id="btn-save-plans" class="primary">保存计划</button>
|
||
</div>
|
||
<h3 style="margin-top:20px;">新增本日计划</h3>
|
||
<div class="grid-2">
|
||
<div><label>计划名称</label><input type="text" id="add-plan-name"></div>
|
||
<div style="display:flex;align-items:flex-end;"><button id="btn-add-plan" class="secondary">新增计划</button></div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
|
||
<!-- 新增/编辑 模态框 -->
|
||
<div id="modal-form" class="modal">
|
||
<div class="modal-content">
|
||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
|
||
<h3 style="margin: 0;">📝 记录运动</h3>
|
||
<button id="btn-close-modal" style="background: none; border: none; font-size: 24px; cursor: pointer;">×</button>
|
||
</div>
|
||
|
||
<form id="record-form">
|
||
<div style="margin-bottom: 16px;">
|
||
<label>日期</label>
|
||
<input type="date" name="record_date" required style="width: 100%;">
|
||
</div>
|
||
|
||
<div style="margin-bottom: 16px;">
|
||
<label>每日计划</label>
|
||
<select name="daily_plan_id" id="daily-plan-select" style="width: 100%;">
|
||
<option value="">加载中...</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div style="display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 12px; margin-bottom: 16px;">
|
||
<div>
|
||
<label>活动千卡</label>
|
||
<input type="number" name="calories" value="0" style="width: 100%;">
|
||
</div>
|
||
<div>
|
||
<label>运动时长(分)</label>
|
||
<input type="number" name="exercise_duration" value="0" style="width: 100%;">
|
||
</div>
|
||
<div>
|
||
<label>站立次数</label>
|
||
<input type="number" name="stand_count" value="0" style="width: 100%;">
|
||
</div>
|
||
</div>
|
||
|
||
<div style="margin-bottom: 16px;">
|
||
<label>运动项目明细 <button type="button" id="add-item-btn" class="secondary" style="padding: 4px 8px; font-size: 12px; margin-left: 8px;">+ 添加项目</button></label>
|
||
<div id="items-container"></div>
|
||
</div>
|
||
|
||
<div class="health-metrics-grid" style="display: grid; grid-template-columns: 1fr 1fr 1fr 1fr 1fr; gap: 12px; margin-bottom: 20px; padding-top: 16px; border-top: 1px dashed #eee;">
|
||
<div>
|
||
<label>舒张压(mmHg)</label>
|
||
<input type="number" name="diastolic_bp" min="1" step="1" style="width: 100%;">
|
||
</div>
|
||
<div>
|
||
<label>收缩压(mmHg)</label>
|
||
<input type="number" name="systolic_bp" min="1" step="1" style="width: 100%;">
|
||
</div>
|
||
<div>
|
||
<label>心率(bpm)</label>
|
||
<input type="number" name="heart_rate" min="1" step="1" style="width: 100%;">
|
||
</div>
|
||
<div>
|
||
<label>腰围(cm)</label>
|
||
<input type="number" name="waist_circ" min="1" step="1" style="width: 100%;">
|
||
</div>
|
||
<div>
|
||
<label>体重(kg)</label>
|
||
<input type="number" name="weight_kg" min="1" step="0.1" style="width: 100%;">
|
||
</div>
|
||
</div>
|
||
|
||
<button type="submit" class="primary" style="width: 100%; padding: 14px;">保存记录</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="record-detail-modal" class="modal">
|
||
<div class="modal-content">
|
||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:20px;">
|
||
<h3 style="margin:0;">记录详情</h3>
|
||
<button id="btn-close-detail" style="background:none;border:none;font-size:24px;cursor:pointer;">×</button>
|
||
</div>
|
||
<div id="record-detail-content"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Waiting Box Modal -->
|
||
<div id="waiting-modal" class="modal" style="z-index: 200;">
|
||
<div class="modal-content" style="max-width: 400px;">
|
||
<h3 id="waiting-title" style="margin-top:0; border-bottom: 2px solid var(--primary); padding-bottom: 10px;">处理中...</h3>
|
||
<div id="waiting-steps" class="waiting-steps"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Templates -->
|
||
<template id="item-template">
|
||
<div class="item-row">
|
||
<select class="item-type-select" style="flex: 2;">
|
||
<option value="">选择项目...</option>
|
||
</select>
|
||
<input type="number" class="item-quantity" placeholder="数量" style="flex: 1;">
|
||
<span class="item-unit unit">次</span>
|
||
<button type="button" class="danger btn-remove" style="padding: 8px;">×</button>
|
||
</div>
|
||
</template>
|
||
|
||
<script src="app.js"></script>
|
||
</body>
|
||
</html>
|