// // SessionExpiredDialogViewController.swift // suixinkan // import SnapKit import UIKit /// 登录凭证失效时展示的强制确认弹窗,用户确认后由调用方执行退出登录。 @MainActor final class SessionExpiredDialogViewController: UIViewController { private let onConfirm: () -> Void private let confirmButton = AppButton(title: "确认并退出登录") private var didConfirm = false /// 创建不可通过点击遮罩关闭的登录失效弹窗。 init(onConfirm: @escaping () -> Void) { self.onConfirm = onConfirm super.init(nibName: nil, bundle: nil) modalPresentationStyle = .overFullScreen modalTransitionStyle = .crossDissolve isModalInPresentation = true } @available(*, unavailable) required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() setupUI() } private func setupUI() { view.backgroundColor = UIColor.black.withAlphaComponent(0.32) view.accessibilityViewIsModal = true view.accessibilityIdentifier = "sessionExpired.dialog" let cardView = UIView() cardView.backgroundColor = AppColor.cardBackground cardView.layer.cornerRadius = AppRadius.lg cardView.clipsToBounds = true let warningImageView = UIImageView( image: UIImage(systemName: "exclamationmark.circle.fill") ) warningImageView.tintColor = UIColor(hex: 0xF05A5A) warningImageView.contentMode = .scaleAspectFit warningImageView.isAccessibilityElement = true warningImageView.accessibilityLabel = "登录状态异常" let titleLabel = UILabel() titleLabel.text = "登录提醒" titleLabel.textColor = AppColor.textPrimary titleLabel.font = .systemFont(ofSize: 20, weight: .semibold) titleLabel.textAlignment = .center let messageLabel = UILabel() messageLabel.text = "当前用户已在其他设备登录,\n请重新登录" messageLabel.textColor = UIColor(hex: 0x4B5563) messageLabel.font = .systemFont(ofSize: 14) messageLabel.textAlignment = .center messageLabel.numberOfLines = 0 confirmButton.accessibilityIdentifier = "sessionExpired.confirmButton" confirmButton.addTarget(self, action: #selector(confirmTapped), for: .touchUpInside) let contentStack = UIStackView(arrangedSubviews: [ warningImageView, titleLabel, messageLabel, confirmButton, ]) contentStack.axis = .vertical contentStack.alignment = .fill contentStack.spacing = 16 contentStack.setCustomSpacing(4, after: titleLabel) contentStack.setCustomSpacing(20, after: messageLabel) view.addSubview(cardView) cardView.addSubview(contentStack) cardView.snp.makeConstraints { make in make.center.equalToSuperview() make.leading.trailing.equalToSuperview().inset(32) } contentStack.snp.makeConstraints { make in make.edges.equalToSuperview().inset(24) } warningImageView.snp.makeConstraints { make in make.height.equalTo(64) } } @objc private func confirmTapped() { guard !didConfirm else { return } didConfirm = true confirmButton.isEnabled = false onConfirm() } }