Files
suixinkan_uikit/suixinkan/UI/CooperationOrder/CooperationOrderListViewController.swift
汉秋 77fec21563 Add scenic application flow aligned with Android.
Implement scenic apply models, API, upload, UI, and tests; wire entry from permission apply pages and include related permission/scenic selection UI fixes.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-07 11:09:27 +08:00

216 lines
8.2 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.

//
// CooperationOrderListViewController.swift
// suixinkan
//
import SnapKit
import UIKit
/// Android `CooperationOrderListScreen`
final class CooperationOrderListViewController: BaseViewController, UITableViewDataSource, UITableViewDelegate {
private let viewModel = CooperationOrderListViewModel()
private let orderAPI = NetworkServices.shared.orderAPI
private let tabBarView = CooperationOrderTabBar()
private let searchBar = CooperationOrderSearchBar()
private let tableView = UITableView(frame: .zero, style: .plain)
private let refreshControl = UIRefreshControl()
private let loadingIndicator = UIActivityIndicatorView(style: .medium)
private let footerSpinner = UIActivityIndicatorView(style: .medium)
private let footerLabel = UILabel()
private let emptyLabel = UILabel()
private var isApplyingTab = false
override func setupNavigationBar() {
title = "合作订单"
navigationItem.rightBarButtonItem = UIBarButtonItem(
title: "合作获客员",
style: .plain,
target: self,
action: #selector(openAcquirer)
)
navigationItem.rightBarButtonItem?.tintColor = AppColor.primary
}
override func setupUI() {
view.backgroundColor = AppColor.pageBackground
searchBar.isHidden = true
tableView.backgroundColor = .clear
tableView.separatorStyle = .none
tableView.dataSource = self
tableView.delegate = self
tableView.register(ReferralLeadCell.self, forCellReuseIdentifier: ReferralLeadCell.reuseIdentifier)
tableView.register(AcquisitionOrderCell.self, forCellReuseIdentifier: AcquisitionOrderCell.reuseIdentifier)
tableView.refreshControl = refreshControl
loadingIndicator.hidesWhenStopped = true
loadingIndicator.color = AppColor.primary
footerSpinner.hidesWhenStopped = true
footerSpinner.color = AppColor.primary
footerLabel.font = .systemFont(ofSize: 14)
footerLabel.textColor = AppColor.textTertiary
footerLabel.textAlignment = .center
footerLabel.text = "没有更多"
emptyLabel.text = "暂无相关合作订单"
emptyLabel.font = .systemFont(ofSize: 14)
emptyLabel.textColor = AppColor.textTertiary
emptyLabel.textAlignment = .center
emptyLabel.isHidden = true
view.addSubview(tabBarView)
view.addSubview(searchBar)
view.addSubview(tableView)
view.addSubview(loadingIndicator)
view.addSubview(emptyLabel)
}
override func setupConstraints() {
tabBarView.snp.makeConstraints { make in
make.top.equalTo(view.safeAreaLayoutGuide)
make.leading.trailing.equalToSuperview()
}
searchBar.snp.makeConstraints { make in
make.top.equalTo(tabBarView.snp.bottom)
make.leading.trailing.equalToSuperview()
}
tableView.snp.makeConstraints { make in
make.top.equalTo(searchBar.snp.bottom)
make.leading.trailing.bottom.equalToSuperview()
}
loadingIndicator.snp.makeConstraints { make in
make.center.equalTo(tableView)
}
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) }
}
tabBarView.onTabSelected = { [weak self] index in
guard let self else { return }
self.viewModel.onTabSelected(index)
Task { await self.viewModel.refreshCurrentTab(api: self.orderAPI) }
}
searchBar.onSearchTextChange = { [weak self] text in
self?.viewModel.onSearchTextChange(text)
}
searchBar.onSearch = { [weak self] in
guard let self else { return }
Task { await self.viewModel.refreshAcquisitionOrders(api: self.orderAPI) }
}
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
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
Task { await viewModel.refreshCurrentTab(api: orderAPI) }
}
@objc private func openAcquirer() {
navigationController?.pushViewController(CooperationAcquirerViewController(), animated: true)
}
@objc private func refreshTriggered() {
Task { await viewModel.refreshCurrentTab(api: orderAPI) }
}
private func applyViewModel() {
if !isApplyingTab {
isApplyingTab = true
tabBarView.setSelectedTab(viewModel.selectedTab)
isApplyingTab = false
}
searchBar.isHidden = viewModel.selectedTab != 1
searchBar.textField.text = viewModel.searchText
let isEmpty = viewModel.selectedTab == 0 ? viewModel.leads.isEmpty : viewModel.orders.isEmpty
let isLoading = viewModel.isRefreshing && isEmpty
if viewModel.isRefreshing {
if !refreshControl.isRefreshing { refreshControl.beginRefreshing() }
} else {
refreshControl.endRefreshing()
}
if isLoading {
loadingIndicator.startAnimating()
emptyLabel.isHidden = true
tableView.tableFooterView = nil
} else {
loadingIndicator.stopAnimating()
emptyLabel.isHidden = !isEmpty
tableView.tableFooterView = tableFooterView(isEmpty: isEmpty)
}
tableView.reloadData()
}
private func tableFooterView(isEmpty: Bool) -> UIView? {
guard !isEmpty else { return nil }
if viewModel.isLoadingMore {
let container = UIView(frame: CGRect(x: 0, y: 0, width: tableView.bounds.width, height: 44))
footerSpinner.center = CGPoint(x: container.bounds.midX, y: container.bounds.midY)
footerSpinner.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin]
container.addSubview(footerSpinner)
footerSpinner.startAnimating()
return container
}
footerSpinner.stopAnimating()
guard !viewModel.canLoadMore else { return nil }
footerLabel.frame = CGRect(x: 0, y: 0, width: tableView.bounds.width, height: 44)
return footerLabel
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
viewModel.selectedTab == 0 ? viewModel.leads.count : viewModel.orders.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if viewModel.selectedTab == 0 {
guard let cell = tableView.dequeueReusableCell(
withIdentifier: ReferralLeadCell.reuseIdentifier,
for: indexPath
) as? ReferralLeadCell else {
return UITableViewCell()
}
cell.configure(with: viewModel.leads[indexPath.row])
cell.onImageTap = { [weak self] index, urls in
let preview = ImagePreviewViewController(imageURLs: urls, startIndex: index)
self?.present(preview, animated: true)
}
return cell
}
guard let cell = tableView.dequeueReusableCell(
withIdentifier: AcquisitionOrderCell.reuseIdentifier,
for: indexPath
) as? AcquisitionOrderCell else {
return UITableViewCell()
}
cell.configure(with: viewModel.orders[indexPath.row])
return cell
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
guard viewModel.shouldLoadMore(at: indexPath.row) else { return }
Task { await viewModel.loadMore(api: orderAPI) }
}
}