v85: 首页日程刻度按结束时间定范围 / Markdown 标题真正有层级

用户报了两处(网页版):

① 「今天的日程,有一个日程到下午五点半,首页日程刻度只有九点。」
   真根因:掐头去尾只按 `time`(开始时间)算范围,`end_time` 压根没参与
   ⇒ 08:30-17:30 被当成"8 点半结束",endH = 8 + 2 = 10,
     刻度只画到 09:00;色块高 540 分钟硬塞进 3 小时格子,被 min(96, …) 夹住糊成一片。
   修法:收集「开始 + 结束」两组分钟数,endH 由 max(结束) 向上取整到小时;
   保留"区间必须包含此刻"的原逻辑与下限保护。

② 「日记 markdown 代码都没解析,## 后面的是标题,现在显示的还是和正文一样。」
   真根因:渲染一直是对的(`## x` → `<h4 class="md-h">`),问题全在视觉 ——
   `h4.md-h` 是 15px,而阅读态正文 `.note-read-block` 也是 15px,字号完全同号;
   标题只有 font-weight:500,肉眼看不出层级。
   修法:h3/h4/h5/h6 分别 18/17/15.5/14.5px,父级 .md-h 字重 600、行高 1.45,
   h6 用 muted 色;`:first-child` 去掉多余的顶部外边距。

反向验证:
  _fb_v85_agenda_range.py    13/0(钉死 08:00 做 A/B + 真实 now 复核 5 条)
  _fb_v85_md_heading.py       9/0(真实 Markdown::render + 真实 CSS + 计算值)
  _fb_v85_static_falsify.py   7/0(部署静态断言 6 处注入各自都能变红)

