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>
130 lines
3.7 KiB
Swift
130 lines
3.7 KiB
Swift
//
|
||
// 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?()
|
||
}
|
||
}
|