// // SettingsUserIssueView.swift // punchnet // // Created by 安礼成 on 2026/1/19. // import SwiftUI // MARK: - 用户反馈页面 (完整逻辑版) struct SettingsUserIssueView: View { @Environment(UserContext.self) var userContext: UserContext // 表单状态 @State private var account: String = "" @State private var text: String = "" // 交互状态 @State private var isSubmitting: Bool = false @State private var showSuccessToast: Bool = false var body: some View { ZStack { // 主滚动视图 ScrollView(.vertical, showsIndicators: false) { VStack(alignment: .leading, spacing: 24) { // 1. 头部标题 HStack(spacing: 12) { Image(systemName: "envelope.badge.fill") .foregroundColor(.blue) Text("用户反馈") .font(.system(size: 18, weight: .bold)) } .padding(.leading, 4) // 2. 输入表单区域 VStack(alignment: .leading, spacing: 20) { // 联系方式 VStack(alignment: .leading, spacing: 8) { Text("联系方式 (选填)") .font(.caption.bold()) .foregroundColor(.secondary) TextField("邮箱或用户名", text: $account) .textFieldStyle(.plain) .padding(10) .background(Color.primary.opacity(0.04)) .cornerRadius(8) } // 问题描述 (带 Placeholder 逻辑) VStack(alignment: .leading, spacing: 8) { Text("问题描述") .font(.caption.bold()) .foregroundColor(.secondary) ZStack(alignment: .topLeading) { if text.isEmpty { Text("请详细描述您遇到的问题...") .foregroundColor(.gray.opacity(0.5)) .padding(.horizontal, 12).padding(.vertical, 12) .font(.system(size: 14)) } TextEditor(text: $text) .font(.system(size: 14)) .scrollContentBackground(.hidden) // 移除原生白色背景 .padding(8) .background(Color.primary.opacity(0.04)) .cornerRadius(8) } .frame(minHeight: 160) } } .padding(20) .background(Color.primary.opacity(0.02)) .cornerRadius(12) .overlay(RoundedRectangle(cornerRadius: 12).stroke(Color.primary.opacity(0.05), lineWidth: 1)) // 3. 提交按钮 Button { Task { @MainActor in await self.submitFeedback() } } label: { HStack { if isSubmitting { ProgressView() .controlSize(.small).brightness(1) } else { Image(systemName: "paperplane.fill") } Text("发送反馈").fontWeight(.semibold) } .frame(maxWidth: .infinity) .padding(.vertical, 12) .background(text.isEmpty ? Color.gray : Color.blue) .foregroundColor(.white) .cornerRadius(10) } .buttonStyle(.plain) .disabled(text.isEmpty || isSubmitting) } .padding(32) .frame(maxWidth: 600, alignment: .leading) } .blur(radius: showSuccessToast ? 8 : 0) // 成功时背景模糊 .disabled(showSuccessToast) // 弹出时禁用底层交互 // 4. 成功提示 Overlay if showSuccessToast { successPopup } } } // MARK: - 提交逻辑 private func submitFeedback() async { withAnimation { isSubmitting = true } var params: [String: Any] = [ "access_token": self.userContext.networkSession?.accessToken ?? "", "contact": self.account, "platform": SystemConfig.systemInfo, "content": self.text, "client_id": SystemConfig.getClientId(), "mac": SystemConfig.macAddressString(mac: SystemConfig.getMacAddress()) ] do { _ = try await SDLAPIClient.doPost(path: "/app/issue", params: params, as: String.self) } catch let err as SDLAPIError { } catch let err { } // 模拟网络延迟 DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { withAnimation(.spring(response: 0.4, dampingFraction: 0.7)) { isSubmitting = false showSuccessToast = true text = "" // 清空表单 } // 2.5秒后自动关闭弹窗 DispatchQueue.main.asyncAfter(deadline: .now() + 2.5) { withAnimation(.easeOut(duration: 0.3)) { showSuccessToast = false } } } } // MARK: - 成功弹窗视图 private var successPopup: some View { VStack(spacing: 16) { Image(systemName: "checkmark.seal.fill") .font(.system(size: 44)) .foregroundStyle(.green.gradient) Text("发送成功") .font(.headline) Text("感谢您的支持!") .font(.subheadline) .foregroundColor(.secondary) } .padding(40) .background(.ultraThinMaterial) // macOS 磨砂质感 .cornerRadius(24) .shadow(color: .black.opacity(0.15), radius: 20) .transition(.asymmetric( insertion: .scale(scale: 0.8).combined(with: .opacity), removal: .opacity.combined(with: .scale(scale: 1.1)) )) } }