// // CooperationAcquirerViewModel.swift // suixinkan // import Foundation /// 合作获客员 ViewModel,对齐 Android `CooperationAcquirerViewModel`。 final class CooperationAcquirerViewModel { private(set) var acquirers: [CooperativeSalerEntity] = [] private(set) var isRefreshing = false private(set) var remarkEditingAcquirer: CooperativeSalerEntity? private(set) var remarkDraft = "" private(set) var commissionEditingAcquirer: CooperativeSalerEntity? private(set) var commissionRateDraft = "" private(set) var commissionSmsCodeDraft = "" private(set) var commissionSmsCountdown = 0 var onStateChange: (() -> Void)? var onShowMessage: ((String) -> Void)? var onNavigateBindAcquirer: ((Int) -> Void)? private let appStore: AppStore private var commissionSmsTimerTask: Task? init(appStore: AppStore = .shared) { self.appStore = appStore } deinit { commissionSmsTimerTask?.cancel() } func loadAcquirers(api: OrderAPI, initial: Bool = false) async { let storeId = appStore.session.currentStoreId let storeIdParam = storeId > 0 ? String(storeId) : nil do { let response = try await api.cooperativeSalers(storeId: storeIdParam, pageSize: "20") acquirers = response.list } catch { onShowMessage?(error.localizedDescription) } isRefreshing = false notifyStateChange() } func refresh(api: OrderAPI) async { isRefreshing = true notifyStateChange() await loadAcquirers(api: api, initial: false) } func startEditRemark(_ acquirer: CooperativeSalerEntity) { remarkEditingAcquirer = acquirer remarkDraft = acquirer.photogRemarkName notifyStateChange() } func updateRemarkDraft(_ text: String) { remarkDraft = String(text.prefix(CooperationOrderFeature.remarkNameMaxLength)) notifyStateChange() } func dismissRemarkDialog() { remarkEditingAcquirer = nil remarkDraft = "" notifyStateChange() } func saveRemark(api: OrderAPI) async { guard let acquirer = remarkEditingAcquirer else { return } let saleUserId = acquirer.saleUserId guard saleUserId > 0 else { return } let trimmedRemark = remarkDraft.trimmingCharacters(in: .whitespacesAndNewlines) if let message = CooperationOrderFeature.remarkNameValidationMessage(remarkDraft) { onShowMessage?(message) return } dismissRemarkDialog() do { try await api.saleUserUpdateRemark(saleUserId: saleUserId, photogRemarkName: trimmedRemark) acquirers = acquirers.map { item in item.saleUserId == saleUserId ? item.withRemarkName(trimmedRemark) : item } onShowMessage?("备注已保存") notifyStateChange() } catch { onShowMessage?(error.localizedDescription) } } func startEditCommissionRate(_ acquirer: CooperativeSalerEntity) { stopCommissionSmsTimer() commissionEditingAcquirer = acquirer commissionRateDraft = String(acquirer.commissionRate) commissionSmsCodeDraft = "" notifyStateChange() } func updateCommissionRateDraft(_ text: String) { commissionRateDraft = String(text.filter(\.isNumber).prefix(3)) notifyStateChange() } func updateCommissionSmsCodeDraft(_ text: String) { commissionSmsCodeDraft = String(text.filter(\.isNumber).prefix(6)) notifyStateChange() } func dismissCommissionRateDialog() { commissionEditingAcquirer = nil commissionRateDraft = "" commissionSmsCodeDraft = "" stopCommissionSmsTimer() notifyStateChange() } func requestCommissionSmsCode(api: OrderAPI) async { guard let acquirer = commissionEditingAcquirer else { return } if commissionSmsCountdown > 0 { onShowMessage?("请在倒计时结束后重新获取") return } let phone = acquirer.salerPhone.isEmpty ? acquirer.displayPhone : acquirer.salerPhone let trimmedPhone = phone.trimmingCharacters(in: .whitespacesAndNewlines) guard !trimmedPhone.isEmpty else { onShowMessage?("获客员手机号为空") return } do { try await api.saleUserCommissionRateSendSmsCode(phone: trimmedPhone) startCommissionSmsTimer() onShowMessage?("验证码已发送") } catch { onShowMessage?(error.localizedDescription) } } func saveCommissionRate(api: OrderAPI) async { guard let acquirer = commissionEditingAcquirer else { return } let saleUserId = acquirer.saleUserId guard saleUserId > 0 else { return } guard let commissionRate = Int(commissionRateDraft.trimmingCharacters(in: .whitespacesAndNewlines)) else { onShowMessage?("请输入分成比例") return } guard (0...100).contains(commissionRate) else { onShowMessage?("分成比例需在0到100之间") return } let smsCode = commissionSmsCodeDraft.trimmingCharacters(in: .whitespacesAndNewlines) guard !smsCode.isEmpty else { onShowMessage?("请输入验证码") return } do { let updated = try await api.saleUserUpdateCommissionRate( saleUserId: saleUserId, commissionRate: commissionRate, smsCode: smsCode ) dismissCommissionRateDialog() if updated.saleUserId > 0 { acquirers = acquirers.map { item in item.saleUserId == updated.saleUserId ? updated : item } } else { await loadAcquirers(api: api, initial: false) } onShowMessage?("分成比例已修改") notifyStateChange() } catch { onShowMessage?(error.localizedDescription) } } func processScanResult(_ scanResult: String) { guard let saleUserId = SaleUserQrParser.parseSaleUserId(scanResult), saleUserId > 0 else { onShowMessage?("请扫描正确的获客员二维码") return } onNavigateBindAcquirer?(saleUserId) } private func startCommissionSmsTimer() { commissionSmsTimerTask?.cancel() commissionSmsCountdown = 60 notifyStateChange() commissionSmsTimerTask = Task { [weak self] in guard let self else { return } try? await Task.sleep(nanoseconds: 1_000_000_000) for second in stride(from: 59, through: 1, by: -1) { if Task.isCancelled { return } commissionSmsCountdown = second notifyStateChange() try? await Task.sleep(nanoseconds: 1_000_000_000) } if !Task.isCancelled { commissionSmsCountdown = 0 notifyStateChange() } } } private func stopCommissionSmsTimer() { commissionSmsTimerTask?.cancel() commissionSmsTimerTask = nil commissionSmsCountdown = 0 } private func notifyStateChange() { onStateChange?() } }