feat(admin): 分区增加「允许子分组」开关(与类型解耦)

- node 新增 allow_groups(迁移 v18):应用默认开、海报/图文默认关,已有分组的非应用分区自动开启
- 后台每行一个「子分组」开关;分组管理、卡片预览、内容弹窗选组、侧栏建组都跟随开关
- 关闭开关时条目平铺且不丢内容;首页卡片指向分组会自动挪回分区
- 三种类型共用同一模板,类型只决定渲染方式
- 测试 59 passed(迁移 15→18、开关建组、类型切换)
This commit is contained in:
2026-10-30 20:05:33 +08:00
parent 8df9ecdfda
commit be7a0747ed
8 changed files with 167 additions and 57 deletions
+27 -3
View File
@@ -46,6 +46,8 @@ CREATE TABLE IF NOT EXISTS node (
empty_text TEXT, -- 分区为空时的提示文案
show_in_sidebar INTEGER NOT NULL DEFAULT 1 CHECK (show_in_sidebar IN (0, 1)),
-- 是否出现在侧栏:0 表示只当首页卡片/内容,不进导航
allow_groups INTEGER NOT NULL DEFAULT 0 CHECK (allow_groups IN (0, 1)),
-- 是否允许子分组(与类型无关,后台开关)
sort INTEGER NOT NULL DEFAULT 0, -- 同级顺序,越小越靠前
CHECK (
(kind = 'section' AND parent_key IS NULL AND view_mode IS NOT NULL)
@@ -154,6 +156,22 @@ CREATE TABLE IF NOT EXISTS audit (
);
"#;
/// v17 → v18:分区增加「允许子分组」开关(与类型无关)。
///
/// 老库默认保持原行为:应用类开启,其余类型关闭;已经有分组的非应用分区也开启。
const V18_SQL: &str = r#"
ALTER TABLE node ADD COLUMN allow_groups INTEGER NOT NULL DEFAULT 1;
UPDATE node SET allow_groups = 0
WHERE kind = 'section' AND view_mode <> 'apps';
UPDATE node SET allow_groups = 1
WHERE kind = 'section' AND key IN (
SELECT DISTINCT parent_key FROM node
WHERE kind = 'group' AND parent_key IS NOT NULL
);
"#;
/// v15 → v16 的增量(老库升级用;新库直接走 SCHEMA_SQL)。
const V16_SQL: &str = r#"
CREATE TABLE IF NOT EXISTS admin (
@@ -195,7 +213,7 @@ pub struct SeedReport {
///
/// 从 v16 起有了第一套迁移:`migrate` 会把老库逐级升上来,
/// 只有「比程序更新」或「没有迁移路径」的版本才拒绝启动。
pub const SCHEMA_VERSION: i64 = 17;
pub const SCHEMA_VERSION: i64 = 18;
fn current_version(conn: &Connection) -> Result<i64, StashError> {
conn.pragma_query_value(None, "user_version", |row| row.get(0))
@@ -239,6 +257,11 @@ pub fn migrate(conn: &Connection) -> Result<i64, StashError> {
version = 17;
}
if version == 17 {
conn.execute_batch(V18_SQL).map_err(map_error)?;
version = 18;
}
conn.pragma_update(None, "user_version", version)
.map_err(map_error)?;
@@ -283,8 +306,8 @@ pub fn seed(conn: &mut Connection) -> Result<SeedReport, StashError> {
}
tx.execute(
"INSERT INTO node (key, parent_key, title, kind, view_mode, bar_color, icon, preview_limit, empty_text, show_in_sidebar, sort)
VALUES (?1, NULL, ?2, 'section', ?3, ?4, ?5, ?6, ?7, ?8, ?9)",
"INSERT INTO node (key, parent_key, title, kind, view_mode, bar_color, icon, preview_limit, empty_text, show_in_sidebar, allow_groups, sort)
VALUES (?1, NULL, ?2, 'section', ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)",
params![
section.key,
section.title,
@@ -294,6 +317,7 @@ pub fn seed(conn: &mut Connection) -> Result<SeedReport, StashError> {
section.preview_limit,
section.empty_text,
i64::from(section.show_in_sidebar),
i64::from(view == "apps"),
section.sort,
],
)