Integrate CYLTabBar center scan button and unify UIKit navigation.
Add CYLTabBarController with a global scan entry, promote MainTabBarController to the window root after login, replace RouterPath-based navigation with AppNavigator, and fix Profile diffable cell reconfiguration crashes. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@ -8,7 +8,7 @@ Orders 模块负责登录后的订单 Tab。当前已覆盖订单管理、核销
|
||||
|
||||
## 核心对象
|
||||
|
||||
- `OrdersView`:订单 Tab 根视图,读取 `AccountContext`、`PermissionContext`、`AppRouter` 和 `OrdersAPI`。
|
||||
- `OrdersView`:订单 Tab 根视图,读取 `AccountContext`、`PermissionContext` 和 `OrdersAPI`,并接收 `AppNavigator` 传入的订单入口与扫码结果。
|
||||
- `OrdersViewModel`:管理订单子入口、筛选条件、分页状态、加载状态和手动核销状态。
|
||||
- `OrderDetailViewModel`:管理订单详情接口加载、错误提示和列表摘要兜底展示。
|
||||
- `DepositOrderListViewModel`:管理押金订单分页、核销、退款和操作后刷新。
|
||||
@ -44,6 +44,6 @@ Orders 模块负责登录后的订单 Tab。当前已覆盖订单管理、核销
|
||||
|
||||
## 路由边界
|
||||
|
||||
首页 `photographer_orders` 和 `/scenic-order-manage` 会进入订单管理,`verification_order` 会进入核销订单,`deposit_order_detail`、`deposit_order`、`deposit_order_shooting_info` 会进入押金订单页。订单详情、核销订单详情、押金详情、押金拍摄信息、历史拍摄、任务上传和订单尾片已接入 `AppRoute.orders` 真实路由,push 后继续隐藏 TabBar。
|
||||
首页 `photographer_orders` 和 `/scenic-order-manage` 会进入订单管理,`verification_order` 会进入核销订单,`deposit_order_detail`、`deposit_order`、`deposit_order_shooting_info` 会进入押金订单页。全局扫码和推送通知通过 `AppNavigator.openOrdersEntry` 切到订单 Tab root,再由 `OrdersViewController` 应用入口状态;订单卡片、核销卡片、押金详情、押金拍摄信息、历史拍摄、任务上传和订单尾片已接入 `AppRoute.orders` 真实路由,push 后继续隐藏 TabBar。
|
||||
|
||||
未明确接口的订单后续能力继续进入占位页,避免入口崩溃。
|
||||
|
||||
@ -96,7 +96,7 @@ final class DepositOrderListViewController: UIViewController, UITableViewDelegat
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: DepositOrderCell.reuseID, for: indexPath) as! DepositOrderCell
|
||||
cell.configure(item: orderItem, isOperating: self.viewModel.operatingOrderNumber == orderItem.orderNumber)
|
||||
cell.onDetail = { [weak self] in
|
||||
self.flatMap { HomeMenuRouting.pushOrders(.depositDetail(orderNumber: orderItem.orderNumber), from: $0) }
|
||||
self.flatMap { $0.appServices.appNavigator.push(.orders(.depositDetail(orderNumber: orderItem.orderNumber)), from: $0) }
|
||||
}
|
||||
cell.onWriteOff = { [weak self] in self?.writeOff(orderItem) }
|
||||
cell.onRefund = { [weak self] in self?.refund(orderItem) }
|
||||
@ -154,7 +154,7 @@ final class DepositOrderListViewController: UIViewController, UITableViewDelegat
|
||||
@objc private func openDetail() {
|
||||
let text = orderNumberField.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
||||
guard !text.isEmpty else { return }
|
||||
HomeMenuRouting.pushOrders(.depositDetail(orderNumber: text), from: self)
|
||||
appServices.appNavigator.push(.orders(.depositDetail(orderNumber: text)), from: self)
|
||||
}
|
||||
|
||||
/// 刷新。
|
||||
|
||||
@ -289,13 +289,13 @@ final class StoreOrderDetailViewController: UIViewController, UITableViewDelegat
|
||||
let orderNumber = viewModel.display.orderNumber
|
||||
switch index {
|
||||
case 0:
|
||||
HomeMenuRouting.pushOrders(.historicalShooting(orderNumber: orderNumber), from: self)
|
||||
appServices.appNavigator.push(.orders(.historicalShooting(orderNumber: orderNumber)), from: self)
|
||||
case 1 where item.orderType == 19:
|
||||
HomeMenuRouting.pushOrders(.multiTravelTaskUpload(orderNumber: orderNumber), from: self)
|
||||
appServices.appNavigator.push(.orders(.multiTravelTaskUpload(orderNumber: orderNumber)), from: self)
|
||||
case 2:
|
||||
HomeMenuRouting.pushOrders(.orderTrailer(orderNumber: orderNumber, title: "视频预告"), from: self)
|
||||
appServices.appNavigator.push(.orders(.orderTrailer(orderNumber: orderNumber, title: "视频预告")), from: self)
|
||||
case 3:
|
||||
HomeMenuRouting.pushOrders(.orderTrailer(orderNumber: orderNumber, title: "尾片上传"), from: self)
|
||||
appServices.appNavigator.push(.orders(.orderTrailer(orderNumber: orderNumber, title: "尾片上传")), from: self)
|
||||
case 4:
|
||||
presentRefund()
|
||||
default:
|
||||
|
||||
@ -37,6 +37,7 @@ final class OrdersViewController: UIViewController {
|
||||
private let viewModel = OrdersViewModel()
|
||||
private var manualOrderNumber = ""
|
||||
private var scanHintMessage: String?
|
||||
private var pendingScanCode: String?
|
||||
|
||||
private lazy var collectionView: UICollectionView = {
|
||||
let layout = makeCollectionLayout()
|
||||
@ -77,25 +78,34 @@ final class OrdersViewController: UIViewController {
|
||||
self?.applySnapshot()
|
||||
}
|
||||
|
||||
appServices.appRouter.onChange = { [weak self] in
|
||||
guard let self else { return }
|
||||
if self.viewModel.selectedEntry != self.appServices.appRouter.selectedOrdersEntry {
|
||||
self.viewModel.selectedEntry = self.appServices.appRouter.selectedOrdersEntry
|
||||
Task { await self.reload(showLoading: true) }
|
||||
}
|
||||
Task { await self.consumePendingScanCodeIfNeeded() }
|
||||
}
|
||||
appServices.accountContext.onChange = { [weak self] in
|
||||
Task { await self?.reload(showLoading: true) }
|
||||
}
|
||||
|
||||
viewModel.selectedEntry = appServices.appRouter.selectedOrdersEntry
|
||||
Task {
|
||||
await reload(showLoading: true)
|
||||
await consumePendingScanCodeIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
/// 应用来自首页、推送或全局扫码入口的订单子入口状态。
|
||||
func applyOrdersEntry(_ entry: OrdersEntry, scannedCode: String?) {
|
||||
let didChangeEntry = viewModel.selectedEntry != entry
|
||||
viewModel.selectedEntry = entry
|
||||
if let scannedCode {
|
||||
pendingScanCode = scannedCode
|
||||
}
|
||||
|
||||
guard isViewLoaded else { return }
|
||||
|
||||
Task {
|
||||
if didChangeEntry {
|
||||
await reload(showLoading: true)
|
||||
}
|
||||
await consumePendingScanCodeIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
/// 构建 Compositional Layout,按 section 类型选用全宽布局。
|
||||
private func makeCollectionLayout() -> UICollectionViewCompositionalLayout {
|
||||
UICollectionViewCompositionalLayout { [weak self] sectionIndex, _ in
|
||||
@ -345,7 +355,6 @@ final class OrdersViewController: UIViewController {
|
||||
private func switchEntry(_ entry: OrdersEntry) {
|
||||
guard viewModel.selectedEntry != entry else { return }
|
||||
viewModel.selectedEntry = entry
|
||||
appServices.appRouter.selectedOrdersEntry = entry
|
||||
Task { await reload(showLoading: true) }
|
||||
}
|
||||
|
||||
@ -370,7 +379,8 @@ final class OrdersViewController: UIViewController {
|
||||
/// 消费路由中暂存的扫码结果(核销入口)。
|
||||
private func consumePendingScanCodeIfNeeded() async {
|
||||
guard viewModel.selectedEntry == .verificationOrders,
|
||||
let code = appServices.appRouter.consumePendingOrderScanCode() else { return }
|
||||
let code = pendingScanCode else { return }
|
||||
pendingScanCode = nil
|
||||
handleScanResult(code)
|
||||
}
|
||||
|
||||
@ -459,11 +469,11 @@ extension OrdersViewController: UICollectionViewDelegate {
|
||||
if item.hasPrefix("orders:store:") {
|
||||
let orderNumber = String(item.dropFirst("orders:store:".count))
|
||||
guard let order = viewModel.storeOrders.first(where: { $0.orderNumber == orderNumber }) else { return }
|
||||
HomeMenuRouting.pushOrders(.storeDetail(order), from: self)
|
||||
appServices.appNavigator.push(.orders(.storeDetail(order)), from: self)
|
||||
} else if item.hasPrefix("orders:writeoff:") {
|
||||
let orderNumber = String(item.dropFirst("orders:writeoff:".count))
|
||||
guard let order = viewModel.writeOffOrders.first(where: { $0.orderNumber == orderNumber }) else { return }
|
||||
HomeMenuRouting.pushOrders(.writeOffDetail(order), from: self)
|
||||
appServices.appNavigator.push(.orders(.writeOffDetail(order)), from: self)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user