// // ContentView.swift // yana // // Created by P on 2025/4/21. // import SwiftUI import ComposableArchitecture // MARK: - API Response Models struct InitResponse: Codable, Equatable { let status: String let message: String? let data: InitData? } struct InitData: Codable, Equatable { let version: String? let timestamp: Int? let config: [String: String]? } // MARK: - Local UI Log Level Enum enum UILogLevel: String, CaseIterable { case none = "无日志" case basic = "基础日志" case detailed = "详细日志" } struct LoginTabView: View { let store: StoreOf let initStore: StoreOf @Binding var selectedLogLevel: APILogger.LogLevel var body: some View { VStack { // 日志级别选择器 VStack(alignment: .leading, spacing: 8) { Text("日志级别:") .font(.headline) .foregroundColor(.primary) Picker("日志级别", selection: $selectedLogLevel) { Text("无日志").tag(APILogger.LogLevel.none) Text("基础日志").tag(APILogger.LogLevel.basic) Text("详细日志").tag(APILogger.LogLevel.detailed) } .pickerStyle(SegmentedPickerStyle()) } .padding() .background(Color.gray.opacity(0.1)) .cornerRadius(10) Spacer() VStack(spacing: 20) { Text("eparty") .font(.largeTitle) .fontWeight(.bold) VStack(spacing: 15) { TextField("账号", text: Binding( get: { store.account }, set: { store.send(.updateAccount($0)) } )) .textFieldStyle(RoundedBorderTextFieldStyle()) .autocorrectionDisabled(true) SecureField("密码", text: Binding( get: { store.password }, set: { store.send(.updatePassword($0)) } )) .textFieldStyle(RoundedBorderTextFieldStyle()) } .padding(.horizontal) if let error = store.error { Text(error) .foregroundColor(.red) .font(.caption) .multilineTextAlignment(.center) .padding(.horizontal) } VStack(spacing: 10) { Button(action: { store.send(.login) }) { HStack { if store.isLoading { ProgressView() .scaleEffect(0.8) .progressViewStyle(CircularProgressViewStyle(tint: .white)) } Text(store.isLoading ? "登录中..." : "登录") } .frame(maxWidth: .infinity) .padding() .background(store.isLoading ? Color.gray : Color.blue) .foregroundColor(.white) .cornerRadius(10) } .disabled(store.isLoading || store.account.isEmpty || store.password.isEmpty) Button(action: { initStore.send(.initialize) }) { HStack { if initStore.isLoading { ProgressView() .scaleEffect(0.8) .progressViewStyle(CircularProgressViewStyle(tint: .white)) } Text(initStore.isLoading ? "测试中..." : "测试初始化") } .frame(maxWidth: .infinity) .padding() .background(initStore.isLoading ? Color.gray : Color.green) .foregroundColor(.white) .cornerRadius(10) } .disabled(initStore.isLoading) if let response = initStore.response { VStack(alignment: .leading, spacing: 8) { HStack { Text("API 测试结果:") .font(.headline) .foregroundColor(.primary) } ScrollView { VStack(alignment: .leading, spacing: 4) { Text("状态: \(response.status)") if let message = response.message { Text("消息: \(message)") } if let data = response.data { Text("版本: \(data.version ?? "未知")") Text("时间戳: \(data.timestamp ?? 0)") if let config = data.config { Text("配置:") ForEach(Array(config.keys), id: \.self) { key in Text(" \(key): \(config[key] ?? "")") } } } } .font(.system(.caption, design: .monospaced)) .foregroundColor(.secondary) .frame(maxWidth: .infinity, alignment: .leading) .padding(8) .background(Color.gray.opacity(0.1)) .cornerRadius(8) } .frame(maxHeight: 200) } .padding() .background(Color.gray.opacity(0.05)) .cornerRadius(10) } if let error = initStore.error { Text(error) .foregroundColor(.red) .font(.caption) .multilineTextAlignment(.center) .padding() } } .padding(.horizontal) } Spacer() } .padding() } } struct ContentView: View { let store: StoreOf let initStore: StoreOf let configStore: StoreOf @State private var selectedLogLevel: APILogger.LogLevel = APILogger.logLevel @State private var selectedTab = 0 var body: some View { WithPerceptionTracking { TabView(selection: $selectedTab) { LoginTabView(store: store, initStore: initStore, selectedLogLevel: $selectedLogLevel) .tabItem { Label("登录", systemImage: "person.circle") } .tag(0) ConfigView(store: configStore) .tabItem { Label("API 测试", systemImage: "network") } .tag(1) } .onChange(of: selectedLogLevel) { APILogger.logLevel = selectedLogLevel } } } } #Preview { ContentView( store: Store( initialState: LoginFeature.State() ) { LoginFeature() }, initStore: Store( initialState: InitFeature.State() ) { InitFeature() }, configStore: Store( initialState: ConfigFeature.State() ) { ConfigFeature() } ) }