收口创作流程统一总计划并修复等待页窄屏裁切
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::creation_entry_config::UnifiedCreationSpecResponse;
|
||||
|
||||
// 管理后台协议统一收口在 shared-contracts,避免页面脚本和 Rust handler 各自手拼字段。
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@@ -34,6 +36,8 @@ pub struct AdminCreationEntryTypeConfigPayload {
|
||||
pub category_label: String,
|
||||
pub category_sort_order: i32,
|
||||
pub updated_at_micros: i64,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub unified_creation_spec: Option<UnifiedCreationSpecResponse>,
|
||||
}
|
||||
|
||||
/// 后台保存创作入口开关配置请求。
|
||||
@@ -51,6 +55,8 @@ pub struct AdminUpsertCreationEntryTypeConfigRequest {
|
||||
pub category_id: String,
|
||||
pub category_label: String,
|
||||
pub category_sort_order: i32,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub unified_creation_spec: Option<UnifiedCreationSpecResponse>,
|
||||
}
|
||||
|
||||
/// 后台作品可见性列表项。
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@@ -55,7 +56,7 @@ pub struct CreationEntryTypeResponse {
|
||||
pub unified_creation_spec: Option<UnifiedCreationSpecResponse>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UnifiedCreationSpecResponse {
|
||||
pub play_id: String,
|
||||
@@ -66,7 +67,7 @@ pub struct UnifiedCreationSpecResponse {
|
||||
pub fields: Vec<UnifiedCreationFieldResponse>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UnifiedCreationFieldResponse {
|
||||
pub id: String,
|
||||
@@ -75,6 +76,8 @@ pub struct UnifiedCreationFieldResponse {
|
||||
pub required: bool,
|
||||
}
|
||||
|
||||
pub const UNIFIED_CREATION_FIELD_KINDS: [&str; 4] = ["text", "select", "image", "audio"];
|
||||
|
||||
pub fn build_phase1_unified_creation_spec(play_id: &str) -> Option<UnifiedCreationSpecResponse> {
|
||||
let (workspace_stage, generation_stage, result_stage, fields) = match play_id {
|
||||
"puzzle" => (
|
||||
@@ -120,6 +123,95 @@ pub fn build_phase1_unified_creation_spec(play_id: &str) -> Option<UnifiedCreati
|
||||
})
|
||||
}
|
||||
|
||||
pub fn validate_unified_creation_spec_response(
|
||||
spec: &UnifiedCreationSpecResponse,
|
||||
) -> Result<(), String> {
|
||||
if spec.play_id.trim().is_empty() {
|
||||
return Err("统一创作契约 playId 不能为空".to_string());
|
||||
}
|
||||
if spec.title.trim().is_empty() {
|
||||
return Err("统一创作契约标题不能为空".to_string());
|
||||
}
|
||||
|
||||
let workspace_stage = spec.workspace_stage.trim();
|
||||
let generation_stage = spec.generation_stage.trim();
|
||||
let result_stage = spec.result_stage.trim();
|
||||
if workspace_stage.is_empty() || generation_stage.is_empty() || result_stage.is_empty() {
|
||||
return Err("统一创作契约阶段不能为空".to_string());
|
||||
}
|
||||
if workspace_stage == generation_stage
|
||||
|| workspace_stage == result_stage
|
||||
|| generation_stage == result_stage
|
||||
{
|
||||
return Err("统一创作契约阶段不能重复".to_string());
|
||||
}
|
||||
if spec.fields.is_empty() {
|
||||
return Err("统一创作契约 fields 不能为空".to_string());
|
||||
}
|
||||
|
||||
let mut field_ids = BTreeSet::new();
|
||||
for field in &spec.fields {
|
||||
let field_id = field.id.trim();
|
||||
if field_id.is_empty() {
|
||||
return Err("统一创作契约字段 id 不能为空".to_string());
|
||||
}
|
||||
if !field_ids.insert(field_id.to_string()) {
|
||||
return Err(format!("统一创作契约字段 id 重复:{field_id}"));
|
||||
}
|
||||
if field.label.trim().is_empty() {
|
||||
return Err(format!("统一创作契约字段 {field_id} 标签不能为空"));
|
||||
}
|
||||
if !UNIFIED_CREATION_FIELD_KINDS.contains(&field.kind.trim()) {
|
||||
return Err(format!(
|
||||
"统一创作契约字段 {field_id} kind 非法:{}",
|
||||
field.kind
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_unified_creation_spec_for_play(
|
||||
play_id: &str,
|
||||
spec: &UnifiedCreationSpecResponse,
|
||||
) -> Result<(), String> {
|
||||
if spec.play_id.trim() != play_id.trim() {
|
||||
return Err(format!(
|
||||
"统一创作契约 playId 必须与入口 ID 一致:{}",
|
||||
play_id.trim()
|
||||
));
|
||||
}
|
||||
|
||||
validate_unified_creation_spec_response(spec)
|
||||
}
|
||||
|
||||
pub fn encode_unified_creation_spec_response(
|
||||
spec: &UnifiedCreationSpecResponse,
|
||||
) -> Result<String, String> {
|
||||
validate_unified_creation_spec_response(spec)?;
|
||||
serde_json::to_string(spec).map_err(|error| format!("统一创作契约序列化失败:{error}"))
|
||||
}
|
||||
|
||||
pub fn decode_unified_creation_spec_response(
|
||||
value: &str,
|
||||
) -> Result<UnifiedCreationSpecResponse, String> {
|
||||
let spec = serde_json::from_str::<UnifiedCreationSpecResponse>(value)
|
||||
.map_err(|error| format!("统一创作契约 JSON 非法:{error}"))?;
|
||||
validate_unified_creation_spec_response(&spec)?;
|
||||
Ok(spec)
|
||||
}
|
||||
|
||||
pub fn resolve_unified_creation_spec_response(
|
||||
play_id: &str,
|
||||
value: Option<&str>,
|
||||
) -> Option<UnifiedCreationSpecResponse> {
|
||||
match value {
|
||||
Some(raw) => decode_unified_creation_spec_response(raw).ok(),
|
||||
None => build_phase1_unified_creation_spec(play_id),
|
||||
}
|
||||
}
|
||||
|
||||
fn unified_creation_field(
|
||||
id: &str,
|
||||
kind: &str,
|
||||
|
||||
Reference in New Issue
Block a user