Files
UUVPN/iOS-SwiftUI-Code/XiaoXiong/DefaultUI/View/InviteListView.swift
T
2025-01-28 12:28:03 +08:00

392 lines
14 KiB
Swift

//
// InviteListView.swift
// SFI
//
// Created by Mac on 2024/10/21.
//
import Foundation
import SwiftUI
import ApplicationLibrary
//InviteListView
struct InviteListView : View{
@Binding var isPresented: Bool
@State private var codeslist: [InviteCode] = []
@State private var isLoading = false
@State private var errorMessage: String?
@State private var alert: Alert?
@State private var stat: [Int]?
@Environment(\.openURL) private var openURL
@Environment(\.presentationMode) var presentationMode // 环境变量用于控制视图的呈现
var body: some View {
NavigationView(content: {
VStack {
// Navigation Bar
ZStack{
HStack{
Button(action: {
isPresented = false
presentationMode.wrappedValue.dismiss() // 手动触发返回
}, label: {
Image(systemName: "chevron.left")
.foregroundColor(.white)
Text("返回")
.foregroundColor(.white)
}).padding(10) // 增加可点击区域
Spacer()
Button(action: {
Task{
await genoneInvite()
}
}, label: {
Text("生成邀请码").foregroundColor(.white)
})
}
Spacer()
VStack(spacing: 5){
Text("我的邀请")
.fontWeight(.bold).lineLimit(1).frame(width: UIScreen.main.bounds.width*0.5)
}
.foregroundColor(.white)
Spacer()
}
.padding(.all)
if isLoading {
ProgressView()
.progressViewStyle(CircularProgressViewStyle())
.padding()
}
if let errorMessage = errorMessage {
Text(errorMessage)
.bold()
.foregroundColor(.red)
.multilineTextAlignment(.center) // 确保多行文本居中
.padding()
}
//
// // Subscription Plans
ScrollView(.vertical, showsIndicators: false) {
VStack(spacing: 16) {
VStack {
LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: 2), alignment: .leading) {
if let st = stat {
StatusItem("邀请注册人数") {
StatusLine("人数", "\(st[0])")
}
StatusItem("邀请佣金比例") {
StatusLine("比例", "\(st[3])%")
}
StatusItem("确认中的佣金") {
StatusLine("金额(¥)", "\(st[1])")
}
StatusItem("累计获得佣金") {
StatusLine("金额(¥)", "\(st[2])")
}
}
}.background {
GeometryReader { geometry in
Rectangle()
.fill(.clear)
.frame(height: 1)
.onChangeCompat(of: geometry.size.width) { newValue in
//updateColumnCount(newValue)
}
.onAppear {
// updateColumnCount(geometry.size.width)
}
}.padding()
}
}
.frame(alignment: .topLeading)
.padding([.top, .leading, .trailing])
if codeslist.isEmpty {
// Text("Loading plans...") // Loading indicator
if !isLoading
{
Text("暂无记录").font(.caption)
.foregroundColor(.gray)
.multilineTextAlignment(.center) // 确保多行文本居中
.padding()
}
} else {
ForEach(codeslist) { plan in
Button(action: {
UIPasteboard.general.string = UserManager.shared.mainregisterURL()+plan.code
alert = Alert(okMessage: "复制成功: " + UserManager.shared.mainregisterURL()+plan.code )
}, label: {
InviteItemView(invicode: plan)
})
}
}
}
}.padding(.top, 20)
Spacer()
// Subscription Notice
Text(" ")
.font(.footnote)
.foregroundColor(.gray)
.padding(.bottom, 20)
}
.background(
LinearGradient(colors: [
Color("BG1"),
Color("BG1"),
Color("BG2"),
Color("BG2"),
], startPoint: .top, endPoint: .bottom)
)
.navigationBarHidden(true)
// .background(.white)
.onAppear(){
Task{
await getCodesList()
}
}.edgesIgnoringSafeArea(.bottom)
})
.navigationBarHidden(true)
.navigationBarBackButtonHidden(true) // 隐藏返回按钮
.alertBinding($alert)
}
public func genoneInvite() async {
let userInfoUrl = URL(string: "\(UserManager.shared.baseURL())user/invite/save")!
var request = URLRequest(url: userInfoUrl)
request.httpMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue(UserManager.shared.getAutoData(), forHTTPHeaderField: "Authorization")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
DispatchQueue.main.async {
if let error = error {
alert = Alert(error)
return
}
guard let data = data else {
return
}
struct InviteReponse2: Codable {
let status, message: String?
}
// Parse the user info response
if let response = try? JSONDecoder().decode(InviteReponse2.self, from: data),let message = response.message {
if let status = response.status, status == "success" {
alert = Alert(okMessage: message){
Task{
await getCodesList()
}
}
}else{
alert = Alert(errorMessage: message)
}
}
}
}
task.resume()
}
private struct StatusLine: View {
private let name: String
private let value: String
init(_ name: String, _ value: String) {
self.name = name
self.value = value
}
var body: some View {
HStack {
Text(name)
.font(.subheadline)
.foregroundColor(.secondary)
Spacer()
Text(value)
.font(.subheadline)
}
}
}
private struct StatusItem<T>: View where T: View {
private let title: String
@ViewBuilder private let content: () -> T
init(_ title: String, @ViewBuilder content: @escaping () -> T) {
self.title = title
self.content = content
}
var body: some View {
VStack(alignment: .leading) {
HStack {
Text(title)
.font(.subheadline)
Spacer()
}.padding(.bottom, 8)
content()
}
.frame(minWidth: 125, alignment: .topLeading)
#if os(tvOS)
.padding(EdgeInsets(top: 20, leading: 26, bottom: 20, trailing: 26))
#else
.padding(EdgeInsets(top: 10, leading: 13, bottom: 10, trailing: 13))
#endif
.background(backgroundColor.opacity(0.3))
.cornerRadius(10)
}
private var backgroundColor: Color {
#if os(iOS)
return Color(.gray)
#elseif os(macOS)
return Color(nsColor: .textBackgroundColor)
#elseif os(tvOS)
return Color(uiColor: .black)
#endif
}
}
public func getCodesList() async {
isLoading = true
errorMessage = nil
let userInfoUrl = URL(string: "\(UserManager.shared.baseURL())user/invite/fetch")!
var request = URLRequest(url: userInfoUrl)
request.httpMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue(UserManager.shared.getAutoData(), forHTTPHeaderField: "Authorization")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
DispatchQueue.main.async {
self.isLoading = false
if let error = error {
self.errorMessage = "数据请求失败: \(error.localizedDescription)"
return
}
guard let data = data else {
self.errorMessage = "数据请求失败"
return
}
// if let jsonString = String(data: data, encoding: .utf8) {
// print("Response data: \(jsonString)")
// } else {
// print("Failed to convert data to string.")
// }
//
// Parse the user info response
if let Subscribe = try? JSONDecoder().decode(InviteReponse.self, from: data) {
if let codes = Subscribe.data?.codes {
codeslist = codes
stat = Subscribe.data?.stat
}else{
self.errorMessage = Subscribe.message ?? ""
}
}else{
self.errorMessage = "数据请求失败: JSON 解析错误"
}
}
}
task.resume()
}
}
struct InviteItemView: View {
var invicode : InviteCode
var body: some View {
HStack {
VStack(alignment: .leading, spacing: 4) {
Text("邀请码:" + invicode.code )
.font(.headline)
.foregroundColor(.black).multilineTextAlignment(.leading)
.frame(maxWidth: .infinity)
Spacer()
Text("创建时间:"+TimestampConverter.convertTimestampToDateString(invicode.createdAt))
.font(.caption)
.fontWeight(.bold)
.padding(2)
.frame(maxWidth: .infinity)
.foregroundColor(.gray)
// .offset(x: -16, y:16)
.offset(y:10)
}
}
.padding()
.background(Color.white)
.cornerRadius(10)
.shadow(color: Color.black.opacity(0.1), radius: 5, x: 0, y: 3)
.padding(.horizontal, 20)
}
}