// // CooperationAcquirerView.swift // suixinkan // // Created by Codex on 2026/6/29. // import SwiftUI import Combine /// 合作获客员列表页,支持查看已绑定获客员与扫码绑定。 struct CooperationAcquirerView: View { @EnvironmentObject private var accountContext: AccountContext @EnvironmentObject private var toastCenter: ToastCenter @Environment(\.cooperationOrderAPI) private var cooperationOrderAPI @Environment(\.globalLoading) private var globalLoading @Environment(\.openURL) private var openURL @StateObject private var viewModel = CooperationAcquirerViewModel() @State private var showRemarkAlert = false @State private var remarkEditingAcquirer: CooperativeSaler? @State private var remarkDraft = "" @State private var sendingCommissionSms = false @State private var submittingCommissionRate = false let onScanBind: () -> Void var body: some View { ScrollView { LazyVStack(spacing: 12) { if viewModel.hasLoadedOnce && viewModel.acquirers.isEmpty { Text("暂无合作获客员") .font(.system(size: 14)) .foregroundStyle(CooperationOrderColors.text999) .frame(maxWidth: .infinity) .padding(.vertical, 48) } else { ForEach(viewModel.acquirers, id: \.displayId) { acquirer in CooperativeSalerCard(acquirer: acquirer) { phone in dialPhone(phone) } onEditRemark: { remarkEditingAcquirer = acquirer remarkDraft = acquirer.photogRemarkName showRemarkAlert = true } onEditCommission: { viewModel.startEditCommissionRate(acquirer) } } } } .padding(.horizontal, 14) .padding(.vertical, 12) } .navigationTitle("合作获客员") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .topBarTrailing) { Button("扫码绑定") { onScanBind() } .font(.system(size: 14)) .foregroundStyle(CooperationOrderColors.primary) } } .background(CooperationOrderColors.pageBg.ignoresSafeArea()) .refreshable { await reload(showLoading: false) } .task { await reload(showLoading: true) } .sheet(item: $viewModel.commissionEditingAcquirer, onDismiss: { viewModel.dismissCommissionRateDialog() }) { acquirer in CommissionRateEditSheet( acquirer: acquirer, commissionRate: Binding( get: { viewModel.commissionRateDraft }, set: { viewModel.updateCommissionRateDraft($0) } ), smsCode: Binding( get: { viewModel.commissionSmsCodeDraft }, set: { viewModel.updateCommissionSmsCodeDraft($0) } ), smsCountdown: viewModel.commissionSmsCountdown, sending: sendingCommissionSms, submitting: submittingCommissionRate, onSendSmsCode: { Task { await sendCommissionSms() } }, onConfirm: { Task { await saveCommissionRate() } }, onCancel: { viewModel.dismissCommissionRateDialog() } ) .presentationDetents([.height(430)]) .presentationDragIndicator(.hidden) } .alert("修改备注", isPresented: $showRemarkAlert) { TextField("备注名", text: $remarkDraft) Button("取消", role: .cancel) { remarkEditingAcquirer = nil } Button("保存") { // 必须在弹窗关闭前同步捕获,避免 alert dismiss 清空 state 导致接口未调用。 guard let acquirer = remarkEditingAcquirer else { return } if let message = CooperationOrderRemarkName.validationMessage(for: remarkDraft) { toastCenter.show(message) return } let saleUserId = acquirer.saleUserId let draft = remarkDraft showRemarkAlert = false remarkEditingAcquirer = nil Task { await saveRemark(saleUserId: saleUserId, draft: draft) } } } message: { if let acquirer = remarkEditingAcquirer { Text("为 \(acquirer.salerRealName.cooperationNonEmptyOrDefault("—")) 设置备注名") } } .onReceive(Timer.publish(every: 1, on: .main, in: .common).autoconnect()) { _ in viewModel.tickCommissionSmsCountdown() } } /// 保存当前编辑中的获客员备注名。 private func saveRemark(saleUserId: Int, draft: String) async { guard saleUserId > 0 else { return } await globalLoading.withOptionalLoading(true) { do { try await viewModel.updateRemark( saleUserId: saleUserId, remark: draft, api: cooperationOrderAPI ) toastCenter.show("备注已保存") } catch { toastCenter.show(error.localizedDescription) } } } private func reload(showLoading: Bool) async { await globalLoading.withOptionalLoading(showLoading) { await viewModel.reload(api: cooperationOrderAPI, storeId: accountContext.currentStore?.id) } } /// 发送分成比例修改验证码。 private func sendCommissionSms() async { guard !sendingCommissionSms else { return } sendingCommissionSms = true defer { sendingCommissionSms = false } do { try await viewModel.sendCommissionRateSms(api: cooperationOrderAPI) toastCenter.show("验证码已发送") } catch { toastCenter.show(error.localizedDescription) } } /// 保存分成比例修改。 private func saveCommissionRate() async { guard !submittingCommissionRate else { return } submittingCommissionRate = true defer { submittingCommissionRate = false } do { try await viewModel.saveCommissionRate(api: cooperationOrderAPI) toastCenter.show("分成比例已修改") } catch { toastCenter.show(error.localizedDescription) } } private func dialPhone(_ phone: String) { let trimmed = phone.trimmingCharacters(in: .whitespacesAndNewlines) guard !trimmed.isEmpty, let url = URL(string: "tel:\(trimmed)") else { return } openURL(url) } }