Upgrade scenic picker with search, location sorting, permission apply/status, and blocking home dialog; add cooperation order module and order source picker improvements with unit tests. Co-authored-by: Cursor <cursoragent@cursor.com>
197 lines
7.0 KiB
Swift
197 lines
7.0 KiB
Swift
//
|
||
// BindAcquirerViewController.swift
|
||
// suixinkan
|
||
//
|
||
|
||
import SnapKit
|
||
import UIKit
|
||
|
||
/// 接受邀请 / 绑定获客员页,对齐 Android `BindAcquirerScreen`。
|
||
final class BindAcquirerViewController: BaseViewController {
|
||
|
||
var onBindSuccess: (() -> Void)?
|
||
|
||
private let saleUserId: Int
|
||
private let viewModel = BindAcquirerViewModel()
|
||
private let orderAPI = NetworkServices.shared.orderAPI
|
||
|
||
private let scrollView = UIScrollView()
|
||
private let contentStack = UIStackView()
|
||
private let headerCard = UIView()
|
||
private let headerIcon = UIImageView()
|
||
private let headerTitleLabel = UILabel()
|
||
private let infoCard = UIView()
|
||
private let salerRow = CooperationInfoRowView(label: "获客员")
|
||
private let phoneRow = CooperationInfoRowView(label: "手机号")
|
||
private let commissionField = UITextField()
|
||
private let acceptButton = AppButton(title: "接受邀请")
|
||
private let loadingIndicator = UIActivityIndicatorView(style: .large)
|
||
private let bottomBar = UIView()
|
||
|
||
init(saleUserId: Int) {
|
||
self.saleUserId = saleUserId
|
||
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() {
|
||
contentStack.axis = .vertical
|
||
contentStack.spacing = AppSpacing.sm
|
||
|
||
headerCard.backgroundColor = AppColor.primary
|
||
headerCard.layer.cornerRadius = AppRadius.md
|
||
headerIcon.image = UIImage(systemName: "person.fill")
|
||
headerIcon.tintColor = .white
|
||
headerTitleLabel.text = "邀请信息"
|
||
headerTitleLabel.font = .systemFont(ofSize: 16, weight: .bold)
|
||
headerTitleLabel.textColor = .white
|
||
|
||
infoCard.backgroundColor = .white
|
||
infoCard.layer.cornerRadius = AppRadius.md
|
||
|
||
commissionField.placeholder = "请输入分账比例(0-100)"
|
||
commissionField.keyboardType = .numberPad
|
||
commissionField.borderStyle = .roundedRect
|
||
commissionField.font = .systemFont(ofSize: 15)
|
||
|
||
bottomBar.backgroundColor = .white
|
||
acceptButton.addTarget(self, action: #selector(acceptTapped), for: .touchUpInside)
|
||
|
||
loadingIndicator.hidesWhenStopped = true
|
||
loadingIndicator.color = AppColor.primary
|
||
|
||
view.addSubview(scrollView)
|
||
view.addSubview(bottomBar)
|
||
scrollView.addSubview(contentStack)
|
||
bottomBar.addSubview(acceptButton)
|
||
scrollView.addSubview(loadingIndicator)
|
||
|
||
contentStack.addArrangedSubview(headerCard)
|
||
contentStack.addArrangedSubview(infoCard)
|
||
|
||
headerCard.addSubview(headerIcon)
|
||
headerCard.addSubview(headerTitleLabel)
|
||
|
||
let infoStack = UIStackView(arrangedSubviews: [salerRow, phoneRow, commissionField])
|
||
infoStack.axis = .vertical
|
||
infoStack.spacing = AppSpacing.sm
|
||
infoCard.addSubview(infoStack)
|
||
infoStack.snp.makeConstraints { make in
|
||
make.edges.equalToSuperview().inset(AppSpacing.md)
|
||
}
|
||
|
||
headerIcon.snp.makeConstraints { make in
|
||
make.leading.equalToSuperview().offset(AppSpacing.md)
|
||
make.centerY.equalToSuperview()
|
||
make.size.equalTo(24)
|
||
}
|
||
headerTitleLabel.snp.makeConstraints { make in
|
||
make.leading.equalTo(headerIcon.snp.trailing).offset(AppSpacing.sm)
|
||
make.trailing.equalToSuperview().inset(AppSpacing.md)
|
||
make.top.bottom.equalToSuperview().inset(AppSpacing.md)
|
||
}
|
||
headerCard.snp.makeConstraints { make in
|
||
make.height.greaterThanOrEqualTo(56)
|
||
}
|
||
commissionField.snp.makeConstraints { make in
|
||
make.height.equalTo(44)
|
||
}
|
||
}
|
||
|
||
override func setupConstraints() {
|
||
bottomBar.snp.makeConstraints { make in
|
||
make.leading.trailing.bottom.equalToSuperview()
|
||
}
|
||
acceptButton.snp.makeConstraints { make in
|
||
make.edges.equalToSuperview().inset(AppSpacing.md)
|
||
}
|
||
scrollView.snp.makeConstraints { make in
|
||
make.top.leading.trailing.equalTo(view.safeAreaLayoutGuide)
|
||
make.bottom.equalTo(bottomBar.snp.top)
|
||
}
|
||
contentStack.snp.makeConstraints { make in
|
||
make.edges.equalToSuperview().inset(AppSpacing.md)
|
||
make.width.equalTo(scrollView.snp.width).offset(-AppSpacing.md * 2)
|
||
}
|
||
loadingIndicator.snp.makeConstraints { make in
|
||
make.center.equalTo(scrollView)
|
||
}
|
||
}
|
||
|
||
override func bindActions() {
|
||
viewModel.onStateChange = { [weak self] in
|
||
Task { @MainActor in self?.applyViewModel() }
|
||
}
|
||
viewModel.onShowMessage = { [weak self] message in
|
||
Task { @MainActor in self?.showToast(message) }
|
||
}
|
||
viewModel.onBindSuccess = { [weak self] in
|
||
Task { @MainActor in
|
||
if let callback = self?.onBindSuccess {
|
||
callback()
|
||
} else {
|
||
self?.navigationController?.popViewController(animated: true)
|
||
}
|
||
}
|
||
}
|
||
viewModel.onShouldPop = { [weak self] in
|
||
Task { @MainActor in self?.navigationController?.popViewController(animated: true) }
|
||
}
|
||
commissionField.addTarget(self, action: #selector(commissionChanged), for: .editingChanged)
|
||
}
|
||
|
||
override func viewWillAppear(_ animated: Bool) {
|
||
super.viewWillAppear(animated)
|
||
guard CooperationOrderFeature.hasPermission(in: AppStore.shared.permissionItems()) else {
|
||
showToast("暂无合作订单权限")
|
||
navigationController?.popViewController(animated: false)
|
||
return
|
||
}
|
||
}
|
||
|
||
override func viewDidLoad() {
|
||
super.viewDidLoad()
|
||
viewModel.initSaleUserId(saleUserId)
|
||
Task { await viewModel.loadInviteInfo(api: orderAPI) }
|
||
}
|
||
|
||
@objc private func commissionChanged() {
|
||
viewModel.updateCommissionRateDraft(commissionField.text ?? "")
|
||
}
|
||
|
||
@objc private func acceptTapped() {
|
||
Task { await viewModel.acceptBind(api: orderAPI) }
|
||
}
|
||
|
||
private func applyViewModel() {
|
||
if viewModel.isLoading, viewModel.inviteInfo == nil {
|
||
loadingIndicator.startAnimating()
|
||
contentStack.isHidden = true
|
||
bottomBar.isHidden = true
|
||
return
|
||
}
|
||
loadingIndicator.stopAnimating()
|
||
contentStack.isHidden = false
|
||
bottomBar.isHidden = false
|
||
|
||
if let info = viewModel.inviteInfo {
|
||
title = info.title.isEmpty ? "接受邀请" : info.title
|
||
salerRow.setValue(info.salerName.isEmpty ? "—" : info.salerName)
|
||
phoneRow.setValue(info.salerPhone.isEmpty ? "—" : info.salerPhone)
|
||
}
|
||
|
||
commissionField.text = viewModel.commissionRateDraft
|
||
commissionField.isEnabled = !viewModel.isAlreadyBound
|
||
acceptButton.isEnabled = !viewModel.isAlreadyBound
|
||
acceptButton.setTitle(viewModel.isAlreadyBound ? "已绑定获客员" : "接受邀请", for: .normal)
|
||
}
|
||
}
|