v24 第 5 轮:十条清单(天气填城市 / 输入即筛选 / 看板列=看板 / 账本盘点折线图 / 纪念日分类)

用户 2026-10-03 的十条,逐条落点:

1. 天气改为**个人设置里填城市**(每人一份):新增 app/Geo.php,内置 197 个
   地级市坐标(离线、逐条核对,生成脚本 _tooling/_fb_geo_gen.py)。填坐标仍
   作为内置表没有时的出口;老的家庭级坐标保留为兜底,升级当天天气不会凭空消失。
2. 所有"找个人"的地方**输入即筛选**:新增 assets/js/filter.js(纯前端显隐,
   不发请求、回车不刷新)+ app/PersonQuery.php 把服务端判据收敛成一份
   (名册 / 挑人 / 高级搜索共用,避免三处实现漂移)。
3. 名册列表:有昵称就不重复显示本名、行变矮、补齐手机/阴历阳历生日(带年份)/
   邮箱/工作单位;「清除」与「搜索」同款同尺寸。
4/5. 日程:撤掉左侧日历本栏改满宽,功能(显隐/颜色/导入/默认视图)全收进
   右侧 ☰;**色块高度改为按起止时长**(旧实现一律 30 分钟,三小时的会跟
   十五分钟的同高);点日历空白处即建日程,开始时间=点的那一格。
6/10. 资源:搜索提到最上;按"最近改动/最新新增"排序,默认只显示最新 10 条并
   给「显示全部」出口。
7. 任务:看板的**列=用户自定义的看板**(不再是写死的待办/进行中),
   拖动/左右键=换看板(改 board_id,不动 status)。
8. 财务:概览在上账目在下、记一笔改右侧按钮、账本设置(共享/改名/新建/删除)
   收进 ☰、默认账本名「xxx的账本」、"挂在谁名下"默认自己且用标准选人框;
   **新增盘点**(新增 ledger_entry_snapshots 只增不改的历史表,旧值不被清空)
   + 上面画金额变化折线图(app/chart.php 服务端画 SVG,零依赖)。
9. 纪念日:手动添加的与名册生日派生的**分两块**、手动的在上;右侧设置可增删
   分类(家庭级,删分类不强改已用的历史)。

本轮另外修掉/加固的四类问题(都由新增的静态或运行时守卫兜住):
- index.php 少写 2 个 use 导入(Pinyin / UserSetting)→ 名册与个人设置
  返回 200 但正文是 Fatal;顺带修了一处早已存在的 Attachment 未导入。
  → 新增 _fb_import_check.py(1f 段)。
- 一次不精确替换弄丢了 app/Calendar.php 开头的 `<?php`,整份源码被当 HTML
  吐给浏览器,而 `php -l` 报"无语法错误"(纯文本输出确实合法)。
  → 新增 _fb_php_open_check.py(1e 段)。
- 模板片段 unset 了宿主模板的变量(账本片段 unset($canWrite))→ 正文里一片
  Undefined variable 而 HTTP 仍 200。同 _datetime.php 早年 $t 的坑。
  → 新增 _fb_fragment_scope_check.py(1g 段)+ _fb_batch_e.py 的 26 页无告警巡检。
- 窄屏下页头动作区不换行 → 周视图横向溢出且按钮被挤成三种高度(用户提过三次
  "按钮要同高")→ .page-head .actions 加 flex-wrap。

验证战绩(全绿):
  e2e 773/0 · 第 5 轮专项 91/0 · 结构升级 126/0 · 几何 428/0 · 移动端 684/0 ·
  交互 97/0 · 家谱 26/0 · 按钮 60/0;三轮反向验证各 3/3 抓到,还原后复绿。
线上:schema v14、指纹一致(9df6c9fccc6796db)、snapshots 表已建、197 城、
  8 个关键文件 md5 与本地逐字节一致、app/ 403 无源码泄漏、错误日志无新增。
