审计修复:前端(模板 / CSS / JS 与无障碍)
- 地图脚本:localStorage 读写走 lsGet/lsSet 兜底(隐私模式下裸访问会打断整段脚本); preview() 在 /api/map-config 还没回来时不丢点(previewQueue 在 if (live) 之前排队); 异步回包一律发序号作废,取消后回来的包不再画 - photo-exif.js:EXIF 时间全 0 不再变成 1899-11-30 写进到访时间;读 count 前先按版本卡宽度 - 数据编辑页:三个筛选表单都把其余条件用隐藏域原样带上,提交不再把别的列表的筛选清掉 - 补全页:sessionStorage 的读写一律包 try(脏数据/隐私模式都会抛) - 窄屏:删掉被后面同特异性规则盖掉的死内边距;宽表堆叠类名成对、判据扩到所有 tb 表 - 无障碍:图片删除按钮补 aria-label,访客画廊图片补 alt - report.html 补上漏掉的 </tr>,fog-mask 的宽表带 tb-stack 本批不碰数据库与导出路径:往返包 823/323/8/30/791/557/2246 全等、 坐标偏差 0.000000000、时间偏差 0s、迷雾 8701 块一致。
This commit is contained in:
@@ -205,6 +205,13 @@
|
||||
<form method="get" action="/admin/edit" class="filter-row" style="margin-top:6px">
|
||||
{{/* back 要跟着走:不然一筛选,「返回地点库」就没了 */}}
|
||||
{{if .Back}}<input type="hidden" name="back" value="{{.BackRaw}}">{{end}}
|
||||
{{/* 三个表单各自只带自己那几个条件,其余条件必须原样带上:
|
||||
否则搜一下就把别的列表的筛选悄悄清掉了。 */}}
|
||||
{{if .VisitQuery}}<input type="hidden" name="vq" value="{{.VisitQuery}}">{{end}}
|
||||
{{if .MovementFilter.Transport}}<input type="hidden" name="mt" value="{{.MovementFilter.Transport}}">{{end}}
|
||||
{{if .MovementFilter.PlaceID}}<input type="hidden" name="mp" value="{{.MovementFilter.PlaceID}}">{{end}}
|
||||
{{if .MovementFilter.From}}<input type="hidden" name="mfrom" value="{{.MovementFilter.From}}">{{end}}
|
||||
{{if .MovementFilter.To}}<input type="hidden" name="mto" value="{{.MovementFilter.To}}">{{end}}
|
||||
<label class="f" style="flex:1 1 200px"><span>搜索</span><input type="text" name="q" value="{{.Query}}" placeholder="名称 / 城市 / 区县"></label>
|
||||
<label class="f" style="flex:0 1 170px"><span>坐标来源</span>
|
||||
<select name="src">
|
||||
@@ -343,6 +350,15 @@
|
||||
<h2>到访记录</h2>
|
||||
<form method="get" action="/admin/edit" class="search-row" style="margin-top:6px">
|
||||
{{if .Back}}<input type="hidden" name="back" value="{{.BackRaw}}">{{end}}
|
||||
{{/* 只搜到访不能把别的列表的筛选清掉(原来只带 vq+back,一搜 q/src/sus
|
||||
和行程的 mt/mp/mfrom/mto 全丢了)。 */}}
|
||||
{{if .Query}}<input type="hidden" name="q" value="{{.Query}}">{{end}}
|
||||
{{if .SourceFilter}}<input type="hidden" name="src" value="{{.SourceFilter}}">{{end}}
|
||||
{{if .SuspectOnly}}<input type="hidden" name="sus" value="1">{{end}}
|
||||
{{if .MovementFilter.Transport}}<input type="hidden" name="mt" value="{{.MovementFilter.Transport}}">{{end}}
|
||||
{{if .MovementFilter.PlaceID}}<input type="hidden" name="mp" value="{{.MovementFilter.PlaceID}}">{{end}}
|
||||
{{if .MovementFilter.From}}<input type="hidden" name="mfrom" value="{{.MovementFilter.From}}">{{end}}
|
||||
{{if .MovementFilter.To}}<input type="hidden" name="mto" value="{{.MovementFilter.To}}">{{end}}
|
||||
<label class="f"><span>搜索</span><input type="text" name="vq" value="{{.VisitQuery}}" placeholder="地点 / 城市 / 备注 / 活动 / 日期 / #编号"></label>
|
||||
<div class="act"><button class="btn" type="submit">搜索</button><a class="btn" href="{{.EditLink "vq"}}">重置</a></div>
|
||||
</form>
|
||||
@@ -424,6 +440,8 @@
|
||||
{{if .Back}}<input type="hidden" name="back" value="{{.BackRaw}}">{{end}}
|
||||
{{if .Query}}<input type="hidden" name="q" value="{{.Query}}">{{end}}
|
||||
{{if .VisitQuery}}<input type="hidden" name="vq" value="{{.VisitQuery}}">{{end}}
|
||||
{{if .SourceFilter}}<input type="hidden" name="src" value="{{.SourceFilter}}">{{end}}
|
||||
{{if .SuspectOnly}}<input type="hidden" name="sus" value="1">{{end}}
|
||||
<label class="f" style="flex:0 1 150px"><span>交通方式</span>
|
||||
<select name="mt">
|
||||
<option value="">全部</option>
|
||||
|
||||
@@ -40,14 +40,15 @@
|
||||
<div class="card">
|
||||
<h2>已有遮罩区({{len .Masks}})</h2>
|
||||
{{if .Masks}}
|
||||
<table class="tb">
|
||||
<div class="tw">
|
||||
<table class="tb tb-stack">
|
||||
<thead><tr><th>名称</th><th>圆心(纬度, 经度)</th><th>半径</th><th></th></tr></thead>
|
||||
<tbody>
|
||||
{{range .Masks}}
|
||||
<tr>
|
||||
<td>{{if .Name}}{{.Name}}{{else}}<span class="muted">(未命名)</span>{{end}}</td>
|
||||
<td class="mono">{{printf "%.5f" .Lat}}, {{printf "%.5f" .Lon}}</td>
|
||||
<td>{{printf "%.0f" .RadiusM}} 米</td>
|
||||
<td class="mono" data-label="圆心">{{printf "%.5f" .Lat}}, {{printf "%.5f" .Lon}}</td>
|
||||
<td data-label="半径">{{printf "%.0f" .RadiusM}} 米</td>
|
||||
<td>
|
||||
<button class="btn sm" type="button" data-edit
|
||||
data-id="{{.ID}}" data-name="{{.Name}}"
|
||||
@@ -62,6 +63,7 @@
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="muted">还没有遮罩区。在地图上点选圆心、设置半径后保存即可。</div>
|
||||
{{end}}
|
||||
|
||||
@@ -520,7 +520,11 @@
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ coord: coordSel(), points: coords })
|
||||
}).then(function (r) { return r.json(); }).then(function (d) {
|
||||
}).then(function (r) {
|
||||
// 500 时回的是 HTML,直接 r.json() 会抛 SyntaxError(英文),先判状态码
|
||||
if (!r.ok) throw new Error('HTTP ' + r.status);
|
||||
return r.json();
|
||||
}).then(function (d) {
|
||||
if (d.error) throw new Error(d.error);
|
||||
return d.items || [];
|
||||
});
|
||||
@@ -671,29 +675,24 @@
|
||||
|
||||
// ---- 单个点位的地图弹窗:只建一个 Leaflet 实例,之后靠 setPoints/setView 复用 ----
|
||||
var modal = document.getElementById('point-modal');
|
||||
var modalInited = false;
|
||||
function openPointMap(lat, lon, name, addr) {
|
||||
document.getElementById('point-modal-title').textContent = name || '点位';
|
||||
document.getElementById('point-modal-meta').textContent =
|
||||
(addr && addr !== '—' ? addr + ' · ' : '') + lat.toFixed(6) + ', ' + lon.toFixed(6);
|
||||
modal.style.display = 'flex';
|
||||
var pts = [{ lat: lat, lon: lon, n: name || '', v: 1 }];
|
||||
if (!modalInited) {
|
||||
if (!window.rondMap) { document.getElementById('point-modal-meta').textContent += '(地图脚本未就绪)'; return; }
|
||||
window.rondMap.preview({ id: 'point-modal-map', points: pts });
|
||||
modalInited = true;
|
||||
// 单个点 fitBounds 会顶到最大缩放,等底图就绪后固定到街区级
|
||||
var pin = function () {
|
||||
var st = window.rondMap._state['point-modal-map'];
|
||||
if (st && st.map) { st.map.invalidateSize(); st.map.setView([lat, lon], 16); }
|
||||
};
|
||||
setTimeout(pin, 400);
|
||||
setTimeout(pin, 1200);
|
||||
} else {
|
||||
if (!window.rondMap) { document.getElementById('point-modal-meta').textContent += '(地图脚本未就绪)'; return; }
|
||||
// 统一交给 preview:它自己区分「首次建图」与「复用换点」,配置还没回来时也会把点排队补画。
|
||||
// 原来这里同步置 modalInited=true,第二次打开时地图实例其实还没建好(_state 里没有条目),
|
||||
// 于是走 else 分支拿不到 st,该画的点被静默丢掉。
|
||||
window.rondMap.preview({ id: 'point-modal-map', points: pts });
|
||||
// 单个点 fitBounds 会顶到最大缩放,等底图就绪后固定到街区级
|
||||
var pin = function () {
|
||||
var st = window.rondMap._state['point-modal-map'];
|
||||
if (st && st.setPoints) st.setPoints(pts);
|
||||
if (st && st.map) { st.map.invalidateSize(); st.map.setView([lat, lon], 16); }
|
||||
}
|
||||
};
|
||||
setTimeout(pin, 400);
|
||||
setTimeout(pin, 1200);
|
||||
}
|
||||
function closePointMap() { modal.style.display = 'none'; }
|
||||
document.getElementById('point-modal-close').addEventListener('click', closePointMap);
|
||||
|
||||
Reference in New Issue
Block a user