fix: 图片生成失败后重试 前端一直显示生成中

This commit is contained in:
yangshilin
2026-03-13 16:23:51 +08:00
parent e751114354
commit 672abf5ec7
7 changed files with 105 additions and 43 deletions

View File

@@ -83,12 +83,12 @@ class ChapterReadingImageBlocksTest {
composeRule.setContent { ChapterReadingView(chapter = chapter) }
composeRule.onNodeWithTag("memoir-image-error-0").assertIsDisplayed()
composeRule.onNodeWithText("图片生成失败,暂不可恢复").assertIsDisplayed()
composeRule.onNodeWithTag("memoir-image-error-0").assertDoesNotExist()
composeRule.onNodeWithText("图片生成失败,暂不可恢复").assertDoesNotExist()
}
@Test
fun chapterReadingView_showsUnavailablePlaceholder_forCompletedImageWithoutUrl() {
fun chapterReadingView_hidesCompletedImageWithoutUrl() {
val chapter = ChapterContentDto(
id = "chapter-1",
title = "童年的夏天",
@@ -120,7 +120,44 @@ class ChapterReadingImageBlocksTest {
composeRule.setContent { ChapterReadingView(chapter = chapter) }
composeRule.onNodeWithTag("memoir-image-error-0").assertIsDisplayed()
composeRule.onNodeWithText("图片暂不可用").assertIsDisplayed()
composeRule.onNodeWithTag("memoir-image-error-0").assertDoesNotExist()
composeRule.onNodeWithText("图片暂不可用").assertDoesNotExist()
}
@Test
fun chapterReadingView_showsLoadingForRetryableFailedImage() {
val chapter = ChapterContentDto(
id = "chapter-1",
title = "童年的夏天",
content = "那条路我一直记得。\n\n{{{{IMAGE:南方小镇的青石板路}}}}",
orderIndex = 0,
status = "completed",
category = "childhood",
pageCount = null,
updatedAt = 0L,
quotes = emptyList(),
images = listOf(
ChapterImageDto(
index = 0,
placeholder = "{{{{IMAGE:南方小镇的青石板路}}}}",
description = "南方小镇的青石板路",
prompt = null,
url = null,
status = "failed",
retryable = true,
provider = "liblib",
style = "watercolor",
size = "1024x1024",
error = "provider timeout",
created_at = null,
updated_at = null,
)
),
)
composeRule.setContent { ChapterReadingView(chapter = chapter) }
composeRule.onNodeWithTag("memoir-image-loading-0").assertIsDisplayed()
composeRule.onNodeWithText("图片生成中…").assertIsDisplayed()
}
}

View File

@@ -40,10 +40,10 @@ fun splitMemoirContent(content: String, images: List<ChapterImageDto>): List<Mem
internal fun shouldRenderMemoirImageBlock(image: ChapterImageDto): Boolean {
return when (image.status) {
MEMOIR_IMAGE_STATUS_COMPLETED,
MEMOIR_IMAGE_STATUS_COMPLETED -> !image.url.isNullOrBlank()
MEMOIR_IMAGE_STATUS_PENDING,
MEMOIR_IMAGE_STATUS_PROCESSING,
MEMOIR_IMAGE_STATUS_FAILED -> true
MEMOIR_IMAGE_STATUS_PROCESSING -> true
MEMOIR_IMAGE_STATUS_FAILED -> image.retryable == true
else -> false
}
}

View File

@@ -246,10 +246,10 @@ fun MemoirInlineImage(
modifier = modifier,
text = "图片生成中…",
)
MEMOIR_IMAGE_STATUS_FAILED -> MemoirImageStatusPlaceholder(
MEMOIR_IMAGE_STATUS_FAILED -> MemoirImageLoadingPlaceholder(
image = image,
text = memoirImageFailureText(image),
modifier = modifier,
text = "图片生成中…",
)
else -> Unit
}

View File

@@ -81,14 +81,14 @@ class MemoirContentBlocksTest {
)
)
assertTrue(blocks.any { it is MemoirContentBlock.Image })
val imageBlock = blocks[1] as MemoirContentBlock.Image
assertEquals("failed", imageBlock.image.status)
assertEquals(false, imageBlock.image.retryable)
assertFalse(blocks.any { it is MemoirContentBlock.Image })
assertEquals(2, blocks.size)
assertTrue((blocks[0] as MemoirContentBlock.Text).content.contains("开头"))
assertTrue((blocks[1] as MemoirContentBlock.Text).content.contains("结尾"))
}
@Test
fun splitMemoirContent_keepsCompletedImageBlock_whenSignedUrlIsUnavailable() {
fun splitMemoirContent_skipsCompletedImageBlock_whenSignedUrlIsUnavailable() {
val blocks = splitMemoirContent(
content = "开头。\n\n{{{{IMAGE:签名失败的图}}}}\n\n结尾。",
images = listOf(
@@ -110,9 +110,7 @@ class MemoirContentBlocksTest {
)
)
assertTrue(blocks.any { it is MemoirContentBlock.Image })
val imageBlock = blocks[1] as MemoirContentBlock.Image
assertEquals("completed", imageBlock.image.status)
assertEquals(null, imageBlock.image.url)
assertFalse(blocks.any { it is MemoirContentBlock.Image })
assertEquals(2, blocks.size)
}
}