Files
suixinkan_uikit/suixinkan/UI/MessageCenter/MessageDetailViewController.swift
汉秋 6336feff27 完善景区排队设置页与全局按钮配置迁移。
重构排队设置与变更日志交互,补充 Overlay 与资源,并将多页面主操作按钮统一到 UIButton Configuration,同步更新相关单元测试。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-14 16:21:53 +08:00

170 lines
6.1 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// MessageDetailViewController.swift
// suixinkan
//
import SnapKit
import UIKit
/// Android `MsgDetailScreen`
final class MessageDetailViewController: BaseViewController {
var onDeleted: ((Int) -> Void)?
private let viewModel: MessageDetailViewModel
private let api: any MessageCenterServing
private let scrollView = UIScrollView()
private let contentView = UIView()
private let typeImageView = UIImageView()
private let titleLabel = UILabel()
private let timeContainer = UIView()
private let timeLabel = UILabel()
private let bodyLabel = UILabel()
private let bottomBar = UIView()
private let deleteButton = UIButton(type: .system)
///
init(message: MessageItem, api: (any MessageCenterServing)? = nil) {
viewModel = MessageDetailViewModel(message: message)
self.api = api ?? NetworkServices.shared.messageCenterAPI
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 = .white
typeImageView.contentMode = .scaleAspectFit
typeImageView.image = UIImage(named: MessageTypeIcon.assetName(for: viewModel.message.type))
titleLabel.text = viewModel.message.displayTitle
titleLabel.font = .systemFont(ofSize: 20, weight: .bold)
titleLabel.textColor = .black
titleLabel.textAlignment = .center
titleLabel.numberOfLines = 0
timeContainer.backgroundColor = UIColor(hex: 0xF4F4F4)
timeContainer.layer.cornerRadius = 4
timeContainer.clipsToBounds = true
timeLabel.text = viewModel.message.createdAt
timeLabel.font = .systemFont(ofSize: 12)
timeLabel.textColor = UIColor(hex: 0x4B5563)
timeLabel.textAlignment = .center
timeLabel.numberOfLines = 1
bodyLabel.text = viewModel.message.content
bodyLabel.font = .systemFont(ofSize: 16)
bodyLabel.textColor = .black
bodyLabel.numberOfLines = 0
bodyLabel.textAlignment = .left
bottomBar.backgroundColor = .white
deleteButton.setTitle("删除并返回", for: .normal)
deleteButton.setTitleColor(.white, for: .normal)
deleteButton.titleLabel?.font = .systemFont(ofSize: 16)
deleteButton.backgroundColor = UIColor(hex: 0xEF4444)
deleteButton.layer.cornerRadius = 8
deleteButton.clipsToBounds = true
view.addSubview(scrollView)
scrollView.addSubview(contentView)
[typeImageView, titleLabel, timeContainer, bodyLabel].forEach(contentView.addSubview)
timeContainer.addSubview(timeLabel)
view.addSubview(bottomBar)
bottomBar.addSubview(deleteButton)
}
override func setupConstraints() {
bottomBar.snp.makeConstraints { make in
make.leading.trailing.bottom.equalToSuperview()
}
deleteButton.snp.makeConstraints { make in
make.top.equalToSuperview().offset(16)
make.leading.trailing.equalToSuperview().inset(32)
make.height.equalTo(52)
make.bottom.equalTo(view.safeAreaLayoutGuide).inset(16)
}
scrollView.snp.makeConstraints { make in
make.top.leading.trailing.equalTo(view.safeAreaLayoutGuide)
make.bottom.equalTo(bottomBar.snp.top)
}
contentView.snp.makeConstraints { make in
make.edges.equalTo(scrollView.contentLayoutGuide)
make.width.equalTo(scrollView.frameLayoutGuide)
make.height.greaterThanOrEqualTo(scrollView.frameLayoutGuide)
}
typeImageView.snp.makeConstraints { make in
make.top.equalToSuperview().offset(32)
make.centerX.equalToSuperview()
make.size.equalTo(64)
}
titleLabel.snp.makeConstraints { make in
make.top.equalTo(typeImageView.snp.bottom).offset(8)
make.leading.trailing.equalToSuperview().inset(32)
}
timeContainer.snp.makeConstraints { make in
make.top.equalTo(titleLabel.snp.bottom).offset(8)
make.centerX.equalToSuperview()
}
timeLabel.snp.makeConstraints { make in
make.edges.equalToSuperview().inset(UIEdgeInsets(top: 2, left: 4, bottom: 2, right: 4))
}
bodyLabel.snp.makeConstraints { make in
make.top.equalTo(timeContainer.snp.bottom).offset(24)
make.leading.trailing.equalToSuperview().inset(32)
make.bottom.lessThanOrEqualToSuperview().inset(24)
}
}
override func bindActions() {
deleteButton.addTarget(self, action: #selector(deleteTapped), for: .touchUpInside)
viewModel.onStateChange = { [weak self] in
Task { @MainActor in
self?.applyState()
}
}
viewModel.onShowMessage = { [weak self] message in
Task { @MainActor in
self?.showToast(message)
}
}
viewModel.onDeleted = { [weak self] id in
Task { @MainActor in
self?.onDeleted?(id)
self?.navigationController?.popViewController(animated: true)
}
}
}
@objc private func deleteTapped() {
let alert = UIAlertController(title: "删除消息", message: "确定要删除这条消息吗?", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "取消", style: .cancel))
alert.addAction(UIAlertAction(title: "确认", style: .destructive) { [weak self] _ in
guard let self else { return }
Task { @MainActor in
await self.viewModel.delete(api: self.api)
}
})
present(alert, animated: true)
}
private func applyState() {
deleteButton.isEnabled = !viewModel.isDeleting
deleteButton.alpha = viewModel.isDeleting ? 0.65 : 1
if viewModel.isDeleting {
showLoading()
} else {
hideLoading()
}
}
}