c86658966c927705602d75c97401480e6453a315
11
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
190dc56301 |
v55:笔记详情不重复标题 / 任务状态选完即改(去按钮)/ 编辑任务弹框 / 子任务截止时间换最新控件
用户 2026-10-17 四条。
① 笔记详情:正文里不再重复显示标题
用户原话:「笔记详情里面的标题已经变成这个日笔记的题目了,那**下面那个里面
就不用再显示这个题目**了。」
背景:v52 已把**页头**改成笔记自己的标题(并参与 <title>),
而**正文区里又写了一遍**同一个标题 ⇒ 同一页同一个名字出现两次。
⇒ 删正文里那个 `<h1 class="note-read-title">`;**页头那份保留**。
连带删掉已无使用者的 `.note-read-title` CSS 规则
(留一条没有使用者的规则,只会让下一个人以为"正文里还该有个标题")。
② 任务详情:状态**选一下就改**(去掉「改」按钮)
用户原话:「任务详情里边,状态后面**不用加按钮**了。不是说选了之后再点一下才改,
而是**只要一选就让它改**:选一下,状态就发生改变就行了。」
⇒ `<select>` 的 `change` 直接 fetch 提交到**既有的** `tasks/status`
(它本来就认 `X-Requested-With` 并回 JSON —— 不新开路由、不加新契约)。
成功后**就地**同步三处(不刷页、不丢滚动位置):
· 下拉本身;
· 页头副标题的状态词;
· 页头那颗「标记完成 ↔ 重新打开」按钮的文案与 hidden 值
(改了状态而按钮还写"标记完成"就自相矛盾)。
反馈:一条**浮在顶部**的轻提示 `.tk-flash`(`position:fixed` 不占文档流 ⇒
改状态不会让页面跳动)。循环任务那句"下一次也排上了"(`d.msg`)照旧显示 ——
不能因为改交互把 v24 定下的行为丢掉。
⚠️ **无 JS 兜底**:`<noscript>` 里那颗「改」按钮
(规范:脚本开启时 noscript **整块不渲染**)。不要用 `<button hidden>`+JS
去"显示"它(会闪、脚本报错时永远不出现)。
🔴🔴 **踩坑(本轮最值钱)**:第一版写成"先 `sel.disabled = true`、再
`new FormData(form)`" ⇒ **HTML 规范:禁用的控件不参与表单数据构造** ⇒
字段丢了 ⇒ 服务端收到空 status ⇒ 落回 `todo`。
症状是"请求成功、回包 ok、页面还给了提示,唯独值不对" —— 极具误导性。
⇒ **先构建、后禁用**。
③ 编辑任务 = 弹框
用户原话:「**编辑任务,弹框处理**。」
原来详情页是个 `<details>` 就地展开表单(展开会把下面的子任务/附件/评论整段往下推);
现在点「编辑这项任务」**浮起弹框**(`.cal-modal`,与「新建任务 / 新建日程 /
编辑观影记录」同一套类名)。
⚠️ **表单一个字没改** —— 仍 require 同一份 `_edit_form.php`
(条目浮层 `tasks/edit?embed=1` 也用它,两处永远同一张)。
这次只加了个 `$tkEditModal` 开关:true 时套 `.cal-modal` 壳 +
「保存」挪到底栏(与新建任务一致:主要动作在右下角)。
⚠️ 打开那一刻才 `fbBootAntd()` / `fbUpgradeRange()` 升级里面的日期控件
(hidden 时也能挂上,但 antd 弹层定位需要元素有实际尺寸)。
⚠️ 事件委托挂 `document`(与观影详情页同一理由:校验失败若重画这块,委托仍有效)。
④ 子任务截止时间:换最新控件
用户原话:「**子任务的截止时间,使用最新的时间控件**。」
**真根因**:`tasks/show.php` 子任务那块 require `_datetime.php` 时
**漏传 `$dtPlugin`** ⇒ 空值时走**旧的三下拉(年/月/日)**
⇒ 与「新建任务」「任务编辑」里的 antd 控件**不一样**。
⇒ 补 `$dtPlugin = 'antd-single'`(截止时间是**单个时刻**,不是范围)。
⚠️ 全仓这一族的调用点**逐处核对过**:只有子任务这一处漏了;其余
(日程起止 / 观影起止 / 任务新建 / 任务编辑 / 行程起止 / 修正起止)
都已有 `'antd'` 或 `'antd-single'`。
⚠️ `people/form.php`(生日)**有意不传** —— 生日是"日期",年份要能下拉到 1900,
与"截止时间"不是一回事,别顺手改。
验证(新增 2 套件 + 更新 deploy 断言):
· _fb_v55_ui.py(**30 条**真机断言)
· _b55_falsify.py(**8 注入 / 8 全抓**,基线 30/0)
· e2e **1518/0**;familybook_deploy.sh 加「第55批形态」段(**13 条**)
· 部署 **0 FAIL**;线上 4 文件 md5 逐字节一致;
线上剥注释核实:笔记模板/`app.css` 里已无 `note-read-title`(反向)、
任务模板有 `data-st-select` / `fd=FormData` / `noscript` 兜底 / `antd-single`、
编辑表单有 `tkEditCard`/`tkEditSubmit`、`app.css` 有 `.tk-flash`;
诊断页已删复验 404
⚠️ 本轮踩坑(已写进 pitfalls.md):
· 🔴🔴 **先 `disabled=true` 再 `new FormData(form)` ⇒ 字段会丢**(表单数据不含禁用控件);
· 连带印证:**用裸 `strpos`/`grep` 做反向断言会命中注释**(我的线上诊断脚本
就因为这个连报两次"还有",剥注释后才对)—— 反向断言一律走"剥注释"。
⚠️ 另:工作树里 `app/ApiHandler.php` / `app/PersonQuery.php` / `app/Home.php` /
`app/Api.php` / `app/ApiToken.php` / `app/Schema.php` / `index.php` /
`templates/settings/me.php` 是**另一个会话**正在做的 App 端 / 设备管理改动,
一字未碰、也未提交。
|
||
|
|
8c651b43eb |
v43 第 43 批:六条反馈(界面 5 + 条目详情浮层)
用户 2026-10-11 反馈六条,逐条定位真根因后修复: ① 纪念日「日期」多出一个控件 —— 只保留最新的那个 两层根因:(a)原生 `input[type=date]` 当初没包在 `.dt-native` 里, v42 那条"AntD 挂上后收起原生框"的选择器根本不命中;(b)更要命的是 `.dt-native` 基类写着 `display: contents` —— 该元素**没有盒子**, 给它 position/width 完全无效 ⇒ 必须把 display 显式改回 block 才收得起来。 ② 编辑纪念日把底层列表页弄没 —— 「修改」原来是整页跳 `days/edit` (套 layout = 一张只有弹框的空白页)。改为 `?embed=1` 只吐弹框那一块, 列表页 JS 取回来替换 `#anNewCard` 并打开 —— 与「新建」同一观感。 内嵌形态标 `$anModalOnly` 以免打 standalone 标记(关闭时不再跳页)。 ③ 拖图裁剪的层被弹框盖住 —— `.crop-overlay` 是 z-index:100 而 `.cal-modal` 是 200 ⇒ 裁剪层被整块盖住。提到 260(与 v41 的 .cn-modal 同一处理)。 ④ 行程弹框里"参与的人"弹不出选人框 —— person_picker.js 只绑定一次, 而弹框表单是 AJAX 片段 ⇒ 里面的 `.pp` 从未被 init。三件事一起: 暴露 `window.fbInitPickers()`(幂等)+ layout 暴露 `window.fbLoadPicker()` (脚本是按需加载的)+ 塞完片段后补调初始化。 ⑤ 日程新建排版/控件/文案 —— 改走观影式 `.mv-grid`(标签对齐 + 冒号); 起止补上 `$dtPlugin='antd'`(试点正式推广到日程);标签「时间范围」→「开始 / 结束」; 删三句提示(结束留空 / 多选提醒 / 全天)。 ⑥ 条目详情浮层(首页日程 / 首页近期任务 / 日程页条目)—— 点条目不再直接跳页,弹浮层显示详情;「详细信息」跳该来源详情页; 「编辑」就地换成该来源的编辑表单(四处 `?embed=1` 片段)。 新增 `templates/_entry_popup.php` + `assets/js/entry_popup.js` + `fb_entry_json()`(三个入口共用一个编码函数)。 验证:php -l 157 文件全过;div 深度 33 组合全配平;片段体检 20 片段无越界; 本地 e2e 1510/0;v43 真机 33/0;v43 反向验证 8/0;v38 36/0;v42 33/0; b31/b32 反向验证 8/0 与 5/0;部署断言本地空跑 RC=0;完整流水线 PUSH_RC=0。 |
||
|
|
d83c94e127 |
v37 第 37 批:日期控件换成「年/月/日 + 时/分」五个原生下拉 + 五处界面重做
用户原话(6 条,一次给全):
①「观影详情页面。观影图片下面有一个块…要加照片请点上方「编辑」…这个块不要,
直接把这个块删除。」
②「编辑页面的时间…选日期的这个控件非常非常不好用。就是如果我把年和月那个地方
拉下来,我选完年和月之后,它并不会回到让我选日的那个界面,它还是不动的…
要么换一个控件,要么在那个地方加一个确定按钮…现在开始和结束时间分在了两行…
能放得下的话就应该放一排…不要让它默认显示在两行上…"散场时间可不填。"这句话去掉。」
③「首页上今天的日程…分了几列,列之间的空隙非常非常的大…日程里面的那两个色块
就是紧挨着的。所以…应该让它们紧挨着。」
④「现在怎么部署的时间这么长?…你修改了哪些页面,你就只测试哪些页面就可以了。」
⑤「日程模块的新建日程…"加上"和"取消"两个按钮在右上角,离得特别远,根本看不到…
每个输入框前面的标题都太小了…都应该加粗、变大。」
⑥「1.新建任务的截止时间,也和观影一致。2.新建任务时竟然没有添加附件…
3.新建任务也弹出一个框,新建完之后刷新看板页面。4.观影新增也弹框输入所有信息。」
② 日期控件:**真根因是"这个控件给不了"**
`<input type="date">` 的日历弹层由**浏览器自己画**,我们碰不到 DOM、也控制不了流程;
Chrome 在"点顶部 `2026年 10月` 切到年月视图"之后,要靠用户**再点一次日期或按 Esc**
才回得到日期视图,各家还不一致 ⇒ 用户遇到的"选完年月就卡住、选不了日"。
修:`_datetime.php` 重写成 **年 / 月 / 日 三个原生 <select> + 时 / 分**,
选完即生效、无需"确定";秒默认去掉(用户"只记录到时和分")。
⚠️ 提交契约**一字未改**:`*_date` 仍是真字段(改 `type=hidden`)+ `*_hour/_minute`。
⚠️ `required` 落在隐藏控件上会让 Chrome 报 "not focusable"(点保存什么都不发生)
⇒ 改用 `data-dt-required` 声明、JS 自查(12 个调用点全部受影响)。
起止两端:`.dt-range.dt-cols` + `flex-wrap` → **宽屏一行、窄屏自动换行**
(不用 JS 量宽度:字体/动画/缩放时量不准,flex-wrap 是浏览器布局的一部分)。
🔴 顺带挖出真 bug:旅程「修正」表单的 `.dt-range` 只有 **22px 宽**
—— 它长在 `.node-ops`(一排小按钮的容器)里,展开的内容只有"修正"两个字那么宽。
修:`.rev-panel{position:absolute}` 纯 CSS 浮出来(不动 DOM,避免牵动节点列表排版)。
③ 首页冲突色块"空隙特别大":与日历页逐字对比出来的
日历页 `left: calc(2px + L%)` / `width: calc(W% - 4px)` → 只留 4px、紧挨;
首页却写死 `calc(46px + L%)` / `calc(W% - 50px)` —— 每块左右各扣 23/25px,
两列时那 46px **没法均分**、全挤进了中间的缝(实测 ≈50px)。
修:`left: calc(46px + L% + 2px)` / `width: calc(W% - 4px)` → 缝恒为 4px。
⑤ 日程弹框"按钮看不到":**两个**根因叠加
① `calendar/index.php` 里**多写了一个 `</div>`** —— `.cal-modal-panel` 被提前闭合,
底栏 `<div class="cal-modal-foot">` 成了 `.cal-modal` 的直接子元素、被挤到面板外;
② `.cal-modal-panel` 是 flex 列,但**它下面的 `<form>` 不是** →
`.cal-modal-body{flex:1 1 auto}` 的上下文只到 form 为止,body 压不下去也不滚。
另有 `.cal-modal-panel` 的 max-height 没算上 `.cal-modal` 自己的 padding(差 4px)。
三处都修;标签只对**弹框里**的 `.field > label` 加粗放大(14px/600/深色)。
⑥ 任务新建:内联卡片 → 弹框;**新增附件**(`attach[]`,服务端零改动能收);
`back=tasks` → 新建完回**看板**刷新。观影新增:列表页内嵌同一份 form.php 弹框。
① 详情页删掉那句提示块。④ 流水线改**增量**:`run_suite_if <标签>` + 从 git 改动
推模块;**一碰共用件就退回全量**(app.js/app.css/layout/index.php/_datetime.php…),
认不出来也全量(保守:少跑一段发坏东西的代价远大于多跑十分钟)。
🔴🔴 本轮最值得记的教训:**DOM 嵌套错误比语法错误难查得多**
在 movies/form.php 与 calendar/index.php 各写坏一次嵌套(多/少 `</div>`、多 `</form>`),
两处**都通过 php -l、页面也打得开**,症状却是"按钮跑到面板外"与
"编辑保存静默失效"(保存键落到 form 外面)。⇒ 模板里 `<?php if ?>` 与 `</div>`
必须**按分支配对**,改完用真机渲染 dump 一次 div 深度;光靠 php -l 发现不了。
验证(全部真机 + 反向验证):
· _fb_b34_dtrange.py **61/0**(四个页面:年/月/日/时/分 都可见可点 +
选完三个下拉**立刻**写回 *_date + 改月重建"日"列 + 起止默认同一行 + 无 JS 报错);
· _fb_b34_dtrange_falsify **7/0**(三处注入各自必须变红);
· _fb_b37_ui.py **27/0**(详情页无提示块 / 首页冲突缝 ≤8px / 弹框按钮在面板内且在
视口内 / 标签加粗 / 任务弹框+附件+回看板 / 观影列表页弹框);
· _fb_b37_falsify **5/0**;
· _fb_b35_movie_media.py **16/0**、_fb_geom_interact **109/0**、e2e **1503/0**、
b30_ui2 16/0(含首页冲突分列)、_b30_import 26/0、b18/b21/b23/…全绿、
DAV 三套全绿、部署静态断言空跑通过;
· 线上 app.js / app.css / movies/form.php / calendar/index.php 的 SHA256 与本地一致。
· 顺带修掉 _b30_import 的一个**时序竞争**:它用外部上游(联想词服务)的二次探测
当对照,浏览器取词在前、探测在后,上游抖一下会误报成"回归"(已改成两次确认)。
|
||
|
|
c8839fa728 |
v26 第 26 批(5 条):财务多选按集合取图 / 首页全天置顶与红线定位 / 任务复选框去提示与看板颜色 / 导航搜索引擎切换与站点复用 / 详情页去复选框
- 财务:勾选多个标签时上面那张「总金额」图按**选中集合**统计(新增 ledger/total_chart 路由 + 单一容器 data-ck-total-host,按集合现取并缓存; Ledger::timeline 第二参数放宽为 string|array) - 首页日程:全天日程移出滚动容器固定置顶;进场把当前时刻红线居中 (scrollTop 计算,不用 scrollIntoView),触发条件不绑 $showNow - 任务:复选框去除 title 提示;看板可设颜色(Task::boardColor/updateBoard), 首页任务行用该颜色显示所属看板 - 导航:展示页补回 id=engine-tabs(切换搜索引擎无效的根因);补内置引擎; 新增站点输 URL 可复用他人已加过的站点(sharedByUrl/copyIconFile/adoptSite) - 任务详情页页头去掉复选框(已有「标记完成」按钮) |
||
|
|
a5e559b2b3 |
v25 第 25 批(9 条):名册分组不刷页 / 纪念日多人 / 首页等高 / 移出不回流 /
名册点击看详情拖动才排序 / 任务复选框与状态 / 财务标签多选 / 微信读书同步与统计 /
导航线上数据与图标
用户本轮 9 条需求(原话见 templates/ 与 app/ 内的逐条注释):
1. 名册:列表里给某人分组改为 AJAX 就地挪卡片(不再整页刷新)。
2. 纪念日:关联人改**多选**(复用 _person_picker,字段 person_ids[]);
自建纪念日的按钮与其它模块统一(改=蓝 .btn、删=黄 .btn-warn);
列表新增「关联人」列并给人名前加头像。
3. 首页:日程/任务两块**完全等高**(align-items:stretch + 固定总高 + flex 子项
min-height:0);修「0 件待办」——数字与右侧列表同源(原来各算各的)。
4. 🔴 名册里被移出的人过一阵又回来:根因是 PersonRoster::seedFromPersons()
**每次 Schema::ensure() 都无条件重灌**(线上实测每跑一次 +1 行)。
修:给它加自守卫(只有在 persons 还留着 group_id/sort_order 的**老库**才跑)。
5. 名册:点击=看详情、**只有拖 ⠿ 手柄**才是排序(原来整行既能点又能拖,语义混乱)。
6. 任务:所有任务前加复选框,任何位置点勾即完成;
状态语义照业界整理为 To Do / Doing / Done 并写出说明(用户要求参考别人的做法)。
7. 财务:类别标签改**多选非互斥**(再点一次取消该类别),上下两图 + 图例 + 表格
全部按同一个集合联动;高亮条刻意不给「合计」(多选下各类金额不能相加)。
8. 微信读书:新增**懒同步**(访问时顺手做,6h TTL,只补空字段不覆盖用户填的)、
封面图**拉下来存本站存储**(原来只存外链 → 看不到)、接官方 /readdata/detail 统计。
9. 导航:线上数据只搬了一半(5 板块 29 站 → 7 板块 67 站 + 67 图标)、
展示页头像不显示 / 搜索按钮错位 / 点登录 404。三个真根因:
· 相对地址在 /nav/ 下全 404 → 新增 Nav::abs();
· 搜索容器丢了 id="search"(CSS 是 #search button.submit 绝对定位);
· Nav::iconKey() 与 SimpleNav 的 icon_key() **算法不一致**(少一次 md5 归一化)
→ 搬来的图标文件名对不上;且 uploads/ 整目录 Require all denied。
新增两个**免登录公开出口** nav_icon.php / nav_avatar.php。
顺带修掉一个「数据损坏级」的真 bug(做第 4 条线上反证时发现的,之前一直没人注意):
app/Region.php 三处用中文标点当 trim/ltrim 的 charlist,而 PHP 的 charlist 是
**按字节**匹配的 —— 「。」= E3 80 **82** → 字节 82 进了可剥集合 →
「层」= E5 B1 **82** 被切掉尾字节 → 非法 UTF-8 → backfillAddress 的 UPDATE 报
`1366 Incorrect string value` → **地址拆分升级从上线起一直在失败被跳过**(每请求报一次)。
改成字符级 preg_replace('/…/u');线上实测 ensure() 现在无报错、待拆行数真的在下降。
验证战绩:
- e2e 1289/0(新增 Region 字节级用例等)
- 真机探针:选人 19/0 · 首页/导航 24/0 · 导航模块 34/0 · b18 暂存+确定 10/0 ·
第23批 52/0
- 桌面几何 428/0 · 移动端几何 680/0 · 交互 92/0 · 窄屏 24/0
- 老库升级 153/0(含 anniversary_people 迁移 + 「再跑 ensure() 名册行数不变」)
- 部署静态断言 180 OK / 0 FAIL · 反向验证 3/3 + Region 三变体各被两条断言同时抓住
- 线上 26 个文件与本地**逐字节一致**;展示页 200、图标 66/66 200、登录 200、
越权/不存在均 404、签发短语后 ensure() 不再报错。
|
||
|
|
f0437e6c93 |
v24 第 21 批:无刷新删除与新建日程 / 实际行程不回退 / 行程按时间排 / 统一上传框 / 时间范围控件修复(用户 8 条)
用户 8 条原话要点:
①「名册页面,删除一个联系人后,能否不刷新页面,删除成功后,直接把这个人,
从当前页面的 dom 中删除,页面保持不动。」
②「观影模块,海报和票根以及照片都带进来了,但是没有缩放,把页面撑破了,
应该缩放成缩略图。」
③「个人设置页面,天气设置那里,把:只影响你自己首页上的那一格 / 填个城市名就行
(如「青岛」)… 这些提示,都删除。把城市单独放一行,精度维度放在一行。」
④「旅程模块,实际行程编辑后,点击保存,竟然又变成计划行程了,这个不合理,
实际行程永远是实际行程,不会再变回计划行程了。」
⑤「旅程模块,旅程列表,行程列表,都是按照行程的开始时间排序的,最新的在最上面,
而不是按照编辑修改时间。」
⑥「旅程的详情页面,右上角的按钮,设置在最右侧,和其他模块保持统一。」
⑦「所有上传图片等附件的地方,都不再放按钮,而是放一个框,点击这个框实现点击上传
按钮的功能,拖动图片进这个框里,实现拖动多个上传功能。框里面写一句话:
点击或拖动进行上传,其他的功能和现在保持一致。」
⑧「日历中新建日程,无论是点击按钮还是点击日历中间,都是采用弹框的形式进行添加,
这样不影响当前日历的显示,添加完成后,动态修改当前视图,不要刷新。添加日历日程,
开始时间和结束时间那里,用我们统一的时间范围选择器重做,现在功能无法使用。
选择日历本,带上颜色。」
🔴 五个真根因(全都不像 bug):
① 🔴 **④「实际行程变回计划」= 表单字段同名合并**(本批最要紧的一条)
暂存上传的令牌字段原叫 `stage[]`,与行程表单里那个隐藏的 `stage`(plan/actual)
**同名**。PHP 解析表单时同名会**合并进同一个键**:
`stage=actual` + `stage[]=tok` → `$_POST['stage'] = ['actual','tok']`
(`[]` 只是"往同一个键追加"的记号,**不构成另一个键名**。)
于是路由里 `(string)($_POST['stage'] ?? 'plan')` 得到 `"Array"` →
`in_array('Array', ['plan','actual'])` 为假 → **静默回落成 'plan'**。
⚠️ 只有"拖过图片的行程"会犯(没拖就没有 `stage[]`)→ 症状是"时好时坏"。
修法:令牌字段改名成 `stage_token[]`(改的是**字段名本身**,不是"是数组就取第一个"
绕过去 —— 同名合并是 PHP 的表单语义,绕过去只会把坑留给下一次加字段)。
**另加一道语义保险**:编辑路径**一律沿用库里那条自己的 stage**,不读表单 ——
编辑表单里根本没有改阶段的控件(改阶段走详情页那几个显式动作)。
这样即便将来又冒出某个字段名冲突,也不可能把「实际」悄悄变回「计划」。
② 🔴 **⑧「时间范围选择器无法使用」= 三道门叠在一起**
① `_event_fields.php` 的**结束端默认带 `hidden`**(要点「+ 添加结束时间」才出现);
② `app.js` 的 `upgradeRange()` 有「**两端都得可见**才升级」的判断 → 永远不成立
(实测 `data-semi-range-done` 恒为 `null`);
③ CSS `html.js .dt-range:not(.is-semi-range) .dt-input { visibility: hidden }` →
未升级时原生控件**也是不可见的** ⇒ 屏幕上一片空白、点哪儿都没反应。
修法:两端**始终可见**("没有结束"由清空后半段表达,不再靠开关);
并把旧的「+ 添加结束时间 / 去掉结束时间」开关整套删掉。
⚠️ 顺带挖出:`upgradeRange()` 里 `group.insertBefore(host, a)` 在"两端各自被
`.field` 包着"时 `a` 不是 `group` 的子节点 → 直接抛
`Failed to execute 'insertBefore' on 'Node'`。这个异常**以前从没触发过**
(被 ② 的提前 return 挡住了)—— 一旦放出来就炸。修成插在"端点最外层包装"之前。
⚠️ 观察器加了 `attributes: true, attributeFilter: ['hidden']`(并把 childList
分支的 `return` 去掉):弹框/折叠面板/tab 里"稍后才露出来"的日期控件从此都能自动升级。
③ 🔴 **⑧「新建日程默认建出观影记录」= 产品缺口,不只是显示问题**
`Calendar::DEFAULT_KINDS` 原来只有 6 本**派生**本(观影/旅行/农历/节假日/传统节日/
节气),**一本可写的普通本都没有**。于是"放在哪本"里全是派生本、默认选中排最前的
**观影** → 用户直接打字点「加上」,建出来的是一条**观影记录**
(日历里看着是多了条日程,观影列表里莫名多一条)。这是"建错东西",事后极难发现。
→ ① 默认本补成「我的日程」(kind='custom'),模板里默认选中也改成**优先 custom 本**;
② 选择器里把**纯派生只读本**禁用并标「(自动生成)」
(直接不列会让人以为本子丢了;列为可选又会白选一次再吃错误)。
⚠️ 顺带发现 `Calendar::READONLY_KINDS` 把 `movie`/`trip` 也算进去了,而
`event_add` 里**紧跟着**就有两段专门处理它们的分支(「已加进观影」/「已加进旅程」)
—— 那两段**永远走不到**(校验先一步把请求打回去了)。判据要按**能不能写**分,
不是按"是不是派生"。
④ 🔴 **②「观影编辑页图片撑破」= `.mv-slot` 这个类在样式表里根本不存在**
第 21 批加模板时只写了结构没写样式 → `<img>` 按**原始像素**渲染:600×900 的海报
在 236px 宽的格子里撑出 942px 高,还把整页横向顶破(实测 docW 1297 > vw 1280)。
→ 补 `.mv-slot` 规格:固定 108×162 缩略图 + `object-fit: cover`。
⚠️ **高度必须写死** —— 不写死就又会由原图比例决定,等于没修。
⑤ **⑤行程列表排序 = `category, position` 主导**
`position` 默认同一个数(旧迁移给的多是 0/100),于是顺序被 position 挤乱。
实测线上 #222 渲染成「返回青岛(10-5) → 出发去菏泽(9-30) → 去姥姥家(10-2)」。
→ 改成 `ORDER BY (starts_at IS NULL), starts_at, id`。
⚠️ 方向是**正序**(早的在前,已跟用户确认);旅程列表仍是 DESC(最新在最上)。
两者方向不同是**刻意的**:一个是"挑哪趟旅行",一个是"读这趟旅行的行程"。
⚠️ 详情页**按阶段分三组**渲染(计划/实际/未成行),排序只需在**组内**有序。
本批新增能力:
- **统一上传框**(⑦):`templates/_stage_drop.php` 现在**同时**负责
「sr-only 的真文件框 + 看得见的上传框 + 暂存清单」,调用方只 require 一行。
框是 `role="button" tabindex="0"`,JS 转发 `input.click()`(键盘 Enter/Space 也通),
拖文件进框走既有的暂存上传(拖一个立刻传、可续拖、失败标红、未传完拦住保存)。
⚠️ 框用 `<div>` 不是 `<button>`:里面要放暂存清单(含「撤掉这张」按钮),
按钮里嵌按钮是非法 HTML(第 21 批刚在 `<form>` 嵌套上栽过同一个跟头)。
⚠️ 文件框用 `.sr-only` 不是 `display:none`:后者不可聚焦,带 `required` 时
Chrome 会报 "An invalid form control is not focusable" —— 点了什么都不发生。
落了 11 处:行程照片 / 观影海报·票根·合影 / 资源 / 任务 / 日程附件 / 书籍 /
联系人导入 / ics 导入 / 观影补传 / 资源补传。
⚠️ 清单与提示行移到框**外面**(放框内会变成"一个大框套五张图"),
所以 app.js 改从 `.upfield` 容器里找它们。
- **无刷新删除(①)与无刷新新建日程(⑧)**:路由按 `X-Requested-With`
(或 `Accept: application/json`)区分调用者 —— 带它回 JSON、不带照旧 302
(无 JS 的兜底**不变**,两边的反向都写了断言)。
· 名册删除:成功 → 摘卡片 + 就地改「共 N 人」与分组人数 + 派发 `input` 让
filter.js 自己重算(**不抄它的判据**);失败 → 把原因说出来(不刷页);
拿不到 JSON → **退回原生提交**(绝不静默失败)。
· 日历新建:JSON 带齐前端插入当前视图要用的字段(时间/颜色/链接/是否全天/cal)。
月视图**按时间插入**(不能 append —— 服务端只渲染前 3 条、按时间序取,
append 会让"新加的早间日程"掉进「+N 条」里看不见,刷新后又跑到第一位);
周/日视图按"24h = 100%"算 top/height 插块。
· 观影 / 旅行本是**可写派生本**:AJAX 时不再跳详情页(跳走就离开了日历),
改在提示行给一个「去看详情 →」链接。
- **⑧日历本带颜色**:原生 `<option>` 画不出色块(浏览器不允许在 option 里放元素),
所以做成「色块 + 下拉」并排,色块跟着当前选中的本子变色。
- **③天气卡片**:三句提示全删;城市单独一行、纬度/经度同一行(`.loc-row`)。
删的只是说明文字,三个输入框 + 保存 + 状态回显都保留。
- **⑥设置按钮贴最右**:原来顺序是「… → 设置 ☰ → 删除 🗑」,设置被删除键挤到**倒数第二**;
改成删除在前、设置恒为最后一个(与观影/日程/任务/资源同一个手势)。
验证(本地全套):
- e2e **1059/0**(本批新增约 40 条断言)· 结构升级 149/0 · 桌面几何 428/0
- **真机探针 75/0**(`_fb_b21_ui.py`):AJAX 删除真的没导航 / 卡片真被摘掉 /
滚动位置保持;缩略图几何(108×162,不再溢出);上传框(框在、原生框不可见、
点框真打开文件选择框、连拖两张都上去且清单可见);日历弹框(打开时网格一动不动、
范围控件真的挂上且可见、能弹面板、色块跟着换、无刷新提交后当前视图里立刻出现、
周视图也能插时间块、全程无 JS 报错)。
- **反向验证 12 条**(`_fb_b21_falsify.py`):逐条把修复改回旧行为看断言是否变红 ——
令牌字段改回 stage[] / 编辑读表单 stage / 排序改回 position / 设置按钮挪走 /
框不转发点击 / 文件框不再 sr-only / 删缩略图规格 / 删除不回 JSON /
结束端改回 hidden / 日历本默认改回第一个 / 天气提示加回 / 弹框改回内联。
- 部署脚本静态断言段本地空跑 **307/0**。
|
||
|
|
c3d00ad66a |
v24 第 20 批:拖动即时上传 / 观影图片带出 / 行程保存修复 / 日程红线与删除范围与多提醒 / 悬停统一(用户 9 条)
用户 9 条原话要点:
①「观影模块,编辑观影,已经保存的海报和票根、合影,都没带进来。」
②「个人设置页面,"只影响你自己看到的样子"这个提示删除,不要了。我怎么称呼家人,
这个卡片,不要了。我的资料这个卡片,不要了。」
③「旅程模块,编辑行程,点击保存没有反应。」
④「所有上传图片视频和附件的模块,都允许多次拖动添加文件上传,拖动一个进去,
就开始上传,还可以继续拖动,继续上传,最后统一保存即可。」
⑤「添加行程,线路名、承运方,都不要了。车辆,只在出行方式选择自驾时才出现,
其他情况下默认不出现。出发地和到达地,应该在同一行。」
⑥「日程模块,周视图和日视图,应该在视图中间显示一条红线,用来表示当前进行的时间…
用一个不断从上到下的红线,来表示当前时间在视图上的刻度和位置。」
⑦「对于重复的日程,当点击删除的时候,应该提示是删除这一次,还是全部都删除,
还是删除这一次及以后的。」
⑧「日程的提醒,是可以多选的,就是说,一个日程,我可以选择让它 5 分钟提醒,
10 分钟提醒等等。」
⑨「很多按钮的悬停效果非常奇怪,感觉纯粹是换了一个背景色…应该调整所有按钮的悬停效果,
保持统一,但是不要单纯的换一个不协调的背景色。」
🔴 三个真根因(都是"看着不像 bug"的地方):
1. **③ 点保存没反应 = `<form>` 嵌套**(HTML 非法):`trips/node_form.php` 的照片缩略图上
套了 `<form action=photo_del>`,而整块在**外层行程表单内部**。浏览器解析到内层
`</form>` 时**把外层表单提前关掉** → 「保存」按钮**掉出表单**(真机实测
`button.form === null`)。源码里完全看不出,**只有真浏览器量 `btn.form` 才现形**;
且**只有这段行程已经有照片时才触发** —— 所以表现为"有时候好、有时候坏"。
→ 按钮留在原位(布局不动),用 HTML5 `form="id"` 关联到**表单外**的独立表单。
2. **⑤ 车辆藏不住(第 17 批就写过、一直没生效)**:`.field` 自己声明 `display:flex`,
作者样式压过浏览器默认的 `[hidden]{display:none}` → `hidden` 形同虚设。
**本项目第 4 次栽同一个坑**(.att-item / .pv / .pp-item 各一次)→ 补 `.field[hidden]`。
3. **④ 拖动即时上传的卡片"看不见"**:模板给 `.stage-list` 加了 `hidden`(没人上传时
不留空边框),JS 建卡片时忘了 `list.hidden = false` → 卡片在 DOM 里但整条清单
`display:none`、尺寸 0×0。**HTTP 层断言全绿**(HTML 里确实有卡片),
**只有真机量尺寸才发现** —— 由新写的真机探针抓到。
本批新增能力:
- **拖动即时上传**(第 4 条):新增 `upload_stage.php` + `app/StagedUpload.php` +
`templates/_stage_drop.php`。拖进来 → **立刻** POST 到暂存目录 → 回 `stoken` →
放进隐藏字段 `stage[]` → 保存时在 `attach_save_files()` 里**认领**(移文件 + 建附件行)。
`media.php` 加 `?stage=` 预览(拖完立刻看得见缩略图)。
⚠️ 三个必须踩准:**串行队列**(并发会让缩略图顺序乱跳)、**提交守卫**
(还有没传完就 preventDefault,否则"拖了但没保存上"必然发生)、**卡片清单要 un-hide**。
⚠️ 海报/票根走**独立字段名** `stage_poster`/`stage_ticket`(各自单槽位、要按比例重裁)。
⚠️ 落点**就近取**(`input.closest('.field')`):一个表单里多个上传区不能串到第一个去。
- **观影编辑带出已存图片**(第 1 条):编辑页显示海报 / 票根 / 合影 + 各自的删除入口;
新增 `movies/media_del`(只删不换也能删,槽位走白名单);`movies/update` 收编辑页
新选的照片时**合并**而不是替换(否则一编辑就把已有合影冲掉)。
- **行程表单**(第 5 条):去掉线路名 / 承运方(**库里的值保留**:UPDATE 时不参与,
与 seat_info/gate 同一套);出发地/到达地包进 `.loc-row` 真同一行;车辆按自驾显隐。
- **当前时间红线**(第 6 条):位置在服务端算(与 `.tg-block` 同一套"24h = 100%"坐标),
前端每分钟自己挪(对齐到下一分钟整再起定时器),跨午夜 reload;只画在**今天那一列**。
- **重复日程删除三档**(第 7 条):与「编辑」那三档同名同序(全部 / 这一次及以后 /
只这一次)。「只删这一次」→ `skipOnce`(**绝不删整条系列**);「这一次及以后」→
老系列截 UNTIL,**必须清掉 COUNT**(两者并存时 COUNT 优先,不清就截不断)。
- **提醒多选**(第 8 条):同列存逗号串(`5,15,60`);Schema 把它从 **INT 改 VARCHAR**
(INT 存逗号串会被隐式转换,多档会静默只剩第一档);ICS 导出吐**多个 VALARM**。
- **悬停统一**(第 9 条):原来 14 种互不相干的 hover 底色 → 统一成**两套手法**:
有底色 `filter: brightness(.92)` 同色系加深 + 轻抬升;描边白底 `--hov-veil` 中性薄雾
+ 边框微显。放在 CSS **最末**用一条兜底收口(新按钮自动继承),并把十几条旧规则
清成"交给统一段"。`person_picker.js` 同时改为按需加载。
验证(本地全套):
- e2e **1004/0**(+21 条本批断言)· 升级 149/0 · 桌面几何 428/0 ·
**真机探针 25/0**(连续拖两次 / 红线位置与颜色与几何 / 车辆显隐 / 出发到达同行)。
- **反向验证 5/5**:①删除按钮改回嵌套 form ②卡片清单不 un-hide ③观影编辑不渲染海报
④车辆隐藏失效 ⑤「只删这一次」做成删全部 —— 五种坏法全部被抓住,还原后复绿 1004/0。
过程中还**抓到两条弱断言**(只查 DOM 有无、不查可见性/是否真渲染),已一并加强。
- 部署脚本静态断言段本地空跑 **305 条全过**。
|
||
|
|
7138314dc7 |
v24 第 15 批:活动 / 旅程两级语义(术语 · 派生时间城市 · 表单三项 · 题图可点)
用户原话四条,逐条落地:
1. 「旅程模块,按钮是记一次活动,而不是记一趟旅程。旅程是活动里面的概念。」
→ 顶层一律改称**活动**:按钮「记一次活动」、页标题「活动」、`N 次` / `N 段旅程`;
活动详情三组改叫「计划的旅程 / 走过的旅程 / 没成行的」;
节点表单「这段旅程叫什么」「阶段」;flash 文案 17 处同步。
(导航条仍叫「旅程」——用户就是这么称呼这个模块,列表页加副标题说清两级关系。)
2. 「活动不需要开始和结束时间,是根据活动中的旅程,最早的旅程开始时间,和最晚的
旅程结束时间,计算出来的。目的地也不需要…去的城市,也是根据旅程,得到的。」
→ 活动**不再存**这三样,全部**读时算出来**:
· Trip::derived() 最早开始 / 最晚结束 / 城市去重
· Trip::cities() 按最早出现时间排(先后顺序本身是信息,不是字母序)
· Trip::attachDerived() 列表页批量补(避免 N+1)
· Trip::activitySpan() 没有旅程时说「还没有旅程」,不用「日期待补」
create/update 不再写 events 的起止与地点(老值保留不动,页面不读)。
列表排序/搜索、首页「最近去了」改走子查询。
3. 「题图那里,没有办法上传图片,点击哪里都没反应。」——**真 bug**
「点图 = 开文件框」那句 JS 只写在 people/form.php 的内页脚本里(头像专用);
第 14 批加的旅程题图与图书封面照抄了同一套 DOM 却没有对应的 JS,
于是图块有 cursor:pointer 与 hover 高亮(看着能点),点下去毫无反应。
→ 做成声明式通用绑定:图上写 data-pick-input="#fileInputId",
app.js 统一接管(一个页面多个也各绑各的),并删掉旧的那份专用实现。
三处(头像 / 题图 / 图书封面)全挂上。
4. 「添加活动的页面,顺序是这样的:添加标题,上传并裁剪题图,然后一段简介,就可以了。」
→ 主区就这三项,顺序照原话;时间/城市不做输入项(只留一句说明它们从哪来,
不说清用户会满页找"怎么没地方填时间")。
备注 / 公开 / 同行的人收进「更多设置」折叠区——功能一个没丢。
顺带修掉两处会炸的实现问题:
· ORDER BY 引用聚合别名(first_at)在 MariaDB/MySQL 报 1247,且只在运行时炸、
php -l 看不出 → 改成 ORDER BY MIN(starts_at),否则整个旅程模块 Fatal。
· e2e 里"详情页显示了派生时间"原本写成整页查找,下面每段旅程自己也渲染日期,
于是把派生值塞成 null 也照样绿(借光假绿)→ 判据收进页头那一段。
验证:e2e 845/0(+15 条本批断言)· 升级 134/0 · 桌面几何 428/0 · 移动几何 688/0 ·
交互 92/0 · 题图真机点击 4/0 · 读书窄屏 15/0 · 家谱 34/0 + 10/0 + 反向 3/3 ·
观影按钮 60/0 + 反向 3/3 · 本批反向验证 4/4(题图绑定抽掉→红、派生值不挂→红、
城市退回读 location→红、时间字段加回表单→红)· 部署静态断言新增两组(含"活动不许
再写起止时间/目的地"与"ORDER BY 不许引用聚合别名"的反退化防线)。
部署后服务器自检 19/19,五个关键文件 md5 与线上逐一核对一致。
|
||
|
|
864e281265 |
v24 第 8 条:凡「选人」都走同一套弹窗 + 拼音首字母(补上唯一漏做的一条)
用户原话:「名册详情页面,添加关系那里,选择一个人,应该也是和观影人一样, 点击弹窗,用拼音首字母选择,否则人多的时候,这个选择起来太麻烦了。」 - 成员详情页:①「添加关系 → 对方」 ②「分享他的名片给…」→ 全局选人组件(单选) - 任务:③ 列表页「共享给(多选)」 ④ 列表页「负责人」 ⑤ 详情页「负责人」 (共享候选人先把自己过滤掉 —— 共享给自己是空操作) - 纪念日:「与谁相关」→ 单选,且保留原下拉第一项「不指定」(ppAllowEmpty) - 「对方」是必填,但组件里是原生 radio(HTML 没有"必选一个 radio"的可靠约束) → 页面补一道 submit 拦截,否则用户点了按钮会静默无反应 顺带修一个用户没提、我自己抓到的真 bug: _person_picker.php 原用**文件顶层**的 `static $ppSeq` 做 id 计数 —— PHP 里被 include 的文件,顶层 static 初值**每次 include 都重新绑定**(与函数体内的 static 不同)→ 同一页 include 两次都拿 pp1 → DOM id 撞车(getElementById / <label for> 全抓到第一个)。实测 include 三次得到 pp1,pp1,pp1。改用 $GLOBALS['ppSeq']。这个坑只有同一页出现两个组件时才暴露,且资源页第二个组件 只有真有资源时才渲染 —— 所以写成**单元级**探针(同一请求 include 两次)。 另修一个构建层隐患(本轮部署时踩到,白查了一轮): 本机 core.autocrlf=true,一次 git stash 往返就把 6 个文件全改成 CRLF;而部署 打包取的是工作树 → 包里带 CRLF 上去 → 部署脚本里 grep -qxF '<整行 CSS 选择器>' 的校验在 Linux 上一条都匹配不到(报错却指向"CSS 少了某条规则",极易误诊)。 → .gitattributes 加 `* text=auto eol=lf`(必须排在 -text 那几条之前), 并在打包前加一道行尾体检 _fb_eol_check.py(失败时点名文件)。 验证:反向验证对着 git stash 出来的真·改动前状态跑 → 11 通过 / 17 失败; 新增 _fb_picker_unify.py 28/0;e2e 785/0;几何 428/0;移动端 688/0;交互 97/0; 升级 126/0;家谱 34/0;专项 91/0;导入 21/0;豆瓣 22/0;行尾体检 + 两道新静态 门禁均实测可失败。线上 6 文件 md5 一致、CR=0。 |
||
|
|
8f80f3e835 |
v24 第 2 轮:19 条清单收尾(附件预览/CalDAV/任务分类看板/全局选人/家谱/纪念日/财务)
用户 2026-10-02 提的 19 条需求,本轮完成剩下的 8 条 + CalDAV 服务端:
- ③ 附件:图片/视频给缩略图,PDF/Word/Excel 给**同尺寸**图标;可预览的在本页
弹层里看(不再新开标签页),渲染不了的点了直接下载;预览层右上角恒有下载按钮。
- ⑦b CalDAV:把「我的日历本」按 RFC 4791 只读子集分享出去(OPTIONS/PROPFIND/
REPORT/GET,写方法一律 403)。用**专用口令**(库里只存 sha256),不是登录口令。
- ⑨⑩ 任务:分类与看板都由用户自建;已完成的任务从看板消失,改在「已完成」页
按分类查看/搜索;设置入口在「新建任务」旁的 ☰。
- ⑪ 全局人员选择器:一个片段铺到观影/旅程/资源/日历共享/任务共享/财务共享;
修掉了老组件「名字和拼音都搜不动」的 bug —— .att-item 自己声明了 display:flex,
压过了浏览器 [hidden]{display:none},过滤根本没生效。
- ⑫ 家谱:头像改方形不再裁切;姻亲不在图上的卡片给「⇄ 姻亲」入口,
以 TA 为中心重画 + 「返回我的家谱」。
- ⑬ 纪念日:阴历/阳历都能设且按对应历法重复;名册里每个人的生日默认可见
(实时派生,不复制一份);全部作为全天日程进日历。
- ⑮ 财务:账本可共享,双方都能记账、都能看全部账目,资产−负债=净资产;
金额一律以「分」存,不用浮点。
验证:端到端 724 项通过 / 0 失败;几何 368、交互 97、移动端 516、家谱 24、
升级 123 全绿;SQL 列名静态校验 0 处可疑;部署 11 条线上探针全过。
|
||
|
|
71a7ec35a0 |
v14: 观影/家谱/日程/旅程/资源/任务六模块统一,首页改 dashboard
用户 14 条需求一次交付(1-13 功能 + 14 工作方式)。 观影(1-4) - 返回文案全模块统一为「返回观影」(不再有「返回列表」「返回观影记录」三种叫法) - 观影人一律用彩色人物标签 person_chip:底色由头像主色算出来(上传时存库), 瀑布流卡片也按人显示;五处观影模板全部改用它 - 人员显示统一走 person_name()(shown → 我给他起的称呼 → 姓名) - 影院管理页与年度报告页的上下两块用 .card + .card 统一给间距(原来紧贴成一整块) 家谱(5) - 树根从「我」换成**辈分最高的祖先**:库画的是"树根的祖先链+后代+树根的兄弟姐妹", 根=我 时伯父/堂兄/嫂子/侄子一个都不画(12 人夹具只画出 8 人) - focusMap 按**代数**圈定三代(不再按步数),normalizeLinks 把子女对称挂到父母双方 —— 修掉"母亲登录看不到孩子" - 新增「看全部 / 回到我」两个按钮,放在画布外(画布整块被库接管了手势) 统一事件原语(6-9) - 旅程:TripLog 全量迁入(3 趟旅程 / 21 段行程 / 72 张照片 / 5 个人)。 复用 events(kind='trip') + trip_details + trip_nodes(计划/执行双轨保留) - 日程:每人可建日历本(自定义色)+ 共享只读/可写;观影与旅行是每人默认两本, 内容是**从各模块实时派生**的(不复制,所以改了观影日期日历立刻跟着变); 没有具体时分 = 全天;月视图参照群晖 Calendar - 资源:挂在某人名下的附属信息(标题+正文+多附件),可共享给多人并设只读/读写, 默认折叠、可搜标题与正文 - 任务:看板三列 + 两级子任务 + 评论@人 + 共享 + 循环(完成时按原截止日推下一期) - 统一附件表:四个模块的附件共用一张,下载地址不落库、一律由 media.php 现算 模块化(10-11) - App\Module 是模块的唯一来源(加一行 = 导航条/主题色/个人设置三处自动出现) - 个人设置里可勾选要显示哪些模块、拖动排序(关掉的模块**不会**被兜底补回来) - 每个模块一套主题色(家庭级),只覆盖 --brand 三兄弟,不碰纸墨底色 其他(12-13) - 新增成员表单可选所属分组(编辑表单没有:分组是"我和他的关系",只归我自己) - 首页改 dashboard:接下来的日子 / 未来七天 / 手头在做 / 往年今日。 家人卡片从首页撤走(看人去名册) 验证(全部通过) - e2e 542 条(新增 4 模块端到端 60+ 条) - 桌面几何 368 / 移动端几何 520 / 家谱 12 / 交互 97 / 老库升级 123 - SQL 列名静态校验 0 处可疑(对着真实表结构) - 反向验证 18 条新注入全部抓住 顺带修掉的既有问题 - 老库升级回填 SQL 按实际存在的列动态拼(缺列不再 1054 炸断升级) - 全新安装时 Schema::ensure 跑在"人还没建"之前 → 补建日历本三处齐备 - 窄屏导航横向溢出(模块从 4 个加到 8 个后顶栏撑破视口) |