Files
suixinkan_ios_new/suixinkan/Features/CooperationOrder/Views/BindAcquirerView.swift
汉秋 1970572edd 迁移合作订单完整能力,并统一 AppRoleCode 角色权限与首页菜单展示。
新增 CooperationOrder 模块(双 Tab 列表、获客员绑定、主 Tab 扫码)、订单来源/带客单绑定及配套 API 测试;同步引入 roleCode 权限匹配与相关单元测试。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 13:33:00 +08:00

142 lines
5.5 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// BindAcquirerView.swift
// suixinkan
//
// Created by Codex on 2026/6/29.
//
import SwiftUI
///
struct BindAcquirerView: View {
@EnvironmentObject private var toastCenter: ToastCenter
@Environment(\.cooperationOrderAPI) private var cooperationOrderAPI
@Environment(\.dismiss) private var dismiss
@StateObject private var viewModel = BindAcquirerViewModel()
let saleUserId: Int
let onSuccess: () -> Void
@State private var binding = false
var body: some View {
VStack(spacing: 12) {
if viewModel.isLoading && viewModel.inviteInfo == nil && !viewModel.isAlreadyBound {
Spacer()
ProgressView()
Spacer()
} else if let info = viewModel.inviteInfo {
VStack(alignment: .leading, spacing: 12) {
VStack(alignment: .leading, spacing: 8) {
Text(info.title.cooperationNonEmptyOrDefault("绑定获客员"))
.font(.system(size: 16, weight: .semibold))
.foregroundStyle(.white)
if !info.subtitle.isEmpty {
Text(info.subtitle)
.font(.system(size: 13))
.foregroundStyle(.white.opacity(0.9))
}
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding(16)
.background(AppDesign.primary, in: RoundedRectangle(cornerRadius: 10))
infoCard(title: "获客员", value: info.salerName)
infoCard(title: "手机号", value: info.salerPhone)
}
.padding(16)
Spacer()
Button {
Task { await acceptBind() }
} label: {
Text(binding ? "提交中..." : (viewModel.isAlreadyBound ? "已绑定获客员" : "接受邀请"))
.font(.system(size: 16, weight: .semibold))
.foregroundStyle(.white)
.frame(maxWidth: .infinity)
.frame(height: 48)
.background(
viewModel.isAlreadyBound ? AppDesign.textSecondary : AppDesign.primary,
in: RoundedRectangle(cornerRadius: 8)
)
}
.buttonStyle(.plain)
.disabled(binding || viewModel.isAlreadyBound)
.padding(.horizontal, 16)
.padding(.bottom, 12)
} else if viewModel.isAlreadyBound {
Spacer()
Text("已绑定获客员")
.font(.system(size: 14))
.foregroundStyle(AppDesign.textSecondary)
Spacer()
Button {} label: {
Text("已绑定获客员")
.font(.system(size: 16, weight: .semibold))
.foregroundStyle(.white)
.frame(maxWidth: .infinity)
.frame(height: 48)
.background(AppDesign.textSecondary, in: RoundedRectangle(cornerRadius: 8))
}
.buttonStyle(.plain)
.disabled(true)
.padding(.horizontal, 16)
.padding(.bottom, 12)
} else if let error = viewModel.errorMessage {
Spacer()
Text(error)
.font(.system(size: 14))
.foregroundStyle(AppDesign.textSecondary)
.multilineTextAlignment(.center)
.padding()
Spacer()
}
}
.navigationTitle(viewModel.inviteInfo?.title.cooperationNonEmptyOrDefault("接受邀请") ?? "接受邀请")
.navigationBarTitleDisplayMode(.inline)
.background(Color(hex: 0xF5F7FA).ignoresSafeArea())
.task {
await viewModel.load(api: cooperationOrderAPI, saleUserId: saleUserId)
if viewModel.errorMessage != nil && viewModel.inviteInfo == nil && !viewModel.isAlreadyBound {
if let message = viewModel.errorMessage {
toastCenter.show(message)
}
dismiss()
}
}
}
private func infoCard(title: String, value: String) -> some View {
VStack(alignment: .leading, spacing: 6) {
Text(title)
.font(.system(size: 13))
.foregroundStyle(AppDesign.textSecondary)
Text(value.isEmpty ? "--" : value)
.font(.system(size: 15, weight: .medium))
.foregroundStyle(AppDesign.textPrimary)
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding(14)
.background(.white, in: RoundedRectangle(cornerRadius: 10))
}
private func acceptBind() async {
binding = true
defer { binding = false }
do {
try await viewModel.acceptBind(api: cooperationOrderAPI)
toastCenter.show("绑定成功")
onSuccess()
dismiss()
} catch {
viewModel.handleBindError(error.localizedDescription.isEmpty ? "绑定失败" : error.localizedDescription)
if let message = viewModel.errorMessage {
toastCenter.show(message)
}
if !viewModel.isAlreadyBound {
dismiss()
}
}
}
}