From 829a318400b37eb99c3ddd413b8539dd47a92cdd Mon Sep 17 00:00:00 2001 From: tamakyi Date: Mon, 12 Oct 2026 17:35:55 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=B0=E5=BF=86=EF=BC=9A=E5=90=8E=E5=8F=B0?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E5=8C=BA=E7=BC=96=E8=BE=91=E5=99=A8=EF=BC=88?= =?UTF-8?q?=E5=9C=B0=E5=9B=BE=E7=82=B9=E9=80=89=EF=BC=89+=20HasMap=20?= =?UTF-8?q?=E9=99=B7=E9=98=B1=20+=20=E8=AE=B0=E5=BF=86=E7=B4=A2=E5=BC=95?= =?UTF-8?q?=E5=8E=8B=E7=BC=A9=E5=88=B0=208919?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .workbuddy/memory/2026-10-12.md | 47 +++++++++++++++++++++++++++++ .workbuddy/memory/MEMORY-details.md | 35 +++++++++++++++++++-- .workbuddy/memory/MEMORY.md | 2 +- 3 files changed, 80 insertions(+), 4 deletions(-) diff --git a/.workbuddy/memory/2026-10-12.md b/.workbuddy/memory/2026-10-12.md index d1a5b25..e8f039c 100644 --- a/.workbuddy/memory/2026-10-12.md +++ b/.workbuddy/memory/2026-10-12.md @@ -46,3 +46,50 @@ 我连着写错两版正则(先是 `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 节。 diff --git a/.workbuddy/memory/MEMORY-details.md b/.workbuddy/memory/MEMORY-details.md index f9d2238..23ee6fa 100644 --- a/.workbuddy/memory/MEMORY-details.md +++ b/.workbuddy/memory/MEMORY-details.md @@ -1204,7 +1204,36 @@ HTML,一行里必然带 ``,一拒就把正常用法挡死了(我 并集也亮(无洞)**,整体集合差异 0.013%;迷雾掩码 86,776 px 按并集解析式判**圆外 0 个**, 两个圆内分别 52,609 / 46,757 px ⇒ 第二个圆真的被认了。 -### 待办 +### 后台编辑器:地图点选(2026-10-12 当天补完) -后台的**地图点选编辑器**(专题表单内嵌地图、多圆增删拖拽)还没做 —— 这是用户诉求的 -第二半,专题表单目前仍是三个手填输入框(走兼容桥:合成一个圆写进 areas)。 +三个手填输入框(中心纬度/经度/半径)换成**地图 + 圆列表**(`static/js/topic-areas.js`: +点地图加圆、拖圆心移动、拖圆边改半径、列表里可改半径/定位/删除/清空)。改动立刻写进 +隐藏字段 `areas`(JSON) 与 `crs`,随专题表单一起提交。复用 `/admin/fog-mask` 那套约定 +(`/api/map-config` 取底图、底图坐标系随表单带上、后端换算 GCJ-02)。 +地图初始视野取生效数据集的地点包围盒(`placesBounds`),一上来就落在自己的地界上。 + +⚠️ **三条容易再踩的**: + +- 🔴 **`/admin/topics` 必须 `p.HasMap = true`**(`topicsAdminPage`)。漏了的表现极隐蔽: + 脚本加载了、`rondTopicAreas` 也在,就是 `window.L` 永远 undefined,`init` 静默返回、 + **控制台不报错**、页面看着像「什么都没发生」。守卫 `TestTopicsAdminPageLoadsLeaflet` + (按函数体截取后断言含 `HasMap = true`)。 +- 🔴 **`areas` 的初值要渲染进隐藏字段**(`value="{{.Form.AreasJSON}}"`),JS 也从隐藏字段 + 读初值而不是另传一份:脚本没加载上时提交的仍是服务端渲染的原值,否则**一次保存就把 + 已有显示区静默清空**。守卫 `TestTopicAdminUsesMapEditorNotCoordInputs` 钉住初值来源、 + 挂点 id 齐全、以及「三个旧输入框必须没了」(留着就是第二套只写第 1 个圆的入口)。 +- **上限两边各写一份**(JS `MAX_AREAS/MIN_KM/MAX_KM` vs Go `maxTopicAreas` 等), + 守卫 `TestTopicAreaLimitsMatchBetweenGoAndJS` 直接比对数字;前端还据此**禁用提交**。 + 不一致的表现是「前端放行、后端拒绝,用户看到红字却不知道改哪里」。 + +小坑:半径输入框得套一层**定宽容器**(`.area-km-box`)——站点全局 input 规则是 +`width:100%` 且带 10 个 `:not()`(特异性 (0,11,1)),直接给 input 写宽度压不过。 +`topic-areas.js` 只把**纯函数**暴露给 node 单测,另加最小测试钩子 `api._map` +供无头验证(同 `window.rondMap._state` 惯例)—— 不留把手就只能真拿鼠标点地图。 + +### gofmt / 行尾(同一天的附带结论) + +`gofmt -l` 报「整文件重写」有两层原因:① Go 1.19 起 gofmt 会重排**文档注释**里的缩进列表 +(`// ① …` 要改成 tab 缩进块);② 工作区 CRLF 而 `.gitattributes` 声明 `eol=lf`。 +`gofmt -w` 归一后 `git diff` **没有额外噪声** ⇒ **blob 本来就是 LF,CRLF 只是检出产物**, +而不是仓库内容问题(之前担心的「模板 CRLF 冲突」可以放下了)。 diff --git a/.workbuddy/memory/MEMORY.md b/.workbuddy/memory/MEMORY.md index 87f2b30..ecd9eb6 100644 --- a/.workbuddy/memory/MEMORY.md +++ b/.workbuddy/memory/MEMORY.md @@ -30,7 +30,7 @@ - 瓦片须与底图同 `crs`;带地图页须 `p.HasMap=true`。 - `tileDigits` 补前导 0;`tileName` 尾缀 `len(s)-2` 单数字编号时为 -1 ⇒ panic;解码守卫 `len(name)<8`。 - `fogIndexV` 必须 `atomic.Pointer`(普通指针=真 data race)。`fog_race_test.go`(-race) -- **专题显示区=一组圆(并集)**:存 `topics.areas` jsonb(不单开表);SQL 是 N 个圆的 **OR**(每圆 3 个占位符,编号须恰好覆盖 `[prefix+1,len(args)]`)。裁剪=**单独 pane**(不能裁 `tilePane`)+ `clip-path: path()`,每圆一段**同绕向**子路径(反了重叠处会挖成洞);圆心须 `project()`;⚠️ 注册必须排在 `applyFit()` **之后**(视图未定会抛「Set map center and zoom first.」并打断后续图层=迷雾整片消失且不报错)。`TestTopicFogIsClippedToAreas`(四十五、四十六) +- **专题显示区=一组圆(并集)**:存 `topics.areas` jsonb(不单开表);SQL 是 N 个圆的 **OR**(每圆 3 个占位符,编号须恰好覆盖 `[prefix+1,len(args)]`)。裁剪=**单独 pane**(不能裁 `tilePane`)+ `clip-path: path()`,每圆一段**同绕向**子路径(反了重叠处会挖成洞);圆心须 `project()`;⚠️ 注册必须排在 `applyFit()` **之后**(视图未定会抛「Set map center and zoom first.」并打断后续图层=迷雾整片消失且不报错)。后台=地图点选(`topic-areas.js`);⚠️ areas 初值必须渲染进隐藏字段(脚本没加载就静默清空)、上限两边写死须一致(四十五、四十六) ## 前端 / 模板 / CSS(details 六~八、十七、廿三、廿八D、卅七) - ⚠️ **对访客公开的块,措辞必须按身份分支**(`{{if .IsAdmin}}我的…{{else}}站长…{{end}}`):