线上真值复核(family.yangyq.net,真实库 #1853 工程管理硕士开题 08:30~17:30):
  旧模板 刻度 07~09(3 行)下沿 10:00,色块 top=50%/h=50%  —— 复现用户所见
  新模板 刻度 07~17(11 行)下沿 18:00,色块 top=13.64%/h=81.82% = 95.46% 完整在车道内
  CSS    h4.md-h 17px / 正文 15px / .md-h font-weight 600
This commit is contained in:
2026-10-24 09:31:08 +08:00
parent 4b58fec796
commit a7b3d8cfd8
2 changed files with 71 additions and 13 deletions
+27 -4
View File
@@ -5400,10 +5400,33 @@ button.btn, a.btn, summary.btn, .seg-btn, .icon-btn, .rv-act-btn, .cs-btn, .bf-b
/* ---- Markdown 渲染出来的元素(列表页/预览共用同一套)---- */
.md-p { margin: 0 0 8px; }
.md-p:last-child { margin-bottom: 0; }
.md-h { margin: 10px 0 6px; font-weight: 500; color: var(--ink); }
h3.md-h { font-size: 16px; }
h4.md-h { font-size: 15px; }
h5.md-h, h6.md-h { font-size: 14px; }
/* 🔴🔴 v85(用户 2026-10-24):「还有日记功能,markdown 代码都没解析,
`##` 后面的是标题,现在显示的还是和正文一样。」
------------------------------------------------------------------
渲染**一直是对的**(`## x` → `<h4 class="md-h">`),问题全在**视觉**:
① 旧规则 `h4.md-h { font-size: 15px }`,而阅读态正文
`.note-read-block { font-size: 15px }` —— **两者完全相同**;
② 标题只有 `font-weight: 500`,而 .md-h 继承了正文的行高与颜色
⇒ 用户看到的"标题"和"正文"逐像素一致,当然认为"没解析"。
⇒ 三条一起改,缺一条都还是"看不出是标题":
① **字号必须拉开 ≥2px 且各级之间也要分级**(h4 < h5 那种倒挂是旧 bug:
`##` 给的是 h4、`###` 给的是 h5,而旧表里 h4=15px、h5=14px 只差 1px);
② **字重加到 600**(500 在中文无衬线里与常规几乎无差);
③ **加上下边距**,让标题与正文之间出现明确的段落呼吸。
⚠️ 为什么从 h4 起而不是 h1/h2:见 `Markdown::render()` 里的说明 ——
h1/h2 留给页面本身,笔记里的标题不许盖过页面标题。
所以这里必须把 **h4/h5/h6 这三级**都调大,光调 h4 不够。 */
.md-h {
margin: 16px 0 8px;
font-weight: 600;
color: var(--ink);
line-height: 1.45;
}
.md-h:first-child { margin-top: 0; }
h3.md-h { font-size: 18px; }
h4.md-h { font-size: 17px; }
h5.md-h { font-size: 15.5px; }
h6.md-h { font-size: 14.5px; color: var(--muted); }
.md-list { margin: 4px 0 8px; padding-left: 22px; }
.md-li { margin: 2px 0; }
/* 多级清单:子层用空心点,层级一眼可分(用户第 12 条"清单可以多级") */
+44 -9
View File
@@ -22,18 +22,53 @@ foreach (($todayEvents ?? []) as $ev) {
}
}
// ---- 掐头去尾:只画"第一个日程前一小时"到"最后一个日程后一小时" ----
// ---- 掐头去尾:只画"第一个日程前一小时"到"最后一个日程结束后一小时" ----
$startH = 0;
$endH = 24;
if ($timed) {
$mins = array_map(static function (array $e): int {
// ⚠️ 变量名带 `ag` 前缀:这是**被 require 进来的片段**,裸赋值 $p 会撞上
// 宿主模板里同名的 $p(流水线的"片段不许覆盖宿主变量"检查会拦下来)。
$agHM = explode(':', (string)$e['time']);
return ((int)($agHM[0] ?? 0)) * 60 + (int)($agHM[1] ?? 0);
}, $timed);
$startH = max(0, intdiv(min($mins), 60) - 1);
$endH = min(24, intdiv(max($mins), 60) + 2);
/* 🔴🔴 v85(用户 2026-10-24):「今天的日程,有一个日程到下午五点半,
首页日程刻度只有九点。」
真根因:这里**只按 `time`(开始时间)算范围**,`end_time` 压根没参与
⇒ 一条 08:30–17:30 的日程被当成"8 点半就结束了",
于是 `endH = 8 + 2 = 10`,刻度只画到 09:00,
色块高 540 分钟却只塞进 3 小时的格子里(被 `min(96, …)` 夹住,糊成一片)。
⚠️ 判据必须是「**结束时间也参与**」,不能只是"把 +2 改成 +12":
写死一个更大的偏移量,遇到 20:00 结束的日程照样截断,
而且会把"只有一条 9 点日程"的卡片硬拉成 12 小时高(用户嫌空)。
⚠️ `end_time` 可能是空(服务端没给)⇒ 那时按"开始 + 30 分钟"兜底,
与下面算 `hPct` 时的兜底口径**必须一致**,否则刻度与色块又会错位。 */
$agStarts = [];
$agEnds = [];
foreach ($timed as $agEv) {
$agHM0 = explode(':', (string)$agEv['time']);
$agStart = ((int)($agHM0[0] ?? 0)) * 60 + (int)($agHM0[1] ?? 0);
$agStarts[] = $agStart;
$agEnd = 0;
$agET = (string)($agEv['end_time'] ?? '');
if ($agET !== '' && preg_match('/^(\d{1,2}):(\d{2})/', $agET, $agMM)) {
$agEnd = ((int)$agMM[1]) * 60 + ((int)$agMM[2]);
}
/* 跨天(结束 <= 开始)时按"到当天 24 点"算 —— 不能取 24:00 以上的值,
否则 $endH 被夹到 24 之后刻度会凭空多出几行。 */
if ($agEnd <= $agStart) {
$agEnd = $agStart + 30;
}
if ($agEnd > 1440) {
$agEnd = 1440;
}
$agEnds[] = $agEnd;
}
/* ⚠️ 变量名带 `ag` 前缀:这是**被 require 进来的片段**,裸赋值会撞上
宿主模板里的同名变量(流水线的"片段不许覆盖宿主变量"检查会拦下来)。 */
$startH = max(0, intdiv(min($agStarts), 60) - 1);
/* 🔴 用**结束时间**的上界(向上取整到小时)—— 这就是本条的真修法。
`+1` 之后又 `ceil`:17:30 → ceil(1050/60)=18,留半小时缓冲;再 +0(不额外留
一小时),因为卡片本来就矮,"最后一个日程结束再画一整小时空行"太浪费。 */
$endH = min(24, (int)ceil(max($agEnds) / 60));
if ($endH <= intdiv(max($agStarts), 60)) {
$endH = min(24, intdiv(max($agStarts), 60) + 1);
}
/* 🔴 v28 用户第 1 条:「今天的日程,并没有定位到红线所在的位置」。
根因:**区间里没有"现在"**,于是红线不画、定位算出来是越界值。
⇒ 让区间永远包含当前时刻(用户要的正是"一眼看到现在处在哪儿")。