v63:卡片配色 / 日历本靠右 / 地图题图 / 设置页清理 / 公共标签颜色 / 令牌下线

- 卡片右上角按钮改用「来自哪个模块」的主题色:HomeCards 登记表新增 mod 字段
  与 module(),首页从登记表取色(原来是模板里硬编码 in_array(['agenda','tasks'])
  白名单,新加带按钮的卡片会默默变灰)
- 首页日程把日历本放到色块右侧:.ag-ev 改弹性行,「时间+标题」包进
  .ag-ev-main(flex:1 1 auto; min-width:0),日历本作右侧兄弟。
  原来 display:block 会把日历本顶到第二行,色块一矮就完全看不见
- 旅程地图显示题图:服务端把 media_url(cover_key) 塞进地图数据,
  地图卡片左侧 40x40 题图(object-fit:cover),没有题图不留灰框
- 系统设置第一块改叫「系统标语」;删掉「首页上那一行小字」提示、
  「不是全家的统一口号」说明、「上次结构升级有步骤失败了」整框;
  运行环境删「排错时看这一块」与「亲属连线」那一行(功能与数据未动)
- 公共标签:说明文字全删;列表与编辑合并成一行(色块+名字+N人+箭头+编辑);
  person_groups 加 color 列(Schema addColumn,老库可升);点「编辑」弹框
  改名字与颜色、点「完成」提交;下面那个独立编辑列表撤掉。删除挪进弹框
- 个人设置删掉「手动签发接口令牌」整块;settings/api_token 路由保留但挡下提交
  (只删界面会留下知道地址就能用的后门);令牌只由登录后自动签发,
  设备管理卡保留。apiTokens/apiPlain/apiLabel/apiBase 四个变量一并撤掉
