Files
FamilyBook/templates/notifications/index.php
T
laoyang df6fe894d0 v32 第 32 批(4 条):资源共享弹框真落库 / 消息通知覆盖全部共享入口 / 浏览器通知(站内消息+日程到期提醒) / 首页任务随看板色
用户原话:
①「资源共享功能有问题,弹框中,点击共享给某个人后,弹框消失,但是并没有共享成功。」
②「消息通知,在所有引用自己的地方,都通知,包括别人分享了日历本给自己,
   分享了笔记给自己,分享了资源给自己等等。」
③「当有消息通知时,还有日历中日程到期提醒时,比如一个日程,设置了10点开始,
   提前十分钟提醒,则需要在 9:50 时浏览器中发提醒通知。」
④「首页,近期任务,任务的文字和前面的圆点,颜色并没有跟看板颜色一致,这个需要修正。」

四条真根因:
① v28 把资源编辑改成三页签后,每个页签各有自己的 form 与 <input name=id>,
   而设 id 的代码是 panel.querySelector() → 只命中文档序第一个(info 的 update),
   ⇒ share/att 表单的 id 恒空 ⇒ 提交 id=0 ⇒ Resource::find(familyId,0,me) 返回 null
   ⇒ 静默不共享。修:表单打 data-res-idform 标记 + querySelectorAll 逐个填。
② v30 只在 saveAttendees 后调 syncForTarget,6 个共享入口一个都没接。
   新增 Notification::syncShares(家庭,类型,宿主id,动作人) —— 照共享表现状重建差额
   (写表后调用;漏调只会没通知,不会状态不一致)。SHARE_KINDS 抽常量。
③ 完全没有浏览器通知。新增 Calendar::remindersBetween()(窗口留 -2 分钟防后台节流)
   + ?r=notifications/poll JSON 路由 + assets/js/notify.js(轮询 + Notification API
   + id@at 去重)+ 顶栏铃铛(权限只能用户点一下才要,自动申请会被 Chrome 静默拒绝)。
④ v30 把用户那句和主题颜色一样理解成了**任务模块主题色**,用户要的是**看板色**。
   新增 Task::boardColorById(家庭,看板id)(没设色按看板名派生稳定色),home.php 两处改 $tkColor。

验证:诊断探针 18/0、真机 25/0(真点共享→库里真的多一行;三类共享真发通知;
9:50 窗口真算出 10:00 那条;首页每条任务色 == 其看板色)、反向 5/0、
e2e 1502/0、升级 153/0、几何 428+680+92、城市 32/0。
部署脚本静态断言段本地空跑通过;线上站点自检 19 条全过,notifications/poll 未登录 302。
2026-10-09 07:25:08 +08:00

74 lines
3.3 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* 通知消息(v30 第 5 条)。
*
* 用户原话:「引入通知模块,这个模块,不在导航显示,在个人头像点击那里显示,
* 放在个人设置前面,名字:通知消息。就是当有人在观影、旅程等地方
* 加我的时候,发一个通知。」
*
* 所以这一页**只有一条线**:谁、在什么时候、把"我"加进了哪件事 —— 点进去就是那件事。
*
* ⚠️ 进页面即全部标已读(在路由里做的)—— 消息中心的惯例:
* 打开看看就等于"看过了",不需要再让用户手动一条条点"已读"。
* 但**未读的才会被"撤销"**(被移出参与人时):已读的是历史,不删(见 Notification 头部)。
*
* @param array $items 我的通知(最新在前,含 actor_name / actor_nick / actor_avatar)
*/
$items = $items ?? [];
?>
<div class="page-head">
<h1>通知消息</h1>
<span class="sub">共 <?= count($items) ?> 条</span>
<div class="actions">
<?php if ($items): ?>
<form method="post" action="<?= e(url('notifications/clear')) ?>"
onsubmit="return confirm('清空全部通知?清掉就找不回来了。')" style="display:inline">
<?= csrf_field() ?>
<button class="btn btn-ghost btn-sm" type="submit">清空</button>
</form>
<?php endif; ?>
<a class="btn btn-ghost btn-sm" href="<?= e(url('home')) ?>">返回首页</a>
</div>
</div>
<div class="card card-pad">
<?php if (!$items): ?>
<p class="empty-hint">
还没有通知。别人在观影、旅程里把你加进去时,这里就会有消息。
</p>
<?php else: ?>
<ul class="ntf-list">
<?php foreach ($items as $n): ?>
<?php
// 谁发起的:优先用"我叫他什么"(与全站称呼口径一致)
$actorName = \App\Nickname::display(
(int)\App\Auth::personId(),
['name' => $n['actor_name'] ?? '', 'my_nickname' => $n['actor_nick'] ?? '']
);
if (trim((string)$actorName) === '') { $actorName = '有人'; }
$isUnread = empty($n['is_read']);
// 图标:按 kind 分(观影 = 胶片,旅程 = 脚印,其余 = 铃铛)
$kind = (string)($n['kind'] ?? '');
?>
<li class="ntf-row ntf-row-<?= e($kind) ?><?= $isUnread ? ' is-unread' : '' ?>">
<img class="ntf-av" src="<?= e(avatar_url($n['actor_avatar'] ?? null)) ?>" alt="">
<a class="ntf-main" href="<?= e(\App\Notification::href($n)) ?>">
<span class="ntf-title">
<b><?= e((string)$actorName) ?></b>
<?= e(\App\Notification::bodyWithoutActor((string)$n['title'])) ?>
</span>
<span class="ntf-time"><?= e(fb_time_ago((string)$n['created_at'])) ?></span>
</a>
<span class="ntf-kind ntf-kind-<?= e($kind) ?>" aria-hidden="true">
<?= \App\Notification::icon($kind) ?>
</span>
<form method="post" action="<?= e(url('notifications/del')) ?>" class="ntf-del">
<?= csrf_field() ?>
<input type="hidden" name="id" value="<?= (int)$n['id'] ?>">
<button class="btn btn-ghost btn-sm" type="submit" title="删除这条">删除</button>
</form>
</li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</div>