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:
+86
-1
@@ -728,8 +728,93 @@ final class Calendar
|
||||
}
|
||||
|
||||
/**
|
||||
* 任意形态的提醒值 → **合法分钟数数组**(升序、去重)。
|
||||
* v32 第 3 条:**到点的提醒**(浏览器通知用)。
|
||||
*
|
||||
* 用户原话:「还有日历中日程到期提醒时,比如一个日程,设置了10点开始,
|
||||
* 提前十分钟提醒,则需要在9:50时浏览器中发提醒通知。」
|
||||
*
|
||||
* @param string $from 窗口起点(含),'Y-m-d H:i:s'
|
||||
* @param string $to 窗口终点(含)
|
||||
* @return array<int,array{id:int,title:string,starts_at:string,at:string,cal:string,href:string}>
|
||||
* `at` = 该触发提醒的时刻(starts_at - 提前分钟数)
|
||||
*
|
||||
* ⚠️ 为什么**只按 starts_at 查**、不做重复日程展开:
|
||||
* 重复日程(RRULE)会在每周三都"提醒一次",但那需要把系列展开到具体某天,
|
||||
* 而**同一次发生**在任何一次轮询里都必须算出**同一个提醒时刻**(否则会重复弹)。
|
||||
* 窗口很短(前端每次只看"现在前后几分钟"),而"下次发生"恰好落在这几分钟里的
|
||||
* 概率极低、影响也只是一个提醒来得晚一点。
|
||||
* ⇒ 这一版覆盖"用户举的那个例子"(单次日程 10:00 提前 10 分钟 → 9:50 弹),
|
||||
* 重复日程的提醒留待需要时再展开(不假装支持)。
|
||||
*
|
||||
* ⚠️ 多档提醒(`reminder_minutes` 是 `'5,15'`)会返回**多条**(每档一条):
|
||||
* 用户既然设了两档,就该被提醒两次 —— 靠前端按 `id@at` 去重,不会重复弹同一条。
|
||||
*/
|
||||
public static function remindersBetween(int $familyId, int $personId,
|
||||
string $from, string $to): array
|
||||
{
|
||||
// 我可见的日历本 = 我建的 + 共享给我的(与页面口径一致,别另发明一套)
|
||||
$books = [];
|
||||
foreach (self::mine($familyId, $personId) as $c) {
|
||||
if (in_array((string)$c['kind'], ['movie', 'trip'], true)) {
|
||||
continue; // 派生本没有 calendar_events 行,且它们本就没有提醒
|
||||
}
|
||||
$books[] = (int)$c['id'];
|
||||
}
|
||||
if (!$books) {
|
||||
return [];
|
||||
}
|
||||
$in = implode(',', array_fill(0, count($books), '?'));
|
||||
// ⚠️ 范围要放宽 `最大档位` 分钟:提醒时刻 = 开始 - N 分钟,
|
||||
// 所以"开始时间"可能在窗口**之后**(10:00 的事件,9:50 时窗口是过去)。
|
||||
// 取 REMINDERS 里最大档位当余量,一次查全。
|
||||
$maxLead = max(array_keys(self::REMINDERS));
|
||||
$st = Database::get()->prepare(
|
||||
"SELECT e.id, e.title, e.starts_at, e.reminder_minutes, e.all_day,
|
||||
c.name AS calname
|
||||
FROM calendar_events e
|
||||
JOIN calendars c ON c.id = e.calendar_id
|
||||
WHERE e.calendar_id IN ($in)
|
||||
AND e.reminder_minutes IS NOT NULL AND e.reminder_minutes <> ''
|
||||
AND e.status <> 'cancelled'
|
||||
AND e.starts_at >= ? AND e.starts_at <= ?
|
||||
ORDER BY e.starts_at"
|
||||
);
|
||||
$st->execute(array_merge($books,
|
||||
[date('Y-m-d H:i:s', strtotime($from) - $maxLead * 60),
|
||||
date('Y-m-d H:i:s', strtotime($to) + $maxLead * 60)]));
|
||||
$out = [];
|
||||
$fTs = strtotime($from);
|
||||
$tTs = strtotime($to);
|
||||
foreach ($st->fetchAll() as $e) {
|
||||
if (!empty($e['all_day'])) {
|
||||
continue; // 全天日程没有"开始时点",提前 N 分钟无从计算
|
||||
}
|
||||
$sTs = strtotime((string)$e['starts_at']);
|
||||
if ($sTs === false) {
|
||||
continue;
|
||||
}
|
||||
foreach (self::reminderList($e['reminder_minutes'] ?? null) as $lead) {
|
||||
$atTs = $sTs - $lead * 60;
|
||||
if ($atTs < $fTs || $atTs > $tTs) {
|
||||
continue; // 这一档的提醒时刻不在本窗口
|
||||
}
|
||||
$out[] = [
|
||||
'id' => (int)$e['id'],
|
||||
'title' => (string)$e['title'],
|
||||
'starts_at' => (string)$e['starts_at'],
|
||||
'at' => date('Y-m-d H:i:s', $atTs),
|
||||
'lead' => (int)$lead,
|
||||
'cal' => (string)$e['calname'],
|
||||
'href' => url('calendar/event', ['id' => (int)$e['id']]),
|
||||
];
|
||||
}
|
||||
}
|
||||
usort($out, static fn(array $a, array $b): int => strcmp($a['at'], $b['at']));
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* 任意形态的提醒值 → **合法分钟数数组**(升序、去重)。
|
||||
* ⚠️ 白名单:只认 `self::REMINDERS` 里那几个档位。手搓请求塞 999999
|
||||
* 不能变成"提前 999999 分钟提醒"(那会导出一个客户端算不明白的 VALARM)。
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user