Files
spark-tracker/templates/admin.html
T
luff 0e6065897b 星火纪元 个人成长追踪 v1.0
- Flask + SQLite 自托管,单用户无 PIN
- 仪表盘:学科进度环轮播、健康双线图、任务接龙、书架墙、浮动打卡
- 后台:孩子信息、学科/单元课表、健康历史录入、数据管理(重置/新学期)
- 徽章由进度实时派生;主题由后台设置
2026-08-11 15:20:53 +08:00

182 lines
8.8 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "base.html" %}
{% block title %}家长后台{% endblock %}
{% block content %}
<div class="admin-head">
<h1>🛠️ 家长后台</h1>
<a href="{{ url_for('admin_export') }}" class="btn-outline">⬇ 导出全部数据(JSON)</a>
<a href="{{ url_for('admin_logout') }}" class="btn-outline">退出</a>
</div>
<section class="card">
<h2>👦 孩子信息</h2>
<form method="post" action="{{ url_for('admin_child_update') }}" class="row wrap">
<label>姓名<input name="name" value="{{ child.name }}" placeholder="姓名"></label>
<label>出生日期<input type="date" name="birth_date" value="{{ child.birth_date or '' }}"></label>
<label>性别
<select name="gender">
<option value="M" {% if child.gender == 'M' %}selected{% endif %}></option>
<option value="F" {% if child.gender == 'F' %}selected{% endif %}></option>
</select>
</label>
<label>学期起<input type="date" name="term_start" value="{{ child.term_start or '' }}"></label>
<label>学期止<input type="date" name="term_end" value="{{ child.term_end or '' }}"></label>
<label>进度环轮播(秒)<input name="ring_sec" type="number" value="{{ child.ring_sec or 6 }}" style="width:80px" min="2"></label>
<label>学科轮播(秒)<input name="carousel_sec" type="number" value="{{ child.carousel_sec or 8 }}" style="width:80px" min="2"></label>
<label>默认主题
<select name="default_theme">
{% for t,label in themes %}
<option value="{{ t }}" {% if child.default_theme == t %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
</label>
<button>保存</button>
</form>
{% if age is not none %}
<p class="sub">当前年龄约 <b>{{ '%.1f'|format(age) }}</b> 岁 · 标准身高 <b>{{ std_h }} cm</b> · 标准体重 <b>{{ std_w }} kg</b>WHO 中位参考)</p>
{% endif %}
</section>
<section class="card">
<h2>🎯 年度目标</h2>
<form method="post" action="{{ url_for('admin_goal_update') }}" class="row">
<label>读书目标(本/年)
<input name="book_target" type="number" value="{{ goal.book_target }}" style="width:90px">
</label>
<label>运动目标(分钟/周)
<input name="week_exercise_min" type="number" value="{{ goal.week_exercise_min }}" style="width:90px">
</label>
<button>保存</button>
</form>
</section>
<section class="card">
<h2>📈 健康记录(可补历史数据)</h2>
<p class="sub">填入任意日期即可补录历史身高体重;仪表盘「健康综合」会展示最近两年。</p>
<form method="post" action="{{ url_for('health_add') }}" class="row wrap">
<label>日期<input type="date" name="date" value="{{ now }}" required></label>
<label>身高(cm)<input name="height_cm" type="number" step="0.1" placeholder="如 130.5" style="width:90px"></label>
<label>体重(kg)<input name="weight_kg" type="number" step="0.1" placeholder="如 27.2" style="width:90px"></label>
<label>睡眠(时)<input name="sleep_hours" type="number" step="0.1" style="width:80px"></label>
<label>喝水(杯)<input name="water_cups" type="number" style="width:70px"></label>
<label>心情<input name="mood" placeholder="如 开心" style="width:90px"></label>
<button>添加记录</button>
</form>
</section>
<section class="card">
<h2>📚 学科与单元(整年课表)</h2>
<form method="post" action="{{ url_for('admin_subject_add') }}" class="row">
<input name="name" placeholder="学科名,如 语文" required>
<input name="icon" placeholder="图标" style="width:70px" value="📘">
<input name="color" type="color" value="#3b82f6" style="width:50px">
<button>加学科</button>
</form>
{% for s in subjects %}
<div class="admin-subject">
<div class="admin-subject-head">
<span>{{ s.icon }} <b>{{ s.name }}</b></span>
<span class="admin-subject-controls">
<form method="post" action="{{ url_for('admin_subject_delete', sid=s.id) }}" class="inline"
onsubmit="return confirm('删除该学科及其所有单元?')">
<button class="mini danger">删除学科</button>
</form>
</span>
</div>
<ul class="admin-units">
{% for u in s.units %}
<li>
<span class="unit-state unit-{{ u.status }}">
{% if u.status==2 %}已完成{% elif u.status==1 %}进行中{% else %}未开始{% endif %}
</span>
{{ u.title }}
{% if u.target_date %}<span class="muted">(🎯{{ u.target_date }}</span>{% endif %}
<form method="post" action="{{ url_for('admin_unit_delete', uid=u.id) }}" class="inline"
onsubmit="return confirm('删除该单元?')">
<button class="mini danger">×</button>
</form>
</li>
{% endfor %}
</ul>
<form method="post" action="{{ url_for('admin_unit_add') }}" class="row">
<input type="hidden" name="subject_id" value="{{ s.id }}">
<input name="title" placeholder="新增单元/章节名" required>
<input name="target_date" type="date" placeholder="目标完成日">
<button>加单元</button>
</form>
</div>
{% endfor %}
</section>
<section class="card">
<h2>📖 书目(含封面)</h2>
<form method="post" action="{{ url_for('book_add') }}" class="row" enctype="multipart/form-data">
<input name="title" placeholder="书名" required>
<input name="author" placeholder="作者">
<input name="total_pages" type="number" placeholder="页数" style="width:80px">
<select name="category">
{% for c in book_categories %}<option value="{{ c }}">{{ c }}</option>{% endfor %}
</select>
<input type="file" name="cover" accept="image/*" style="width:170px">
<button>加书</button>
</form>
<p class="sub">支持本地上传封面(png/jpg/gif/webp<b>不限制大小</b>,离线可见);上传后会<b>自动标准化</b>为统一的 2:3 封面并生成缩略图。也可在下方每本书填图片 URL。<br>
<b>分类与评分</b>决定书架墙上的筛选标签和排序,改完记得点「保存」。</p>
<table class="tbl">
<tr><th>封面</th><th>书名</th><th>作者</th><th>状态</th><th>分类 / 评分</th><th>更新封面</th></tr>
{% for b in books %}
<tr>
<td>{% if b.cover_thumb or b.cover_url %}<img src="{{ b.cover_thumb or b.cover_url }}" alt="" style="height:60px;border-radius:3px">{% else %}<span class="muted"></span>{% endif %}</td>
<td>{{ b.title }}</td>
<td>{{ b.author or '—' }}</td>
<td>{% if b.status=='done' %}已读完{% elif b.status=='reading' %}在读{% else %}想读{% endif %}</td>
<td>
<form method="post" action="{{ url_for('admin_book_meta', bid=b.id) }}" class="row" style="margin:0">
<select name="category">
{% for c in book_categories %}
<option value="{{ c }}" {% if (b.category or '未分类') == c %}selected{% endif %}>{{ c }}</option>
{% endfor %}
</select>
<select name="rating" title="评分">
{% for r in range(6) %}
<option value="{{ r }}" {% if (b.rating or 0) == r %}selected{% endif %}>{{ r }}★</option>
{% endfor %}
</select>
<button class="mini">保存</button>
</form>
</td>
<td>
<form method="post" action="{{ url_for('admin_book_cover', bid=b.id) }}" enctype="multipart/form-data" class="row" style="margin:0">
<input type="file" name="cover" accept="image/*" style="width:150px">
<input name="cover_url" placeholder="或图片URL" value="{{ b.cover_url or '' }}" style="width:130px">
<button class="mini">设封面</button>
</form>
{% if b.cover_url and b.cover_url.startswith('/static/covers/') %}
<form method="post" action="{{ url_for('admin_book_cover_delete', bid=b.id) }}" class="inline" style="margin-top:6px" onsubmit="return confirm('删除这张封面?')">
<button class="mini danger">删除封面</button>
</form>
{% endif %}
</td>
</tr>
{% endfor %}
</table>
</section>
<section class="card">
<h2>🧹 数据管理</h2>
<p class="sub">徽章由进度/读书/运动实时派生,重置或新学期后会自动重新累积,无需手动发徽章。</p>
<div class="row" style="gap:12px;flex-wrap:wrap">
<form method="post" action="{{ url_for('admin_reset') }}"
onsubmit="return confirm('确定清空全部进度 / 打卡 / 健康记录?学科与书目结构保留。此操作不可撤销!')">
<button class="mini danger">🗑️ 重置全部数据</button>
</form>
<form method="post" action="{{ url_for('admin_new_term') }}"
onsubmit="return confirm('开启新学期:进度重置为未开始、清空打卡,并把学期起设为今天。确定?')">
<button class="mini">🎒 开启新学期</button>
</form>
</div>
</section>
{% endblock %}