- 新增 ?back= 贯穿链路:列表页(地点库 / 时间线 / 统计 / 专题地图 / 主页)生成详情链接时 带上当前完整地址,详情页的「返回」「编辑」与编辑页的返回按钮据此回到原来那份筛选结果。 只放行站内路径(挡 //host、伪协议、控制字符),参数编码走 template.URL 避免二次转义。 - 修 EditData.PageLink 把 & 手工写成 & 又被模板转义一次的 bug(&)—— 参数名会变成 amp;vpage,表现为「带筛选时翻页没反应、筛选还丢了」(既有问题)。 - 编辑页三个筛选表单与三个「重置」带上 back(重置改走 EditData.EditLink,各清各的, 顺带修掉搜索词含 & 或空格时重置链接被拆坏)。 - 详情页「在地图中查看」的地点名改走 QueryEscape(名字含 & / # 会拆坏地址)。 - 窄屏修正:把被基础规则压掉的 .chip / .btn / .check 覆盖挪到最后; checkbox 20px、select 44px、file/color 字号 16px(iOS 聚焦不再自放大整页)、 .tag 12px、导航 logo 触摸区 44×44。 - 新增回归 internal/web/pagelink_test.go(翻页链接、返回文案、地图链接)。
99 lines
3.9 KiB
HTML
99 lines
3.9 KiB
HTML
{{define "content"}}
|
|
{{if not .HasData}}
|
|
<div class="wrap">{{template "emptystate" .}}</div>
|
|
{{else}}
|
|
<div class="wrap">
|
|
<div class="page-head">
|
|
<div>
|
|
<h1>{{.Topic.Title}}</h1>
|
|
{{if .Topic.Subtitle}}<div class="sub">{{.Topic.Subtitle}}</div>{{end}}
|
|
{{/* 时间范围独立成行:塞进 KPI 网格里会被挤成好几行 */}}
|
|
<div class="topic-range">{{.Topic.RangeLabel}}{{if .Topic.DayCount}} · 共 {{num .Topic.DayCount}} 天{{end}}</div>
|
|
</div>
|
|
<div class="row">
|
|
<a class="btn" href="/topics">← 全部专题</a>
|
|
{{if .IsAdmin}}<a class="btn" href="/admin/topics?edit={{.Topic.ID}}">编辑</a>{{end}}
|
|
</div>
|
|
</div>
|
|
|
|
{{if not .Topic.Enabled}}<div class="alert err">这个专题尚未对外展示,只有你自己能看到。</div>{{end}}
|
|
|
|
{{if .Topic.Description}}<div class="card topic-desc">{{.Topic.Description}}</div>{{end}}
|
|
|
|
<div class="card">
|
|
<div class="kpis">
|
|
<div class="kpi"><div class="k">{{if .Topic.HasArea}}区域内地点{{else}}地点{{end}}</div><div class="v">{{num .Topic.PlaceCount}}</div></div>
|
|
<div class="kpi"><div class="k">到访次数</div><div class="v">{{num .Topic.VisitCount}}</div></div>
|
|
<div class="kpi"><div class="k">涉及城市</div><div class="v">{{num .Topic.CityCount}}</div></div>
|
|
<div class="kpi"><div class="k">累计停留</div><div class="v">{{dur .Topic.DwellMin}}</div></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card" style="padding:10px">
|
|
{{/* 高度写 inline:站点里 #map{height:100%} 是 ID 选择器,只靠外部 CSS 类
|
|
容易在别处规则变动/缓存不一致时把容器算成 0 高,地图就整块消失 */}}
|
|
<div id="map" class="topic-map" style="height:520px">
|
|
<div id="map-fallback" class="map-fallback">地图加载中……若一直不出现,请强制刷新(Ctrl+F5)或检查浏览器是否拦截了地图脚本</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h2>去过的地方</h2>
|
|
<div class="card-sub">共 {{num .Topic.PlaceCount}} 个,按到访次数排序</div>
|
|
{{if .Points}}
|
|
<div class="tw">
|
|
<table class="tb">
|
|
<thead><tr><th>地点</th><th>城市</th><th>类型</th><th class="num">到访</th><th class="num">停留</th><th>最近一次</th></tr></thead>
|
|
<tbody>
|
|
{{range .Points}}
|
|
<tr>
|
|
<td>{{if .Name}}{{.Name}}{{else}}<span class="muted">(未命名)</span>{{end}}</td>
|
|
<td class="muted">{{.City}}</td>
|
|
<td class="muted">{{if .Act}}<span class="dot" style="background:{{colorof .Color}}"></span>{{.Act}}{{end}}</td>
|
|
<td class="num">{{num .Count}}</td>
|
|
<td class="num muted">{{dur .Dwell}}</td>
|
|
<td class="muted mono">{{.LastAt}}</td>
|
|
</tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{{else}}
|
|
<div class="empty">这个时间 / 区域范围内没有记录</div>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
(function () {
|
|
function whenReady(cb) {
|
|
if (document.readyState === 'complete') { setTimeout(cb, 0); return; }
|
|
window.addEventListener('load', cb);
|
|
}
|
|
whenReady(function () {
|
|
var el = document.getElementById('map');
|
|
// 移动端矮一些(inline 高度优先于外部 CSS,只能在这里按视口改)
|
|
if (el && window.matchMedia('(max-width: 620px)').matches) el.style.height = '360px';
|
|
|
|
if (window.rondMap) {
|
|
window.rondMap.full({
|
|
id: 'map',
|
|
points: {{.PointsJSON}},
|
|
fitCircle: {{.FitCircleJSON}},
|
|
fitBBox: {{.FitBBoxJSON}},
|
|
showFog: {{if .Topic.ShowFog}}true{{else}}false{{end}},
|
|
back: '{{.BackQS}}'
|
|
});
|
|
}
|
|
|
|
// 地图脚本没就绪(被拦 / 加载失败)时,把兜底提示留在原位,用户至少知道发生了什么
|
|
setTimeout(function () {
|
|
var fb = document.getElementById('map-fallback');
|
|
if (fb && el && el.classList.contains('leaflet-container')) fb.style.display = 'none';
|
|
}, 1200);
|
|
});
|
|
})();
|
|
</script>
|
|
{{end}}
|
|
{{end}}
|