v59 服务端:标语(个人→家庭→默认)/ 最近纪念日 / 真实头像
配合端上「界面六条」,服务端只补三样数据:
① Family::slogan(fam, pid) —— 三层优先级
用户:「如果这个用户自己有标语,他可以写一句自己的标语;如果他有自己的标语,
这个地方就是用户自己自定义的标语。如果他没有标语,就用我们给他的这个标语。」
优先级:persons.slogan → families.motto → Family::DEFAULT_SLOGAN。
DEFAULT_SLOGAN = '一家人用岁月写成的一本书'(用户明确指定,别再改)。
与网页端 templates/home.php 的 heroSlogan 同一套规则,两边永远一致。
/login 与 /me 都返回 slogan —— 每次启动都会打 /me,所以网页端改了 slogan
手机下次启动就跟上,不必为此另加接口。
② /home 新增 recent_days —— 首页「最近纪念日」
用户:「未来最近的三个纪念日,包括每个人的生日,以及手动填写的各个纪念日。」
= Anniversary::upcoming(fam, pid, 370) 取前 3。
· 为什么是 370 天而不是网页端概述卡那样的 30 天:只取 30 天时,
一个"刚过完生日"的家庭会**一个都取不到**,模块直接空着 ——
而用户要的是一个永远的倒计时。取满一年保证"接下来的三个"一定有。
· 数据源 all() = 派生生日 + 自建纪念日(正好覆盖用户说的两样,
不必再去 Birthday:: 那套单独取一遍,否则迟早口径不一)。
· 每条带 days(倒计天数)、source(custom / birthday_solar / birthday_lunar),
顺序由服务端排好(最近的在前),端上不再排一遍。
③ 真实头像
用户:「右上角的头像应该是真实的。」
· /home 新增 me_avatar(当前登录者的 avatar_url());
· /login 的 person 增加 avatar_url。
avatar_url() 负责按线上存储驱动决定走 /uploads 还是 OSS 直链 ——
端上不自己拼路径(拼错了就是永远破图)。
验证:_fb_home_api.py 60/0(新增 16 条:recent_days 真数据/天数/排序/≤3 条、
me_avatar、slogan 三层优先级实测 —— 给 persons#1 写一句个人 slogan,
必须优先返回他那句);php -l 通过;部署脚本增「第59批形态」9 条。
真机实测:抽屉显示「修身,齐家」= 杨永全自己的 slogan(个人优先生效)。
This commit is contained in:
+79
-4
@@ -224,6 +224,20 @@ final class ApiHandler
|
||||
error_log('[familybook] 登录取家庭名失败(已跳过):' . $ex->getMessage());
|
||||
}
|
||||
|
||||
/* 🔴 2026-10-18:登录响应直接带上**我该显示的那句标语**。
|
||||
用户要求把抽屉左上角那行(原来是「我的家」)换成标语:
|
||||
有个人 slogan 用个人的、没有用家庭的、再没有用应用默认口号
|
||||
(三层优先级见 `Family::slogan()`,与网页端首页同一个函数)。
|
||||
⚠️ 放在登录里而不是只放 `/me`:登录后**立刻**就要渲染抽屉,
|
||||
少一次请求就少一次"先显示旧值再跳变"的闪烁。 */
|
||||
$slogan = Family::DEFAULT_SLOGAN;
|
||||
try {
|
||||
$slogan = Family::slogan($familyId, $personId);
|
||||
} catch (\Throwable $ex) {
|
||||
error_log('[familybook] 登录取标语失败(回退默认):' . $ex->getMessage());
|
||||
}
|
||||
$avatarRaw = (string)($row['avatar'] ?? '');
|
||||
|
||||
Api::ok([
|
||||
'token' => $token,
|
||||
// 到期时间由**服务端**算(端上只拿来显示,绝不据此判断"还能不能用")
|
||||
@@ -234,11 +248,16 @@ final class ApiHandler
|
||||
'person' => [
|
||||
'id' => $personId,
|
||||
'name' => (string)$row['name'],
|
||||
'avatar' => (string)($row['avatar'] ?? ''),
|
||||
'avatar' => $avatarRaw,
|
||||
/* 🔴 头像 URL 与 `/me` 同口径(`avatar_url()` 会按线上存储驱动
|
||||
决定走 /uploads 还是 OSS 直链)。
|
||||
⚠️ 端上顶栏原来只拿色块字、拿不到真图 —— 用户 2026-10-18:
|
||||
「右上角的头像应该是真实的」。 */
|
||||
'avatar_url'=> avatar_url($avatarRaw !== '' ? $avatarRaw : null),
|
||||
'role' => (string)$row['role'],
|
||||
'family_id' => $familyId,
|
||||
],
|
||||
'family' => ['id' => $familyId, 'name' => $familyName],
|
||||
'family' => ['id' => $familyId, 'name' => $familyName, 'slogan' => $slogan],
|
||||
// 回显设备,端上可以核对"服务器记住的是不是这台"
|
||||
'device' => [
|
||||
'id' => $deviceId,
|
||||
@@ -451,9 +470,22 @@ final class ApiHandler
|
||||
'avatar' => avatar_url($p['avatar'] ?? null),
|
||||
'role' => (string)($act['role'] ?? 'member'),
|
||||
'can_write'=> (bool)($act['can_write'] ?? false),
|
||||
'family' => (function () use ($fam): array {
|
||||
'family' => (function () use ($fam, $pid): array {
|
||||
$f = Family::find($fam) ?: [];
|
||||
return ['id' => $fam, 'name' => (string)($f['name'] ?? '')];
|
||||
/* 🔴 2026-10-18:标语一并给出来(抽屉左上角那行要它)。
|
||||
每次启动都会打 `/me`,所以网页端改了 slogan 之后
|
||||
手机下次启动就会跟上 —— 不必专门为它加一个接口。 */
|
||||
$sl = Family::DEFAULT_SLOGAN;
|
||||
try {
|
||||
$sl = Family::slogan($fam, $pid);
|
||||
} catch (\Throwable $ex) {
|
||||
// 读不到就用默认,不挡登录校验
|
||||
}
|
||||
return [
|
||||
'id' => $fam,
|
||||
'name' => (string)($f['name'] ?? ''),
|
||||
'slogan' => $sl,
|
||||
];
|
||||
})(),
|
||||
// 各模块主题色:App 端顶部/分类色块直接用它,不必自己维护一张表
|
||||
'colors' => $this->moduleColors($fam),
|
||||
@@ -647,6 +679,33 @@ final class ApiHandler
|
||||
// ---- 日子标记:节气 / 法定节日 / 传统节日 / 纪念日 / 生日 ----
|
||||
$marks = Home::todayMarks($fam, $pid, $today);
|
||||
|
||||
/* ---- 🔴 v59(用户 2026-10-18):最近三个纪念日(含生日),倒计时用 ----
|
||||
用户原话:「首页应该加一个『最近纪念日』模块,放在『往年的今天』前面、
|
||||
『近期任务』后面。内容包括:1. 未来最近的三个纪念日,包括每个人的生日,
|
||||
以及手动填写的各个纪念日。2. 以倒计时形式展示:距离哪个纪念日还有多少天,
|
||||
距离谁谁谁的生日还有多少天。」
|
||||
⇒ 位置是**近期任务之后、往年的今天之前**(端上按这个顺序摆)。
|
||||
|
||||
⚠️ 为什么要 370 天的窗口(而不是像网页端概述卡那样只取 30 天):
|
||||
「未来最近的三个」如果窗口太小,一个刚过完生日的家庭会**一个都取不到**,
|
||||
模块直接空着 —— 而用户要的是一个**永远的倒计时**。
|
||||
取满一年,保证"接下来的三个"一定有(只要有纪念日或生日)。
|
||||
⚠️ 数据来源 `Anniversary::upcoming()` → `occurrences()` → `all()`,
|
||||
而 `all()` = **派生生日 + 自建纪念日** —— 正好一次满足用户说的两样,
|
||||
不必再去 `Birthday::` 那套单独取一遍(两处取必然口径不一)。
|
||||
⚠️ 已经过完今天的同样包含在内(`from` 从今天起算,含今天)。
|
||||
今天那条 `days=0` 端上会显示成「就是今天」。 */
|
||||
$recentDays = [];
|
||||
try {
|
||||
$recentDays = array_slice(Anniversary::upcoming($fam, $pid, 370), 0, 3);
|
||||
} catch (\Throwable $ex) {
|
||||
error_log('[familybook] 首页取最近纪念日失败(已跳过):' . $ex->getMessage());
|
||||
}
|
||||
|
||||
// 当前登录者本人(顶栏右上角要显示**真实头像**,用户 2026-10-18:
|
||||
// "右上角的头像应该是真实的")。取不到就留空串,端上回落成色块字。
|
||||
$meRow = Person::find($pid) ?: [];
|
||||
|
||||
// ---- 天气(三级回落:个人经纬度 → 内置城市表 → 家庭级兜底 → 不显示)----
|
||||
$wloc = Home::weatherLocation($pid, $fam);
|
||||
$weather = $wloc === null
|
||||
@@ -700,9 +759,25 @@ final class ApiHandler
|
||||
* `kind` ∈ `movie` | `trip_node`(端上据此决定图标与圆点色)。
|
||||
*/
|
||||
'memories' => Home::memories($fam, 6)['rows'],
|
||||
/**
|
||||
* 🔴 v59:未来最近的三个纪念日(用户 2026-10-18 要的「最近纪念日」模块)。
|
||||
*
|
||||
* 每条:`{id, date, title, kind, person_id, person_name?, source, days, age, nth}`
|
||||
* · `days` —— 距今天还有几天(0 = 就是今天;**永远是 0 或正数**)
|
||||
* · `kind` —— 用户填的类别("生日" / "结婚纪念" / …),端上直接显示
|
||||
* · `source`—— `'custom'` = 手动填的纪念日;其余(`birthday_solar`
|
||||
* / `birthday_lunar`)= 派生生日,端上据此区分"纪念日 / 生日"
|
||||
* · `title` —— 已含姓名(如「老杨 的生日」「结婚纪念日」),端上直接用
|
||||
*
|
||||
* ⚠️ 顺序就是"最近的在前"(`upcoming` 内部已按 date 升序),
|
||||
* 端上**不要再排一遍** —— 排序口径分散在两处迟早不一致。
|
||||
*/
|
||||
'recent_days' => $recentDays,
|
||||
'today_events' => $todayEvents,
|
||||
'tasks' => $tasks,
|
||||
'unread' => Notification::unreadCount($pid),
|
||||
/** 当前登录者的真实头像 URL(顶栏右上角要显示真图,用户 2026-10-18) */
|
||||
'me_avatar' => avatar_url($meRow['avatar'] ?? null),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user