feat: move creation entry config to database
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
use crate::runtime::analytics_date_dimension::analytics_date_dimension;
|
||||
use crate::runtime::creation_entry_config::{creation_entry_config, creation_entry_type_config};
|
||||
use crate::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use spacetimedb::sats::de::serde::DeserializeWrapper;
|
||||
@@ -167,6 +168,8 @@ macro_rules! migration_tables {
|
||||
ai_task_event,
|
||||
runtime_snapshot,
|
||||
runtime_setting,
|
||||
creation_entry_config,
|
||||
creation_entry_type_config,
|
||||
user_browse_history,
|
||||
profile_dashboard_state,
|
||||
profile_wallet_ledger,
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
use crate::*;
|
||||
|
||||
#[spacetimedb::table(accessor = creation_entry_config)]
|
||||
pub struct CreationEntryConfig {
|
||||
#[primary_key]
|
||||
pub(crate) config_id: String,
|
||||
pub(crate) start_title: String,
|
||||
pub(crate) start_description: String,
|
||||
pub(crate) start_idle_badge: String,
|
||||
pub(crate) start_busy_badge: String,
|
||||
pub(crate) modal_title: String,
|
||||
pub(crate) modal_description: String,
|
||||
pub(crate) updated_at: Timestamp,
|
||||
}
|
||||
|
||||
#[spacetimedb::table(
|
||||
accessor = creation_entry_type_config,
|
||||
index(accessor = by_creation_entry_type_sort_order, btree(columns = [sort_order]))
|
||||
)]
|
||||
pub struct CreationEntryTypeConfig {
|
||||
#[primary_key]
|
||||
pub(crate) id: String,
|
||||
pub(crate) title: String,
|
||||
pub(crate) subtitle: String,
|
||||
pub(crate) badge: String,
|
||||
pub(crate) image_src: String,
|
||||
pub(crate) visible: bool,
|
||||
pub(crate) open: bool,
|
||||
pub(crate) sort_order: i32,
|
||||
pub(crate) updated_at: Timestamp,
|
||||
}
|
||||
|
||||
#[spacetimedb::procedure]
|
||||
pub fn get_creation_entry_config(
|
||||
ctx: &mut ProcedureContext,
|
||||
) -> CreationEntryConfigProcedureResult {
|
||||
match ctx.try_with_tx(|tx| get_or_seed_creation_entry_config_snapshot(tx)) {
|
||||
Ok(record) => CreationEntryConfigProcedureResult {
|
||||
ok: true,
|
||||
record: Some(record),
|
||||
error_message: None,
|
||||
},
|
||||
Err(message) => CreationEntryConfigProcedureResult {
|
||||
ok: false,
|
||||
record: None,
|
||||
error_message: Some(message),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn get_or_seed_creation_entry_config_snapshot(
|
||||
ctx: &ReducerContext,
|
||||
) -> Result<CreationEntryConfigSnapshot, String> {
|
||||
seed_creation_entry_config_if_missing(ctx);
|
||||
let header = ctx
|
||||
.db
|
||||
.creation_entry_config()
|
||||
.config_id()
|
||||
.find(CREATION_ENTRY_CONFIG_GLOBAL_ID.to_string())
|
||||
.ok_or_else(|| "创作入口配置初始化失败".to_string())?;
|
||||
let mut creation_types = ctx
|
||||
.db
|
||||
.creation_entry_type_config()
|
||||
.iter()
|
||||
.map(|row| CreationEntryTypeSnapshot {
|
||||
id: row.id,
|
||||
title: row.title,
|
||||
subtitle: row.subtitle,
|
||||
badge: row.badge,
|
||||
image_src: row.image_src,
|
||||
visible: row.visible,
|
||||
open: row.open,
|
||||
sort_order: row.sort_order,
|
||||
updated_at_micros: row.updated_at.to_micros_since_unix_epoch(),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
creation_types.sort_by(|left, right| {
|
||||
left.sort_order
|
||||
.cmp(&right.sort_order)
|
||||
.then_with(|| left.id.cmp(&right.id))
|
||||
});
|
||||
|
||||
Ok(CreationEntryConfigSnapshot {
|
||||
config_id: header.config_id,
|
||||
start_card: CreationEntryStartCardSnapshot {
|
||||
title: header.start_title,
|
||||
description: header.start_description,
|
||||
idle_badge: header.start_idle_badge,
|
||||
busy_badge: header.start_busy_badge,
|
||||
},
|
||||
type_modal: CreationEntryTypeModalSnapshot {
|
||||
title: header.modal_title,
|
||||
description: header.modal_description,
|
||||
},
|
||||
creation_types,
|
||||
updated_at_micros: header.updated_at.to_micros_since_unix_epoch(),
|
||||
})
|
||||
}
|
||||
|
||||
fn seed_creation_entry_config_if_missing(ctx: &ReducerContext) {
|
||||
let now = ctx.timestamp;
|
||||
if ctx
|
||||
.db
|
||||
.creation_entry_config()
|
||||
.config_id()
|
||||
.find(CREATION_ENTRY_CONFIG_GLOBAL_ID.to_string())
|
||||
.is_none()
|
||||
{
|
||||
ctx.db.creation_entry_config().insert(CreationEntryConfig {
|
||||
config_id: CREATION_ENTRY_CONFIG_GLOBAL_ID.to_string(),
|
||||
start_title: DEFAULT_CREATION_ENTRY_START_TITLE.to_string(),
|
||||
start_description: DEFAULT_CREATION_ENTRY_START_DESCRIPTION.to_string(),
|
||||
start_idle_badge: DEFAULT_CREATION_ENTRY_START_IDLE_BADGE.to_string(),
|
||||
start_busy_badge: DEFAULT_CREATION_ENTRY_START_BUSY_BADGE.to_string(),
|
||||
modal_title: DEFAULT_CREATION_ENTRY_MODAL_TITLE.to_string(),
|
||||
modal_description: DEFAULT_CREATION_ENTRY_MODAL_DESCRIPTION.to_string(),
|
||||
updated_at: now,
|
||||
});
|
||||
}
|
||||
|
||||
for seed in default_creation_entry_type_configs(now) {
|
||||
if ctx
|
||||
.db
|
||||
.creation_entry_type_config()
|
||||
.id()
|
||||
.find(&seed.id)
|
||||
.is_none()
|
||||
{
|
||||
ctx.db.creation_entry_type_config().insert(seed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn default_creation_entry_type_configs(now: Timestamp) -> Vec<CreationEntryTypeConfig> {
|
||||
vec![
|
||||
build_creation_entry_type_seed("rpg", "文字冒险", "经典 RPG 体验", "内测", "/creation-type-references/rpg.webp", false, true, 10, now),
|
||||
build_creation_entry_type_seed("big-fish", "摸鱼", "轻量闯关玩法", "可创建", "/creation-type-references/big-fish.webp", false, true, 20, now),
|
||||
build_creation_entry_type_seed("puzzle", "拼图", "拼图关卡创作", "可创建", "/creation-type-references/puzzle.webp", true, true, 30, now),
|
||||
build_creation_entry_type_seed("match3d", "抓大鹅", "3D 消除关卡", "可创建", "/creation-type-references/match3d.webp", true, true, 40, now),
|
||||
build_creation_entry_type_seed("square-hole", "方洞", "形状投放挑战", "可创建", "/creation-type-references/square-hole.webp", true, true, 50, now),
|
||||
build_creation_entry_type_seed("visual-novel", "视觉小说", "分支叙事体验", "可创建", "/creation-type-references/visual-novel.webp", true, true, 60, now),
|
||||
build_creation_entry_type_seed("airp", "AI RPG", "原生角色扮演", "即将开放", "/creation-type-references/airp.webp", true, false, 70, now),
|
||||
build_creation_entry_type_seed("creative-agent", "智能体创作", "对话式创作实验", "内测", "/creation-type-references/creative-agent.webp", false, true, 80, now),
|
||||
]
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn build_creation_entry_type_seed(
|
||||
id: &str,
|
||||
title: &str,
|
||||
subtitle: &str,
|
||||
badge: &str,
|
||||
image_src: &str,
|
||||
visible: bool,
|
||||
open: bool,
|
||||
sort_order: i32,
|
||||
now: Timestamp,
|
||||
) -> CreationEntryTypeConfig {
|
||||
CreationEntryTypeConfig {
|
||||
id: id.to_string(),
|
||||
title: title.to_string(),
|
||||
subtitle: subtitle.to_string(),
|
||||
badge: badge.to_string(),
|
||||
image_src: image_src.to_string(),
|
||||
visible,
|
||||
open,
|
||||
sort_order,
|
||||
updated_at: now,
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
pub mod analytics_date_dimension;
|
||||
pub mod creation_entry_config;
|
||||
mod browse_history;
|
||||
mod profile;
|
||||
mod settings;
|
||||
mod snapshots;
|
||||
|
||||
pub use analytics_date_dimension::*;
|
||||
pub use creation_entry_config::*;
|
||||
pub use browse_history::*;
|
||||
pub use profile::*;
|
||||
pub use settings::*;
|
||||
|
||||
Reference in New Issue
Block a user