将扫码页提升到列表层弹出并补齐 AppDelegate.window,避免扫码时 UIKit 取主窗口崩溃;Toast 改用独立 UIWindow 显示在 sheet 之上;合作获客员支持短信验证修改分成比例,同时优化冷启动根视图创建时机并补充相关测试。 Co-authored-by: Cursor <cursoragent@cursor.com>
143 lines
5.4 KiB
Swift
143 lines
5.4 KiB
Swift
//
|
||
// CooperationAcquirerViewModel.swift
|
||
// suixinkan
|
||
//
|
||
// Created by Codex on 2026/6/29.
|
||
//
|
||
|
||
import Foundation
|
||
import Combine
|
||
|
||
/// 合作获客员列表 ViewModel。
|
||
@MainActor
|
||
final class CooperationAcquirerViewModel: ObservableObject {
|
||
@Published var acquirers: [CooperativeSaler] = []
|
||
@Published private(set) var hasLoadedOnce = false
|
||
@Published var commissionEditingAcquirer: CooperativeSaler?
|
||
@Published var commissionRateDraft = ""
|
||
@Published var commissionSmsCodeDraft = ""
|
||
@Published var commissionSmsCountdown = 0
|
||
|
||
/// 重新加载当前门店下的合作获客员。
|
||
func reload(api: CooperationOrderServing, storeId: Int?) async {
|
||
do {
|
||
let storeParam = storeId.flatMap { $0 > 0 ? $0 : nil }
|
||
let data = try await api.cooperativeSalers(storeId: storeParam, page: 1, pageSize: 20)
|
||
acquirers = data.list
|
||
} catch {
|
||
if !hasLoadedOnce {
|
||
acquirers = []
|
||
}
|
||
}
|
||
hasLoadedOnce = true
|
||
}
|
||
|
||
/// 更新指定获客员的备注名,成功后刷新本地列表项。
|
||
func updateRemark(
|
||
saleUserId: Int,
|
||
remark: String,
|
||
api: CooperationOrderServing
|
||
) async throws {
|
||
guard saleUserId > 0 else { return }
|
||
if let message = CooperationOrderRemarkName.validationMessage(for: remark) {
|
||
throw CooperationOrderRemarkValidationError(message: message)
|
||
}
|
||
let trimmedRemark = CooperationOrderRemarkName.trimmed(remark)
|
||
try await api.saleUserUpdateRemark(saleUserId: saleUserId, photogRemarkName: trimmedRemark)
|
||
acquirers = acquirers.map { acquirer in
|
||
guard acquirer.saleUserId == saleUserId else { return acquirer }
|
||
return acquirer.withPhotogRemarkName(trimmedRemark)
|
||
}
|
||
}
|
||
|
||
/// 打开分成比例编辑弹窗。
|
||
func startEditCommissionRate(_ acquirer: CooperativeSaler) {
|
||
commissionEditingAcquirer = acquirer
|
||
commissionRateDraft = "\(acquirer.commissionRate)"
|
||
commissionSmsCodeDraft = ""
|
||
commissionSmsCountdown = 0
|
||
}
|
||
|
||
/// 更新分成比例输入,只保留数字且最多 3 位。
|
||
func updateCommissionRateDraft(_ text: String) {
|
||
commissionRateDraft = String(text.filter(\.isNumber).prefix(3))
|
||
}
|
||
|
||
/// 更新短信验证码输入,只保留数字且最多 6 位。
|
||
func updateCommissionSmsCodeDraft(_ text: String) {
|
||
commissionSmsCodeDraft = String(text.filter(\.isNumber).prefix(6))
|
||
}
|
||
|
||
/// 关闭分成比例编辑弹窗并清理状态。
|
||
func dismissCommissionRateDialog() {
|
||
commissionEditingAcquirer = nil
|
||
commissionRateDraft = ""
|
||
commissionSmsCodeDraft = ""
|
||
commissionSmsCountdown = 0
|
||
}
|
||
|
||
/// 发送分成比例修改验证码,成功后启动本地 60 秒倒计时。
|
||
func sendCommissionRateSms(api: CooperationOrderServing) async throws {
|
||
guard commissionSmsCountdown == 0 else {
|
||
throw CooperationOrderCommissionRateValidationError(message: "请在倒计时结束后重新获取")
|
||
}
|
||
guard let acquirer = commissionEditingAcquirer else { return }
|
||
let phone = acquirer.salerPhone.cooperationNonEmptyOrDefault(acquirer.displayPhone)
|
||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||
guard !phone.isEmpty else {
|
||
throw CooperationOrderCommissionRateValidationError(message: "获客员手机号为空")
|
||
}
|
||
try await api.saleUserCommissionRateSendSmsCode(phone: phone)
|
||
commissionSmsCountdown = 60
|
||
}
|
||
|
||
/// 保存分成比例,成功后用接口返回数据刷新本地列表。
|
||
func saveCommissionRate(api: CooperationOrderServing) async throws {
|
||
guard let acquirer = commissionEditingAcquirer else { return }
|
||
guard acquirer.saleUserId > 0 else { return }
|
||
guard let commissionRate = Int(commissionRateDraft.trimmingCharacters(in: .whitespacesAndNewlines)) else {
|
||
throw CooperationOrderCommissionRateValidationError(message: "请输入分成比例")
|
||
}
|
||
guard (0...100).contains(commissionRate) else {
|
||
throw CooperationOrderCommissionRateValidationError(message: "分成比例需在0到100之间")
|
||
}
|
||
let smsCode = commissionSmsCodeDraft.trimmingCharacters(in: .whitespacesAndNewlines)
|
||
guard !smsCode.isEmpty else {
|
||
throw CooperationOrderCommissionRateValidationError(message: "请输入验证码")
|
||
}
|
||
|
||
let updated = try await api.saleUserUpdateCommissionRate(
|
||
saleUserId: acquirer.saleUserId,
|
||
commissionRate: commissionRate,
|
||
smsCode: smsCode
|
||
)
|
||
if updated.saleUserId > 0 {
|
||
acquirers = acquirers.map { item in
|
||
item.saleUserId == updated.saleUserId ? updated : item
|
||
}
|
||
}
|
||
dismissCommissionRateDialog()
|
||
}
|
||
|
||
/// 倒计时递减,由页面定时器驱动。
|
||
func tickCommissionSmsCountdown() {
|
||
if commissionSmsCountdown > 0 {
|
||
commissionSmsCountdown -= 1
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 合作获客员备注名校验失败错误。
|
||
struct CooperationOrderRemarkValidationError: LocalizedError {
|
||
let message: String
|
||
|
||
var errorDescription: String? { message }
|
||
}
|
||
|
||
/// 合作获客员分成比例校验失败错误。
|
||
struct CooperationOrderCommissionRateValidationError: LocalizedError {
|
||
let message: String
|
||
|
||
var errorDescription: String? { message }
|
||
}
|