// // CooperationAcquirerViewController.swift // suixinkan // import AVFoundation import SnapKit import UIKit /// 合作获客员页,对齐 Android `CooperationAcquirerScreen`。 final class CooperationAcquirerViewController: BaseViewController, UITableViewDataSource, UITableViewDelegate { private let viewModel = CooperationAcquirerViewModel() private let orderAPI = NetworkServices.shared.orderAPI private let tableView = UITableView(frame: .zero, style: .plain) private let refreshControl = UIRefreshControl() private let emptyLabel = UILabel() private var shouldRefreshOnAppear = false override func setupNavigationBar() { title = "合作获客员" navigationItem.rightBarButtonItem = UIBarButtonItem( title: "扫码绑定", style: .plain, target: self, action: #selector(startScanBind) ) navigationItem.rightBarButtonItem?.tintColor = AppColor.primary } override func setupUI() { tableView.backgroundColor = .clear tableView.separatorStyle = .none tableView.dataSource = self tableView.delegate = self tableView.register(CooperationAcquirerCell.self, forCellReuseIdentifier: CooperationAcquirerCell.reuseIdentifier) tableView.refreshControl = refreshControl emptyLabel.text = "暂无合作获客员" emptyLabel.font = .systemFont(ofSize: 14) emptyLabel.textColor = AppColor.textTertiary emptyLabel.textAlignment = .center emptyLabel.isHidden = true view.addSubview(tableView) view.addSubview(emptyLabel) } override func setupConstraints() { tableView.snp.makeConstraints { make in make.edges.equalTo(view.safeAreaLayoutGuide) } emptyLabel.snp.makeConstraints { make in make.center.equalTo(tableView) } } 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.onNavigateBindAcquirer = { [weak self] saleUserId in Task { @MainActor in self?.pushBindAcquirer(saleUserId: saleUserId) } } refreshControl.addTarget(self, action: #selector(refreshTriggered), for: .valueChanged) } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) guard CooperationOrderFeature.hasPermission(in: AppStore.shared.permissionItems()) else { showToast("暂无合作订单权限") navigationController?.popViewController(animated: false) return } if shouldRefreshOnAppear { shouldRefreshOnAppear = false Task { await viewModel.refresh(api: orderAPI) } } } override func viewDidLoad() { super.viewDidLoad() Task { showLoading() defer { hideLoading() } await viewModel.loadAcquirers(api: orderAPI, initial: true) } } @objc private func startScanBind() { switch AVCaptureDevice.authorizationStatus(for: .video) { case .authorized: presentScanner() case .notDetermined: AVCaptureDevice.requestAccess(for: .video) { [weak self] granted in Task { @MainActor in if granted { self?.presentScanner() } } } default: showToast("需要相机权限才能扫码") } } @objc private func refreshTriggered() { Task { await viewModel.refresh(api: orderAPI) } } private func presentScanner() { let scanner = QRCodeScannerViewController() scanner.onScanResult = { [weak self] result in self?.viewModel.processScanResult(result) } let nav = UINavigationController(rootViewController: scanner) nav.modalPresentationStyle = .fullScreen present(nav, animated: true) } private func pushBindAcquirer(saleUserId: Int) { let controller = BindAcquirerViewController(saleUserId: saleUserId) controller.onBindSuccess = { [weak self] in self?.shouldRefreshOnAppear = true self?.navigationController?.popViewController(animated: true) } if presentedViewController != nil { dismiss(animated: true) { [weak self] in self?.navigationController?.pushViewController(controller, animated: true) } return } navigationController?.pushViewController(controller, animated: true) } private func applyViewModel() { if viewModel.isRefreshing { if !refreshControl.isRefreshing { refreshControl.beginRefreshing() } } else { refreshControl.endRefreshing() } emptyLabel.isHidden = !viewModel.acquirers.isEmpty || viewModel.isRefreshing tableView.reloadData() } private func presentRemarkDialog(for acquirer: CooperativeSalerEntity) { viewModel.startEditRemark(acquirer) let alert = UIAlertController(title: "修改备注", message: "最多\(CooperationOrderFeature.remarkNameMaxLength)个字符", preferredStyle: .alert) alert.addTextField { [weak self] field in field.text = self?.viewModel.remarkDraft } alert.addAction(UIAlertAction(title: "取消", style: .cancel) { [weak self] _ in self?.viewModel.dismissRemarkDialog() }) alert.addAction(UIAlertAction(title: "保存", style: .default) { [weak self] _ in guard let self else { return } if let text = alert.textFields?.first?.text { self.viewModel.updateRemarkDraft(text) } Task { await self.viewModel.saveRemark(api: self.orderAPI) } }) present(alert, animated: true) } private func presentCommissionDialog(for acquirer: CooperativeSalerEntity) { viewModel.startEditCommissionRate(acquirer) let alert = UIAlertController(title: "修改分成比例", message: nil, preferredStyle: .alert) alert.addTextField { [weak self] field in field.placeholder = "分成比例 0-100" field.keyboardType = .numberPad field.text = self?.viewModel.commissionRateDraft } alert.addTextField { [weak self] field in field.placeholder = "验证码" field.keyboardType = .numberPad field.text = self?.viewModel.commissionSmsCodeDraft } let phone = acquirer.salerPhone.isEmpty ? acquirer.displayPhone : acquirer.salerPhone alert.message = "验证码将发送至 \(CooperationOrderPhoneMask.mask(phone))" alert.addAction(UIAlertAction(title: "取消", style: .cancel) { [weak self] _ in self?.viewModel.dismissCommissionRateDialog() }) alert.addAction(UIAlertAction(title: "获取验证码", style: .default) { [weak self] _ in guard let self else { return } if let rateText = alert.textFields?.first?.text { self.viewModel.updateCommissionRateDraft(rateText) } if let codeText = alert.textFields?.last?.text { self.viewModel.updateCommissionSmsCodeDraft(codeText) } Task { await self.viewModel.requestCommissionSmsCode(api: self.orderAPI) } }) alert.addAction(UIAlertAction(title: "确认修改", style: .default) { [weak self] _ in guard let self else { return } if let rateText = alert.textFields?.first?.text { self.viewModel.updateCommissionRateDraft(rateText) } if let codeText = alert.textFields?.last?.text { self.viewModel.updateCommissionSmsCodeDraft(codeText) } Task { await self.viewModel.saveCommissionRate(api: self.orderAPI) } }) present(alert, animated: true) } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { viewModel.acquirers.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell( withIdentifier: CooperationAcquirerCell.reuseIdentifier, for: indexPath ) as? CooperationAcquirerCell else { return UITableViewCell() } let acquirer = viewModel.acquirers[indexPath.row] cell.configure(with: acquirer) cell.onEditRemark = { [weak self] in self?.presentRemarkDialog(for: acquirer) } cell.onEditCommission = { [weak self] in self?.presentCommissionDialog(for: acquirer) } cell.onCall = { let phone = acquirer.displayPhone.trimmingCharacters(in: .whitespacesAndNewlines) guard !phone.isEmpty, let url = URL(string: "tel://\(phone)") else { return } UIApplication.shared.open(url) } return cell } }