1
Some checks failed
CI / verify (pull_request) Waiting to run
CI / verify (push) Has been cancelled

This commit is contained in:
2026-05-13 03:11:00 +08:00
parent e4a8bd42bb
commit b13870f71b
8 changed files with 273 additions and 55 deletions

View File

@@ -3862,12 +3862,6 @@ fn is_match3d_generated_asset_image_ready(asset: &Match3DGeneratedItemAsset) ->
})
.count();
view_count >= MATCH3D_ITEM_VIEW_COUNT
|| asset
.image_object_key
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty())
.is_some()
}
fn has_match3d_required_item_images(
@@ -4952,7 +4946,7 @@ mod tests {
}
#[test]
fn match3d_required_item_images_require_object_keys() {
fn match3d_required_item_images_require_five_views() {
let assets = vec![
Match3DGeneratedItemAsset {
item_id: "match3d-item-1".to_string(),
@@ -5024,6 +5018,47 @@ mod tests {
];
assert!(!has_match3d_required_item_images(&assets, 3));
let five_view_assets = (1..=3)
.map(|index| Match3DGeneratedItemAsset {
item_id: format!("match3d-item-{index}"),
item_name: format!("物品{index}"),
image_src: Some(format!(
"/generated-match3d-assets/s/p/items/i{index}/views/view-01.png"
)),
image_object_key: Some(format!(
"generated-match3d-assets/s/p/items/i{index}/views/view-01.png"
)),
image_views: (1..=MATCH3D_ITEM_VIEW_COUNT)
.map(|view_index| Match3DGeneratedItemImageView {
view_id: format!("view-{view_index:02}"),
view_index: view_index as u32,
image_src: Some(format!(
"/generated-match3d-assets/s/p/items/i{index}/views/view-{view_index:02}.png"
)),
image_object_key: Some(format!(
"generated-match3d-assets/s/p/items/i{index}/views/view-{view_index:02}.png"
)),
})
.collect(),
model_src: None,
model_object_key: None,
model_file_name: None,
task_uuid: None,
subscription_key: None,
sound_prompt: None,
background_music_title: None,
background_music_style: None,
background_music_prompt: None,
background_music: None,
click_sound: None,
background_asset: None,
status: "image_ready".to_string(),
error: None,
})
.collect::<Vec<_>>();
assert!(has_match3d_required_item_images(&five_view_assets, 3));
}
#[test]

View File

@@ -1338,7 +1338,7 @@ fn count_ready_generated_item_types(value: Option<&str>) -> Result<usize, String
let status_ready = asset
.get("status")
.and_then(Value::as_str)
.map(|status| matches!(status, "image_ready" | "model_ready"))
.map(|status| status == "image_ready")
.unwrap_or(false);
let view_count = asset
.get("imageViews")
@@ -1363,19 +1363,7 @@ fn count_ready_generated_item_types(value: Option<&str>) -> Result<usize, String
.count()
})
.unwrap_or(0);
let has_primary_image = asset
.get("imageSrc")
.or_else(|| asset.get("image_src"))
.and_then(Value::as_str)
.map(|value| !value.trim().is_empty())
.unwrap_or(false)
|| asset
.get("imageObjectKey")
.or_else(|| asset.get("image_object_key"))
.and_then(Value::as_str)
.map(|value| !value.trim().is_empty())
.unwrap_or(false);
status_ready && (view_count >= 5 || has_primary_image)
status_ready && view_count >= 5
})
.count())
}
@@ -1893,6 +1881,68 @@ mod tests {
);
}
#[test]
fn match3d_publish_ready_requires_five_image_views_per_item() {
let base_work = Match3DWorkProfileRow {
profile_id: "profile-1".to_string(),
owner_user_id: "user-1".to_string(),
source_session_id: "session-1".to_string(),
author_display_name: "作者".to_string(),
game_name: "水果抓大鹅".to_string(),
theme_text: "水果".to_string(),
summary_text: "水果主题".to_string(),
tags_json: "[\"水果\"]".to_string(),
cover_image_src: "/cover.png".to_string(),
cover_asset_id: String::new(),
clear_count: 8,
difficulty: 2,
config_json: to_json_string(&Match3DCreatorConfigSnapshot {
theme_text: "水果".to_string(),
reference_image_src: None,
clear_count: 8,
difficulty: 2,
asset_style_id: None,
asset_style_label: None,
asset_style_prompt: None,
generate_click_sound: false,
}),
publication_status: MATCH3D_PUBLICATION_DRAFT.to_string(),
play_count: 0,
updated_at: Timestamp::from_micros_since_unix_epoch(1),
published_at: None,
generated_item_assets_json: Some(
r#"[{"itemId":"match3d-item-1","itemName":"草莓","imageSrc":"/generated-match3d-assets/session/profile/items/item/image.png","status":"image_ready"},{"itemId":"match3d-item-2","itemName":"苹果","imageViews":[{"imageSrc":"/v1.png"},{"imageSrc":"/v2.png"},{"imageSrc":"/v3.png"},{"imageSrc":"/v4.png"},{"imageSrc":"/v5.png"}],"status":"model_ready"},{"itemId":"match3d-item-3","itemName":"香蕉","imageViews":[{"imageSrc":"/v1.png"},{"imageSrc":"/v2.png"},{"imageSrc":"/v3.png"},{"imageSrc":"/v4.png"}],"status":"image_ready"}]"#
.to_string(),
),
};
let error = validate_publishable_work(&base_work).unwrap_err();
assert!(error.contains("当前已有 0 种"));
let ready_assets = (1..=3)
.map(|index| {
let views = (1..=5)
.map(|view_index| {
format!(
r#"{{"imageSrc":"/generated-match3d-assets/session/profile/items/i{index}/views/view-{view_index:02}.png"}}"#
)
})
.collect::<Vec<_>>()
.join(",");
format!(
r#"{{"itemId":"match3d-item-{index}","itemName":"物品{index}","imageViews":[{views}],"status":"image_ready"}}"#
)
})
.collect::<Vec<_>>()
.join(",");
let ready_work = Match3DWorkProfileRow {
generated_item_assets_json: Some(format!("[{ready_assets}]")),
..base_work
};
assert!(validate_publishable_work(&ready_work).is_ok());
}
#[test]
fn match3d_compile_without_metadata_payload_preserves_existing_metadata() {
let existing = Match3DWorkProfileRow {