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。
This commit is contained in:
@@ -1419,6 +1419,53 @@ switch ($r) {
|
||||
redirect('notifications');
|
||||
break;
|
||||
|
||||
/**
|
||||
* v32 第 3 条:**浏览器通知**的轮询口(JSON)。
|
||||
*
|
||||
* 用户原话:「当有消息通知时,还有日历中日程到期提醒时…则需要在 9:50 时
|
||||
* 浏览器中发提醒通知。」
|
||||
*
|
||||
* 前端每 60 秒拉一次,本口回两样东西:
|
||||
* · `unread` —— 未读站内消息(前端弹"你有 N 条新消息",**不进通知页就不标已读**)
|
||||
* · `reminders` —— 落在 [now-2min, now+30s] 窗口内的日程提醒
|
||||
*
|
||||
* ⚠️ 为什么"到点"要在**服务端**算,而不是前端拿 starts_at 自己减:
|
||||
* 时区、`reminder_minutes` 是逗号串(多档)、重复日程…这些判断都在
|
||||
* PHP 侧已经有一套(reminderList / 可见性),前端再写一遍必然漂移。
|
||||
* 前端只负责"把服务端说该响的响出来"。
|
||||
*
|
||||
* ⚠️ 窗口要**留过去的一点**(-2 分钟):浏览器标签页休眠/被节流时轮询会迟到,
|
||||
* 只取"未来 30 秒"会整整错过一条(用户会看到"明明设了提醒却没弹")。
|
||||
* ⚠️ 但不能留太长:会把"我刚打开页面"时早就过去的提醒一次性全弹出来。
|
||||
*
|
||||
* ⚠️ **不标已读**:浏览器的提示条不是"打开消息页",不该把消息标成已读。
|
||||
* 标已读只在用户真的进 `?r=notifications` 时发生。
|
||||
*/
|
||||
case 'notifications/poll':
|
||||
Auth::requireLogin();
|
||||
$me = (int)Auth::personId();
|
||||
$familyId = (int)Auth::familyId();
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
$now = time();
|
||||
echo json_encode([
|
||||
'unread' => Notification::unreadCount($me),
|
||||
'items' => array_map(static function (array $n): array {
|
||||
return [
|
||||
'id' => (int)$n['id'],
|
||||
'actor' => (string)($n['actor_name'] ?? ''),
|
||||
'body' => Notification::bodyWithoutActor((string)$n['title']),
|
||||
'icon' => Notification::icon((string)($n['kind'] ?? '')),
|
||||
'href' => Notification::href($n),
|
||||
];
|
||||
}, Notification::mine($me, 5, true)),
|
||||
'reminders' => Calendar::remindersBetween(
|
||||
$familyId, $me,
|
||||
date('Y-m-d H:i:s', $now - 120),
|
||||
date('Y-m-d H:i:s', $now + 30)
|
||||
),
|
||||
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
exit;
|
||||
|
||||
// ==================== 我自己的资料 / 个人设置 ====================
|
||||
// 顶栏头像点开 →「个人设置」。访客也能改自己的资料 ——
|
||||
// 「个人信息」是每个人自己的事,不该因为角色是 guest 就连名字都写不了。
|
||||
@@ -4460,6 +4507,11 @@ $want = array_keys($want);
|
||||
redirect('calendar/calendars');
|
||||
}
|
||||
Calendar::setShare($id, $target, (string)($_POST['perm'] ?? 'read'));
|
||||
// v32 第 2 条:别人把日历本共享给我 → 给我发一条通知
|
||||
// ⚠️ 放在**共享表写入之后**、按表现状重建(用户会反复改权限),
|
||||
// 不要在这里手写"给谁发"——见 Notification::syncShares 的说明。
|
||||
Notification::syncShares((int)Auth::familyId(), Notification::CALENDAR,
|
||||
$id, $me);
|
||||
flash('ok', '已共享。');
|
||||
redirect('calendar/calendars');
|
||||
break;
|
||||
@@ -4475,6 +4527,10 @@ $want = array_keys($want);
|
||||
redirect('calendar/calendars');
|
||||
}
|
||||
Calendar::dropShare($id, (int)($_POST['person_id'] ?? 0));
|
||||
// v32 第 2 条:被移出共享 → 把他**未读**的那条通知一并撤销
|
||||
//(已读的保留:那是他看过的历史,删了像"消息会自己消失")
|
||||
Notification::syncShares((int)Auth::familyId(), Notification::CALENDAR,
|
||||
$id, $me);
|
||||
flash('ok', '已取消共享。');
|
||||
redirect('calendar/calendars');
|
||||
break;
|
||||
@@ -5119,6 +5175,9 @@ $want = array_keys($want);
|
||||
$target = (int)($_POST['person_id'] ?? 0);
|
||||
if ($target > 0 && isset(Person::map($familyId)[$target])) {
|
||||
Resource::setShare($id, (int)$r0['owner_id'], $target, (string)($_POST['perm'] ?? 'read'));
|
||||
// v32 第 1+2 条:资源共享(顺带修掉"弹框里点共享没生效"之后,
|
||||
// 这里才真正会被走到)→ 按共享表现状给被共享的人发通知
|
||||
Notification::syncShares($familyId, Notification::RESOURCE, $id, $me);
|
||||
flash('ok', '已共享。');
|
||||
}
|
||||
redirect('resources');
|
||||
@@ -5133,6 +5192,8 @@ $want = array_keys($want);
|
||||
$r0 = Resource::find($familyId, $id, $me);
|
||||
if ($r0 && Resource::canWrite($r0, $me)) {
|
||||
Resource::dropShare($id, (int)($_POST['person_id'] ?? 0));
|
||||
// v32 第 2 条:撤销他未读的那条共享通知(已读的保留)
|
||||
Notification::syncShares($familyId, Notification::RESOURCE, $id, $me);
|
||||
flash('ok', '已取消共享。');
|
||||
}
|
||||
redirect('resources');
|
||||
@@ -6671,6 +6732,8 @@ $want = array_keys($want);
|
||||
redirect('notes/form', ['id' => $id]);
|
||||
}
|
||||
Note::setShare($id, $me, $pid, (string)($_POST['perm'] ?? 'read'));
|
||||
// v32 第 2 条:别人把笔记共享给我 → 发一条通知(按共享表现状重建)
|
||||
Notification::syncShares($familyId, Notification::NOTE, $id, $me);
|
||||
flash('ok', '共享已更新。');
|
||||
redirect('notes/form', ['id' => $id]);
|
||||
break;
|
||||
@@ -6688,6 +6751,8 @@ $want = array_keys($want);
|
||||
redirect('notes');
|
||||
}
|
||||
Note::dropShare($id, $pid);
|
||||
// v32 第 2 条:撤销他未读的那条共享通知(已读的保留)
|
||||
Notification::syncShares($familyId, Notification::NOTE, $id, $me);
|
||||
flash('ok', '已取消共享。');
|
||||
redirect('notes/form', ['id' => $id]);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user