编辑页:新增「重复到访」卡片 —— 以基线(手机包)为参照清掉站点侧的历史副本

站点库里有一批「到达时间 + 地点与手机包里某条完全相同、但 UUID 不同」的到访副本,
合并/差异按 UUID 认人会把它们当成备份新增,导出到 rond 就成了成对的两条重复记录。
判定与 tools/dedup_site_visits.py 同一套语义:UUID 是前提(只按时间+地点判会误删手机包
自身合法的成对条目);基线跟本站一条都对不上时只给说明、不给按钮。清理在单事务里删
副本 + 其位移/天气/留档,并把指向副本的 ZMERGEDTO/ZPARENT 改指到保留项——只动本来
就有的那个键,工具那版会凭空补出一个 ZMERGEDTO(真机里是「已并入别处」,会白丢记录)。

顺带修一个「一补录天气就整包导出失败」的洞:rond 导出把 weather.is_daylight 扫进裸 bool,
而站点「新增天气」不写这一列 ⇒ NULL ⇒ sql.Scan 报错。改成 COALESCE(is_daylight,false),
与导入侧读真机包同口径。

验收:301 PASS / 0 FAIL / 0 SKIP(新增 4 个用例,含变异验证:去掉 UUID 前提/改回
create_if_missing=true/不删副本位移,三种改法都被用例抓到)。
This commit is contained in:
tamakyi
2026-09-29 19:17:29 +08:00
parent 40441ba900
commit 152af81f6a
7 changed files with 1097 additions and 1 deletions
+45
View File
@@ -346,6 +346,51 @@
{{else}}<div class="empty">没有匹配的地点</div>{{end}}
</div>
{{/* 重复到访:站点侧跟手机包「同一到达时间 + 同一地点」的历史副本。判定见
edit_duplicates.go(与 tools/dedup_site_visits.py 同一套语义)。
只在检出 >0 对时出现;判定不了时只给一行说明、不给按钮。 */}}
{{if .DupUnavailable}}
<div class="card" data-card="dup-visits">
<h2>重复到访</h2>
<div class="card-sub">{{.DupUnavailable}}</div>
</div>
{{else if .DupVisits}}
<div class="card" data-card="dup-visits">
<h2>重复到访 {{num (len .DupVisits)}} 对</h2>
<div class="card-sub">
这些到访跟手机包里的某条<b>到达时间 + 地点完全相同、但 UUID 不同</b>,是站点侧的历史副本,
导出到 rond 后会变成成对的两条。默认全选:删掉勾选的副本会连它的位移 / 天气 / 留档一起清,
并把指向它的合并标记改指到保留项(不动就会在导出时留下悬空引用)。
</div>
<form method="post" action="/admin/edit/dup/clean">
<div class="tw">
<table class="tb tb-stack">
<thead><tr><th>到达时间</th><th>地点</th><th>保留(手机来源)</th><th>删除(站点副本)</th></tr></thead>
<tbody>
{{range .DupVisits}}
<tr>
<td class="muted mono" data-label="到达时间">{{.ArrivalStr}}</td>
<td data-label="地点">{{if .PlaceName}}{{.PlaceName}}{{else}}<span class="muted">(未命名地点)</span>{{end}}</td>
<td class="mono" data-label="保留">#{{.Keep}}</td>
<td data-label="删除">
<label class="check"><input type="checkbox" name="victim" value="{{.Victim}}" checked>
<span class="mono">#{{.Victim}}</span></label>
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
<div class="row" style="margin-top:10px;gap:8px;align-items:center">
<button class="btn primary" type="submit"
onclick="return confirm('删除勾选的副本?连它们的位移 / 天气 / 留档一起清掉,不可撤销。')">清理选中的副本</button>
<a class="btn" href="{{.EditLink}}">全部保留</a>
<span class="muted">「全部保留」什么都不改,只是取消勾选。</span>
</div>
</form>
</div>
{{end}}
<div class="card" data-card="visits">
<h2>到访记录</h2>
<form method="get" action="/admin/edit" class="search-row" style="margin-top:6px">