This commit is contained in:
2026-10-19 17:27:37 +08:00
parent 2e40133d8f
commit 2f7dc6ca23
11 changed files with 450 additions and 189 deletions
+40 -18
View File
@@ -313,17 +313,15 @@ function render_me_settings(array $person, array $errors = []): void
// 通讯录同步范围要和名册页**完全一致**(用户 2026-10-06 第 22 批确认):
// 名册页看到谁就同步谁。这里把人数带过去,用户当场就能对上。
'davRosterN' => PersonRoster::countFor($familyId, $me),
/* 🔴 v44(用户 2026-10-12 第 6 条):移动端 API 令牌。
⚠️ 明文同样只在**一次性会话槽位**里取一次(`api_plain`),
取完后面 unset —— 与 DAV 口令同一条纪律。 */
'apiTokens' => \App\ApiToken::listFor($me),
'apiPlain' => (string)($_SESSION['api_plain'] ?? ''),
'apiLabel' => (string)($_SESSION['api_plain_label'] ?? ''),
'apiBase' => rtrim((string)fb_config('base_url', ''), '/'),
/* 🔴 v63(用户 2026-10-19 第 7 条):`apiTokens` / `apiPlain` / `apiLabel` / `apiBase`
四个变量**随"手动签发令牌"那块一起撤掉** —— 界面已经不渲染它们,
还每次进设置页查一遍令牌表只是白花钱(`listFor` 是一次真实查询)。
⚠️ 但 `api_plain` 那两个会话槽位**仍然要 unset**(见本函数尾部):
用户可能在升级前那一刻生成过令牌、明文还挂在会话里,
不清掉它就等于这页永远留着一份能看的明文。 */
/* 🔴 v57(用户 2026-10-17):「在个人设置里面有这个设备管理」。
⚠️ 这里传的是**按设备聚合**的列表(`listDevices`),不是令牌清单 ——
同一台手机重登过 5 次,网页上只该出现 1 行。
与上面 `apiTokens`(原始令牌行、只给"手动签发/吊销"用)不是一回事。 */
同一台手机重登过 5 次,网页上只该出现 1 行。 */
'devices' => \App\ApiToken::listDevices($me),
'deviceMax' => \App\ApiToken::MAX_DEVICES,
'deviceTtl' => \App\ApiToken::TTL_HOURS,
@@ -1925,7 +1923,12 @@ switch ($r) {
} else {
$owner = (int)Auth::personId();
}
$res = PersonGroup::add((int)Auth::familyId(), (string)($_POST['name'] ?? ''), $owner);
// 🔴 v63:颜色可随新建一起给(`settings/groups/add` 的公共标签加色块选择)。
// ⚠️ 没传 `color` 这个键 = 不设颜色(存 NULL,界面按 id 取默认色);
// 传了空值 = 用户主动选了"不要颜色"⇒ 同样存 NULL。
// 两种都落到同一个值上,所以这里不用像 rename 那样区分 null / ''。
$res = PersonGroup::add((int)Auth::familyId(), (string)($_POST['name'] ?? ''), $owner,
(string)($_POST['color'] ?? ''));
flash($res['ok'] ? 'ok' : 'err', $res['ok']
? '已加上分组「' . trim((string)($_POST['name'] ?? '')) . '」。'
: (string)($res['error'] ?? '加不上。'));
@@ -1946,8 +1949,16 @@ switch ($r) {
} else {
$owner = (int)Auth::personId();
}
/* 🔴 v63(用户 2026-10-19 第 5 条):改名与改颜色走**同一个动作**
(「每个标签增加一个颜色。如果要编辑,就点击这个标签后面的编辑按钮,
然后弹出一个框,编辑后点击完成就行了」)。
⚠️ 用 `array_key_exists` 判断"表单里到底有没有这个字段",
不能用 `!== ''` —— 空值是一个**合法输入**(= 清掉颜色),
用 `!== ''` 就再也清不掉了。 */
$hasColor = array_key_exists('color', $_POST);
$newColor = $hasColor ? (string)$_POST['color'] : null;
$res = PersonGroup::rename((int)Auth::familyId(), (int)($_POST['id'] ?? 0),
(string)($_POST['name'] ?? ''), $owner);
(string)($_POST['name'] ?? ''), $owner, $newColor);
flash($res['ok'] ? 'ok' : 'err', $res['ok']
? '分组名已改。'
: (string)($res['error'] ?? '改不了。'));
@@ -5158,17 +5169,28 @@ $want = array_keys($want);
/* 🔴 v44(用户 2026-10-12 第 6 条):移动端 API 令牌的**签发 / 吊销**。
与 DAV 那两条同一个形态(明文进一次性会话槽位、只显示一次)。 */
/* 🔴🔴 v63(用户 2026-10-19 第 7 条):**手动签发令牌这条入口整条下线**。
用户原话:「个人设置中:手动签发接口令牌,这一部分删除,不允许用户修改,
不允许用户手动签发令牌,只能通过登录后,系统自动签发令牌。」
⇒ `settings/api_token`(生成)**不再接受提交**:界面上那块已经删了;
若只删界面不删路由,它就变成一个"找不到按钮、但知道地址就能用"的后门 ——
那种入口比显式按钮危险。这里直接 302 回个人设置并给一句明确的话。
⚠️ **`settings/api_revoke` 保留**:踢掉设备是用户该有的能力,
「设备管理」卡里那两个动作(移除一台 / 退出全部设备)还在用它。
换句话说:**签发只自动、吊销仍可用**,这条线才是用户要的形态。
⚠️ 令牌机制本身(ApiToken 类、Bearer 校验、设备聚合)一个字没改。 */
case 'settings/api_token':
Auth::requireLogin();
flash('err', '令牌由登录后自动签发,不能手动生成。要清掉某台设备,去「设备管理」移除它。');
redirect('settings/me');
break;
case 'settings/api_revoke':
$me = (int)Auth::personId();
Auth::requireWrite();
csrf_check();
if ($r === 'settings/api_token') {
$label = trim((string)($_POST['label'] ?? ''));
$_SESSION['api_plain'] = \App\ApiToken::issue($me, $label);
$_SESSION['api_plain_label'] = $label;
flash('ok', 'API 令牌已生成(只显示这一次,请立刻复制到 App 里)。');
} elseif ((int)($_POST['id'] ?? 0) > 0) {
if ((int)($_POST['id'] ?? 0) > 0) {
\App\ApiToken::revoke($me, (int)$_POST['id']);
flash('ok', '这枚 API 令牌已吊销。');
} else {
@@ -5176,7 +5198,7 @@ $want = array_keys($want);
unset($_SESSION['api_plain'], $_SESSION['api_plain_label']);
flash('ok', '全部 API 令牌已吊销,所有 App 都需要重新登录。');
}
redirect('settings/me', [], 'api');
redirect('settings/me', [], 'devices');
break;
/* 🔴 v57(用户 2026-10-17):「设备管理」——把某一台设备远程退掉。