// // FeedbackViewController.swift // VenusKitto // // Created by Neoa on 2025/8/27. // import Foundation import UIKit final class VKWhistleBoardController: UIViewController { // MARK: - UI Elements // 问题描述部分 private let bx_wrap: UIView = { let view = UIView() view.translatesAutoresizingMaskIntoConstraints = false return view }() private let bx_bar: UIView = { let view = UIView() view.backgroundColor = UIColor(hex: "#FFE059") view.translatesAutoresizingMaskIntoConstraints = false return view }() private let bx_title: UILabel = { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false // 创建属性字符串 let mainString = "问题描述(必填)" let attributedString = NSMutableAttributedString(string: mainString) // 设置整体样式 attributedString.addAttributes([ .font: UIFont.systemFont(ofSize: 15), .foregroundColor: UIColor.black ], range: NSRange(location: 0, length: mainString.count)) // 将"(必填)"设置为红色 if let range = mainString.range(of: "(必填)") { let nsRange = NSRange(range, in: mainString) attributedString.addAttributes([ .foregroundColor: UIColor.red ], range: nsRange) } label.attributedText = attributedString return label }() private let bx_hint: UILabel = { let label = UILabel() label.text = "请尽量将问题描述详细" label.font = UIFont.boldSystemFont(ofSize: 14) label.textAlignment = .left label.textColor = .lightGray label.translatesAutoresizingMaskIntoConstraints = false return label }() private let bx_text: UITextView = { let textView = UITextView() textView.font = UIFont.systemFont(ofSize: 16) textView.text = "" textView.textColor = .lightGray textView.layer.borderWidth = 0.5 textView.layer.borderColor = UIColor.lightGray.cgColor textView.layer.cornerRadius = 4 textView.translatesAutoresizingMaskIntoConstraints = false return textView }() // 联系方式部分 private let cx_wrap: UIView = { let view = UIView() view.translatesAutoresizingMaskIntoConstraints = false return view }() private let cx_bar: UIView = { let view = UIView() view.backgroundColor = UIColor(hex: "#FFE059") view.translatesAutoresizingMaskIntoConstraints = false return view }() private let cx_title: UILabel = { let label = UILabel() label.text = "联系方式(选填)" label.font = UIFont.systemFont(ofSize: 15) label.textColor = .black label.translatesAutoresizingMaskIntoConstraints = false return label }() private let cx_hint: UILabel = { let label = UILabel() label.text = "请输入手机号或QQ号" label.font = UIFont.systemFont(ofSize: 14) label.textColor = .lightGray label.translatesAutoresizingMaskIntoConstraints = false return label }() private let cx_text: UITextView = { let textView = UITextView() textView.font = UIFont.systemFont(ofSize: 16) textView.text = "" textView.textColor = .lightGray textView.layer.borderWidth = 0.5 textView.layer.borderColor = UIColor.lightGray.cgColor textView.layer.cornerRadius = 4 textView.translatesAutoresizingMaskIntoConstraints = false return textView }() private let mx_commit: UIButton = { let button = UIButton(type: .system) button.setTitle("提交反馈", for: .normal) button.titleLabel?.font = UIFont.systemFont(ofSize: 16) button.setTitleColor(.black, for: .normal) button.backgroundColor = UIColor(hex: "#FFE059") button.layer.cornerRadius = 25 button.translatesAutoresizingMaskIntoConstraints = false return button }() // MARK: - Lifecycle override func viewDidLoad() { super.viewDidLoad() buildUI() wireConstraints() hookDelegates() installGestures() navigationItem.title = "意见反馈" navigationItem.leftBarButtonItem = UIBarButtonItem( image: UIImage(systemName: "chevron.left"), style: .plain, target: self, action: #selector(ax_back) ) navigationController?.navigationBar.tintColor = .black mx_commit.addTarget(self, action: #selector(ax_submit), for: .touchUpInside) } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) navigationController?.setNavigationBarHidden(false, animated: animated) } @objc private func ax_submit() { // 验证问题描述是否为空 if bx_text.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { vx_emit("请填写问题描述") return } // TODO: 在此处添加提交反馈的逻辑 vx_emit("提交成功") // 延迟后返回上一页 DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { self.navigationController?.popViewController(animated: true) } } private func vx_emit(_ message: String) { let toastLabel = UILabel() toastLabel.text = message toastLabel.font = UIFont.systemFont(ofSize: 14) toastLabel.textColor = .white toastLabel.backgroundColor = UIColor.black.withAlphaComponent(0.7) toastLabel.textAlignment = .center toastLabel.alpha = 0.0 toastLabel.layer.cornerRadius = 8 toastLabel.clipsToBounds = true toastLabel.translatesAutoresizingMaskIntoConstraints = false view.addSubview(toastLabel) NSLayoutConstraint.activate([ toastLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor), toastLabel.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -100), toastLabel.widthAnchor.constraint(equalToConstant: 160), toastLabel.heightAnchor.constraint(equalToConstant: 40) ]) UIView.animate(withDuration: 0.3) { toastLabel.alpha = 1.0 } completion: { _ in DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { UIView.animate(withDuration: 0.3) { toastLabel.alpha = 0.0 } completion: { _ in toastLabel.removeFromSuperview() } } } } // MARK: - Setup private func buildUI() { view.backgroundColor = .white // 添加主要视图组件 view.addSubview(bx_wrap) view.addSubview(bx_hint) view.addSubview(cx_wrap) view.addSubview(mx_commit) // 问题描述容器内的组件 bx_wrap.addSubview(bx_bar) bx_wrap.addSubview(bx_title) bx_wrap.addSubview(bx_text) // 联系方式容器内的组件 cx_wrap.addSubview(cx_bar) cx_wrap.addSubview(cx_title) cx_wrap.addSubview(cx_hint) cx_wrap.addSubview(cx_text) } private func wireConstraints() { // 问题描述容器 NSLayoutConstraint.activate([ bx_wrap.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20), bx_wrap.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16), bx_wrap.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16), ]) // 蓝色分割线 NSLayoutConstraint.activate([ bx_bar.leadingAnchor.constraint(equalTo: bx_wrap.leadingAnchor), bx_bar.topAnchor.constraint(equalTo: bx_title.topAnchor), bx_bar.bottomAnchor.constraint(equalTo: bx_title.bottomAnchor), bx_bar.widthAnchor.constraint(equalToConstant: 3), ]) // 问题描述标题和文本框 NSLayoutConstraint.activate([ bx_title.leadingAnchor.constraint(equalTo: bx_bar.trailingAnchor, constant: 8), bx_title.trailingAnchor.constraint(equalTo: bx_wrap.trailingAnchor), bx_title.topAnchor.constraint(equalTo: bx_wrap.topAnchor), bx_hint.leadingAnchor.constraint(equalTo: bx_title.leadingAnchor, constant: 0), bx_hint.topAnchor.constraint(equalTo: bx_title.bottomAnchor, constant: 8), bx_text.topAnchor.constraint(equalTo: bx_hint.bottomAnchor, constant: 8), bx_text.leadingAnchor.constraint(equalTo: bx_wrap.leadingAnchor, constant: 8), bx_text.trailingAnchor.constraint(equalTo: bx_wrap.trailingAnchor, constant: -8), bx_text.heightAnchor.constraint(equalToConstant: 150), bx_text.bottomAnchor.constraint(equalTo: bx_wrap.bottomAnchor), ]) // 联系方式容器 NSLayoutConstraint.activate([ cx_wrap.topAnchor.constraint(equalTo: bx_wrap.bottomAnchor), cx_wrap.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16), cx_wrap.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16), ]) // 蓝色分割线 NSLayoutConstraint.activate([ cx_bar.leadingAnchor.constraint(equalTo: cx_wrap.leadingAnchor), cx_bar.topAnchor.constraint(equalTo: cx_title.topAnchor), cx_bar.bottomAnchor.constraint(equalTo: cx_title.bottomAnchor), cx_bar.widthAnchor.constraint(equalToConstant: 3), ]) // 联系方式标题和文本框 NSLayoutConstraint.activate([ cx_title.leadingAnchor.constraint(equalTo: cx_bar.trailingAnchor, constant: 8), cx_title.trailingAnchor.constraint(equalTo: cx_wrap.trailingAnchor), cx_title.topAnchor.constraint(equalTo: cx_wrap.topAnchor, constant: 16), cx_hint.leadingAnchor.constraint(equalTo: cx_title.leadingAnchor, constant: 0), cx_hint.topAnchor.constraint(equalTo: cx_title.bottomAnchor, constant: 8), cx_text.topAnchor.constraint(equalTo: cx_hint.bottomAnchor, constant: 8), cx_text.leadingAnchor.constraint(equalTo: cx_wrap.leadingAnchor, constant: 8), cx_text.trailingAnchor.constraint(equalTo: cx_wrap.trailingAnchor, constant: -8), cx_text.heightAnchor.constraint(equalToConstant: 150), cx_text.bottomAnchor.constraint(equalTo: cx_wrap.bottomAnchor), ]) // 提交按钮 NSLayoutConstraint.activate([ mx_commit.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -50), mx_commit.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), mx_commit.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), mx_commit.heightAnchor.constraint(equalToConstant: 50) ]) } private func hookDelegates() { bx_text.delegate = self cx_text.delegate = self } private func installGestures() { let tapGesture = UITapGestureRecognizer(target: self, action: #selector(ax_hideKB)) view.addGestureRecognizer(tapGesture) } @objc private func ax_hideKB() { view.endEditing(true) } @objc private func ax_back() { if presentingViewController != nil { dismiss(animated: true, completion: nil) } else { navigationController?.popViewController(animated: true) } } } // MARK: - TextView Delegate extension VKWhistleBoardController: UITextViewDelegate { func textViewDidBeginEditing(_ textView: UITextView) { if textView.textColor == .lightGray { textView.text = nil textView.textColor = .black } } func textViewDidEndEditing(_ textView: UITextView) { if textView.text.isEmpty { textView.text = "" textView.textColor = .lightGray } } } // MARK: - TextField Delegate extension VKWhistleBoardController: UITextFieldDelegate { func textFieldShouldReturn(_ textField: UITextField) -> Bool { textField.resignFirstResponder() return true } } // Compatibility alias for legacy code typealias FeedbackViewController = VKWhistleBoardController