v26 第 26 批(5 条):财务多选按集合取图 / 首页全天置顶与红线定位 / 任务复选框去提示与看板颜色 / 导航搜索引擎切换与站点复用 / 详情页去复选框

- 财务:勾选多个标签时上面那张「总金额」图按**选中集合**统计(新增
  ledger/total_chart 路由 + 单一容器 data-ck-total-host,按集合现取并缓存;
  Ledger::timeline 第二参数放宽为 string|array)
- 首页日程:全天日程移出滚动容器固定置顶;进场把当前时刻红线居中
  (scrollTop 计算,不用 scrollIntoView),触发条件不绑 $showNow
- 任务:复选框去除 title 提示;看板可设颜色(Task::boardColor/updateBoard),
  首页任务行用该颜色显示所属看板
- 导航:展示页补回 id=engine-tabs(切换搜索引擎无效的根因);补内置引擎;
  新增站点输 URL 可复用他人已加过的站点(sharedByUrl/copyIconFile/adoptSite)
- 任务详情页页头去掉复选框(已有「标记完成」按钮)
This commit is contained in:
2026-10-07 15:31:26 +08:00
parent a5e559b2b3
commit c8839fa728
15 changed files with 964 additions and 93 deletions
+77 -6
View File
@@ -137,6 +137,79 @@ final class Task
return $v === false ? '' : (string)$v;
}
// ====================================================================
// 看板颜色(v24 第 26 批 用户第 3 条)
//
// 用户原话:「任务在设置看板的时候,可以选择颜色,这样在首页列表中显示的时候,
// 就可以更加直观的看到他属于哪个看板。」
//
// 设计要点(两条,都是为了"一眼能认出来"):
// ① 用户没选过颜色时**按看板名派生**一个稳定色 —— 同名永远同色。
// 若改成"按 id 派生",看板一改名颜色就跳,用户反而记不住;
// 若统一给一个默认色,所有看板长得一样,就完全失去这条需求的意义。
// ② 派生只从**固定调色板**里挑(跟名册头像色块同一套观感),
// 不做 HSL 随机 —— 随机色会造出刺眼/低对比的颜色,白字压不住。
// ====================================================================
/** 看板可选色的调色板(10 个,覆盖暖冷中性;都够深,能压白字) */
public const BOARD_COLORS = [
'#C0533F', '#B87333', '#8A7B3F', '#5E9E4E', '#3F8F7A',
'#3E7A9E', '#5B6DC0', '#8B5CF6', '#B0508A', '#7A6A5E',
];
/**
* 取一个看板该用什么颜色。
*
* @param string|null $color 库里存的(可能为 NULL / 空 / 非法值)
* @param string $name 看板名(没存颜色时按它派生)
* @return string '#RRGGBB'
*/
public static function boardColor(?string $color, string $name = ''): string
{
$c = strtolower(trim((string)$color));
if (preg_match('/^#[0-9a-f]{6}$/', $c)) {
return $c;
}
// 按名字派生:同一个名字永远同一个色(改 id 不影响,用户能记住)
$h = 0;
foreach (preg_split('//u', $name, -1, PREG_SPLIT_NO_EMPTY) ?: [] as $ch) {
// 用码点而不是字节:中文名在不同编码下字节不同,码点是稳的
$h = ($h * 31 + (int)(mb_ord($ch, 'UTF-8') ?: 0)) % 1000000007;
}
return self::BOARD_COLORS[abs($h) % count(self::BOARD_COLORS)];
}
/** 看板 id → 颜色(board_name 一起取,省一次查询;查不到给灰) */
public static function boardColorById(int $familyId, ?int $boardId): string
{
if (!$boardId) {
return self::boardColor(null, '默认看板');
}
$st = Database::get()->prepare('SELECT name, color FROM task_boards WHERE id = ? AND family_id = ?');
$st->execute([$boardId, $familyId]);
$r = $st->fetch();
if (!$r) {
return self::boardColor(null, '');
}
return self::boardColor($r['color'] ?? null, (string)$r['name']);
}
/**
* 改看板名 + 颜色(设置页那一行表单)。
*
* ⚠️ 颜色与名字**同一个动作**:用户改色时不该被迫把名字也重打一遍
* (表单里两个都在、一起提交,这里是它们共同的落点)。
* ⚠️ 颜色合法性在这里收口(只认 `#RRGGBB`),空串 = 清除自定义、回到按名派生。
*/
public static function updateBoard(int $familyId, int $id, string $name, string $color): void
{
$db = Database::get();
$c = strtolower(trim($color));
$c = preg_match('/^#[0-9a-f]{6}$/', $c) ? $c : null;
$db->prepare('UPDATE task_boards SET name = ?, color = ? WHERE id = ? AND family_id = ?')
->execute([self::shortName($name), $c, $id, $familyId]);
}
/**
* 这个家庭至少有一个看板(升级时给老家庭补,新家庭在建号时补)。
* @return int 默认看板的 id
@@ -164,11 +237,9 @@ final class Task
return (int)$db->lastInsertId();
}
public static function renameBoard(int $familyId, int $id, string $name): void
{
Database::get()->prepare('UPDATE task_boards SET name = ? WHERE id = ? AND family_id = ?')
->execute([self::shortName($name), $id, $familyId]);
}
/* ⚠️ 原来的 `renameBoard()` 已在 v24 第 26 批**并入 `updateBoard()`**(用户第 3 条
要给看板加颜色,两个字段同一个动作),这里不再保留 —— 留一个只改名字的方法,
下一个改颜色的人会顺手调错它("改了色但名字被重置"这类事故就是这么来的)。 */
/**
* 删看板:里头的任务**不删**,挪到默认看板上(删看板 ≠ 删任务,这个代价太突然)。
@@ -428,7 +499,7 @@ final class Task
'SELECT t.*, a.name AS assignee_name, a.avatar, a.avatar_color,
na.nickname AS assignee_nick,
c.name AS category_name,
b.name AS board_name,
b.name AS board_name, b.color AS board_color,
(SELECT COUNT(*) FROM tasks k WHERE k.parent_id = t.id) AS child_total,
(SELECT COUNT(*) FROM tasks k WHERE k.parent_id = t.id AND k.status = "done") AS child_done
FROM tasks t