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,101 @@
//
// BindAcquirerViewModel.swift
// suixinkan
//
import Foundation
/// / ViewModel Android `BindAcquirerViewModel`
final class BindAcquirerViewModel {
private(set) var inviteInfo: SaleUserInviteInfoResponse?
private(set) var isLoading = false
private(set) var isAlreadyBound = false
private(set) var commissionRateDraft = ""
var onStateChange: (() -> Void)?
var onShowMessage: ((String) -> Void)?
var onBindSuccess: (() -> Void)?
var onShouldPop: (() -> Void)?
private var saleUserId = 0
func initSaleUserId(_ id: Int) {
guard saleUserId != id || (inviteInfo == nil && !isAlreadyBound) else { return }
saleUserId = id
isAlreadyBound = false
commissionRateDraft = ""
inviteInfo = nil
notifyStateChange()
}
func updateCommissionRateDraft(_ text: String) {
commissionRateDraft = String(text.filter(\.isNumber).prefix(3))
notifyStateChange()
}
func loadInviteInfo(api: OrderAPI) async {
guard saleUserId > 0 else {
onShowMessage?("获客员信息无效")
onShouldPop?()
return
}
isLoading = true
notifyStateChange()
do {
let data = try await api.saleUserInviteInfo(saleUserId: String(saleUserId))
let resolvedSaleUserId = data.saleUserId > 0 ? data.saleUserId : saleUserId
inviteInfo = SaleUserInviteInfoResponse(
saleUserId: resolvedSaleUserId,
isBound: data.isBound,
photographerName: data.photographerName,
photographerPhone: data.photographerPhone,
salerName: data.salerName,
salerPhone: data.salerPhone,
shareCode: data.shareCode,
subtitle: data.subtitle,
title: data.title
)
if data.isBound {
isAlreadyBound = true
}
} catch {
handleBindError(error.localizedDescription.isEmpty ? "获取邀请信息失败" : error.localizedDescription)
}
isLoading = false
notifyStateChange()
}
func acceptBind(api: OrderAPI) async {
guard saleUserId > 0, !isAlreadyBound else { return }
guard let commissionRate = Int(commissionRateDraft.trimmingCharacters(in: .whitespacesAndNewlines)) else {
onShowMessage?("请输入分账比例")
return
}
guard (0...100).contains(commissionRate) else {
onShowMessage?("分账比例需在0到100之间")
return
}
do {
try await api.saleUserAcceptBind(saleUserId: saleUserId, commissionRate: commissionRate)
onShowMessage?("绑定成功")
onBindSuccess?()
} catch {
handleBindError(error.localizedDescription.isEmpty ? "绑定失败" : error.localizedDescription)
}
}
private func handleBindError(_ message: String) {
onShowMessage?(message)
if message.contains("已绑定") {
isAlreadyBound = true
notifyStateChange()
return
}
onShouldPop?()
}
private func notifyStateChange() {
onStateChange?()
}
}