// // WildReportSupplementEvidenceViewController.swift // suixinkan // import SnapKit import UIKit /// 补充证据页面,允许为已有举报追加说明和 Mock 附件。 final class WildReportSupplementEvidenceViewController: BaseViewController { private let viewModel: WildReportSupplementEvidenceViewModel private let scrollView = UIScrollView() private let stack = UIStackView() private let textView = UITextView() private let submitButton = AppButton(title: "提交补充证据") init(reportID: String, homeViewModel: WildPhotographerReportHomeViewModel) { self.viewModel = WildReportSupplementEvidenceViewModel(reportID: reportID, homeViewModel: homeViewModel) super.init(nibName: nil, bundle: nil) } @available(*, unavailable) required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func setupNavigationBar() { title = "补充证据" } override func setupUI() { view.backgroundColor = AppColor.pageBackgroundSoft scrollView.keyboardDismissMode = .interactive stack.axis = .vertical stack.spacing = AppSpacing.sm textView.font = .app(.body) textView.textColor = AppColor.textPrimary textView.backgroundColor = AppColor.inputBackground textView.layer.cornerRadius = AppRadius.md textView.textContainerInset = UIEdgeInsets(top: 12, left: 10, bottom: 12, right: 10) textView.delegate = self submitButton.addTarget(self, action: #selector(submitTapped), for: .touchUpInside) view.addSubview(scrollView) scrollView.addSubview(stack) view.addSubview(submitButton) rebuildContent() } override func setupConstraints() { submitButton.snp.makeConstraints { make in make.leading.trailing.equalToSuperview().inset(AppSpacing.md) make.bottom.equalTo(view.safeAreaLayoutGuide).inset(AppSpacing.sm) } scrollView.snp.makeConstraints { make in make.top.leading.trailing.equalTo(view.safeAreaLayoutGuide) make.bottom.equalTo(submitButton.snp.top).offset(-AppSpacing.sm) } stack.snp.makeConstraints { make in make.edges.equalToSuperview().inset(UIEdgeInsets(top: AppSpacing.sm, left: AppSpacing.md, bottom: AppSpacing.lg, right: AppSpacing.md)) make.width.equalTo(scrollView.snp.width).offset(-AppSpacing.md * 2) } } override func bindActions() { viewModel.onStateChange = { [weak self] in Task { @MainActor in self?.rebuildContent() } } viewModel.onShowMessage = { [weak self] message in Task { @MainActor in self?.showToast(message) } } viewModel.onSubmitSuccess = { [weak self] in Task { @MainActor in self?.showToast("补充证据已提交") self?.navigationController?.popViewController(animated: true) } } } @MainActor private func rebuildContent() { stack.arrangedSubviews.forEach { view in stack.removeArrangedSubview(view) view.removeFromSuperview() } let textCard = WildReportCardView(spacing: AppSpacing.sm) textCard.stack.addArrangedSubview(WildReportUI.label("补充说明", font: .app(.title), color: AppColor.textPrimary)) textView.text = viewModel.text textCard.stack.addArrangedSubview(textView) textView.snp.makeConstraints { make in make.height.equalTo(150) } let count = WildReportUI.label("\(viewModel.text.count)/500", font: .app(.caption), color: AppColor.textTertiary) count.textAlignment = .right textCard.stack.addArrangedSubview(count) stack.addArrangedSubview(textCard) let attachmentCard = WildReportCardView(spacing: AppSpacing.sm) attachmentCard.stack.addArrangedSubview(WildReportUI.label("补充材料", font: .app(.title), color: AppColor.textPrimary)) let row = UIStackView() row.axis = .horizontal row.spacing = AppSpacing.sm row.distribution = .fillEqually let imageButton = WildReportUI.iconButton(title: "添加图片", imageName: "photo", style: .secondary) imageButton.addTarget(self, action: #selector(addImageTapped), for: .touchUpInside) let videoButton = WildReportUI.iconButton(title: "添加视频", imageName: "video", style: .secondary) videoButton.addTarget(self, action: #selector(addVideoTapped), for: .touchUpInside) [imageButton, videoButton].forEach { button in button.snp.makeConstraints { make in make.height.equalTo(44) } row.addArrangedSubview(button) } attachmentCard.stack.addArrangedSubview(row) (viewModel.images + viewModel.videos).forEach { attachment in let chip = WildReportAttachmentChipView(attachment: attachment) chip.onRemove = { [weak self] in self?.viewModel.removeAttachment(attachment) } attachmentCard.stack.addArrangedSubview(chip) } stack.addArrangedSubview(attachmentCard) } @objc private func addImageTapped() { viewModel.addImage() } @objc private func addVideoTapped() { viewModel.addVideo() } @objc private func submitTapped() { viewModel.submit() } } extension WildReportSupplementEvidenceViewController: UITextViewDelegate { func textViewDidChange(_ textView: UITextView) { viewModel.updateText(textView.text) } }