Files
spark-tracker/templates/admin.html
T

212 lines
11 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>(中国儿童生长标准 WS/T 612-2018</p>
{% endif %}
</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>
<form method="post" action="{{ url_for('admin_reset') }}"
onsubmit="return confirm('确定重置数据?未勾选保留的项将被清空,此操作不可撤销!')">
<div class="row" style="gap:18px;flex-wrap:wrap;align-items:flex-start">
<label class="chk"><input type="checkbox" name="keep_health" value="1"> 保留健康记录(身高/体重/睡眠/运动)</label>
<label class="chk"><input type="checkbox" name="keep_bookshelf" value="1"> 保留书架(书目与阅读记录)</label>
</div>
<div class="row" style="margin-top:12px">
<button class="mini danger">🗑️ 重置数据</button>
</div>
</form>
</section>
<section class="card">
<h2>⚡ 浮动打卡项(可增删改)</h2>
<p class="sub">仪表盘右下角的竖排打卡按钮;这里新增 / 改名 / 删除,仪表盘即时更新。</p>
<form method="post" action="{{ url_for('admin_checkin_add') }}" class="row wrap">
<input name="key" placeholder="标识,如 walk" required style="width:120px">
<input name="icon" placeholder="图标" style="width:60px" value="🚶">
<input name="name" placeholder="按钮名,如 走路打卡" required>
<input name="done_name" placeholder="完成后文案,如 已走路" style="width:120px">
<button>加一项</button>
</form>
{% for k in checkin_kinds %}
<div class="admin-subject">
<div class="admin-subject-head">
<span>{{ k.icon }} <b>{{ k.name }}</b> <span class="muted">{{ k.key }} · 完成显示「{{ k.done_name }}」)</span></span>
<span class="admin-subject-controls">
<form method="post" action="{{ url_for('admin_checkin_update', kid=k.id) }}" class="inline row" style="margin:0">
<input name="icon" value="{{ k.icon }}" style="width:46px">
<input name="name" value="{{ k.name }}" style="width:120px">
<input name="done_name" value="{{ k.done_name }}" style="width:110px">
<button class="mini">保存</button>
</form>
<form method="post" action="{{ url_for('admin_checkin_delete', kid=k.id) }}" class="inline"
onsubmit="return confirm('删除该打卡项及其打卡记录?')">
<button class="mini danger">删除</button>
</form>
</span>
</div>
</div>
{% endfor %}
</section>
<section class="card">
<h2>🗓️ 补卡(补录历史打卡)</h2>
<p class="sub">为过去的某一天补记一次打卡;同一天同一项目不会重复记。仪表盘日历会显示该日已打卡。</p>
<form method="post" action="{{ url_for('admin_checkin_backfill') }}" class="row wrap">
<label>日期<input type="date" name="date" value="{{ now }}" required></label>
<select name="kind">
{% for k in checkin_kinds %}<option value="{{ k.key }}">{{ k.icon }} {{ k.name }}</option>{% endfor %}
</select>
<button>补卡</button>
</form>
</section>
{% endblock %}