名册点击看详情拖动才排序 / 任务复选框与状态 / 财务标签多选 / 微信读书同步与统计 /
导航线上数据与图标
用户本轮 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() 不再报错。
67 lines
4.0 KiB
ApacheConf
67 lines
4.0 KiB
ApacheConf
# 家书 FamilyBook · Apache 重写规则
|
||
#
|
||
# ⚠️ 这个文件**不随包上线**(familybook_push.sh 的打包白名单里没有它)。
|
||
# 原因:线上站点根那份 .htaccess 是**宝塔面板生成的**(PHP 版本段、防盗链、
|
||
# 缓存段、伪静态…),整份覆盖会把面板的东西清空,而且面板下次重写还会改回来,
|
||
# 变成"时好时坏"。
|
||
# /dav/ 与 /carddav/ 的重写规则由 `familybook_deploy.sh` 第 5c 段**追加**到线上那份里
|
||
# (带 `# >>> FamilyBook CalDAV` 标记,幂等)。
|
||
#
|
||
# 那这份文件是干什么用的?
|
||
# · 新建站点(没有宝塔那层)时,可直接把它作为站点根的 .htaccess;
|
||
# · 它是那段规则的**唯一书面来源**,push 脚本会断言部署脚本里的规则串
|
||
# 与它完全一致(防两处漂移)。
|
||
#
|
||
# 只做一件事:把 /dav/ 与 /carddav/ 开头的 URL 分别交给 dav.php / carddav.php。
|
||
# 其余一律不动 —— index.php 那套 ?r=xxx 路由不依赖重写,
|
||
# 少写规则就少一处"上线才发现 404"的地方。
|
||
|
||
<IfModule mod_rewrite.c>
|
||
RewriteEngine On
|
||
|
||
# CalDAV:/dav/、/dav/3.ics/、/dav/3.ics/12.ics 全部交给 dav.php
|
||
RewriteRule ^dav(/.*)?$ dav.php [L,QSA]
|
||
|
||
# CardDAV(v24 第 22 批):/carddav/、/carddav/1.vcf/、/carddav/1.vcf/12.vcf 交给 carddav.php
|
||
# ⚠️ 两条规则**顺序无关但都必须有**:它们的前缀(dav vs carddav)互不包含,
|
||
# 不会互相抢;写成 `^dav` 在前是因为历史顺序,真要调也不能写成 `^dav(/|$)` 之外的
|
||
# 宽松形式 —— 那会把 /dav2/ 之类也吞进来。
|
||
RewriteRule ^carddav(/.*)?$ carddav.php [L,QSA]
|
||
|
||
# 导航展示页(v24 第 24 批 用户第 4 条):/nav/?<短语> —— 全站唯一免登录页面。
|
||
# ⚠️ suggest 那条**必须排在前面**:`^nav(/.*)?$` 会把 /nav/suggest.php 也吞进去,
|
||
# 顺序反了就变成"每次联想都去渲染展示页"(返回一页 HTML、前端拿到非 JSON)。
|
||
# 这也是本批新踩的一条:之前只有 dav/carddav 两条互不包含的前缀,
|
||
# 到这里第一次出现"一个前缀包含另一个"的情况,顺序**变成有语义的**了。
|
||
RewriteRule ^nav/suggest\.php$ nav_suggest.php [L,QSA]
|
||
RewriteRule ^nav/?$ nav_show.php [L,QSA]
|
||
</IfModule>
|
||
|
||
# ⚠️ 导航图标与展示页头像**不需要重写规则**(v24 第 25 批):
|
||
# nav_icon.php / nav_avatar.php 是站点根下的**真实文件**,Apache 直接就能执行。
|
||
# 展示页里的地址由 Nav::abs() 拼成 `<base_url>/nav_icon.php?f=…`,落在站点根,
|
||
# 不经过 /nav/ 这个重写前缀 —— 所以上面那两条规则一个字都不用动。
|
||
# (这正是选"站点根下的两个独立入口"而不是"塞进 /nav/ 子路径"的原因:
|
||
# 塞进去就得再加两条重写规则,而重写规则的顺序语义已经踩过一次坑了。)
|
||
|
||
# ⚠️⚠️ DAV 的 Basic 鉴权**必须**靠这一行才能在 Apache 上工作:
|
||
# Apache 默认**不把 `Authorization` 头交给 PHP-FPM** → `$_SERVER['PHP_AUTH_USER']`
|
||
# 和 `HTTP_AUTHORIZATION` 都是 null → /dav/ 与 /carddav/ 无论口令填得多正确都 401。
|
||
# 线上实测(Apache 2.4.53,直接监听 80/443):
|
||
# 没有这行 : {"PHP_AUTH_USER":null,"HTTP_AUTHORIZATION":null}
|
||
# 加上这行 : {"PHP_AUTH_USER":"abc","HTTP_AUTHORIZATION":"(有)"}
|
||
# `CGIPassAuth` 是 Apache **2.4.13+ 的核心指令**,不需要额外模块。
|
||
# (本地 `php -S` 会自己填好 PHP_AUTH_USER,所以 e2e 全绿而线上全 401 ——
|
||
# 典型的"本地好好的、线上不行"。部署脚本也会把这一段追加到线上那份里。)
|
||
<IfModule mod_authz_core.c>
|
||
CGIPassAuth On
|
||
</IfModule>
|
||
|
||
# 备份/临时文件永远不给出去(这条线上很要紧:*.php.bak 曾经可被直接下载)
|
||
<FilesMatch "\.(bak|old|orig|save|swp|swo|tmp)$">
|
||
Require all denied
|
||
</FilesMatch>
|
||
<FilesMatch "^\.|~$">
|
||
Require all denied
|
||
</FilesMatch>
|