移动端有 7 张表要横滑 300+px 才看得全,滑着还对不上表头(地点库 8 列、统计 3 张、专题详情、 首页天气、后台数据集表与数据说明、专题管理、报告页 2 张)。给这些表加 tb-stack: 窄屏隐藏 thead、每行一屏一块、每格「字段名 + 值」竖排,值多行时用悬挂缩进。 - 字段名取自 td 的 data-label(首格是这行主角,故意不带标签;操作格给「操作」)—— 这样改列顺序也不会串标签,比把名字写进 CSS 的 nth-child 稳。 - 表格结构、链接、表单、按钮一律没动(只是隐藏 thead + 改 display),桌面与平板仍是原表。 - 断点只用 @media (max-width:620px):试过容器查询(能顺手治掉「宽屏里 g2 窄卡片也要横滑」), 但实测会把 /stats 三个卡片撑高 1300px,太臃肿,不划算。 实测:390/620 十张表需横滑全部为 0、每行每格都有标签;621/700/1440 的横滑量与改动前一致 (桌面零变化);128 个链接/按钮滚动到可见后逐个点测均可点中,无裁切;全站审计 390 站长/访客 + 320 + 1440 溢出全 0、0 JS 报错,小触控与小字数与改动前逐页一致(320 下露外元素 /places 277→2、 /stats 114→12、/admin 46→4,剩下的都是有意的横滑容器)。 新增回归 internal/web/tb_stack_test.go:渲染 7 个页面、逐行核对「每个非首格都有 data-label」 且「格子数 == 表头列数」(变异验证过:去掉一个标签立刻 FAIL)。
170 lines
9.0 KiB
HTML
170 lines
9.0 KiB
HTML
{{define "content"}}
|
||
<div class="wrap">
|
||
<div class="page-head">
|
||
<div>
|
||
<h1>后台管理</h1>
|
||
<div class="sub">上传 rond 备份、切换展示的数据、调整站点设置</div>
|
||
</div>
|
||
<div class="row">
|
||
<a class="btn" href="/admin/edit">数据编辑</a>
|
||
<a class="btn" href="/admin/topics">专题管理</a>
|
||
<a class="btn" href="/admin/photos">照片导入</a>
|
||
<a class="btn" href="/admin/settings">站点设置</a>
|
||
<a class="btn" href="/admin/twofa">两步验证</a>
|
||
<a class="btn" href="/admin/notes">地点备注</a>
|
||
<a class="btn" href="/admin/password">账号设置</a>
|
||
<a class="btn" href="/" target="_blank">查看站点</a>
|
||
</div>
|
||
</div>
|
||
|
||
{{if .Flash}}<div class="alert ok">{{.Flash}}</div>{{end}}
|
||
{{if .Err}}<div class="alert err">{{.Err}}</div>{{end}}
|
||
{{if .DefaultPW}}<div class="alert err">⚠️ 您仍在使用初始口令 <span class="mono">rond-admin</span>,站点对公网开放时任何人都可以用这组口令登录后台。请尽快<a href="/admin/password">修改密码</a>,并在<a href="/admin/twofa">两步验证</a>中绑定动态口令。</div>{{end}}
|
||
|
||
<div class="card">
|
||
<h2>上传备份</h2>
|
||
<div class="card-sub">
|
||
在 rond App 中导出备份,得到 <span class="mono">.rondbackup</span> 文件后上传。
|
||
单次最大 {{size .MaxSize}}。
|
||
<b>上传是以备份为准重建数据</b>:站点里删掉的地点、改过的记录,只要下次传一份
|
||
<b>内容不同</b>的备份,就会被备份里的原样覆盖回来(重复传同一份文件不会,会提示「完全一致」)。
|
||
在站点上新加的地点属于当时那个数据集,传新备份后要看它们,可在下面的数据集列表里切回。
|
||
</div>
|
||
<form method="post" action="/admin/upload" enctype="multipart/form-data">
|
||
<label class="f" style="max-width:520px">
|
||
<span>选择文件</span>
|
||
<input type="file" name="backup" accept=".rondbackup,.zip" required
|
||
style="padding:8px;border:1px dashed var(--line);border-radius:8px;background:var(--bg-2)">
|
||
</label>
|
||
<button class="btn primary" type="submit">上传并导入</button>
|
||
</form>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<h2>世界迷雾</h2>
|
||
<div class="card-sub">
|
||
导入 Fog of World 导出的 <span class="mono">.fwss</span> 快照,在足迹地图上叠加已探索区域。
|
||
迷雾网格为 WGS-84,站点会自动对高德等 GCJ-02 底图做纠偏。
|
||
迷雾是站点级数据,不属于任何数据集,删除数据集不影响迷雾。
|
||
{{if gt .FogBlocks 0}}
|
||
当前已入库 <span class="mono">{{num .FogBlocks}}</span> 块 / <span class="mono">{{num .FogCells}}</span> 格,
|
||
估算已探索 <span class="mono">{{printf "%.1f" .FogArea}}</span> km²{{if .FogUpdatedAt}},最近更新 {{dtt .FogUpdatedAt}}{{end}}。
|
||
{{else}}
|
||
<b>尚未导入迷雾</b>——把 Fog of World 的 <span class="mono">.fwss</span>(在 App 内导出,通常在 zip 里)上传即可点亮地图。
|
||
{{end}}
|
||
</div>
|
||
<form method="post" action="/admin/fog" enctype="multipart/form-data">
|
||
<label class="f" style="max-width:520px">
|
||
<span>选择快照</span>
|
||
<input type="file" name="fwss" accept=".fwss,.zip" required
|
||
style="padding:8px;border:1px dashed var(--line);border-radius:8px;background:var(--bg-2)">
|
||
</label>
|
||
<label class="f" style="max-width:520px">
|
||
<span>导入方式</span>
|
||
<select name="mode">
|
||
<option value="overlay" selected>叠加 — 保留现有迷雾,把新路线合并进来</option>
|
||
<option value="cover">覆盖 — 清空现有迷雾,整体替换</option>
|
||
</select>
|
||
</label>
|
||
<button class="btn primary" type="submit">导入迷雾</button>
|
||
</form>
|
||
{{if gt .FogBlocks 0}}
|
||
<div style="margin:10px 0 0;display:flex;gap:8px;flex-wrap:wrap">
|
||
<a class="btn" href="/admin/fog/export">导出当前迷雾(.fwss)</a>
|
||
<a class="btn" href="/admin/fog/mask">迷雾遮罩区{{if .FogMasks}}({{.FogMasks}}){{end}}</a>
|
||
<form method="post" action="/admin/fog/clear"
|
||
onsubmit="return confirm('将删除全部迷雾数据(数据库与地图图层同步清空),且不可恢复。确认清空?')">
|
||
<button class="btn danger" type="submit">清空迷雾</button>
|
||
</form>
|
||
</div>
|
||
{{end}}
|
||
</div>
|
||
|
||
<div class="card">
|
||
<h2>数据导出</h2>
|
||
<div class="card-sub">
|
||
把当前展示的数据集导出为通用格式,方便备份或迁移到其他平台。
|
||
坐标保持入库时的 GCJ-02,GeoJSON 里已注明坐标系。
|
||
</div>
|
||
<div class="row">
|
||
<a class="btn" href="/admin/export/places.geojson">导出地点(GeoJSON)</a>
|
||
<a class="btn" href="/admin/export/places.gpx">导出地点(GPX)</a>
|
||
</div>
|
||
<div class="card-sub" style="margin-top:14px">
|
||
也可导出为 rond 原始格式的 <span class="mono">.rondbackup</span>(含你在<a href="/admin/edit">数据编辑</a>里补录的记录),可直接导回 rond App。
|
||
坐标为 GCJ-02,原样写回、无需纠偏。
|
||
</div>
|
||
<a class="btn primary" href="/admin/export/rondbackup">导出 rondbackup(可回导 rond)</a>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="row" style="justify-content:space-between;align-items:center">
|
||
<h2 style="margin:0">已导入的数据集</h2>
|
||
<form method="post" action="/admin/places/backfill"
|
||
onsubmit="return confirm('对缺地址 / 没名字的地点逐个反查高德补全?(每次处理 100 个)')">
|
||
<button class="btn sm" type="submit">补全缺失地址</button>
|
||
</form>
|
||
</div>
|
||
<div class="card-sub">同一时刻只有一份数据处于「展示中」状态,主页与地图读取的就是它</div>
|
||
{{if .Datasets}}
|
||
<div class="tw">
|
||
<table class="tb tb-stack">
|
||
<thead>
|
||
<tr><th>文件</th><th>导入时间</th><th class="num">到访</th><th class="num">地点</th><th>数据跨度</th><th>状态</th><th></th></tr>
|
||
</thead>
|
||
<tbody>
|
||
{{range .Datasets}}
|
||
<tr>
|
||
<td><span class="mono">{{trunc .Name 34}}</span></td>
|
||
<td class="muted" data-label="导入时间">{{dt .UploadedAt}}</td>
|
||
<td class="num" data-label="到访">{{num .Visits}}</td>
|
||
<td class="num" data-label="地点">{{num .Places}}</td>
|
||
<td class="muted" data-label="数据跨度">{{if .First}}{{d .First}} ~ {{d .Last}}{{else}}—{{end}}</td>
|
||
<td data-label="状态">
|
||
{{if and $.Dataset (eq $.Dataset.ID .ID)}}
|
||
<span class="tag">展示中</span>
|
||
{{else}}
|
||
<span class="muted">未启用</span>
|
||
{{end}}
|
||
</td>
|
||
<td data-label="操作" style="white-space:nowrap">
|
||
{{if not (and $.Dataset (eq $.Dataset.ID .ID))}}
|
||
<form method="post" action="/admin/datasets/{{.ID}}/activate" style="display:inline">
|
||
<button class="btn sm" type="submit">启用</button>
|
||
</form>
|
||
{{end}}
|
||
<form method="post" action="/admin/datasets/{{.ID}}/delete" style="display:inline"
|
||
onsubmit="return confirm('删除后该数据集的所有记录都会从数据库移除,且不可恢复。确认删除?')">
|
||
<button class="btn sm danger" type="submit">删除</button>
|
||
</form>
|
||
</td>
|
||
</tr>
|
||
{{end}}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
{{else}}
|
||
<div class="empty"><div class="big">📦</div>还没有导入任何数据集</div>
|
||
{{end}}
|
||
</div>
|
||
|
||
<div class="card">
|
||
<h2>数据说明</h2>
|
||
<div class="card-sub">从备份中读取并转换的字段</div>
|
||
<div class="tw">
|
||
<table class="tb tb-stack">
|
||
<thead><tr><th>来源表</th><th>内容</th><th>用途</th></tr></thead>
|
||
<tbody>
|
||
<tr><td class="mono">ZVISIT</td><td data-label="内容">到访记录(到达 / 离开时间、类型、地点、备注、标签)</td><td data-label="用途">时间线、统计、地图</td></tr>
|
||
<tr><td class="mono">ZLOCATION</td><td data-label="内容">地点(名称、经纬度、城市、省份、POI 分类)</td><td data-label="用途">地图打点、地点库</td></tr>
|
||
<tr><td class="mono">ZACTIVITY</td><td data-label="内容">自定义类型(颜色、图标、是否家 / 工作)</td><td data-label="用途">类型分布</td></tr>
|
||
<tr><td class="mono">ZMOVEMENT</td><td data-label="内容">位移段(交通方式、起止时间)</td><td data-label="用途">出行方式统计</td></tr>
|
||
<tr><td class="mono">ZTAG</td><td data-label="内容">自定义标签及分组</td><td data-label="用途">标签筛选</td></tr>
|
||
<tr><td class="mono">ZHOURLYWEATHER</td><td data-label="内容">逐小时天气(气温、天气现象、湿度)</td><td data-label="用途">天气足迹</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{{end}}
|