189 lines
7.2 KiB
Swift
189 lines
7.2 KiB
Swift
//
|
|
// SettingsUserIssueView.swift
|
|
// punchnet
|
|
//
|
|
// Created by 安礼成 on 2026/1/19.
|
|
//
|
|
import SwiftUI
|
|
|
|
// MARK: - 用户反馈页面 (完整逻辑版)
|
|
struct SettingsUserIssueView: View {
|
|
@Environment(AppContext.self) var appContext: AppContext
|
|
|
|
// 表单状态
|
|
@State private var account: String = ""
|
|
@State private var text: String = ""
|
|
|
|
// 交互状态
|
|
@State private var isSubmitting: Bool = false
|
|
@State private var showSuccessToast: Bool = false
|
|
|
|
// 错误提示
|
|
@State private var showAlert: Bool = false
|
|
@State private var errorMessage: String = ""
|
|
|
|
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
|
|
}
|
|
}
|
|
.alert(isPresented: $showAlert) {
|
|
Alert(title: Text("提示"), message: Text(errorMessage))
|
|
}
|
|
}
|
|
|
|
// MARK: - 提交逻辑
|
|
private func submitFeedback() async {
|
|
withAnimation {
|
|
isSubmitting = true
|
|
}
|
|
|
|
let params: [String: Any] = [
|
|
"access_token": self.appContext.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)
|
|
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
|
|
}
|
|
}
|
|
} catch let err as SDLAPIError {
|
|
self.showAlert = true
|
|
self.errorMessage = err.message
|
|
} catch let err {
|
|
self.showAlert = true
|
|
self.errorMessage = err.localizedDescription
|
|
}
|
|
|
|
self.isSubmitting = 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))
|
|
))
|
|
}
|
|
}
|