Add scenic selection and cooperation order flows aligned with Android.

Upgrade scenic picker with search, location sorting, permission apply/status, and blocking home dialog; add cooperation order module and order source picker improvements with unit tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-07 10:48:43 +08:00
parent 3c4ca7eefb
commit 2bea05b1d9
50 changed files with 5603 additions and 191 deletions

View File

@ -0,0 +1,129 @@
//
// CooperationOrderListViewModel.swift
// suixinkan
//
import Foundation
/// ViewModel Android `CooperationOrderListViewModel`
final class CooperationOrderListViewModel {
private(set) var selectedTab = 0
private(set) var searchText = ""
private(set) var leads: [ReferralLeadEntity] = []
private(set) var orders: [AcquisitionOrderEntity] = []
private(set) var isRefreshing = false
private(set) var isLoadingMore = false
private(set) var canLoadMore = false
var onStateChange: (() -> Void)?
var onShowMessage: ((String) -> Void)?
private let pageSize = 10
private var leadsPage = 1
private var ordersPage = 1
private var leadsTotal = 0
private var ordersTotal = 0
func onTabSelected(_ index: Int) {
guard selectedTab != index else { return }
selectedTab = index
notifyStateChange()
}
func onSearchTextChange(_ text: String) {
searchText = text
notifyStateChange()
}
func refreshCurrentTab(api: OrderAPI) async {
if selectedTab == 0 {
await refreshLeads(api: api)
} else {
await refreshAcquisitionOrders(api: api)
}
}
func refreshLeads(api: OrderAPI) async {
leadsPage = 1
isRefreshing = true
isLoadingMore = false
notifyStateChange()
await loadLeads(api: api)
}
func refreshAcquisitionOrders(api: OrderAPI) async {
ordersPage = 1
isRefreshing = true
isLoadingMore = false
notifyStateChange()
await loadAcquisitionOrders(api: api)
}
func loadMore(api: OrderAPI) async {
guard !isRefreshing, !isLoadingMore, canLoadMore else { return }
isLoadingMore = true
notifyStateChange()
if selectedTab == 0 {
leadsPage += 1
await loadLeads(api: api)
} else {
ordersPage += 1
await loadAcquisitionOrders(api: api)
}
}
func shouldLoadMore(at index: Int) -> Bool {
guard canLoadMore, !isRefreshing, !isLoadingMore else { return false }
let count = selectedTab == 0 ? leads.count : orders.count
return index >= max(0, count - 3)
}
private func loadLeads(api: OrderAPI) async {
do {
let response = try await api.referralLeads(
page: String(leadsPage),
pageSize: String(pageSize)
)
leadsTotal = response.total
if leadsPage == 1 {
leads = response.list
} else {
leads.append(contentsOf: response.list)
}
canLoadMore = leads.count < leadsTotal
} catch {
onShowMessage?(error.localizedDescription)
}
isRefreshing = false
isLoadingMore = false
notifyStateChange()
}
private func loadAcquisitionOrders(api: OrderAPI) async {
let keyword = searchText.trimmingCharacters(in: .whitespacesAndNewlines)
do {
let response = try await api.acquisitionOrders(
keyword: keyword.isEmpty ? nil : keyword,
page: String(ordersPage),
pageSize: String(pageSize)
)
ordersTotal = response.total
if ordersPage == 1 {
orders = response.list
} else {
orders.append(contentsOf: response.list)
}
canLoadMore = orders.count < ordersTotal
} catch {
onShowMessage?(error.localizedDescription)
}
isRefreshing = false
isLoadingMore = false
notifyStateChange()
}
private func notifyStateChange() {
onStateChange?()
}
}