feat: 盲盒数据类型打通
This commit is contained in:
parent
e9cdb82b70
commit
8f369867b2
@ -68,19 +68,37 @@ struct BlindCount: Codable {
|
||||
|
||||
// MARK: - Blind Box Data
|
||||
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?
|
||||
let url: String?
|
||||
let resultFile: FileInfo?
|
||||
let status: String
|
||||
let workflowInstanceId: String?
|
||||
// 视频生成时间
|
||||
let videoGenerateTime: String?
|
||||
let createTime: String
|
||||
let description: String?
|
||||
let coverFile: FileInfo?
|
||||
let description: String
|
||||
|
||||
// 添加计算属性以获取Int64值
|
||||
var idValue: Int64 { Int64(id) ?? 0 }
|
||||
var userIdValue: Int64 { Int64(userId) ?? 0 }
|
||||
|
||||
struct FileInfo: 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
|
||||
}
|
||||
}
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
@ -89,43 +107,68 @@ struct BlindBoxData: Codable {
|
||||
case name
|
||||
case boxType = "box_type"
|
||||
case features
|
||||
case url
|
||||
case resultFile = "result_file"
|
||||
case status
|
||||
case workflowInstanceId = "workflow_instance_id"
|
||||
case videoGenerateTime = "video_generate_time"
|
||||
case createTime = "create_time"
|
||||
case coverFile = "cover_file"
|
||||
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?, resultFile: FileInfo?, status: String, workflowInstanceId: String?, videoGenerateTime: String?, createTime: String, coverFile: FileInfo?, description: String) {
|
||||
self.id = id
|
||||
self.boxCode = boxCode
|
||||
self.userId = userId
|
||||
self.name = name
|
||||
self.boxType = boxType
|
||||
self.features = features
|
||||
self.url = url
|
||||
self.resultFile = resultFile
|
||||
self.status = status
|
||||
self.workflowInstanceId = workflowInstanceId
|
||||
self.videoGenerateTime = videoGenerateTime
|
||||
self.createTime = createTime
|
||||
self.coverFile = coverFile
|
||||
self.description = description
|
||||
}
|
||||
|
||||
init(from listItem: BlindList) {
|
||||
self.init(
|
||||
id: Int64(listItem.id) ?? 0,
|
||||
boxCode: listItem.boxCode,
|
||||
userId: Int64(listItem.userId) ?? 0,
|
||||
name: listItem.name,
|
||||
boxType: listItem.boxType,
|
||||
features: listItem.features,
|
||||
url: listItem.resultFile?.url,
|
||||
status: listItem.status,
|
||||
workflowInstanceId: listItem.workflowInstanceId,
|
||||
videoGenerateTime: listItem.videoGenerateTime,
|
||||
createTime: listItem.createTime,
|
||||
description: listItem.description
|
||||
self.id = listItem.id
|
||||
self.boxCode = listItem.boxCode
|
||||
self.userId = listItem.userId
|
||||
self.name = listItem.name
|
||||
self.boxType = listItem.boxType
|
||||
self.features = listItem.features
|
||||
|
||||
// 转换FileInfo类型
|
||||
if let resultFileInfo = listItem.resultFile {
|
||||
self.resultFile = FileInfo(
|
||||
id: resultFileInfo.id,
|
||||
fileName: resultFileInfo.fileName,
|
||||
url: resultFileInfo.url,
|
||||
metadata: resultFileInfo.metadata
|
||||
)
|
||||
} else {
|
||||
self.resultFile = nil
|
||||
}
|
||||
|
||||
self.status = listItem.status
|
||||
self.workflowInstanceId = listItem.workflowInstanceId
|
||||
self.videoGenerateTime = listItem.videoGenerateTime
|
||||
self.createTime = listItem.createTime
|
||||
|
||||
// 转换coverFile的FileInfo类型
|
||||
if let coverFileInfo = listItem.coverFile {
|
||||
self.coverFile = FileInfo(
|
||||
id: coverFileInfo.id,
|
||||
fileName: coverFileInfo.fileName,
|
||||
url: coverFileInfo.url,
|
||||
metadata: coverFileInfo.metadata
|
||||
)
|
||||
} else {
|
||||
self.coverFile = nil
|
||||
}
|
||||
|
||||
self.description = listItem.description ?? ""
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,57 +14,7 @@ import Foundation
|
||||
// MARK: - Generate Blind Box Response Model
|
||||
struct GenerateBlindBoxResponse: Codable {
|
||||
let code: Int
|
||||
let data: BlindBoxDataWrapper?
|
||||
|
||||
struct BlindBoxDataWrapper: Codable {
|
||||
let id: String
|
||||
let boxCode: String
|
||||
let userId: String
|
||||
let name: String
|
||||
let boxType: String
|
||||
let features: String?
|
||||
let resultFile: FileInfo?
|
||||
let status: String
|
||||
let workflowInstanceId: String?
|
||||
let videoGenerateTime: String?
|
||||
let createTime: String
|
||||
let coverFile: FileInfo?
|
||||
let description: String
|
||||
|
||||
// 添加计算属性以获取Int64值
|
||||
var idValue: Int64 { Int64(id) ?? 0 }
|
||||
var userIdValue: Int64 { Int64(userId) ?? 0 }
|
||||
|
||||
struct FileInfo: 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
|
||||
}
|
||||
}
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case boxCode = "box_code"
|
||||
case userId = "user_id"
|
||||
case name
|
||||
case boxType = "box_type"
|
||||
case features
|
||||
case resultFile = "result_file"
|
||||
case status
|
||||
case workflowInstanceId = "workflow_instance_id"
|
||||
case videoGenerateTime = "video_generate_time"
|
||||
case createTime = "create_time"
|
||||
case coverFile = "cover_file"
|
||||
case description
|
||||
}
|
||||
}
|
||||
let data: BlindBoxData?
|
||||
}
|
||||
|
||||
// MARK: - Blind Box API Client
|
||||
@ -81,7 +31,7 @@ class BlindBoxApi {
|
||||
func generateBlindBox(
|
||||
boxType: String,
|
||||
materialIds: [String],
|
||||
completion: @escaping (Result<GenerateBlindBoxResponse.BlindBoxDataWrapper?, Error>) -> Void
|
||||
completion: @escaping (Result<BlindBoxData?, Error>) -> Void
|
||||
) {
|
||||
// 将Codable结构体转换为字典
|
||||
let parameters: [String: Any] = [
|
||||
@ -108,4 +58,48 @@ class BlindBoxApi {
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// 获取盲盒信息
|
||||
/// - Parameters:
|
||||
/// - boxId: 盲盒ID
|
||||
/// - completion: 完成回调,返回盲盒数据或错误
|
||||
func getBlindBox(
|
||||
boxId: String,
|
||||
completion: @escaping (Result<BlindBoxData?, Error>) -> Void
|
||||
) {
|
||||
let path = "/blind_box/query/\(boxId)"
|
||||
|
||||
NetworkService.shared.getWithToken(
|
||||
path: path,
|
||||
completion: { (result: Result<GenerateBlindBoxResponse, NetworkError>) in
|
||||
DispatchQueue.main.async {
|
||||
switch result {
|
||||
case .success(let response):
|
||||
if response.code == 0 {
|
||||
completion(.success(response.data))
|
||||
} else {
|
||||
completion(.failure(NetworkError.serverError("服务器返回错误码: \(response.code)")))
|
||||
}
|
||||
case .failure(let error):
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// 使用 async/await 获取盲盒信息
|
||||
/// - Parameter boxId: 盲盒ID
|
||||
/// - Returns: 盲盒数据
|
||||
@available(iOS 13.0, *)
|
||||
func getBlindBox(boxId: String) async throws -> BlindBoxData? {
|
||||
let path = "/blind_box/query/\(boxId)"
|
||||
let response: GenerateBlindBoxResponse = try await NetworkService.shared.getWithToken(path: path)
|
||||
|
||||
if response.code == 0 {
|
||||
return response.data
|
||||
} else {
|
||||
throw NetworkError.serverError("服务器返回错误码: \(response.code)")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -108,6 +108,43 @@ extension NetworkService: NetworkServiceProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Async/Await Extensions
|
||||
extension NetworkService {
|
||||
/// 使用 async/await 的 GET 请求(带Token)
|
||||
public func getWithToken<T: Decodable>(
|
||||
path: String,
|
||||
parameters: [String: Any]? = nil
|
||||
) async throws -> T {
|
||||
return try await withCheckedThrowingContinuation { continuation in
|
||||
getWithToken(path: path, parameters: parameters) { (result: Result<T, NetworkError>) in
|
||||
switch result {
|
||||
case .success(let value):
|
||||
continuation.resume(returning: value)
|
||||
case .failure(let error):
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 使用 async/await 的 POST 请求(带Token)
|
||||
public func postWithToken<T: Decodable>(
|
||||
path: String,
|
||||
parameters: [String: Any]
|
||||
) async throws -> T {
|
||||
return try await withCheckedThrowingContinuation { continuation in
|
||||
postWithToken(path: path, parameters: parameters) { (result: Result<T, NetworkError>) in
|
||||
switch result {
|
||||
case .success(let value):
|
||||
continuation.resume(returning: value)
|
||||
case .failure(let error):
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum NetworkError: Error {
|
||||
case invalidURL
|
||||
case noData
|
||||
|
||||
@ -7,7 +7,7 @@ enum AppRoute: Hashable {
|
||||
case feedbackView
|
||||
case feedbackDetail(type: FeedbackView.FeedbackType)
|
||||
case mediaUpload
|
||||
case blindBox(mediaType: BlindBoxMediaType)
|
||||
case blindBox(mediaType: BlindBoxMediaType, blindBoxId: String? = nil)
|
||||
case blindOutcome(media: MediaType, time: String? = nil, description: String? = nil)
|
||||
case memories
|
||||
case subscribe
|
||||
@ -31,8 +31,8 @@ enum AppRoute: Hashable {
|
||||
FeedbackDetailView(feedbackType: type)
|
||||
case .mediaUpload:
|
||||
MediaUploadView()
|
||||
case .blindBox(let mediaType):
|
||||
BlindBoxView(mediaType: mediaType)
|
||||
case .blindBox(let mediaType, let blindBoxId):
|
||||
BlindBoxView(mediaType: mediaType, blindBoxId: blindBoxId)
|
||||
case .blindOutcome(let media, let time, let description):
|
||||
BlindOutcomeView(media: media, time: time, description: description)
|
||||
case .memories:
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import SwiftUI
|
||||
import SwiftData
|
||||
import AVKit
|
||||
import Foundation
|
||||
|
||||
// 添加通知名称
|
||||
extension Notification.Name {
|
||||
@ -69,6 +70,8 @@ struct AVPlayerController: UIViewControllerRepresentable {
|
||||
|
||||
struct BlindBoxView: View {
|
||||
let mediaType: BlindBoxMediaType
|
||||
let currentBoxId: String?
|
||||
|
||||
@State private var showModal = false // 控制用户资料弹窗显示
|
||||
@State private var showSettings = false // 控制设置页面显示
|
||||
@State private var isMember = false // 是否是会员
|
||||
@ -106,8 +109,9 @@ struct BlindBoxView: View {
|
||||
// 查询数据 - 简单查询
|
||||
@Query private var login: [Login]
|
||||
|
||||
init(mediaType: BlindBoxMediaType) {
|
||||
init(mediaType: BlindBoxMediaType, blindBoxId: String? = nil) {
|
||||
self.mediaType = mediaType
|
||||
self.currentBoxId = blindBoxId
|
||||
}
|
||||
|
||||
// 倒计时
|
||||
@ -143,88 +147,138 @@ struct BlindBoxView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func loadMedia() {
|
||||
private func loadBlindBox() async {
|
||||
print("loadMedia called with mediaType: \(mediaType)")
|
||||
|
||||
switch mediaType {
|
||||
case .video:
|
||||
loadVideo()
|
||||
currentBoxType = "Video"
|
||||
startPolling()
|
||||
case .image:
|
||||
loadImage()
|
||||
currentBoxType = "Image"
|
||||
startPolling()
|
||||
case .all:
|
||||
print("Loading all content...")
|
||||
// 检查盲盒列表,如果不存在First/Second盲盒,则跳转到对应的页面重新触发新手引导
|
||||
NetworkService.shared.get(
|
||||
path: "/blind_boxs/query",
|
||||
parameters: nil
|
||||
) { (result: Result<APIResponse<[BlindList]>, NetworkError>) in
|
||||
DispatchQueue.main.async {
|
||||
switch result {
|
||||
case .success(let response):
|
||||
if response.data.count == 0 {
|
||||
// 跳转到新手引导-First盲盒页面
|
||||
print("❌ 没有盲盒,跳转到新手引导-First盲盒页面")
|
||||
// return
|
||||
}
|
||||
if response.data.count == 1 && response.data[0].boxType == "First" {
|
||||
// 跳转到新手引导-Second盲盒页面
|
||||
print("❌ 只有First盲盒,跳转到新手引导-Second盲盒页面")
|
||||
// return
|
||||
if self.currentBoxId != nil {
|
||||
print("指定监听某盲盒结果: ", self.currentBoxId! as Any)
|
||||
// 启动轮询查询盲盒状态
|
||||
await pollingToQuerySingleBox()
|
||||
}
|
||||
|
||||
self.blindList = response.data ?? []
|
||||
// 如果列表为空数组 设置盲盒状态为none
|
||||
if self.blindList.isEmpty {
|
||||
self.animationPhase = .none
|
||||
// switch mediaType {
|
||||
// case .video:
|
||||
// loadVideo()
|
||||
// currentBoxType = "Video"
|
||||
// startPolling()
|
||||
// case .image:
|
||||
// loadImage()
|
||||
// currentBoxType = "Image"
|
||||
// startPolling()
|
||||
// case .all:
|
||||
// print("Loading all content...")
|
||||
// // 检查盲盒列表,如果不存在First/Second盲盒,则跳转到对应的页面重新触发新手引导
|
||||
// // 注意:这部分代码仍使用传统的闭包方式,因为NetworkService.shared.get不支持async/await
|
||||
// NetworkService.shared.get(
|
||||
// path: "/blind_boxs/query",
|
||||
// parameters: nil
|
||||
// ) { (result: Result<APIResponse<[BlindList]>, NetworkError>) in
|
||||
// DispatchQueue.main.async {
|
||||
// switch result {
|
||||
// case .success(let response):
|
||||
// if response.data.count == 0 {
|
||||
// // 跳转到新手引导-First盲盒页面
|
||||
// print("❌ 没有盲盒,跳转到新手引导-First盲盒页面")
|
||||
// // return
|
||||
// }
|
||||
// if response.data.count == 1 && response.data[0].boxType == "First" {
|
||||
// // 跳转到新手引导-Second盲盒页面
|
||||
// print("❌ 只有First盲盒,跳转到新手引导-Second盲盒页面")
|
||||
// // return
|
||||
// }
|
||||
|
||||
// self.blindList = response.data ?? []
|
||||
// // 如果列表为空数组 设置盲盒状态为none
|
||||
// if self.blindList.isEmpty {
|
||||
// self.animationPhase = .none
|
||||
// }
|
||||
// print("✅ 成功获取 \(self.blindList.count) 个盲盒")
|
||||
// case .failure(let error):
|
||||
// self.blindList = []
|
||||
// self.animationPhase = .none
|
||||
// print("❌ 获取盲盒列表失败:", error.localizedDescription)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // // 会员信息
|
||||
// // NetworkService.shared.get(
|
||||
// // path: "/membership/personal-center-info",
|
||||
// // parameters: nil
|
||||
// // ) { (result: Result<MemberProfileResponse, NetworkError>) in
|
||||
// // DispatchQueue.main.async {
|
||||
// // switch result {
|
||||
// // case .success(let response):
|
||||
// // self.memberProfile = response.data
|
||||
// // self.isMember = response.data.membershipLevel == "Pioneer"
|
||||
// // self.memberDate = response.data.membershipEndAt ?? ""
|
||||
// // print("✅ 成功获取会员信息:", response.data)
|
||||
// // print("✅ 用户ID:", response.data.userInfo.userId)
|
||||
// // case .failure(let error):
|
||||
// // print("❌ 获取会员信息失败:", error)
|
||||
// // }
|
||||
// // }
|
||||
// // }
|
||||
// // // 盲盒数量
|
||||
// // NetworkService.shared.get(
|
||||
// // path: "/blind_box/available/quantity",
|
||||
// // parameters: nil
|
||||
// // ) { (result: Result<APIResponse<BlindCount>, NetworkError>) in
|
||||
// // DispatchQueue.main.async {
|
||||
// // switch result {
|
||||
// // case .success(let response):
|
||||
// // self.blindCount = response.data
|
||||
// // print("✅ 成功获取盲盒数量:", response.data)
|
||||
// // case .failure(let error):
|
||||
// // print("❌ 获取数量失败:", error)
|
||||
// // }
|
||||
// // }
|
||||
// // }
|
||||
// }
|
||||
}
|
||||
print("✅ 成功获取 \(self.blindList.count) 个盲盒")
|
||||
case .failure(let error):
|
||||
self.blindList = []
|
||||
|
||||
private func pollingToQuerySingleBox() async {
|
||||
stopPolling()
|
||||
isPolling = true
|
||||
|
||||
// 轮询查询盲盒状态,直到状态为Unopened
|
||||
while isPolling {
|
||||
do {
|
||||
let blindBoxData = try await BlindBoxApi.shared.getBlindBox(boxId: self.currentBoxId!)
|
||||
|
||||
// 更新UI
|
||||
if let data = blindBoxData {
|
||||
self.blindGenerate = data
|
||||
|
||||
// 根据盲盒类型设置媒体URL
|
||||
if mediaType == .video {
|
||||
self.videoURL = data.resultFile?.url ?? ""
|
||||
} else if mediaType == .image {
|
||||
self.imageURL = data.resultFile?.url ?? ""
|
||||
}
|
||||
|
||||
print("✅ 成功获取盲盒数据: \(data.name), 状态: \(data.status)")
|
||||
|
||||
// 检查状态是否为Unopened,如果是则停止轮询
|
||||
if data.status == "Unopened" {
|
||||
print("✅ 盲盒已准备就绪,停止轮询")
|
||||
stopPolling()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 等待2秒后继续轮询
|
||||
try await Task.sleep(nanoseconds: 2_000_000_000)
|
||||
} catch {
|
||||
print("❌ 获取盲盒数据失败: \(error)")
|
||||
// 处理错误情况
|
||||
self.animationPhase = .none
|
||||
print("❌ 获取盲盒列表失败:", error.localizedDescription)
|
||||
stopPolling()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 会员信息
|
||||
NetworkService.shared.get(
|
||||
path: "/membership/personal-center-info",
|
||||
parameters: nil
|
||||
) { (result: Result<MemberProfileResponse, NetworkError>) in
|
||||
DispatchQueue.main.async {
|
||||
switch result {
|
||||
case .success(let response):
|
||||
self.memberProfile = response.data
|
||||
self.isMember = response.data.membershipLevel == "Pioneer"
|
||||
self.memberDate = response.data.membershipEndAt ?? ""
|
||||
print("✅ 成功获取会员信息:", response.data)
|
||||
print("✅ 用户ID:", response.data.userInfo.userId)
|
||||
case .failure(let error):
|
||||
print("❌ 获取会员信息失败:", error)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 盲盒数量
|
||||
NetworkService.shared.get(
|
||||
path: "/blind_box/available/quantity",
|
||||
parameters: nil
|
||||
) { (result: Result<APIResponse<BlindCount>, NetworkError>) in
|
||||
DispatchQueue.main.async {
|
||||
switch result {
|
||||
case .success(let response):
|
||||
self.blindCount = response.data
|
||||
print("✅ 成功获取盲盒数量:", response.data)
|
||||
case .failure(let error):
|
||||
print("❌ 获取数量失败:", error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 轮询接口
|
||||
private func startPolling() {
|
||||
stopPolling()
|
||||
@ -244,52 +298,54 @@ struct BlindBoxView: View {
|
||||
return
|
||||
}
|
||||
|
||||
NetworkService.shared.postWithToken(
|
||||
path: "/blind_box/generate/mock",
|
||||
parameters: ["box_type": currentBoxType]
|
||||
) { (result: Result<APIResponse<BlindBoxData>, NetworkError>) in
|
||||
DispatchQueue.main.async {
|
||||
switch result {
|
||||
case .success(let response):
|
||||
let data = response.data
|
||||
self.blindGenerate = data
|
||||
print("当前盲盒状态: \(data.status)")
|
||||
// 更新显示数据
|
||||
if self.mediaType == .all, let firstItem = self.blindList.first {
|
||||
self.displayData = BlindBoxData(from: firstItem)
|
||||
} else {
|
||||
self.displayData = data
|
||||
}
|
||||
|
||||
// 发送状态变更通知
|
||||
NotificationCenter.default.post(
|
||||
name: .blindBoxStatusChanged,
|
||||
object: nil,
|
||||
userInfo: ["status": data.status]
|
||||
)
|
||||
|
||||
if data.status != "Preparing" {
|
||||
self.stopPolling()
|
||||
print("✅ 盲盒准备就绪,状态: \(data.status)")
|
||||
if self.mediaType == .video {
|
||||
self.videoURL = data.url ?? ""
|
||||
} else if self.mediaType == .image {
|
||||
self.imageURL = data.url ?? ""
|
||||
}
|
||||
} else {
|
||||
self.pollingTimer = Timer.scheduledTimer(
|
||||
withTimeInterval: 2.0,
|
||||
repeats: false
|
||||
) { _ in
|
||||
self.checkBlindBoxStatus()
|
||||
}
|
||||
}
|
||||
case .failure(let error):
|
||||
print("❌ 获取盲盒状态失败: \(error.localizedDescription)")
|
||||
self.stopPolling()
|
||||
}
|
||||
}
|
||||
}
|
||||
// NetworkService.shared.postWithToken(
|
||||
// path: "/blind_box/generate/mock",
|
||||
// parameters: ["box_type": currentBoxType]
|
||||
// ) { (result: Result<GenerateBlindBoxResponse, NetworkError>) in
|
||||
// DispatchQueue.main.async {
|
||||
// switch result {
|
||||
// case .success(let response):
|
||||
// let data = response.data
|
||||
// self.blindGenerate = data
|
||||
// print("当前盲盒状态: \(data?.status ?? "Unknown")")
|
||||
// // 更新显示数据
|
||||
// if self.mediaType == .all, let firstItem = self.blindList.first {
|
||||
// self.displayData = BlindBoxData(from: firstItem)
|
||||
// } else {
|
||||
// self.displayData = data
|
||||
// }
|
||||
//
|
||||
// // 发送状态变更通知
|
||||
// if let status = data?.status {
|
||||
// NotificationCenter.default.post(
|
||||
// name: .blindBoxStatusChanged,
|
||||
// object: nil,
|
||||
// userInfo: ["status": status]
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// if data?.status != "Preparing" {
|
||||
// self.stopPolling()
|
||||
// print("✅ 盲盒准备就绪,状态: \(data?.status ?? "Unknown")")
|
||||
// if self.mediaType == .video {
|
||||
// self.videoURL = data?.resultFile?.url ?? ""
|
||||
// } else if self.mediaType == .image {
|
||||
// self.imageURL = data?.resultFile?.url ?? ""
|
||||
// }
|
||||
// } else {
|
||||
// self.pollingTimer = Timer.scheduledTimer(
|
||||
// withTimeInterval: 2.0,
|
||||
// repeats: false
|
||||
// ) { _ in
|
||||
// self.checkBlindBoxStatus()
|
||||
// }
|
||||
// }
|
||||
// case .failure(let error):
|
||||
// print("❌ 获取盲盒状态失败: \(error.localizedDescription)")
|
||||
// self.stopPolling()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
private func loadImage() {
|
||||
@ -409,40 +465,45 @@ struct BlindBoxView: View {
|
||||
.onAppear {
|
||||
print("🎯 BlindBoxView appeared with mediaType: \(mediaType)")
|
||||
print("🎯 Current thread: \(Thread.current)")
|
||||
|
||||
|
||||
|
||||
// 初始化显示数据
|
||||
if mediaType == .all, let firstItem = blindList.first {
|
||||
displayData = BlindBoxData(from: firstItem)
|
||||
} else {
|
||||
displayData = blindGenerate
|
||||
}
|
||||
// if mediaType == .all, let firstItem = blindList.first {
|
||||
// displayData = BlindBoxData(from: firstItem)
|
||||
// } else {
|
||||
// displayData = blindGenerate
|
||||
// }
|
||||
|
||||
// 添加盲盒状态变化监听
|
||||
NotificationCenter.default.addObserver(
|
||||
forName: .blindBoxStatusChanged,
|
||||
object: nil,
|
||||
queue: .main
|
||||
) { notification in
|
||||
if let status = notification.userInfo?["status"] as? String {
|
||||
switch status {
|
||||
case "Preparing":
|
||||
withAnimation {
|
||||
self.animationPhase = .loading
|
||||
}
|
||||
case "Unopened":
|
||||
withAnimation {
|
||||
self.animationPhase = .ready
|
||||
}
|
||||
default:
|
||||
// 其他状态不处理
|
||||
withAnimation {
|
||||
self.animationPhase = .ready
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// NotificationCenter.default.addObserver(
|
||||
// forName: .blindBoxStatusChanged,
|
||||
// object: nil,
|
||||
// queue: .main
|
||||
// ) { notification in
|
||||
// if let status = notification.userInfo?["status"] as? String {
|
||||
// switch status {
|
||||
// case "Preparing":
|
||||
// withAnimation {
|
||||
// self.animationPhase = .loading
|
||||
// }
|
||||
// case "Unopened":
|
||||
// withAnimation {
|
||||
// self.animationPhase = .ready
|
||||
// }
|
||||
// default:
|
||||
// // 其他状态不处理
|
||||
// withAnimation {
|
||||
// self.animationPhase = .ready
|
||||
// }
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// 调用接口
|
||||
loadMedia()
|
||||
Task {
|
||||
await loadBlindBox()
|
||||
}
|
||||
}
|
||||
.onDisappear {
|
||||
stopPolling()
|
||||
@ -722,10 +783,10 @@ struct BlindBoxView: View {
|
||||
if !showScalingOverlay && !showMedia {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
// 从变量blindGenerate中获取description
|
||||
Text(blindGenerate?.videoGenerateTime ?? "hhsdshjsjdhn")
|
||||
Text(blindGenerate?.name ?? "Some box")
|
||||
.font(Typography.font(for: .body, family: .quicksandBold))
|
||||
.foregroundColor(Color.themeTextMessageMain)
|
||||
Text(blindGenerate?.description ?? "informationinformationinformationinformationinformationinformation")
|
||||
Text(blindGenerate?.description ?? "")
|
||||
.font(.system(size: 14))
|
||||
.foregroundColor(Color.themeTextMessageMain)
|
||||
}
|
||||
@ -876,6 +937,21 @@ struct BlindBoxView: View {
|
||||
}
|
||||
}
|
||||
|
||||
// 预览第一个盲盒
|
||||
#Preview("First Blind Box") {
|
||||
BlindBoxView(mediaType: .image, blindBoxId: "7370140297747107840")
|
||||
.onAppear {
|
||||
// 仅在Preview中设置模拟令牌(不要在生产代码中使用)
|
||||
#if DEBUG
|
||||
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
|
||||
// 设置模拟令牌用于Preview
|
||||
let previewToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFZERTQSJ9.eyJqdGkiOjczNzAwMTY5NzMzODE1NzA1NjAsImlkZW50aXR5IjoiNzM1MDQzOTY2MzExNjYxOTc3NyIsImV4cCI6MTc1Nzc1Mzc3NH0.tZ8p5sW4KX6HFoJpJN0e4VmJOAGhTrYD2yTwQwilKpufzqOAfXX4vpGYBurgBIcHj2KmXKX2PQMOeeAtvAypDA"
|
||||
let _ = KeychainHelper.saveAccessToken(previewToken)
|
||||
print("🔑 Preview token set for testing")
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
// struct TransparentVideoPlayer: UIViewRepresentable {
|
||||
// func makeUIView(context: Context) -> UIView {
|
||||
// let view = UIView()
|
||||
|
||||
@ -198,7 +198,7 @@ struct UserInfo: View {
|
||||
case .success(let blindBoxData):
|
||||
print("✅ 盲盒生成成功: \(blindBoxData?.id ?? "0")")
|
||||
// 导航到首页盲盒等待用户开启第一个盲盒
|
||||
Router.shared.navigate(to: .blindBox(mediaType: .image))
|
||||
Router.shared.navigate(to: .blindBox(mediaType: .image, blindBoxId: blindBoxData?.id ?? "0"))
|
||||
case .failure(let error):
|
||||
print("❌ 盲盒生成失败: \(error.localizedDescription)")
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user