Files
suixinkan_ios_new/suixinkan/Features/CooperationOrder/Views/CooperationOrderListView.swift
汉秋 49e997ddba 修复合作获客扫码绑定崩溃与 Toast 层级,并接入分成比例修改。
将扫码页提升到列表层弹出并补齐 AppDelegate.window,避免扫码时 UIKit 取主窗口崩溃;Toast 改用独立 UIWindow 显示在 sheet 之上;合作获客员支持短信验证修改分成比例,同时优化冷启动根视图创建时机并补充相关测试。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-03 20:37:24 +08:00

144 lines
5.6 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.

//
// CooperationOrderListView.swift
// suixinkan
//
// Created by Codex on 2026/6/29.
//
import SwiftUI
/// 线 Tab
struct CooperationOrderListView: View {
@EnvironmentObject private var toastCenter: ToastCenter
@Environment(\.cooperationOrderAPI) private var cooperationOrderAPI
@Environment(\.globalLoading) private var globalLoading
@StateObject private var viewModel = CooperationOrderListViewModel()
@State private var route: CooperationOrderRoute?
/// navigationDestination fullScreenCover SwiftUI
@State private var showBindScanner = false
var body: some View {
VStack(spacing: 0) {
CooperationOrderTabs(
selectedTab: viewModel.selectedTab,
onTabSelected: { viewModel.onTabSelected($0) }
)
if viewModel.selectedTab == 1 {
CooperationOrderSearchBar(searchText: $viewModel.searchText) {
Task { await searchOrders(showLoading: true) }
}
}
ScrollView {
LazyVStack(spacing: 12) {
if viewModel.selectedTab == 0 {
if viewModel.hasLoadedLeadsOnce && viewModel.leads.isEmpty {
emptyState("暂无获客员线索")
} else {
ForEach(Array(viewModel.leads.enumerated()), id: \.element.id) { index, lead in
ReferralLeadCard(lead: lead)
.onAppear {
guard index >= viewModel.leads.count - 3 else { return }
Task { await viewModel.loadMore(api: cooperationOrderAPI) }
}
}
}
} else {
if viewModel.hasLoadedOrdersOnce && viewModel.orders.isEmpty {
emptyState("暂无相关合作订单")
} else {
ForEach(Array(viewModel.orders.enumerated()), id: \.element.id) { index, order in
AcquisitionOrderCard(order: order)
.onAppear {
guard index >= viewModel.orders.count - 3 else { return }
Task { await viewModel.loadMore(api: cooperationOrderAPI) }
}
}
}
}
if viewModel.isLoadingMore {
ProgressView()
.tint(CooperationOrderColors.primary)
.frame(width: 24, height: 24)
.padding(16)
}
}
.padding(.horizontal, 14)
.padding(.vertical, 12)
}
.refreshable {
await reloadCurrentTab(showLoading: false)
}
}
.navigationTitle("合作订单")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button("合作获客员") {
route = .acquirer
}
.font(.system(size: 14))
.foregroundStyle(CooperationOrderColors.primary)
}
}
.background(CooperationOrderColors.pageBg.ignoresSafeArea())
.fullScreenCover(isPresented: $showBindScanner) {
OrderScannerPage(
onClose: { showBindScanner = false },
onSuccess: { raw in
showBindScanner = false
guard let saleUserId = SaleUserQrParser.parseSaleUserId(raw), saleUserId > 0 else {
toastCenter.show("请扫描正确的获客员二维码")
return
}
route = .bind(saleUserId: saleUserId)
},
onFailure: { error in
showBindScanner = false
toastCenter.show(error.localizedDescription)
}
)
}
.appNavigationDestination(item: $route) { destination in
switch destination {
case .acquirer:
CooperationAcquirerView(onScanBind: {
showBindScanner = true
})
case let .bind(saleUserId):
BindAcquirerView(saleUserId: saleUserId, onSuccess: {
route = .acquirer
})
}
}
.task {
await reloadCurrentTab(showLoading: true)
}
.onChange(of: viewModel.selectedTab) { _ in
Task { await reloadCurrentTab(showLoading: true) }
}
}
private func reloadCurrentTab(showLoading: Bool) async {
await globalLoading.withOptionalLoading(showLoading) {
await viewModel.refreshCurrentTab(api: cooperationOrderAPI)
}
}
private func searchOrders(showLoading: Bool) async {
await globalLoading.withOptionalLoading(showLoading) {
await viewModel.searchOrders(api: cooperationOrderAPI)
}
}
private func emptyState(_ text: String) -> some View {
Text(text)
.font(.system(size: 14))
.foregroundStyle(CooperationOrderColors.text999)
.frame(maxWidth: .infinity)
.padding(.vertical, 48)
}
}