feat: 支持创作入口公告配置

This commit is contained in:
2026-06-03 03:31:45 +08:00
parent 1cb11bc1dd
commit 70ff18ad90
52 changed files with 3045 additions and 504 deletions

View File

@@ -1180,6 +1180,9 @@ fn normalize_migration_row(table_name: &str, value: &serde_json::Value) -> serde
object
.entry("event_ends_at_text".to_string())
.or_insert(serde_json::Value::Null);
object
.entry("event_banners_json".to_string())
.or_insert(serde_json::Value::Null);
}
}
if table_name == "creation_entry_type_config" {

View File

@@ -23,6 +23,9 @@ pub struct CreationEntryConfig {
pub(crate) event_starts_at_text: Option<String>,
#[default(None::<String>)]
pub(crate) event_ends_at_text: Option<String>,
/// 底部加号创作入口页的多 banner JSON 配置,旧单条字段仅用于兼容。
#[default(None::<String>)]
pub(crate) event_banners_json: Option<String>,
}
#[spacetimedb::table(
@@ -85,6 +88,27 @@ pub fn upsert_creation_entry_type_config(
}
}
#[spacetimedb::procedure]
/// 后台保存底部加号创作入口页多 banner 配置的过程入口。
pub fn upsert_creation_entry_event_banners_config(
ctx: &mut ProcedureContext,
input: CreationEntryEventBannersAdminUpsertInput,
) -> CreationEntryConfigProcedureResult {
match ctx.try_with_tx(|tx| upsert_creation_entry_event_banners_config_in_tx(tx, input.clone()))
{
Ok(record) => CreationEntryConfigProcedureResult {
ok: true,
record: Some(record),
error_message: None,
},
Err(message) => CreationEntryConfigProcedureResult {
ok: false,
record: None,
error_message: Some(message),
},
}
}
fn upsert_creation_entry_type_config_in_tx(
ctx: &ReducerContext,
input: CreationEntryTypeAdminUpsertInput,
@@ -122,6 +146,31 @@ fn upsert_creation_entry_type_config_in_tx(
get_or_seed_creation_entry_config_snapshot(ctx)
}
/// 在事务内归一化 banner JSON 并更新全局入口配置表头。
fn upsert_creation_entry_event_banners_config_in_tx(
ctx: &ReducerContext,
input: CreationEntryEventBannersAdminUpsertInput,
) -> Result<CreationEntryConfigSnapshot, String> {
seed_creation_entry_config_if_missing(ctx);
let now = ctx.timestamp;
let config_id = CREATION_ENTRY_CONFIG_GLOBAL_ID.to_string();
let Some(header) = ctx.db.creation_entry_config().config_id().find(&config_id) else {
return Err("创作入口配置初始化失败".to_string());
};
let event_banners_json =
module_runtime::normalize_creation_entry_event_banners_json(&input.event_banners_json)?;
ctx.db
.creation_entry_config()
.config_id()
.update(CreationEntryConfig {
updated_at: now,
event_banners_json: Some(event_banners_json),
..header
});
get_or_seed_creation_entry_config_snapshot(ctx)
}
fn get_or_seed_creation_entry_config_snapshot(
ctx: &ReducerContext,
) -> Result<CreationEntryConfigSnapshot, String> {
@@ -192,12 +241,16 @@ fn get_or_seed_creation_entry_config_snapshot(
header.event_ends_at_text.as_deref(),
DEFAULT_CREATION_ENTRY_EVENT_ENDS_AT_TEXT,
),
render_mode: "structured".to_string(),
html_code: None,
},
event_banners_json: header.event_banners_json,
creation_types,
updated_at_micros: header.updated_at.to_micros_since_unix_epoch(),
})
}
/// 初始化创作入口全局配置,并为旧库补齐默认多 banner JSON。
fn seed_creation_entry_config_if_missing(ctx: &ReducerContext) {
let now = ctx.timestamp;
if ctx
@@ -222,6 +275,7 @@ fn seed_creation_entry_config_if_missing(ctx: &ReducerContext) {
event_prize_pool_mud_points: DEFAULT_CREATION_ENTRY_EVENT_PRIZE_POOL_MUD_POINTS,
event_starts_at_text: Some(DEFAULT_CREATION_ENTRY_EVENT_STARTS_AT_TEXT.to_string()),
event_ends_at_text: Some(DEFAULT_CREATION_ENTRY_EVENT_ENDS_AT_TEXT.to_string()),
event_banners_json: Some(module_runtime::default_creation_entry_event_banners_json()),
});
}