292 lines
11 KiB
Swift
292 lines
11 KiB
Swift
//
|
||
// AccountSelectionViewController.swift
|
||
// suixinkan
|
||
//
|
||
|
||
import SnapKit
|
||
import UIKit
|
||
|
||
@MainActor
|
||
/// 多账号登录时的账号选择页,展示景区/门店账号列表并提交选择。
|
||
final class AccountSelectionViewController: UIViewController {
|
||
|
||
private let payload: AccountSelectionPayload
|
||
private var isLoading: Bool
|
||
private let onCancel: () -> Void
|
||
private let onConfirm: (AccountSwitchAccount) -> Void
|
||
|
||
private var selectedAccountId: String?
|
||
private let tableView = UITableView(frame: .zero, style: .plain)
|
||
private let confirmButton = UIButton(type: .system)
|
||
private let bottomBar = UIView()
|
||
|
||
init(
|
||
payload: AccountSelectionPayload,
|
||
isLoading: Bool,
|
||
onCancel: @escaping () -> Void,
|
||
onConfirm: @escaping (AccountSwitchAccount) -> Void
|
||
) {
|
||
self.payload = payload
|
||
self.isLoading = isLoading
|
||
self.onCancel = onCancel
|
||
self.onConfirm = onConfirm
|
||
super.init(nibName: nil, bundle: nil)
|
||
}
|
||
|
||
@available(*, unavailable)
|
||
required init?(coder: NSCoder) {
|
||
fatalError("init(coder:) has not been implemented")
|
||
}
|
||
|
||
override func viewDidLoad() {
|
||
super.viewDidLoad()
|
||
title = "选择账号"
|
||
view.backgroundColor = UIColor(hex: 0xF5F7FB)
|
||
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "取消", style: .plain, target: self, action: #selector(cancelTapped))
|
||
isModalInPresentation = isLoading
|
||
|
||
selectedAccountId = payload.accounts.first?.id
|
||
configureTableView()
|
||
configureBottomBar()
|
||
}
|
||
|
||
func updateLoading(_ loading: Bool) {
|
||
isLoading = loading
|
||
isModalInPresentation = loading
|
||
confirmButton.isEnabled = canConfirm
|
||
confirmButton.backgroundColor = canConfirm ? AppDesign.primary : UIColor(hex: 0xC9CED6)
|
||
}
|
||
|
||
private var selectedAccount: AccountSwitchAccount? {
|
||
payload.accounts.first { $0.id == selectedAccountId }
|
||
}
|
||
|
||
private var canConfirm: Bool {
|
||
selectedAccount != nil && !isLoading
|
||
}
|
||
|
||
private func configureTableView() {
|
||
tableView.backgroundColor = .clear
|
||
tableView.separatorStyle = .none
|
||
tableView.dataSource = self
|
||
tableView.delegate = self
|
||
tableView.register(AccountSelectionCell.self, forCellReuseIdentifier: AccountSelectionCell.reuseIdentifier)
|
||
view.addSubview(tableView)
|
||
tableView.snp.makeConstraints { make in
|
||
make.top.leading.trailing.equalToSuperview()
|
||
make.bottom.equalTo(view.safeAreaLayoutGuide).inset(90)
|
||
}
|
||
}
|
||
|
||
private func configureBottomBar() {
|
||
bottomBar.backgroundColor = .white
|
||
|
||
let divider = UIView()
|
||
divider.backgroundColor = UIColor.separator
|
||
|
||
confirmButton.setTitle("进入系统", for: .normal)
|
||
confirmButton.titleLabel?.font = .systemFont(ofSize: AppMetrics.FontSize.body, weight: .semibold)
|
||
confirmButton.setTitleColor(.white, for: .normal)
|
||
confirmButton.layer.cornerRadius = AppMetrics.CornerRadius.button
|
||
confirmButton.addTarget(self, action: #selector(confirmTapped), for: .touchUpInside)
|
||
updateLoading(isLoading)
|
||
|
||
view.addSubview(bottomBar)
|
||
bottomBar.addSubview(divider)
|
||
bottomBar.addSubview(confirmButton)
|
||
|
||
bottomBar.snp.makeConstraints { make in
|
||
make.leading.trailing.bottom.equalToSuperview()
|
||
}
|
||
|
||
divider.snp.makeConstraints { make in
|
||
make.top.leading.trailing.equalToSuperview()
|
||
make.height.equalTo(0.5)
|
||
}
|
||
|
||
confirmButton.snp.makeConstraints { make in
|
||
make.top.equalTo(divider.snp.bottom).offset(AppMetrics.Spacing.medium)
|
||
make.leading.trailing.equalToSuperview().inset(AppMetrics.Spacing.medium)
|
||
make.bottom.equalTo(view.safeAreaLayoutGuide).inset(AppMetrics.Spacing.medium)
|
||
make.height.equalTo(AppMetrics.ControlSize.primaryButtonHeight)
|
||
}
|
||
}
|
||
|
||
@objc private func cancelTapped() {
|
||
onCancel()
|
||
dismiss(animated: true)
|
||
}
|
||
|
||
@objc private func confirmTapped() {
|
||
guard let selectedAccount else { return }
|
||
onConfirm(selectedAccount)
|
||
}
|
||
}
|
||
|
||
extension AccountSelectionViewController: UITableViewDataSource, UITableViewDelegate {
|
||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||
payload.accounts.count
|
||
}
|
||
|
||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||
guard let cell = tableView.dequeueReusableCell(
|
||
withIdentifier: AccountSelectionCell.reuseIdentifier,
|
||
for: indexPath
|
||
) as? AccountSelectionCell else {
|
||
return UITableViewCell()
|
||
}
|
||
let account = payload.accounts[indexPath.row]
|
||
cell.configure(account: account, selected: account.id == selectedAccountId)
|
||
return cell
|
||
}
|
||
|
||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||
selectedAccountId = payload.accounts[indexPath.row].id
|
||
tableView.reloadData()
|
||
confirmButton.isEnabled = canConfirm
|
||
confirmButton.backgroundColor = canConfirm ? AppDesign.primary : UIColor(hex: 0xC9CED6)
|
||
}
|
||
}
|
||
|
||
/// 账号选择列表 Cell。
|
||
private final class AccountSelectionCell: UITableViewCell {
|
||
static let reuseIdentifier = "AccountSelectionCell"
|
||
|
||
private let avatarView = UIView()
|
||
private let avatarLabel = UILabel()
|
||
private let titleLabel = UILabel()
|
||
private let subtitleLabel = UILabel()
|
||
private let phoneLabel = UILabel()
|
||
private let typeTag = UILabel()
|
||
private let currentTag = UILabel()
|
||
private let checkmark = UIImageView()
|
||
|
||
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||
selectionStyle = .none
|
||
backgroundColor = .clear
|
||
contentView.backgroundColor = .white
|
||
contentView.layer.cornerRadius = AppMetrics.CornerRadius.button
|
||
contentView.layer.masksToBounds = true
|
||
|
||
avatarView.layer.cornerRadius = AppMetrics.ControlSize.primaryButtonHeight / 2
|
||
avatarLabel.font = .systemFont(ofSize: AppMetrics.FontSize.callout, weight: .semibold)
|
||
|
||
titleLabel.font = .systemFont(ofSize: AppMetrics.FontSize.body, weight: .semibold)
|
||
titleLabel.textColor = AppDesign.textPrimary
|
||
|
||
subtitleLabel.font = .systemFont(ofSize: AppMetrics.FontSize.footnote)
|
||
subtitleLabel.textColor = AppDesign.textSecondary
|
||
|
||
phoneLabel.font = .systemFont(ofSize: AppMetrics.FontSize.caption)
|
||
phoneLabel.textColor = UIColor(hex: 0x9AA1AA)
|
||
|
||
typeTag.font = .systemFont(ofSize: 11, weight: .semibold)
|
||
typeTag.textAlignment = .center
|
||
typeTag.layer.cornerRadius = AppMetrics.Spacing.xxSmall
|
||
typeTag.clipsToBounds = true
|
||
|
||
currentTag.font = .systemFont(ofSize: 11, weight: .semibold)
|
||
currentTag.textAlignment = .center
|
||
currentTag.text = "当前"
|
||
currentTag.textColor = AppDesign.primary
|
||
currentTag.backgroundColor = AppDesign.primarySoft
|
||
currentTag.layer.cornerRadius = AppMetrics.Spacing.xxSmall
|
||
currentTag.clipsToBounds = true
|
||
currentTag.isHidden = true
|
||
|
||
checkmark.contentMode = .scaleAspectFit
|
||
|
||
contentView.addSubview(avatarView)
|
||
avatarView.addSubview(avatarLabel)
|
||
contentView.addSubview(titleLabel)
|
||
contentView.addSubview(subtitleLabel)
|
||
contentView.addSubview(phoneLabel)
|
||
contentView.addSubview(typeTag)
|
||
contentView.addSubview(currentTag)
|
||
contentView.addSubview(checkmark)
|
||
|
||
avatarView.snp.makeConstraints { make in
|
||
make.leading.equalToSuperview().inset(AppMetrics.FontSize.subheadline)
|
||
make.centerY.equalToSuperview()
|
||
make.width.height.equalTo(AppMetrics.ControlSize.primaryButtonHeight)
|
||
}
|
||
|
||
avatarLabel.snp.makeConstraints { make in
|
||
make.center.equalToSuperview()
|
||
}
|
||
|
||
titleLabel.snp.makeConstraints { make in
|
||
make.top.equalToSuperview().inset(AppMetrics.FontSize.subheadline)
|
||
make.leading.equalTo(avatarView.snp.trailing).offset(AppMetrics.FontSize.footnote)
|
||
make.trailing.lessThanOrEqualTo(checkmark.snp.leading).offset(-8)
|
||
}
|
||
|
||
currentTag.snp.makeConstraints { make in
|
||
make.leading.equalTo(titleLabel.snp.trailing).offset(AppMetrics.Spacing.xSmall)
|
||
make.centerY.equalTo(titleLabel)
|
||
make.height.equalTo(AppMetrics.Spacing.sheet)
|
||
}
|
||
|
||
subtitleLabel.snp.makeConstraints { make in
|
||
make.top.equalTo(titleLabel.snp.bottom).offset(AppMetrics.Spacing.xxSmall)
|
||
make.leading.equalTo(titleLabel)
|
||
make.trailing.equalTo(checkmark.snp.leading).offset(-8)
|
||
}
|
||
|
||
phoneLabel.snp.makeConstraints { make in
|
||
make.top.equalTo(subtitleLabel.snp.bottom).offset(AppMetrics.Spacing.xxSmall)
|
||
make.leading.equalTo(titleLabel)
|
||
make.bottom.equalToSuperview().inset(AppMetrics.FontSize.subheadline)
|
||
}
|
||
|
||
typeTag.snp.makeConstraints { make in
|
||
make.trailing.equalTo(checkmark.snp.leading).offset(-AppMetrics.Spacing.xSmall)
|
||
make.top.equalTo(titleLabel)
|
||
make.height.equalTo(AppMetrics.Spacing.sheet)
|
||
}
|
||
|
||
checkmark.snp.makeConstraints { make in
|
||
make.trailing.equalToSuperview().inset(AppMetrics.FontSize.subheadline)
|
||
make.centerY.equalToSuperview()
|
||
make.width.height.equalTo(AppMetrics.ControlSize.passwordIcon)
|
||
}
|
||
}
|
||
|
||
required init?(coder: NSCoder) {
|
||
nil
|
||
}
|
||
|
||
func configure(account: AccountSwitchAccount, selected: Bool) {
|
||
titleLabel.text = account.title.isEmpty ? account.accountTypeLabel : account.title
|
||
subtitleLabel.text = account.subtitle
|
||
subtitleLabel.isHidden = account.subtitle.isEmpty
|
||
phoneLabel.text = account.phone
|
||
phoneLabel.isHidden = account.phone.isEmpty
|
||
currentTag.isHidden = !account.isCurrent
|
||
|
||
if account.isStoreUser {
|
||
avatarView.backgroundColor = UIColor(hex: 0xE8F8F1)
|
||
avatarLabel.text = "店"
|
||
avatarLabel.textColor = UIColor(hex: 0x0F9F6E)
|
||
typeTag.text = " 门店 "
|
||
typeTag.textColor = UIColor(hex: 0x0F9F6E)
|
||
typeTag.backgroundColor = UIColor(hex: 0xE8F8F1)
|
||
} else {
|
||
avatarView.backgroundColor = UIColor(hex: 0xF3ECFF)
|
||
avatarLabel.text = "景"
|
||
avatarLabel.textColor = UIColor(hex: 0x7C3AED)
|
||
typeTag.text = " 景区 "
|
||
typeTag.textColor = UIColor(hex: 0x7C3AED)
|
||
typeTag.backgroundColor = UIColor(hex: 0xF3ECFF)
|
||
}
|
||
|
||
let symbolName = selected ? "checkmark.circle.fill" : "circle"
|
||
checkmark.image = UIImage(systemName: symbolName)
|
||
checkmark.tintColor = selected ? AppDesign.primary : UIColor(hex: 0xB6BECA)
|
||
|
||
contentView.layer.borderWidth = selected ? 1.4 : 1
|
||
contentView.layer.borderColor = (selected ? AppDesign.primary : UIColor(hex: 0xE6ECF4)).cgColor
|
||
}
|
||
}
|