diff --git a/wake/Models/BlindBoxModels.swift b/wake/Models/BlindBoxModels.swift index cd280c4..30ebedc 100644 --- a/wake/Models/BlindBoxModels.swift +++ b/wake/Models/BlindBoxModels.swift @@ -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) + } } diff --git a/wake/View/BlindBox/BlindBoxView.swift b/wake/View/BlindBox/BlindBoxView.swift index d82175f..66a68d2 100644 --- a/wake/View/BlindBox/BlindBoxView.swift +++ b/wake/View/BlindBox/BlindBoxView.swift @@ -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 diff --git a/wake/View/Gate/GateView.swift b/wake/View/Gate/GateView.swift index 1d37dae..fa4341b 100644 --- a/wake/View/Gate/GateView.swift +++ b/wake/View/Gate/GateView.swift @@ -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" }) diff --git a/wake/View/Owner/UserInfo/UserInfo.swift b/wake/View/Owner/UserInfo/UserInfo.swift index a227376..a3497ce 100644 --- a/wake/View/Owner/UserInfo/UserInfo.swift +++ b/wake/View/Owner/UserInfo/UserInfo.swift @@ -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 diff --git a/wake/View/Upload/MediaUploadView.swift b/wake/View/Upload/MediaUploadView.swift index 8379cd6..7723a35 100644 --- a/wake/View/Upload/MediaUploadView.swift +++ b/wake/View/Upload/MediaUploadView.swift @@ -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