325 lines
13 KiB
Swift
325 lines
13 KiB
Swift
|
||
// 我的模块
|
||
//
|
||
|
||
import SwiftUI
|
||
import Combine
|
||
import Alamofire
|
||
import Kingfisher
|
||
|
||
// 数据模型
|
||
struct User: Decodable {
|
||
let user_id: Int
|
||
let nickname: String
|
||
let avatar_url: String
|
||
let signature: String
|
||
let territory: String
|
||
}
|
||
|
||
// 视图模型
|
||
class UserProfileViewModel: ObservableObject {
|
||
static let shared = UserProfileViewModel()
|
||
|
||
|
||
@Published var user: User?
|
||
@Published var isLoading = true
|
||
@Published var errorMessage: String?
|
||
|
||
private init() {
|
||
fetchUserProfile()
|
||
}
|
||
|
||
private var cancellable: AnyCancellable?
|
||
|
||
func fetchUserProfile() {
|
||
makeAlamofireRequest(api: apiprefixV1 + userInfoApi, method: .post, param: Optional<EmptyParams>.none) { (result: Result<HTTPBinResponse<User>, AFError>) in
|
||
DispatchQueue.main.async {
|
||
|
||
self.isLoading = false
|
||
switch result {
|
||
case .success(let body):
|
||
if body.code == 0 {
|
||
self.user = body.data
|
||
|
||
} else {
|
||
self.errorMessage = body.message
|
||
}
|
||
case .failure(let error):
|
||
self.errorMessage = error.localizedDescription
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
struct MineView: View {
|
||
@ObservedObject private var viewModel = UserProfileViewModel.shared
|
||
@State var tagActive = 0
|
||
@State private var showLoginView = false
|
||
@State var items: [TargetData1] = [
|
||
// TargetData1(title:"训练完喝瓶AD钙",progress: 14.29, status_str:"未完成今日打卡",check: true, image:"image-5"),
|
||
// TargetData1(title:"训练完喝瓶AD钙",progress: 14.29, status_str:"未完成今日打卡", check:true, image:"image-5"),
|
||
// TargetData1(title:"哭泣的骆驼",progress: 14.29,status_str: "未完成今日打卡",check: true, image:"image-5"),
|
||
// TargetData1(title:"训练完喝瓶AD钙",progress: 14.29, status_str:"未完成今日打卡",check: true, image:"image-5")
|
||
]
|
||
var body: some View {
|
||
NavigationStack{
|
||
VStack {
|
||
// 头部信息
|
||
VStack {
|
||
// 标题
|
||
HStack {
|
||
Button {} label: {
|
||
Image(systemName: "lines.measurement.horizontal")
|
||
}
|
||
|
||
Spacer()
|
||
|
||
Button (action: {
|
||
// 退出登录
|
||
UserDefaults.standard.removeObject(forKey: "userToken")
|
||
// 展示登录界面
|
||
viewModel.user = nil
|
||
showLoginView = true
|
||
}) {
|
||
Image(systemName: "square.and.arrow.up")
|
||
.rotationEffect(.degrees(90))
|
||
}
|
||
}
|
||
.padding(.horizontal, 12)
|
||
.foregroundStyle(.white)
|
||
.font(.system(size: 21))
|
||
|
||
// 用户信息
|
||
VStack(alignment: .leading) {
|
||
|
||
if let user = viewModel.user {
|
||
HStack(spacing: 20) {
|
||
KFImage(URL(string: user.avatar_url))
|
||
.resizable()
|
||
.placeholder {
|
||
ProgressView()
|
||
}
|
||
.aspectRatio(contentMode: .fill)
|
||
.frame(width: 100, height: 100)
|
||
.clipShape(Circle())
|
||
.overlay(Circle().stroke(Color.white, lineWidth: 2))
|
||
|
||
VStack(alignment: .leading) {
|
||
Text(user.nickname)
|
||
.SetTextStyle(size: 21, color: .white)
|
||
.bold()
|
||
|
||
HStack {
|
||
Text("小红书号:1212121")
|
||
.SetTextStyle(size: 12, color: .white)
|
||
Image(systemName: "qrcode")
|
||
.foregroundStyle(.white)
|
||
.font(.system(size: 12))
|
||
}
|
||
.padding(.top, 1)
|
||
|
||
HStack {
|
||
Text("IP属地:\(user.territory)")
|
||
.SetTextStyle(size: 12, color: .white)
|
||
Image(systemName: "globe.asia.australia")
|
||
.foregroundStyle(.white)
|
||
.font(.system(size: 12))
|
||
}
|
||
.padding(.top, 1)
|
||
}
|
||
|
||
Spacer()
|
||
}
|
||
Text(user.signature)
|
||
.SetTextStyle(size: 17, color: .white)
|
||
.padding(.top, 12)
|
||
|
||
// 信息标签
|
||
HStack {
|
||
Button {} label: {
|
||
Text("处女座")
|
||
.font(.system(size: 12))
|
||
.padding(.vertical, 2)
|
||
.padding(.horizontal, 7)
|
||
.background(.white.opacity(0.2), in: RoundedRectangle(cornerRadius: 12))
|
||
}
|
||
|
||
Button {} label: {
|
||
Text("四川成都")
|
||
.font(.system(size: 12))
|
||
.padding(.vertical, 2)
|
||
.padding(.horizontal, 7)
|
||
.background(.white.opacity(0.2), in: RoundedRectangle(cornerRadius: 12))
|
||
}
|
||
|
||
Button {} label: {
|
||
Text("外卖员")
|
||
.font(.system(size: 12))
|
||
.padding(.vertical, 2)
|
||
.padding(.horizontal, 7)
|
||
.background(.white.opacity(0.2), in: RoundedRectangle(cornerRadius: 12))
|
||
}
|
||
}
|
||
.foregroundStyle(.white)
|
||
} else {
|
||
// 未登录状态下显示登录按钮
|
||
VStack {
|
||
Button(action: {
|
||
showLoginView = true
|
||
}) {
|
||
VStack {
|
||
Image(systemName: "person.crop.circle.fill")
|
||
.resizable()
|
||
.frame(width: 100, height: 100)
|
||
.foregroundColor(.white)
|
||
Text("登录")
|
||
.SetTextStyle(size: 21, color: .white)
|
||
.bold()
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 操作栏
|
||
HStack {
|
||
VStack {
|
||
Text("12")
|
||
.font(.system(size: 13))
|
||
Text("关注")
|
||
.font(.system(size: 11))
|
||
}
|
||
|
||
VStack {
|
||
Text("4")
|
||
.font(.system(size: 13))
|
||
Text("粉丝")
|
||
.font(.system(size: 11))
|
||
}
|
||
|
||
VStack {
|
||
Text("32")
|
||
.font(.system(size: 13))
|
||
Text("获赞与收藏")
|
||
.font(.system(size: 11))
|
||
}
|
||
|
||
Spacer()
|
||
|
||
Button {
|
||
|
||
} label: {
|
||
Text("编辑资料")
|
||
.font(.system(size: 14))
|
||
.padding(.vertical, 2)
|
||
.padding(.horizontal, 7)
|
||
.background(.white.opacity(0.2), in: RoundedRectangle(cornerRadius: 12))
|
||
}
|
||
|
||
Button {} label: {
|
||
Image(systemName: "ellipsis.circle")
|
||
.font(.system(size: 14))
|
||
.padding(.vertical, 2)
|
||
.padding(.horizontal, 7)
|
||
.background(.white.opacity(0.2), in: RoundedRectangle(cornerRadius: 12))
|
||
}
|
||
}
|
||
.foregroundStyle(.white)
|
||
.padding(.top, 12)
|
||
}
|
||
.padding(.horizontal, 12)
|
||
.padding(.top, 22)
|
||
.padding(.bottom, 8)
|
||
}
|
||
.padding(.bottom, 20)
|
||
.background(
|
||
Image("image-3")
|
||
.resizable()
|
||
.aspectRatio(contentMode: .fill)
|
||
.edgesIgnoringSafeArea(.top) // 确保图片覆盖到顶部安全区域
|
||
)
|
||
|
||
HStack(spacing: 35) {
|
||
Button {
|
||
tagActive = 0
|
||
let req = TargetMeReq(page: 1, page_size: 100, status: tagActive)
|
||
getTarget(req: req)
|
||
} label: {
|
||
Text("全部")
|
||
.foregroundStyle(tagActive == 0 ? .blue : .black)
|
||
}
|
||
|
||
Button {
|
||
tagActive = 2
|
||
let req = TargetMeReq(page: 1, page_size: 100, status: tagActive)
|
||
|
||
getTarget(req: req)
|
||
} label: {
|
||
Text("进行中")
|
||
.foregroundStyle(tagActive == 2 ? .blue : .black)
|
||
}
|
||
|
||
Button {
|
||
tagActive = 3
|
||
let req = TargetMeReq(page: 1, page_size: 100, status: tagActive)
|
||
getTarget(req: req)
|
||
} label: {
|
||
Text("已完成")
|
||
.foregroundStyle(tagActive == 3 ? .blue : .black)
|
||
}
|
||
Button {
|
||
tagActive = 4
|
||
let req = TargetMeReq(page: 1, page_size: 100, status: tagActive)
|
||
getTarget(req: req)
|
||
} label: {
|
||
Text("已逾期")
|
||
.foregroundStyle(tagActive == 4 ? .blue : .black)
|
||
}
|
||
}
|
||
.foregroundStyle(.black.opacity(0.6))
|
||
.padding(.vertical, 9)
|
||
|
||
// 内容部分
|
||
List(items){item in
|
||
TargetItemSwift(target: item)
|
||
}
|
||
}
|
||
.navigationDestination(isPresented: $showLoginView) {
|
||
LoginView() // 显示登录界面
|
||
}
|
||
.navigationViewStyle(StackNavigationViewStyle()) // 确保在 iPad 上正确显示
|
||
.toolbar(.hidden)
|
||
}
|
||
.onAppear {
|
||
viewModel.fetchUserProfile()
|
||
let req = TargetMeReq(page: 1, page_size: 100, status: tagActive)
|
||
getTarget(req: req)
|
||
}
|
||
|
||
}
|
||
|
||
func getTarget(req: TargetMeReq){
|
||
GetMeTargets(req: req){ (result: Result<HTTPBinResponse<TargetMeData>, AFError>) in
|
||
switch result {
|
||
case .success(let body):
|
||
items.removeAll()
|
||
if body.code == 0 {
|
||
body.data.list.forEach { T in
|
||
items.append(TargetData1(title: T.name, progress: T.progress, status_str: T.status_str, check: true, image: T.image))
|
||
}
|
||
} else {
|
||
print(body)
|
||
}
|
||
case .failure(let error):
|
||
debugPrint("Error: \(error)")
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
#Preview {
|
||
MineView()
|
||
}
|
||
|
||
|