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>
This commit is contained in:
2026-07-07 11:09:27 +08:00
parent 2bea05b1d9
commit 77fec21563
22 changed files with 2202 additions and 216 deletions

View File

@ -16,6 +16,9 @@ final class CooperationOrderListViewController: BaseViewController, UITableViewD
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
@ -42,6 +45,15 @@ final class CooperationOrderListViewController: BaseViewController, UITableViewD
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
@ -51,6 +63,7 @@ final class CooperationOrderListViewController: BaseViewController, UITableViewD
view.addSubview(tabBarView)
view.addSubview(searchBar)
view.addSubview(tableView)
view.addSubview(loadingIndicator)
view.addSubview(emptyLabel)
}
@ -67,6 +80,9 @@ final class CooperationOrderListViewController: BaseViewController, UITableViewD
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)
}
@ -114,10 +130,7 @@ final class CooperationOrderListViewController: BaseViewController, UITableViewD
}
@objc private func refreshTriggered() {
Task {
await viewModel.refreshCurrentTab(api: orderAPI)
refreshControl.endRefreshing()
}
Task { await viewModel.refreshCurrentTab(api: orderAPI) }
}
private func applyViewModel() {
@ -130,10 +143,42 @@ final class CooperationOrderListViewController: BaseViewController, UITableViewD
searchBar.textField.text = viewModel.searchText
let isEmpty = viewModel.selectedTab == 0 ? viewModel.leads.isEmpty : viewModel.orders.isEmpty
emptyLabel.isHidden = !isEmpty || viewModel.isRefreshing
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
}