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