feat: 接通图片预览 AI 修图流程

This commit is contained in:
2026-08-11 09:52:15 +08:00
parent 5704531f3a
commit 43c75c8e36
14 changed files with 814 additions and 169 deletions
@@ -65,6 +65,7 @@ struct TravelAlbumPreviewAsset: Identifiable, Sendable, Hashable {
/// 一张原图及其所有关联图片组成的预览项目。
struct TravelAlbumPreviewProject: Identifiable, Sendable, Hashable {
let originalMaterialId: Int
let aiRetouchBatchId: Int
let assets: [TravelAlbumPreviewAsset]
var id: Int { originalMaterialId }
@@ -87,6 +88,7 @@ struct TravelAlbumPreviewProject: Identifiable, Sendable, Hashable {
/// 将素材映射为原图及实际存在的 AI 精修、氛围感结果图。
init(material: TravelAlbumMaterial) {
originalMaterialId = material.id
aiRetouchBatchId = material.aiRetouchBatchId
var mappedAssets = [
TravelAlbumPreviewAsset(
id: "original-\(material.id)",
@@ -127,11 +129,32 @@ struct TravelAlbumPreviewProject: Identifiable, Sendable, Hashable {
}
/// 创建包含关联图片的项目,主要供适配器和测试使用。
init(originalMaterialId: Int, assets: [TravelAlbumPreviewAsset]) {
init(originalMaterialId: Int, aiRetouchBatchId: Int = 0, assets: [TravelAlbumPreviewAsset]) {
self.originalMaterialId = originalMaterialId
self.aiRetouchBatchId = aiRetouchBatchId
var seenKinds = Set<TravelAlbumPreviewAssetKind>()
self.assets = assets.filter { seenKinds.insert($0.kind).inserted }
}
/// 根据当前 Tab 生成首次修图或覆盖重修工作流。
func aiRetouchWorkflow(
albumId: Int,
selectedKind: TravelAlbumPreviewAssetKind
) -> TravelAlbumAIRetouchWorkflow? {
guard hasVariants else {
return .initial(albumId: albumId, materialIds: [originalMaterialId])
}
switch selectedKind {
case .original:
return .reretouch(materialId: originalMaterialId, batchId: aiRetouchBatchId, type: .all)
case .retouched:
return .reretouch(materialId: originalMaterialId, batchId: aiRetouchBatchId, type: .refined)
case .atmosphere:
return .reretouch(materialId: originalMaterialId, batchId: aiRetouchBatchId, type: .atmosphere)
case .cover:
return nil
}
}
}
/// 预览分页节点,记录当前图片所属项目及类型。
@@ -180,31 +203,21 @@ enum TravelAlbumPreviewNavigator {
}
}
/// 预览操作执行结果,便于后续替换真实业务接口。
/// 预览删除操作执行结果,统一表达成功、失败与暂不可用状态。
enum TravelAlbumPreviewActionResult: Sendable, Equatable {
case success(String?)
case failure(String)
case unavailable(String)
}
/// 预览页底部操作协议,所有操作均以原素材项目 ID 为目标。
/// 预览页删除操作协议,以原素材项目 ID 为目标。
protocol TravelAlbumPreviewActionHandling: AnyObject {
func requestAIRetouch(originalMaterialId: Int) async -> TravelAlbumPreviewActionResult
func deleteProject(originalMaterialId: Int) async -> TravelAlbumPreviewActionResult
func refreshProject(originalMaterialId: Int) async -> TravelAlbumPreviewActionResult
}
/// 新接口接入前的占位操作实现,不修改任何业务数据。
/// 预览删除接口接入前的占位操作实现,不修改任何业务数据。
final class PlaceholderTravelAlbumPreviewActionHandler: TravelAlbumPreviewActionHandling {
func requestAIRetouch(originalMaterialId: Int) async -> TravelAlbumPreviewActionResult {
.unavailable("AI修图功能待接口接入")
}
func deleteProject(originalMaterialId: Int) async -> TravelAlbumPreviewActionResult {
.unavailable("项目删除接口待接入")
}
func refreshProject(originalMaterialId: Int) async -> TravelAlbumPreviewActionResult {
.unavailable("关联图片刷新接口待接入")
}
}