Files

137 lines
8.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 2026-10-12
## 专题的「迷雾显示区域」改成一组圆(多圆 + 地图点选)
用户提出两点:① 显示区不该只有一个圆,应该能圈多个;② 应该在**地图上点选**,
而不是让他手填经纬度和半径。
### 方案(先出清单获批,分批落地)
先摸清了现状:单圆硬编码在 6 处(`topics` 三列 / `HasArea` / `topicAreaCond` /
`fitParams` / 后台三个输入框 / `topic.html` 的 `fogArea`)。同时发现项目里**已经有**
一套现成的地图选圆交互(`/admin/fog-mask` 那个页面:点选圆心 + 拖拽 + 半径可调 +
多圆列表),可以直接抄它的模式。而 `fog_masks` 是**另一个语义**(圈内迷雾对访客隐藏),
用户明确这轮不动它。
三个岔路口问过用户,都选了推荐项:只改专题(不做站点级)、后台做成**专题表单内嵌地图**
(不是独立管理页)、不动遮罩区。
原计划 B1(存 areas)/B2(查询认多圆)之间会留一个「存了但只认第一个圆」的陷阱状态,
所以合并成一批:数据层与查询层一起做,后台先用兼容桥(仍手填单圆,落进 areas)。
### 落地(三个提交)
- `1bb35db` 后端与查询层:`topics.areas` jsonb 数组 + 存量回填;`Topic.AreaList()`
归一(改为空格时退回老的三列,未回填的老行与直接构造 Topic 的调用方都继续工作);
`topicAreaCond` 改成 N 个圆的 OR;`fitParams` 改用所有圆的并集外接矩形。
- `44763df` 前台渲染:`clip-path` 从 `circle()` 换成 `path()`(多子路径、同绕向 ⇒
nonzero 下自然并集);拼路径抽成 `fog-clip.js` 以便跑 node 单测;顺带清掉已死的
`fitCircle`;`verify.sh` 挂进前端单测。
- 待办(B3):**后台地图编辑器**还没做(专题表单目前仍是三个手填输入框)——
这是用户最初诉求的第二半,下一批做。
### 关键取舍
- **为什么不单开一张表**:圆是专题定义的组成部分、与专题一起读写、没有独立生命周期;
单开表还要过一遍「能不能从备份重导」的归属口径、改 `dataset_ownership_test` 白名单、
注意迁移块顺序。jsonb 一次全绕开。
- **废弃列保留并镜像第一个圆**:回滚旧二进制时退化成「第一个圆」总比「没有区域」强。
- **`fitCircle` 删掉**:多圆表达不了「圆心 + 半径」,留着就是两套并行的贴合口径。
### 只在这轮踩到的坑
- **CSSOM 会把 `clip-path` 规范化**:`style.clipPath` 读回来被补上空格
(`path("M 405 296 a 87 87 …")`),且位置不固定(`296 a87`)、第一个子路径尾部
还可能多个空格。想解析回几何必须每处分隔都用 `\s*`/`\s+` 容忍,别写死 ——
我连着写错两版正则(先是 `Z$` 卡在尾部空格)。
- **`--clip` 截图的 `pad=10`**(×scale)又咬了一次:这次用**自校准**绕开的 ——
用单圆掩码反解出 scale 与 offset(实测 2.0 / 19.2),不再手算元素坐标。
## 后台的显示区编辑器(B3,用户诉求的后半)
三个手填输入框(中心纬度/经度/半径)换成**地图 + 圆列表**:点地图加圆、拖圆心移动、
拖圆边改半径、列表里可改半径/定位/删除、可一次清空;改动立刻写进隐藏字段
`areas`(JSON) 与 `crs`,随专题表单一起提交。复用 `/admin/fog-mask` 那套约定
(`/api/map-config` 取底图、底图坐标系随表单带上、后端换算成 GCJ-02),不另起炉灶。
### 实测抓到的 bug(探针一跑就现形)
`/admin/topics` **没设 `p.HasMap = true`** ⇒ 布局不引入 Leaflet。表现极隐蔽:
脚本加载了、`rondTopicAreas` 也在,就是 `window.L` 永远 undefined,`init` 静默返回、
**控制台不报错**、页面看着像「什么都没发生」。已加守卫
`TestTopicsAdminPageLoadsLeaflet`(按函数体截取后断言含 `HasMap = true`)。
记忆里那条「带地图页须 `p.HasMap=true`」是真的会咬人。
### 两个设计上的取舍
- **areas 的初值渲染进隐藏字段**(`value="{{.Form.AreasJSON}}"`),JS 也从隐藏字段读初值,
而不是另传一份。这样脚本没加载上时,表单提交的仍是服务端渲染的原值 ——
否则一次保存就把已有显示区**静默清空**。守卫
`TestTopicAdminUsesMapEditorNotCoordInputs` 钉住了「初值来源」与「旧输入框必须没了」。
- **上限两边各写一份**(前端 `MAX_AREAS/MIN_KM/MAX_KM` vs 后端 Go 常量),并加守卫
`TestTopicAreaLimitsMatchBetweenGoAndJS` 直接比对数字。不一致的表现很别扭:
前端放行、后端拒绝,用户看到一句红字却不知道改哪里。
### 小坑
- 半径输入框套了一层**定宽容器**:站点全局 input 规则是 `width:100%` 且带 10 个 `:not()`
(特异性 (0,11,1)),直接给 input 写宽度压不过。
- `topic-areas.js` 只把**纯函数**(校验/序列化/增删改/几何换算)暴露出来供 node 单测,
另加一个最小测试钩子 `api._map` 供无头验证(同 `window.rondMap._state` 惯例)——
不给把手就只能真拿鼠标点地图,CDP 下很难稳定复现。
### gofmt / 行尾
`gofmt -l` 报的整文件重写有两层原因,已一并处理:
① Go 1.19 起 gofmt 会重排**文档注释**里的缩进列表(我写的 `// ① …` 被要求改成 tab 缩进块);
② 工作区是 CRLF 而 `.gitattributes` 声明 `eol=lf`。
`gofmt -w` 归一后 `git diff` 没有额外噪声 —— 说明 **blob 本来就是 LF,CRLF 只是检出产物**,
之前担心的「模板 CRLF 与 .gitattributes 冲突」不是仓库内容问题。
### 记忆压缩
`MEMORY.md` 压到 **8919**(原 9285):合并「归属口径/防复发」与「跨备份/附属数据」两节
(同属归属)、若干长条目的**理由**下沉 details(规矩一字未删)、收紧自己新加的那条。
12 节 → 11 节。
## 修 bug:半径输入框被浏览器原生校验误判
用户反馈「输入半径总是提示『请输入一个有效的值,最接近的两个有效值为 XX 和 XX』」。
**根因**:`<input type="number">` 的 **`step` 是相对 `min` 递增**的,不是「`step` 的整数倍」。
`min=0.05` + `step=0.5` ⇒ 合法值只有 `0.05 / 0.55 / 1.05 …`,于是 3、3.5、7.25 全被判非法。
关键是**这是浏览器原生提示**:JS 与后端都拦不到,我们自己的校验根本没机会说话。
实测对照(同一元素只换 step):
`step=0.5` → 0.05✓ 1✗ 3✗ 3.5✗ 7.25✗ 13.37✗;`step=0.05` → 13.37 仍✗;`step=any` → 全✓。
采用 `step="any"`,保留 `min/max`(真实边界 + spinner 范围),把校验交给 JS/后端。
**加了一条通配守卫**(`TestNumberInputStepNeverMismatchesMin`):扫**所有**模板的数字框,
凡「有 `min` 且有数值 `step`」就要求 `min` 是 `step` 的整数倍(或 `step="any"`);
JS 动态建的输入框模板扫不到,另用 `TestTopicAreaRadiusInputAllowsAnyStep` 钉住。
变异验证过(step 改回 0.5 ⇒ 守卫立刻红)。全站其它数字框(`radius_m` min=50/step=50)
本来就合法,未动。
**顺带**:把 `admin/topics.html` 的工作区行尾归一到 LF。`git add` 之后**零改动** ⇒
再次确认 blob 本来就是 LF,CRLF 只是检出产物(那条 CRLF 警告是 stat 缓存假象)。
## 推送这个仓库要认证(非交互环境会卡住)
用户让「提交一次」时本地其实已经全部提交完了(每批做完就提交),工作区干净;
唯一没做的是推送。结果 `git push origin master` **卡了 7 分钟没有任何输出**。
诊断(下次直接照这个查):
- 远端 `git.shiroko.one` 的 **读是匿名的**(`upload-pack` HTTP 200)、
**写要认证**(`receive-pack` HTTP 401)⇒ 所以 `git fetch` 一切正常、唯独 push 卡住。
- `tasklist` 里能看到 `git-credential-helper-selector`(**有可见窗口**,标题
`CredentialHelperSelector`),`git config credential.helper` = `helper-selector` +
PortableGit 自带的 `git-credential-manager.exe`。本机从未推过这个仓库 ⇒ 触发选择器弹窗等人。
- 判据:`netstat` 里到远端的连接**根本没建立**(ESTABLISHED 全是本机 postgres),
说明停在认证之前,不是网络慢。
- ⚠️ `git push | tail -N` 会把进度缓冲住,看起来「一片空白」——排查时别用管道。
处置:结束掉 push 那几个进程(不动本地提交,也不会留 `.git/*.lock`),
**由用户在自己的终端里推**(交互式提示看得见)。
**结论:以后不要在这个环境里代跑 `git push`,直接把命令交给用户。**