feat: 盲盒状态更新
This commit is contained in:
parent
2b300d29fe
commit
06c2de3764
@ -18,19 +18,34 @@ enum BlindBoxAnimationPhase {
|
||||
|
||||
// MARK: - Blind Box Data Models
|
||||
|
||||
// File info used by result_file / cover_file (named uniquely to avoid collision)
|
||||
struct BlindFileInfo: Codable {
|
||||
let id: String
|
||||
let fileName: String?
|
||||
let url: String?
|
||||
let metadata: [String: String]?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case fileName = "file_name"
|
||||
case url
|
||||
case metadata
|
||||
}
|
||||
}
|
||||
|
||||
struct BlindList: Codable, Identifiable {
|
||||
let id: Int64
|
||||
let id: String
|
||||
let boxCode: String
|
||||
let userId: Int64
|
||||
let userId: String
|
||||
let name: String
|
||||
let boxType: String
|
||||
let features: String?
|
||||
let resultFileId: Int64?
|
||||
let resultFile: BlindFileInfo?
|
||||
let status: String
|
||||
let workflowInstanceId: String?
|
||||
let videoGenerateTime: String?
|
||||
let createTime: String
|
||||
let coverFileId: Int64?
|
||||
let coverFile: BlindFileInfo?
|
||||
let description: String
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
@ -40,14 +55,40 @@ struct BlindList: Codable, Identifiable {
|
||||
case name
|
||||
case boxType = "box_type"
|
||||
case features
|
||||
case resultFileId = "result_file_id"
|
||||
case resultFile = "result_file"
|
||||
case status
|
||||
case workflowInstanceId = "workflow_instance_id"
|
||||
case videoGenerateTime = "video_generate_time"
|
||||
case createTime = "create_time"
|
||||
case coverFileId = "cover_file_id"
|
||||
case coverFile = "cover_file"
|
||||
case description
|
||||
}
|
||||
|
||||
// Tolerant decoding for id/userId which may be number or string
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
func decodeString(forKey key: CodingKeys) throws -> String {
|
||||
if let s = try? container.decode(String.self, forKey: key) { return s }
|
||||
if let i = try? container.decode(Int64.self, forKey: key) { return String(i) }
|
||||
if let i = try? container.decode(Int.self, forKey: key) { return String(i) }
|
||||
return ""
|
||||
}
|
||||
|
||||
self.id = try decodeString(forKey: .id)
|
||||
self.boxCode = (try? container.decode(String.self, forKey: .boxCode)) ?? ""
|
||||
self.userId = try decodeString(forKey: .userId)
|
||||
self.name = (try? container.decode(String.self, forKey: .name)) ?? ""
|
||||
self.boxType = (try? container.decode(String.self, forKey: .boxType)) ?? ""
|
||||
self.features = try? container.decodeIfPresent(String.self, forKey: .features)
|
||||
self.resultFile = try? container.decodeIfPresent(BlindFileInfo.self, forKey: .resultFile)
|
||||
self.status = (try? container.decode(String.self, forKey: .status)) ?? ""
|
||||
self.workflowInstanceId = try? container.decodeIfPresent(String.self, forKey: .workflowInstanceId)
|
||||
self.videoGenerateTime = try? container.decodeIfPresent(String.self, forKey: .videoGenerateTime)
|
||||
self.createTime = (try? container.decode(String.self, forKey: .createTime)) ?? ""
|
||||
self.coverFile = try? container.decodeIfPresent(BlindFileInfo.self, forKey: .coverFile)
|
||||
self.description = (try? container.decode(String.self, forKey: .description)) ?? ""
|
||||
}
|
||||
}
|
||||
|
||||
struct BlindCount: Codable {
|
||||
@ -59,9 +100,9 @@ struct BlindCount: Codable {
|
||||
}
|
||||
|
||||
struct BlindBoxData: Codable {
|
||||
let id: Int64
|
||||
let id: String
|
||||
let boxCode: String
|
||||
let userId: Int64
|
||||
let userId: String
|
||||
let name: String
|
||||
let boxType: String
|
||||
let features: String?
|
||||
@ -87,7 +128,7 @@ struct BlindBoxData: Codable {
|
||||
case description
|
||||
}
|
||||
|
||||
init(id: Int64, boxCode: String, userId: Int64, name: String, boxType: String, features: String?, url: String?, status: String, workflowInstanceId: String?, videoGenerateTime: String?, createTime: String, description: String?) {
|
||||
init(id: String, boxCode: String, userId: String, name: String, boxType: String, features: String?, url: String?, status: String, workflowInstanceId: String?, videoGenerateTime: String?, createTime: String, description: String?) {
|
||||
self.id = id
|
||||
self.boxCode = boxCode
|
||||
self.userId = userId
|
||||
@ -110,7 +151,7 @@ struct BlindBoxData: Codable {
|
||||
name: listItem.name,
|
||||
boxType: listItem.boxType,
|
||||
features: listItem.features,
|
||||
url: nil,
|
||||
url: listItem.resultFile?.url,
|
||||
status: listItem.status,
|
||||
workflowInstanceId: listItem.workflowInstanceId,
|
||||
videoGenerateTime: listItem.videoGenerateTime,
|
||||
@ -118,4 +159,28 @@ struct BlindBoxData: Codable {
|
||||
description: listItem.description
|
||||
)
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
func decodeString(forKey key: CodingKeys) -> String? {
|
||||
if let s = try? container.decode(String.self, forKey: key) { return s }
|
||||
if let i = try? container.decode(Int64.self, forKey: key) { return String(i) }
|
||||
if let i = try? container.decode(Int.self, forKey: key) { return String(i) }
|
||||
return nil
|
||||
}
|
||||
|
||||
self.id = decodeString(forKey: .id) ?? ""
|
||||
self.boxCode = (try? container.decode(String.self, forKey: .boxCode)) ?? ""
|
||||
self.userId = decodeString(forKey: .userId) ?? ""
|
||||
self.name = (try? container.decode(String.self, forKey: .name)) ?? ""
|
||||
self.boxType = (try? container.decode(String.self, forKey: .boxType)) ?? ""
|
||||
self.features = try? container.decodeIfPresent(String.self, forKey: .features)
|
||||
self.url = try? container.decodeIfPresent(String.self, forKey: .url)
|
||||
self.status = (try? container.decode(String.self, forKey: .status)) ?? ""
|
||||
self.workflowInstanceId = try? container.decodeIfPresent(String.self, forKey: .workflowInstanceId)
|
||||
self.videoGenerateTime = try? container.decodeIfPresent(String.self, forKey: .videoGenerateTime)
|
||||
self.createTime = (try? container.decode(String.self, forKey: .createTime)) ?? ""
|
||||
self.description = try? container.decodeIfPresent(String.self, forKey: .description)
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,7 +69,7 @@ struct BlindBoxView: View {
|
||||
DispatchQueue.main.async {
|
||||
switch result {
|
||||
case .success(let response):
|
||||
let list = response.data ?? []
|
||||
let list = response.data
|
||||
self.blindList = list
|
||||
let lowered = list.map { ($0.boxType).lowercased() }
|
||||
let statuses = list.map { $0.status }
|
||||
@ -178,7 +178,7 @@ struct BlindBoxView: View {
|
||||
DispatchQueue.main.async {
|
||||
switch result {
|
||||
case .success(let response):
|
||||
self.blindList = response.data ?? []
|
||||
self.blindList = response.data
|
||||
// 如果列表为空数组 设置盲盒状态为none
|
||||
if self.blindList.isEmpty {
|
||||
self.animationPhase = .none
|
||||
|
||||
@ -53,7 +53,7 @@ struct GateView: View {
|
||||
isLoading = false
|
||||
switch result {
|
||||
case .success(let response):
|
||||
let list = response.data ?? []
|
||||
let list = response.data
|
||||
print("[Gate] Success, list count: \(list.count)")
|
||||
let lowered = list.map { ($0.boxType).lowercased() }
|
||||
let hasFirst = lowered.contains(where: { $0 == "first" })
|
||||
|
||||
@ -348,31 +348,13 @@ extension UserInfo {
|
||||
DispatchQueue.main.async {
|
||||
switch result {
|
||||
case .success(let response):
|
||||
guard response.code == 0, let urlStr = response.data?.resultFile?.url, let url = URL(string: urlStr) else {
|
||||
guard response.code == 0 else {
|
||||
self.errorMessage = "Create first blind box failed: invalid response"
|
||||
self.showError = true
|
||||
return
|
||||
}
|
||||
// 下载图片并跳转到盲盒结果页
|
||||
URLSession.shared.dataTask(with: url) { data, _, error in
|
||||
if let error = error {
|
||||
DispatchQueue.main.async {
|
||||
self.errorMessage = "Load result image failed: \(error.localizedDescription)"
|
||||
self.showError = true
|
||||
}
|
||||
return
|
||||
}
|
||||
guard let data = data, let image = UIImage(data: data) else {
|
||||
DispatchQueue.main.async {
|
||||
self.errorMessage = "Invalid image data"
|
||||
self.showError = true
|
||||
}
|
||||
return
|
||||
}
|
||||
DispatchQueue.main.async {
|
||||
Router.shared.navigate(to: .blindOutcome(media: .image(image), time: nil, description: nil))
|
||||
}
|
||||
}.resume()
|
||||
// 首个盲盒创建完成,返回盲盒首页等待用户手动开启
|
||||
Router.shared.navigate(to: .blindBox(mediaType: .all))
|
||||
case .failure(let error):
|
||||
self.errorMessage = "Create first blind box failed: \(error.localizedDescription)"
|
||||
self.showError = true
|
||||
|
||||
@ -461,14 +461,14 @@ struct MediaUploadView: View {
|
||||
DispatchQueue.main.async {
|
||||
switch result {
|
||||
case .success(let response):
|
||||
guard response.code == 0, let id = response.data?.id else {
|
||||
guard response.code == 0 else {
|
||||
print("❌ 创建第二个盲盒失败:响应无效")
|
||||
isGeneratingSecond = false
|
||||
return
|
||||
}
|
||||
generatedSecondBoxId = id
|
||||
// 开始轮询结果
|
||||
startPollingSecondBox(id: id)
|
||||
// 第二个盲盒创建完成,返回盲盒首页等待用户手动开启
|
||||
isGeneratingSecond = false
|
||||
Router.shared.navigate(to: .blindBox(mediaType: .all))
|
||||
case .failure(let error):
|
||||
print("❌ 创建第二个盲盒失败: \(error.localizedDescription)")
|
||||
isGeneratingSecond = false
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user