This commit is contained in:
2026-10-03 15:01:38 +08:00
parent dbcf0c1bcd
commit e0562b8627
31 changed files with 2891 additions and 505 deletions
+133 -2
View File
@@ -149,6 +149,41 @@ a:hover { text-decoration: underline; }
.movie-set .menu-list a:hover .mi,
.movie-set .menu-list a.on .mi { color: currentColor; }
.movie-set .menu-list a.on { color: var(--brand); background: var(--line-2); }
/* ---- 日程页的设置下拉(v24 用户 2026-10-03 第 4、5 条)----
它比观影/任务那个 ☰ 内容多:里面有个**表单**(默认视图 + 显示哪些本子)。
本子清单会随共享/新建变长,所以给列表一个最大高度 + 滚动,
否则菜单会顶出屏幕、底下的「保存」按钮够不着。 */
.cal-set .menu-list { min-width: 260px; max-width: min(320px, 92vw); }
.cal-set-list { padding: 10px; gap: 0; }
.cal-set-form { display: block; }
.cal-set-block { padding: 6px 2px; }
.cal-set-block + .cal-set-block { border-top: 1px solid var(--line-2); margin-top: 4px; }
.cal-set-h { font-size: 12px; color: var(--muted); margin-bottom: 6px; }
.cal-set-views { display: flex; gap: 12px; flex-wrap: wrap; }
.cal-set-view { display: inline-flex; align-items: center; gap: 5px; font-size: 13px; cursor: pointer; }
.cal-set-view input { accent-color: var(--brand); }
/* 本子清单:最多占 42vh,超了内部滚动 —— 菜单本身不滚,否则保存按钮会被推出可视区 */
.cal-set-books { max-height: 42vh; overflow-y: auto; }
.cal-set-book {
display: flex; align-items: center; gap: 7px; padding: 5px 4px;
font-size: 13px; cursor: pointer; border-radius: 6px; white-space: normal;
}
.cal-set-book:hover { background: var(--line-2); }
.cal-set-book input { accent-color: var(--brand); flex: 0 0 auto; }
.cal-set-book .color-preview { width: 11px; height: 11px; border-radius: 3px; flex: 0 0 auto; }
.cal-set-book .cal-name { overflow: hidden; text-overflow: ellipsis; }
.cal-set-book .node-badge { margin-left: auto; flex: 0 0 auto; }
.cal-set-foot { margin-top: 10px; }
.cal-set-foot .btn { width: 100%; justify-content: center; }
.cal-set-links { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--line-2); }
.cal-set-links a { display: flex; align-items: center; gap: 10px; white-space: normal; }
.cal-set-links a .mi { flex: 0 0 16px; color: var(--muted); }
.cal-set-links a:hover .mi { color: currentColor; }
/* 点了日历空白处就建日程 —— 鼠标要能看出那里可点(用户第 5 条)。
⚠️ 只给「能写」的人光标:只读账号点上去弹不出表单,给个十字光标是骗人。 */
.tg-col.rt-writable, .cal-cell.rt-writable { cursor: crosshair; }
.link-quiet { color: var(--muted); font-size: 14px; }
.link-quiet:hover { color: var(--brand); }
@@ -308,6 +343,17 @@ a:hover { text-decoration: underline; }
background: var(--line-2);
}
/* ⚠️⚠️ 过滤用的行必须能真的藏起来。
`[hidden]` 的 display:none 是**浏览器默认样式**,优先级最低 —— 只要作者样式里
给同一个元素写了 display(.person 是 display:block、.pp-item 是 flex、
.att-item 是 inline-flex…),就会把它盖掉:元素"标注了 hidden 却照样显示",
于是「输入即筛选」看着完全没反应(列表一条都不少)。
这个坑本项目已经踩过两次(.att-item、.pp-item),所以统一写成一条通则:
凡是靠 [hidden] 隐藏的列表行,都必须在作者样式里显式再声明一次。 */
[data-search][hidden],
.pick-row[hidden],
.person[hidden] { display: none !important; }
.badge {
display: inline-block; padding: 1px 8px; border-radius: 999px;
font-size: 11px; font-weight: 500; line-height: 1.7;
@@ -734,6 +780,14 @@ textarea.input { min-height: 76px; resize: vertical; }
.hero-stats { margin-left: 0; gap: 20px; }
.page-head { flex-wrap: wrap; align-items: center; }
.page-head .actions { margin-left: 0; width: 100%; }
/* ⚠️ 窄屏下动作区**必须允许换行**:
一行里可能有 6 个按钮(月/周/天 + 上一周/今天/下一周 + 新建 + ☰),
360px 根本放不下。不换行的后果不只是横向溢出(整页被拖走),
还会把按钮**挤扁**成高低不一(实测 91/68/44 三种高度,同排按钮参差不齐)——
而"页头按钮同高"是用户提过三次的明确要求。
换行之后每个按钮保持自己的尺寸,高度自然一致。 */
.page-head .actions { flex-wrap: wrap; }
.page-head .actions > .movie-set { margin-left: 0; }
.kv-row { grid-template-columns: 84px 1fr; }
.search { flex-wrap: wrap; }
.search .input { max-width: none; flex: 1 1 auto; }
@@ -1349,6 +1403,47 @@ textarea.input { min-height: 76px; resize: vertical; }
.led-ops .input { min-width: 140px; }
.led-edit summary { cursor: pointer; }
.led-edit .node-form { min-width: min(520px, 86vw); }
/* ---- 财务:变化折线图 + 设置下拉(v24 用户 2026-10-03 第 7、8 条)---- */
.led-charts { margin-bottom: 0; }
.ck-grid {
display: grid; gap: 14px;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}
.ck-card {
border: 1px solid var(--line-2); border-radius: var(--radius-s);
background: #FDFBF7; padding: 10px 12px;
color: var(--ink); /* SVG 用 currentColor 画基线与日期,靠这里继承 */
}
.ck-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; margin-bottom: 4px; }
.ck-head b { font-size: 14px; }
.ck-svg { display: block; margin-top: 2px; }
/* 盘点面板:与「更正」并列在一个 <details> 里,中间给一条分隔线才分得清两件事 */
.led-recon { padding-bottom: 10px; border-bottom: 1px dashed var(--line-2); margin-bottom: 10px; }
.led-form-h { font-size: 12.5px; color: var(--muted); font-weight: 500; margin: 0 0 8px; }
.led-hist { margin-top: 6px; }
.led-hist summary { cursor: pointer; }
.led-hist-list { list-style: none; margin: 6px 0 0; padding: 0; font-size: 13px; }
.led-hist-list li {
display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
padding: 5px 0; border-top: 1px solid var(--line-2);
}
.led-hist-list li b { font-variant-numeric: tabular-nums; }
/* 账本设置下拉:比观影那个内容多,给个上限 + 内部滚动 */
.led-set .menu-list { min-width: 280px; max-width: min(340px, 94vw); }
.led-set-list { padding: 10px; gap: 0; max-height: 70vh; overflow-y: auto; }
.led-set-block { padding: 8px 2px; }
.led-set-block + .led-set-block { border-top: 1px solid var(--line-2); margin-top: 4px; }
.led-set-shares { list-style: none; margin: 0 0 8px; padding: 0; }
.led-set-shares li {
display: flex; align-items: center; gap: 6px; flex-wrap: wrap; padding: 4px 0;
}
.led-set-shares li .node-badge { flex: 0 0 auto; }
.led-set-form-in { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.led-set-form-in .input { flex: 1 1 120px; min-width: 0; }
.led-set-form-in .pp { flex: 1 1 100%; }
.led-add { margin-bottom: 18px; }
/* ---- 纪念日(v24 第 13 条) ---- */
.ann-up { list-style: none; margin: 0; padding: 0; }
.ann-up-item {
@@ -1876,6 +1971,10 @@ textarea.input { min-height: 76px; resize: vertical; }
/* ---- 日程(月视图,群晖 Calendar 的外观) ---- */
.cal-wrap { display: grid; grid-template-columns: 230px 1fr; gap: 18px; align-items: start; }
/* 用户 2026-10-03 第 4 条:左侧「我的日历本」那一栏撤了,日历占满整宽。
⚠️ 用**单列**改写而不是删掉 .cal-wrap:`.cal-wrap` 还被别处(窄屏媒体查询)
引用着,删掉会连带把那条声明变空。单列 = 视觉上就是"充满整个宽度"。 */
.cal-wrap-full { grid-template-columns: 1fr; }
.cal-side { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 16px 18px; }
.cal-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.cal-item { display: flex; flex-direction: column; gap: 4px; }
@@ -1939,9 +2038,29 @@ textarea.input { min-height: 76px; resize: vertical; }
.res-label { font-size: 12px; color: var(--muted); }
.res-ops { display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
.res-share-add > summary { cursor: pointer; }
/* ---- 资源列表:搜索在上(用户 2026-10-03 第 6 条)、排序与截断提示(第 10 条)---- */
.res-search-card { display: flex; flex-direction: column; gap: 10px; }
.res-search { margin-bottom: 0; }
/* 搜索框给宽一点:资源标题长(「不动产证 / 学区房合同」),窄了看不全 */
.res-search .input { max-width: none; flex: 1 1 auto; min-width: 0; }
.res-sortbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.res-sortbar .seg { margin: 0; }
.res-showall { margin-left: auto; }
.res-more {
display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line-2);
}
/* ---- 任务看板 ---- */
.kanban { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; align-items: start; }
/* ---- 任务看板 ----
⚠️ 列数不再固定为 3:v24(用户 2026-10-03 第 7 条)起**一列 = 用户自己的一个看板**,
看板能加能删,写死 repeat(3, 1fr) 的话加第四个看板就直接掉到第二行去
(看起来像"加了个看板结果没显示")。
改成"横向自动排 + 可横向滚动":几列都放得下,列多了也不挤。 */
.kanban {
display: grid; grid-auto-flow: column;
grid-auto-columns: minmax(230px, 1fr);
gap: 14px; align-items: start; overflow-x: auto; padding-bottom: 2px;
}
.kb-col { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.kb-head {
display: flex; align-items: center; gap: 8px; padding: 12px 16px;
@@ -2012,6 +2131,18 @@ textarea.input { min-height: 76px; resize: vertical; }
.mod-preset { display: flex; flex-wrap: wrap; gap: 4px; }
.mod-preset .preset-color { cursor: pointer; }
/* ---- 纪念日设置下拉(v24 用户 2026-10-03 第 9 条)---- */
.ann-set .menu-list { min-width: 260px; max-width: min(320px, 92vw); }
.ann-set-list { padding: 10px; gap: 0; }
.ann-kind-list { list-style: none; margin: 0; padding: 0; max-height: 46vh; overflow-y: auto; }
.ann-kind-list li {
display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
padding: 5px 2px; border-bottom: 1px solid var(--line-2);
}
.ann-kind-list li:last-child { border-bottom: 0; }
.ann-kind-name { font-size: 13.5px; font-weight: 500; }
.ann-kind-list li .small { margin-left: auto; }
/* ---- 首页 dashboard ---- */
.hero-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.dash-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }