用户发现未登录也显示「推荐 & 踩雷(我的结论)」,访客没法解读「谁的我的」。
顺着把访客可见模板与 static/js 全过了一遍,同病共四处——都是**写模板时站在站长视角下笔、
而那一块又对访客公开**:
1. stats.html:标题 → {{if .IsAdmin}}我的结论{{else}}站长结论{{end}};
副标题「只统计你自己…」→ 站长「你自己」/ 访客「站长」;两列「我推荐/我踩雷的地点」同理。
2. stats.html 访客块:「与我的结论互不影响:你标你的,访客投访客的」——对访客说不通,
改成对两边都成立的「与上面的站长结论互不影响:各存各的表,谁也不会覆盖谁」。
3. home.html:「我的标签」→「足迹标签」(同级卡片全是中性的:足迹地图/城市足迹/天气足迹…)。
4. report.html:「这一年里,你第一次踏足的这些城市」→ 去掉人称(年报是站长的回顾)。
已经写对的照它学:place.html 的投票区早就是 {{if .IsAdmin}} 分支(站长「我的结论」、
访客「大家怎么说」),rond-map.js 的气泡同理;「含家/工作」chip 与一串「只有你自己能看到」
本来就在站长分支里。
门禁 TestVisitorPagesUseThirdPersonCopy:以**访客 ctx(无 user)**渲染 /、/stats、/report,
逐个禁用词断言,同时断言站长那份**仍旧说「我的」**(别把站长自己的视角也改掉);
前置需打开 marks_public(访客才看得到那一块),用完还原。
⚠️ 变异验证时踩了老坑:直接 `go test -run …` 因缺 ROND_TEST_CONF/ROND_SRC 会**静默 skip 并报 ok**
(0.17s 就 ok,一眼假绿)。改用 ./scripts/verify.sh 后变异被正确抓住
(visitor_copy_test.go:85 报「我的结论」),还原后转绿。
全量验收 PASS=339 FAIL=0 SKIP=0。
183 lines
7.4 KiB
HTML
183 lines
7.4 KiB
HTML
{{define "content"}}
|
||
{{if not .HasData}}
|
||
<div class="wrap">{{template "emptystate" .}}</div>
|
||
{{else}}
|
||
<div class="wrap">
|
||
|
||
<div class="page-head">
|
||
<div>
|
||
<h1>{{.Settings.OwnerAvatar}} {{.Settings.OwnerName}}</h1>
|
||
<div class="sub">{{if .Settings.SiteSubtitle}}{{.Settings.SiteSubtitle}} · {{end}}{{.RangeLabel}}</div>
|
||
</div>
|
||
<div class="row">
|
||
<a class="btn" href="/map">全屏地图</a>
|
||
<a class="btn" href="/stats">数据统计</a>
|
||
</div>
|
||
</div>
|
||
|
||
{{if .Settings.Has "overview"}}
|
||
<div class="kpis" style="margin-bottom:16px">
|
||
<div class="kpi"><div class="v">{{num .Overview.Places}}<small>个</small></div><div class="k">去过的地点</div></div>
|
||
<div class="kpi"><div class="v">{{num .Overview.Cities}}<small>座</small></div><div class="k">到过的城市</div></div>
|
||
<div class="kpi"><div class="v">{{num .Overview.Provinces}}<small>个</small></div><div class="k">覆盖省份</div></div>
|
||
<div class="kpi"><div class="v">{{num .Overview.Days}}<small>天</small></div><div class="k">有记录的日子</div></div>
|
||
<div class="kpi"><div class="v">{{num .Overview.Visits}}<small>次</small></div><div class="k">累计到访</div></div>
|
||
<div class="kpi"><div class="v">{{dur .Overview.DwellMin}}</div><div class="k">累计停留</div></div>
|
||
<div class="kpi"><div class="v">{{km .Overview.DistanceKm}}<small>km</small></div><div class="k">出行里程</div></div>
|
||
<div class="kpi"><div class="v">{{if .Overview.FirstAt}}{{since .Overview.FirstAt}}{{else}}—{{end}}</div><div class="k">开始记录于</div></div>
|
||
</div>
|
||
{{end}}
|
||
|
||
{{if and (.Settings.Has "map") .Points}}
|
||
<div class="card">
|
||
<h2>足迹地图</h2>
|
||
<div class="card-sub">共 {{num (len .Points)}} 个地点{{if .Settings.HideHome}} · 已隐藏「家」{{end}}{{if .Settings.HideWork}} · 已隐藏「工作」{{end}}</div>
|
||
<div id="home-map" class="map-preview"></div>
|
||
<div style="margin-top:10px;font-size:12.5px" class="muted">滚轮被禁用,点击地图进入全屏模式查看细节与筛选。</div>
|
||
</div>
|
||
{{end}}
|
||
|
||
<div class="grid g2">
|
||
{{if and (.Settings.Has "types") .ActivityStats}}
|
||
<div class="card">
|
||
<h2>去过的类型</h2>
|
||
<div class="card-sub">按到访次数排序</div>
|
||
<div class="bars">
|
||
{{range .ActivityStats}}
|
||
<div class="bar-row">
|
||
<div class="nm" title="{{.Name}}">{{with icon .Icon}}{{.}} {{end}}{{.Name}}</div>
|
||
<div class="bar-track"><div class="bar-fill" style="width:{{pct .Count $.MaxActivity}}%;background:{{colorof .Color}}"></div></div>
|
||
<div class="vv">{{num .Count}} 次</div>
|
||
</div>
|
||
{{end}}
|
||
</div>
|
||
</div>
|
||
{{end}}
|
||
|
||
{{if and (.Settings.Has "cities") .CityStats}}
|
||
<div class="card">
|
||
<h2>城市足迹</h2>
|
||
<div class="card-sub">按到访次数排序</div>
|
||
<div class="bars">
|
||
{{range .CityStats}}
|
||
<div class="bar-row">
|
||
<div class="nm"><a href="{{$.CityLink .City}}">{{.City}}</a></div>
|
||
<div class="bar-track"><div class="bar-fill" style="width:{{pct .Count $.MaxCity}}%"></div></div>
|
||
<div class="vv">{{num .Count}} 次</div>
|
||
</div>
|
||
{{end}}
|
||
</div>
|
||
<div style="margin-top:12px" class="muted">共覆盖 {{num .Overview.Cities}} 座城市、{{num .Overview.Provinces}} 个省级行政区。</div>
|
||
</div>
|
||
{{end}}
|
||
</div>
|
||
|
||
{{if .Monthly}}
|
||
<div class="card">
|
||
<h2>月度活跃度</h2>
|
||
<div class="card-sub">每月到访次数</div>
|
||
<div class="cols">
|
||
{{range .Monthly}}<div class="col" style="height:{{.Pct}}%" title="{{.Key}}:{{.Count}} 次"></div>{{end}}
|
||
</div>
|
||
<div class="cols-x">{{range .Monthly}}<span>{{.Label}}</span>{{end}}</div>
|
||
</div>
|
||
{{end}}
|
||
|
||
{{if and (.Settings.Has "heatmap") .Calendar}}
|
||
<div class="card">
|
||
<h2>活跃日历</h2>
|
||
<div class="card-sub">每一列是一周,颜色越深记录越多</div>
|
||
<div class="heat">
|
||
{{range .Calendar}}<div class="wk">{{range .Days}}<div class="d {{if gt .Level 0}}l{{.Level}}{{end}}" title="{{.Title}}"></div>{{end}}</div>{{end}}
|
||
</div>
|
||
<div class="heat-legend">少 <span class="d"></span><span class="d l1"></span><span class="d l2"></span><span class="d l3"></span><span class="d l4"></span> 多</div>
|
||
</div>
|
||
{{end}}
|
||
|
||
<div class="grid g2">
|
||
{{if and (.Settings.Has "transport") .Transports}}
|
||
<div class="card">
|
||
<h2>出行方式</h2>
|
||
<div class="card-sub">按次数排序,里程为两点间直线距离估算</div>
|
||
<div class="bars">
|
||
{{range .Transports}}
|
||
<div class="bar-row">
|
||
<div class="nm">{{with icon .Icon}}{{.}} {{end}}{{.Name}}</div>
|
||
<div class="bar-track"><div class="bar-fill" style="width:{{pct .Count $.MaxTransport}}%;background:{{colorof .Color}}"></div></div>
|
||
<div class="vv">{{num .Count}} 次</div>
|
||
</div>
|
||
{{end}}
|
||
</div>
|
||
</div>
|
||
{{end}}
|
||
|
||
{{if and (.Settings.Has "tags") .Tags}}
|
||
<div class="card">
|
||
<h2>足迹标签</h2>
|
||
<div class="card-sub">记录时打上的自定义标签</div>
|
||
<div class="chips">
|
||
{{range .Tags}}
|
||
<a class="chip" href="{{$.TagLink .ID}}" title="{{num .Count}} 次">
|
||
<span class="dot" style="background:{{colorof .Color}}"></span>{{.Name}}
|
||
<span class="muted">{{num .Count}}</span>
|
||
</a>
|
||
{{end}}
|
||
</div>
|
||
</div>
|
||
{{end}}
|
||
</div>
|
||
|
||
{{if and (.Settings.Has "weather") .Weather}}
|
||
<div class="card">
|
||
<h2>天气足迹</h2>
|
||
<div class="card-sub">记录期间经历过的天气</div>
|
||
<div class="tw">
|
||
<table class="tb tb-stack">
|
||
<thead><tr><th>天气</th><th class="num">记录小时数</th><th class="num">平均气温</th><th class="num">范围</th></tr></thead>
|
||
<tbody>
|
||
{{range .Weather}}
|
||
<tr>
|
||
<td>{{condition .Condition}}</td>
|
||
<td class="num" data-label="记录小时数">{{num .Count}}</td>
|
||
<td class="num" data-label="平均气温">{{f1 .AvgTemp}} ℃</td>
|
||
<td class="num" data-label="范围">{{f1 .MinTemp}} ~ {{f1 .MaxTemp}} ℃</td>
|
||
</tr>
|
||
{{end}}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
{{end}}
|
||
|
||
{{if and (.Settings.Has "timeline") .Recent}}
|
||
<div class="card">
|
||
<h2>最近足迹</h2>
|
||
<div class="card-sub">最新 {{num (len .Recent)}} 条到访记录</div>
|
||
<div class="list">
|
||
{{range .Recent}}
|
||
<div class="item">
|
||
<div class="ic" style="background:{{colorof .Color}}22">{{iconor .Icon "📍"}}</div>
|
||
<div>
|
||
<div class="t">{{if .PlaceID}}<a href="{{$.PlaceLink .PlaceID}}">{{.PlaceName}}</a>{{else}}未命名地点{{end}}</div>
|
||
<div class="m">{{day .Arrival}} · {{hm .Arrival}}{{if .City}} · {{.City}}{{end}}{{if .ActivityName}} · {{.ActivityName}}{{end}}{{if .Tags}} · {{range $i, $t := .Tags}}{{if $i}}、{{end}}<span class="tag">{{$t}}</span>{{end}}{{end}}</div>
|
||
</div>
|
||
<div class="r">{{dur .DurationMin}}<br><span class="muted">{{since .Arrival}}</span></div>
|
||
</div>
|
||
{{end}}
|
||
</div>
|
||
<div style="margin-top:12px"><a class="btn sm" href="/timeline">查看完整时间线 →</a></div>
|
||
</div>
|
||
{{end}}
|
||
|
||
</div>
|
||
|
||
{{if and (.Settings.Has "map") .Points}}
|
||
<script>
|
||
window.addEventListener('load', function () {
|
||
window.rondMap.preview({ id: 'home-map', points: {{json .Points}}, clickToFull: true });
|
||
});
|
||
</script>
|
||
{{end}}
|
||
{{end}}
|
||
{{end}}
|