feat: 统一创作页表头跟随后台入口配置

This commit is contained in:
2026-06-06 22:49:38 +08:00
parent 95f17cd920
commit 18908609fc
14 changed files with 276 additions and 53 deletions

View File

@@ -99,6 +99,7 @@ pub struct UnifiedCreationFieldResponse {
}
pub const UNIFIED_CREATION_FIELD_KINDS: [&str; 4] = ["text", "select", "image", "audio"];
pub const LEGACY_UNIFIED_CREATION_TITLE: &str = "想做个什么玩法?";
pub fn build_phase1_unified_creation_spec(play_id: &str) -> Option<UnifiedCreationSpecResponse> {
let (workspace_stage, generation_stage, result_stage, fields) = match play_id {
@@ -172,18 +173,8 @@ pub fn build_phase1_unified_creation_spec(play_id: &str) -> Option<UnifiedCreati
vec![
unified_creation_field("title", "text", "作品标题", true),
unified_creation_field("themeDescription", "text", "主题/场景描述", true),
unified_creation_field(
"playerImageDescription",
"text",
"玩家形象描述",
true,
),
unified_creation_field(
"opponentImageDescription",
"text",
"对手形象描述",
true,
),
unified_creation_field("playerImageDescription", "text", "玩家形象描述", true),
unified_creation_field("opponentImageDescription", "text", "对手形象描述", true),
unified_creation_field("onomatopoeia", "text", "拟声词", false),
unified_creation_field("difficultyPreset", "select", "难度", true),
],
@@ -220,7 +211,7 @@ pub fn build_phase1_unified_creation_spec(play_id: &str) -> Option<UnifiedCreati
Some(UnifiedCreationSpecResponse {
play_id: play_id.to_string(),
title: "想做个什么玩法?".to_string(),
title: default_unified_creation_title(play_id)?.to_string(),
workspace_stage: workspace_stage.to_string(),
generation_stage: generation_stage.to_string(),
result_stage: result_stage.to_string(),
@@ -228,6 +219,43 @@ pub fn build_phase1_unified_creation_spec(play_id: &str) -> Option<UnifiedCreati
})
}
pub fn default_unified_creation_title(play_id: &str) -> Option<&'static str> {
match play_id {
"rpg" => Some("文字冒险"),
"big-fish" => Some("摸鱼"),
"puzzle" => Some("拼图"),
"match3d" => Some("抓大鹅"),
"jump-hop" => Some("跳一跳"),
"wooden-fish" => Some("敲木鱼"),
"square-hole" => Some("方洞"),
"bark-battle" => Some("汪汪声浪"),
"visual-novel" => Some("视觉小说"),
"baby-object-match" => Some("宝贝识物"),
"creative-agent" => Some("智能体创作"),
_ => None,
}
}
pub fn normalize_unified_creation_spec_title_for_entry(
play_id: &str,
entry_title: &str,
mut spec: UnifiedCreationSpecResponse,
) -> UnifiedCreationSpecResponse {
let entry_title = entry_title.trim();
if entry_title.is_empty() {
return spec;
}
let spec_title = spec.title.trim();
let default_title = default_unified_creation_title(play_id).unwrap_or_default();
if spec_title == LEGACY_UNIFIED_CREATION_TITLE
|| (!default_title.is_empty() && spec_title == default_title)
{
spec.title = entry_title.to_string();
}
spec
}
pub fn validate_unified_creation_spec_response(
spec: &UnifiedCreationSpecResponse,
) -> Result<(), String> {
@@ -311,10 +339,27 @@ pub fn resolve_unified_creation_spec_response(
play_id: &str,
value: Option<&str>,
) -> Option<UnifiedCreationSpecResponse> {
match value {
resolve_unified_creation_spec_response_with_entry_title(
play_id,
default_unified_creation_title(play_id).unwrap_or_default(),
value,
)
}
pub fn resolve_unified_creation_spec_response_with_entry_title(
play_id: &str,
entry_title: &str,
value: Option<&str>,
) -> Option<UnifiedCreationSpecResponse> {
let spec = match value {
Some(raw) => decode_unified_creation_spec_response(raw).ok(),
None => build_phase1_unified_creation_spec(play_id),
}
}?;
Some(normalize_unified_creation_spec_title_for_entry(
play_id,
entry_title,
spec,
))
}
fn unified_creation_field(
@@ -338,10 +383,12 @@ mod tests {
#[test]
fn phase1_unified_creation_specs_cover_existing_templates() {
let puzzle = build_phase1_unified_creation_spec("puzzle").expect("puzzle spec");
assert_eq!(puzzle.title, "拼图");
assert_eq!(puzzle.fields[0].id, "pictureDescription");
assert_eq!(puzzle.fields[1].kind, "image");
let match3d = build_phase1_unified_creation_spec("match3d").expect("match3d spec");
assert_eq!(match3d.title, "抓大鹅");
assert_eq!(
match3d
.fields
@@ -352,6 +399,7 @@ mod tests {
);
let jump_hop = build_phase1_unified_creation_spec("jump-hop").expect("jump-hop spec");
assert_eq!(jump_hop.title, "跳一跳");
assert!(
jump_hop
.fields
@@ -389,6 +437,45 @@ mod tests {
);
}
#[test]
fn unified_creation_spec_title_can_fallback_to_entry_title() {
let raw = r#"{
"playId": "puzzle",
"title": "想做个什么玩法?",
"workspaceStage": "puzzle-agent-workspace",
"generationStage": "puzzle-generating",
"resultStage": "puzzle-result",
"fields": [
{
"id": "pictureDescription",
"kind": "text",
"label": "画面描述",
"required": true
}
]
}"#;
let spec = resolve_unified_creation_spec_response_with_entry_title(
"puzzle",
"定制拼图",
Some(raw),
)
.expect("puzzle spec");
assert_eq!(spec.title, "定制拼图");
}
#[test]
fn unified_creation_spec_title_keeps_admin_custom_copy() {
let mut spec = build_phase1_unified_creation_spec("jump-hop").expect("jump-hop spec");
spec.title = "你的跳一跳是...".to_string();
let normalized =
normalize_unified_creation_spec_title_for_entry("jump-hop", "跳一跳", spec);
assert_eq!(normalized.title, "你的跳一跳是...");
}
#[test]
fn creation_entry_event_banner_defaults_to_structured_render_mode() {
let banner = serde_json::from_str::<CreationEntryEventBannerResponse>(