feat: 调取接口
This commit is contained in:
parent
f96edf97c5
commit
ee1b1321ff
@ -74,11 +74,138 @@ struct BlindBoxView: View {
|
|||||||
case image
|
case image
|
||||||
case all
|
case all
|
||||||
}
|
}
|
||||||
|
// 盲盒列表
|
||||||
|
struct BlindList: Codable, Identifiable {
|
||||||
|
let id: Int64
|
||||||
|
let boxCode: String
|
||||||
|
let userId: Int64
|
||||||
|
let name: String
|
||||||
|
let boxType: String
|
||||||
|
let features: String?
|
||||||
|
let resultFileId: Int64?
|
||||||
|
let status: String
|
||||||
|
let workflowInstanceId: String?
|
||||||
|
let videoGenerateTime: String?
|
||||||
|
let createTime: String
|
||||||
|
let coverFileId: Int64?
|
||||||
|
let description: String
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case id
|
||||||
|
case boxCode = "box_code"
|
||||||
|
case userId = "user_id"
|
||||||
|
case name
|
||||||
|
case boxType = "box_type"
|
||||||
|
case features
|
||||||
|
case resultFileId = "result_file_id"
|
||||||
|
case status
|
||||||
|
case workflowInstanceId = "workflow_instance_id"
|
||||||
|
case videoGenerateTime = "video_generate_time"
|
||||||
|
case createTime = "create_time"
|
||||||
|
case coverFileId = "cover_file_id"
|
||||||
|
case description
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 会员信息
|
||||||
|
struct MemberProfile: Codable {
|
||||||
|
let materialCounter: MaterialCounter
|
||||||
|
let userInfo: UserInfo
|
||||||
|
let storiesCount: Int
|
||||||
|
let conversationsCount: Int
|
||||||
|
let remainPoints: Int
|
||||||
|
let totalPoints: Int
|
||||||
|
let usedBytes: Int
|
||||||
|
let totalBytes: Int
|
||||||
|
let titleRankings: [String]
|
||||||
|
let medalInfos: [MedalInfo]
|
||||||
|
let membershipLevel: String
|
||||||
|
let membershipEndAt: String
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case materialCounter = "material_counter"
|
||||||
|
case userInfo = "user_info"
|
||||||
|
case storiesCount = "stories_count"
|
||||||
|
case conversationsCount = "conversations_count"
|
||||||
|
case remainPoints = "remain_points"
|
||||||
|
case totalPoints = "total_points"
|
||||||
|
case usedBytes = "used_bytes"
|
||||||
|
case totalBytes = "total_bytes"
|
||||||
|
case titleRankings = "title_rankings"
|
||||||
|
case medalInfos = "medal_infos"
|
||||||
|
case membershipLevel = "membership_level"
|
||||||
|
case membershipEndAt = "membership_end_at"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 盲盒数量
|
||||||
|
struct BlindCount: Codable {
|
||||||
|
let availableQuantity: Int
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case availableQuantity = "available_quantity"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MaterialCounter: Codable {
|
||||||
|
let userId: Int64
|
||||||
|
let totalCount: MediaCount
|
||||||
|
let categoryCount: [String: MediaCount]
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case userId = "user_id"
|
||||||
|
case totalCount = "total_count"
|
||||||
|
case categoryCount = "category_count"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MediaCount: Codable {
|
||||||
|
let videoCount: Int
|
||||||
|
let photoCount: Int
|
||||||
|
let liveCount: Int
|
||||||
|
let videoLength: Double
|
||||||
|
let coverUrl: String?
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case videoCount = "video_count"
|
||||||
|
case photoCount = "photo_count"
|
||||||
|
case liveCount = "live_count"
|
||||||
|
case videoLength = "video_length"
|
||||||
|
case coverUrl = "cover_url"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct UserInfo: Codable {
|
||||||
|
let userId: String
|
||||||
|
let accessToken: String
|
||||||
|
let avatarFileUrl: String?
|
||||||
|
let nickname: String
|
||||||
|
let account: String
|
||||||
|
let email: String
|
||||||
|
let refreshToken: String?
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case userId = "user_id"
|
||||||
|
case accessToken = "access_token"
|
||||||
|
case avatarFileUrl = "avatar_file_url"
|
||||||
|
case nickname
|
||||||
|
case account
|
||||||
|
case email
|
||||||
|
case refreshToken = "refresh_token"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MedalInfo: Codable, Identifiable {
|
||||||
|
let id: Int
|
||||||
|
let url: String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
let mediaType: BlindBoxMediaType
|
let mediaType: BlindBoxMediaType
|
||||||
@State private var showModal = false // 控制用户资料弹窗显示
|
@State private var showModal = false // 控制用户资料弹窗显示
|
||||||
@State private var showSettings = false // 控制设置页面显示
|
@State private var showSettings = false // 控制设置页面显示
|
||||||
@State private var showLogin = false
|
@State private var showLogin = false
|
||||||
|
@State private var memberProfile: MemberProfile? = nil
|
||||||
|
@State private var blindCount: BlindCount? = nil
|
||||||
|
@State private var blindList: [BlindList] = [] // Changed to array
|
||||||
@State private var showLottieAnimation = true
|
@State private var showLottieAnimation = true
|
||||||
@State private var showScalingOverlay = false
|
@State private var showScalingOverlay = false
|
||||||
@State private var animationPhase: BlindBoxAnimationPhase = .loading
|
@State private var animationPhase: BlindBoxAnimationPhase = .loading
|
||||||
@ -98,27 +225,85 @@ struct BlindBoxView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func loadMedia() {
|
private func loadMedia() {
|
||||||
|
print("loadMedia called with mediaType: \(mediaType)")
|
||||||
|
|
||||||
switch mediaType {
|
switch mediaType {
|
||||||
case .video:
|
case .video:
|
||||||
loadVideo()
|
loadVideo()
|
||||||
|
print("Loading video...")
|
||||||
case .image:
|
case .image:
|
||||||
loadImage()
|
loadImage()
|
||||||
|
print("Loading image...")
|
||||||
case .all:
|
case .all:
|
||||||
loadData()
|
print("Loading all content...")
|
||||||
|
// 会员信息
|
||||||
|
NetworkService.shared.get(
|
||||||
|
path: "/membership/personal-center-info",
|
||||||
|
parameters: nil
|
||||||
|
) { (result: Result<APIResponse<MemberProfile>, NetworkError>) in
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
switch result {
|
||||||
|
case .success(let response):
|
||||||
|
self.memberProfile = response.data
|
||||||
|
print("✅ 成功获取会员信息:", response.data)
|
||||||
|
print("✅ 用户ID:", response.data.userInfo.userId)
|
||||||
|
print("✅ 用户昵称:", response.data.userInfo.nickname)
|
||||||
|
print("✅ 用户邮箱:", response.data.userInfo.email)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 盲盒列表
|
||||||
|
NetworkService.shared.get(
|
||||||
|
path: "/blind_boxs/query",
|
||||||
|
parameters: nil
|
||||||
|
) { (result: Result<APIResponse<[BlindList]>, NetworkError>) in
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
switch result {
|
||||||
|
case .success(let response):
|
||||||
|
self.blindList = response.data ?? []
|
||||||
|
print("✅ 成功获取 \(self.blindList.count) 个盲盒")
|
||||||
|
case .failure(let error):
|
||||||
|
self.blindList = []
|
||||||
|
print("❌ 获取盲盒列表失败:", error.localizedDescription)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func loadData() {
|
private func loadData() {
|
||||||
guard let url = URL(string: MediaURLs.imageURL) else { return }
|
// 会员信息
|
||||||
URLSession.shared.dataTask(with: url) { data, _, _ in
|
NetworkService.shared.get(
|
||||||
if let data = data, let image = UIImage(data: data) {
|
path: "/membership/personal-center-info",
|
||||||
DispatchQueue.main.async {
|
parameters: nil
|
||||||
self.displayImage = image
|
) { (result: Result<APIResponse<MemberProfile>, NetworkError>) in
|
||||||
self.aspectRatio = image.size.width / image.size.height
|
DispatchQueue.main.async {
|
||||||
self.isPortrait = image.size.height > image.size.width
|
switch result {
|
||||||
|
case .success(let response):
|
||||||
|
self.memberProfile = response.data
|
||||||
|
print("✅ Successfully fetched user info:", response.data)
|
||||||
|
case .failure(let error):
|
||||||
|
print("❌ Failed to fetch user info:", error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.resume()
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func loadImage() {
|
private func loadImage() {
|
||||||
@ -183,6 +368,11 @@ struct BlindBoxView: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
Color.themeTextWhiteSecondary.ignoresSafeArea()
|
Color.themeTextWhiteSecondary.ignoresSafeArea()
|
||||||
|
.onAppear {
|
||||||
|
print("🎯 BlindBoxView appeared with mediaType: \(mediaType)")
|
||||||
|
print("🎯 Current thread: \(Thread.current)")
|
||||||
|
loadMedia()
|
||||||
|
}
|
||||||
|
|
||||||
if showScalingOverlay {
|
if showScalingOverlay {
|
||||||
ZStack {
|
ZStack {
|
||||||
@ -299,7 +489,7 @@ struct BlindBoxView: View {
|
|||||||
// LoginView()
|
// LoginView()
|
||||||
// }
|
// }
|
||||||
NavigationLink(destination: SubscribeView()) {
|
NavigationLink(destination: SubscribeView()) {
|
||||||
Text("3290")
|
Text("\(memberProfile?.remainPoints ?? 0)")
|
||||||
.font(Typography.font(for: .subtitle))
|
.font(Typography.font(for: .subtitle))
|
||||||
.fontWeight(.bold)
|
.fontWeight(.bold)
|
||||||
.padding(.horizontal, 12)
|
.padding(.horizontal, 12)
|
||||||
@ -396,7 +586,7 @@ struct BlindBoxView: View {
|
|||||||
SVGImage(svgName: "BlindCount")
|
SVGImage(svgName: "BlindCount")
|
||||||
.frame(width: 100, height: 60)
|
.frame(width: 100, height: 60)
|
||||||
|
|
||||||
Text("2 Boxes")
|
Text("\(blindCount?.availableQuantity ?? 0)Boxes")
|
||||||
.font(Typography.font(for: .body, family: .quicksandBold))
|
.font(Typography.font(for: .body, family: .quicksandBold))
|
||||||
.foregroundColor(.white)
|
.foregroundColor(.white)
|
||||||
.offset(x: 6, y: -18)
|
.offset(x: 6, y: -18)
|
||||||
|
|||||||
@ -16,23 +16,6 @@ struct UserProfile: Codable {
|
|||||||
case email
|
case email
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MemberProfile: Codable {
|
|
||||||
let userId: String
|
|
||||||
let nickname: String
|
|
||||||
let avatarUrl: String?
|
|
||||||
let account: String
|
|
||||||
let email: String
|
|
||||||
|
|
||||||
enum CodingKeys: String, CodingKey {
|
|
||||||
case userId = "user_id"
|
|
||||||
case nickname
|
|
||||||
case avatarUrl = "avatar_file_url"
|
|
||||||
case account
|
|
||||||
case email
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// API Response wrapper
|
// API Response wrapper
|
||||||
struct APIResponse<T: Codable>: Codable {
|
struct APIResponse<T: Codable>: Codable {
|
||||||
let code: Int
|
let code: Int
|
||||||
@ -301,24 +284,6 @@ struct UserProfileModal: View {
|
|||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
isLoading = false
|
isLoading = false
|
||||||
|
|
||||||
switch result {
|
|
||||||
case .success(let response):
|
|
||||||
self.userProfile = response.data
|
|
||||||
print("✅ Successfully fetched user info:", response.data)
|
|
||||||
case .failure(let error):
|
|
||||||
self.errorMessage = error.localizedDescription
|
|
||||||
print("❌ Failed to fetch user info:", error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 会员信息
|
|
||||||
NetworkService.shared.get(
|
|
||||||
path: "/membership/personal-center-info",
|
|
||||||
parameters: nil
|
|
||||||
) { (result: Result<APIResponse<UserProfile>, NetworkError>) in
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
isLoading = false
|
|
||||||
|
|
||||||
switch result {
|
switch result {
|
||||||
case .success(let response):
|
case .success(let response):
|
||||||
self.userProfile = response.data
|
self.userProfile = response.data
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user