v71c:首页「通知消息」改成正规卡片,样式直接复用通知页
用户 2026-10-21:
「先把web端的首页修一下,通知消息这个,也是首页的卡片,可以调整顺序和大小。
另外,这个样式也不好看,我看个人头像点击后,通知消息那个页面的样式就不错,
直接复用就可以了。」
① 卡片化(HomeCards 注册表 + 默认布局 + 取数)
· TYPES 新增 'notif'(w4/h4,route=notifications,more=全部通知)
· DEFAULT_LAYOUT 钉在 brief 之后,与 days 并一行(宽 4)——
若插在 brief 与 agenda 之间,agenda/tasks 会被挤成一上一下(实测 C13 顶边 407 vs 751)
· data() 加 case 'notif' → 新增 notifData():最新 10 条 + 未读数,
与原来的取数口径一字不差;关掉卡片就不查这两条 SQL
· templates/home.php 删掉网格前那块写死区块(v30 第 5 条「必须在往年的今天前面」
这条约束作废 —— 那时还没有卡片体系);index.php 不再单独传 notifs/notifUnread
② 样式复用 templates/notifications/index.php
· 结构与通知页完全一致:头像在前 → 正文 → kind 图标在右(带 ntf-kind-{kind})
(旧首页那块是"图标在前、头像第二",正是用户说不好看的那一版)
· 新增 .hc-ntf 作用域只补"卡片比整页小"的三条差异:正文允许折两行(宽 2 时
单行省略会把正文全吃掉)、时间挪到正文下一行、未读数做小注脚
· 不带每条右侧「删除」按钮(4×4 的卡里塞两个按钮会把正文挤成两三个字),
删除在通知页做,卡片右上角有「全部通知」
③ 顺带修掉 v63 A1 抓住的一处:'notif' 的 mod 给 'home' 而不是空串
(通知不在 Module::LIST,但它是首页自己的卡片;空串会让「全部通知」成为
一排同色模块按钮里唯一白底 ghost 的那个)
⇒ TYPES docstring 立规矩:route 非空就必须有 mod,认不出归哪个模块就归 home
验证(familybook_push.sh 第 6 轮全绿,PUSH_RC=0,2h11m)
v62 首页卡片 56/0 · v62 反向验证 14/0(新增 M8–M12 五条注入)
b30 通知 16/0 · b30 反向验证 18/0
v63 40/0 · v63 反向验证 51/0 · e2e 1523/0 · 部署静态断言空跑 RC=0
同批带上上一轮 v70/v71 的日历修复(已单独验过,本轮流水线一并回归):
· v70 日历导入后条目不显示:+N 条从纯文本 span 改成真按钮,点开是当天全部
条目浮层;AJAX 新建后就地插入与服务端同形(回 entry,不让前端自己拼)
· v71 ICS 导入顺序:主事件 → 覆盖行 → EXDATE 由 Calendar::importIcs() 统一保证
This commit is contained in:
@@ -948,11 +948,14 @@ switch ($r) {
|
||||
// v62 卡片体系
|
||||
'homeCards' => $homeCards,
|
||||
'cardData' => $cardData,
|
||||
// v30 第 5 条:通知块(放在「往年的今天」之前,见 templates/home.php)
|
||||
// ⚠️ 首页只给**最新的几条**(10 条)就够 —— 它是"瞥一眼"的地方,
|
||||
// 真正的消息中心在 ?r=notifications。
|
||||
'notifs' => Notification::mine($me, 10),
|
||||
'notifUnread'=> Notification::unreadCount($me),
|
||||
/* 🔴 v71c(用户 2026-10-21):「通知消息这个,也是首页的卡片,可以调整
|
||||
顺序和大小。」
|
||||
⇒ 通知**不再是**这里单独传的两个变量(`notifs` / `notifUnread`),
|
||||
而是卡片自己的取数(`HomeCards::notifData()`,见 `_card_notif.php`)。
|
||||
⚠️ 这样就**不可能**再出现"卡片被关掉了、SQL 还在跑"这种白查 ——
|
||||
`data()` 只对用到的 key 取数。
|
||||
⚠️ 头像下拉的未读角标**不在这里**:`layout.php` 自己调 unreadCount,
|
||||
与首页摆不摆这张卡片无关(关掉卡片不该让角标也消失)。 */
|
||||
], 'home');
|
||||
break;
|
||||
|
||||
@@ -5487,9 +5490,11 @@ $want = array_keys($want);
|
||||
flash('ok', $okMsg);
|
||||
redirect($kind === 'movie' ? 'movies/show' : 'trips/show', ['id' => $newId]);
|
||||
}
|
||||
$evLoc = trim((string)($_POST['location'] ?? ''));
|
||||
$evRrule = Repeat::build($_POST);
|
||||
$evId = Calendar::addEvent((int)$cal['id'], [
|
||||
'title' => $title,
|
||||
'location' => trim((string)($_POST['location'] ?? '')),
|
||||
'location' => $evLoc,
|
||||
'starts_at' => $startsAt,
|
||||
'ends_at' => $endsAt,
|
||||
'all_day' => $allDay,
|
||||
@@ -5501,7 +5506,7 @@ $want = array_keys($want);
|
||||
'status' => (string)($_POST['status'] ?? 'confirmed'),
|
||||
'transp' => !empty($_POST['transp']),
|
||||
// 用户 2026-10-03 第 5、6 条:重复规则(RFC 5545 RRULE 原文)
|
||||
'rrule' => Repeat::build($_POST),
|
||||
'rrule' => $evRrule,
|
||||
'note' => $note,
|
||||
'created_by' => $me,
|
||||
]);
|
||||
@@ -5516,6 +5521,33 @@ $want = array_keys($want);
|
||||
· cal —— data-cal,前端/样式按它分组。 */
|
||||
if ($ajax) {
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
/* 🔴 v70:「+N 条」点开的是**当天全部条目**浮层,数据来自服务端渲染好的
|
||||
`#calDayData`。AJAX 新建一条之后必须**同步补进那份数据**,否则
|
||||
"刚建的这条在 +N 条清单里看不到"(刷新一次又出现)。
|
||||
⇒ 这里直接回一份 `entry`(就是 `fb_entry_json()` 的产出),
|
||||
前端原样塞进去 —— **不要**让前端自己按字段拼:漏一个 location
|
||||
或把 occ/repeat 拼丢,浮层里的详情、删除就会和服务端渲染的不一样。
|
||||
⚠️ 字段与下面 `Calendar::month()` → `fb_entry_json()` 同一套口径。 */
|
||||
$newDay = substr((string)$startsAt, 0, 10);
|
||||
$newTm = ($allDay || $startsAt === '') ? '' : substr((string)$startsAt, 11, 5);
|
||||
$newEtm = ($allDay || $endsAt === null || $endsAt === '') ? '' : substr((string)$endsAt, 11, 5);
|
||||
$newHref = url('calendar/event', ['id' => (int)$evId, 'd' => $newDay]);
|
||||
$newEntry = fb_entry_json([
|
||||
'title' => $title,
|
||||
'date' => $newDay,
|
||||
'time' => $newTm,
|
||||
'end_time' => $newEtm,
|
||||
'all_day' => $allDay,
|
||||
'cal' => (int)$cal['id'],
|
||||
'calname' => (string)($cal['name'] ?? ''),
|
||||
'location' => $evLoc,
|
||||
'note' => $note,
|
||||
'kind' => 'custom',
|
||||
'ref_id' => (int)$evId,
|
||||
'repeat' => $evRrule,
|
||||
'occ' => $newDay,
|
||||
'_can_write' => true, /* 刚在这本上建成功 ⇒ 当然可写 */
|
||||
], $newHref, url('calendar/event', ['id' => (int)$evId, 'embed' => 1]));
|
||||
echo json_encode([
|
||||
'ok' => true,
|
||||
'msg' => '日程已加上。',
|
||||
@@ -5527,9 +5559,11 @@ $want = array_keys($want);
|
||||
'ends_at' => (string)($endsAt ?? ''),
|
||||
'all_day' => $allDay ? 1 : 0,
|
||||
'cal' => (int)$cal['id'],
|
||||
'calname' => (string)($cal['name'] ?? ''),
|
||||
'color' => (string)($cal['color'] ?? ''),
|
||||
'time' => ($allDay || $startsAt === '') ? '' : substr((string)$startsAt, 11, 5),
|
||||
'href' => url('calendar/event', ['id' => (int)$evId, 'd' => substr((string)$startsAt, 0, 10)]),
|
||||
'time' => $newTm,
|
||||
'href' => $newHref,
|
||||
'entry' => json_decode($newEntry, true),
|
||||
],
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
@@ -5869,22 +5903,16 @@ $want = array_keys($want);
|
||||
flash('err', '这个文件里没有找到任何日程(VEVENT)。');
|
||||
redirect('calendar/calendars');
|
||||
}
|
||||
$added = 0;
|
||||
$updated = 0;
|
||||
foreach ($list as $v) {
|
||||
if (($v['starts_at'] ?? null) === null) {
|
||||
continue; // 没有 DTSTART 的 VEVENT 是坏数据,跳过而不是写成 1970 年
|
||||
}
|
||||
if (trim((string)$v['title']) === '') {
|
||||
$v['title'] = '(无标题日程)';
|
||||
}
|
||||
if (Calendar::importEvent($calId, $v, $me) === 'added') {
|
||||
$added++;
|
||||
} else {
|
||||
$updated++;
|
||||
}
|
||||
/* 🔴 v71(用户 2026-10-19):**不能**在这里 for 循环逐条 importEvent ——
|
||||
那样同一 UID 下的覆盖行会先于主事件落库(ICS 里主事件不一定排第一),
|
||||
或者反过来把主事件改掉。顺序由 `Calendar::importIcs()` 统一保证:
|
||||
主事件 → 覆盖行 → EXDATE。 */
|
||||
$stat = Calendar::importIcs($calId, $list, $me);
|
||||
$msg = '导入完成:新增 ' . $stat['added'] . ' 条,更新 ' . $stat['updated'] . ' 条。';
|
||||
if ($stat['overrides'] > 0) {
|
||||
$msg .= '其中 ' . $stat['overrides'] . ' 条是重复日程里单独调整的某一次。';
|
||||
}
|
||||
flash('ok', '导入完成:新增 ' . $added . ' 条,更新 ' . $updated . ' 条。');
|
||||
flash('ok', $msg);
|
||||
redirect('calendar/calendars');
|
||||
break;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user