迁移合作订单完整能力,并统一 AppRoleCode 角色权限与首页菜单展示。
新增 CooperationOrder 模块(双 Tab 列表、获客员绑定、主 Tab 扫码)、订单来源/带客单绑定及配套 API 测试;同步引入 roleCode 权限匹配与相关单元测试。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@ -0,0 +1,70 @@
|
||||
//
|
||||
// BindAcquirerViewModel.swift
|
||||
// suixinkan
|
||||
//
|
||||
// Created by Codex on 2026/6/29.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
|
||||
/// 绑定获客员 ViewModel,负责邀请信息加载与接受绑定。
|
||||
@MainActor
|
||||
final class BindAcquirerViewModel: ObservableObject {
|
||||
@Published var inviteInfo: SaleUserInviteInfo?
|
||||
@Published var isLoading = false
|
||||
@Published var isAlreadyBound = false
|
||||
@Published var errorMessage: String?
|
||||
|
||||
private var saleUserId = 0
|
||||
|
||||
/// 加载获客员邀请信息。
|
||||
func load(api: CooperationOrderServing, saleUserId: Int) async {
|
||||
guard saleUserId > 0 else {
|
||||
errorMessage = "获客员信息无效"
|
||||
return
|
||||
}
|
||||
if self.saleUserId == saleUserId && (inviteInfo != nil || isAlreadyBound) { return }
|
||||
self.saleUserId = saleUserId
|
||||
isAlreadyBound = false
|
||||
isLoading = true
|
||||
errorMessage = nil
|
||||
defer { isLoading = false }
|
||||
do {
|
||||
var info = try await api.saleUserInviteInfo(saleUserId: saleUserId)
|
||||
if info.saleUserId <= 0 {
|
||||
info = SaleUserInviteInfo(
|
||||
saleUserId: saleUserId,
|
||||
isBound: info.isBound,
|
||||
photographerName: info.photographerName,
|
||||
photographerPhone: info.photographerPhone,
|
||||
salerName: info.salerName,
|
||||
salerPhone: info.salerPhone,
|
||||
shareCode: info.shareCode,
|
||||
subtitle: info.subtitle,
|
||||
title: info.title
|
||||
)
|
||||
}
|
||||
if info.isBound {
|
||||
isAlreadyBound = true
|
||||
}
|
||||
inviteInfo = info
|
||||
} catch {
|
||||
handleBindError(error.localizedDescription.isEmpty ? "获取邀请信息失败" : error.localizedDescription)
|
||||
}
|
||||
}
|
||||
|
||||
/// 提交接受绑定。
|
||||
func acceptBind(api: CooperationOrderServing) async throws {
|
||||
guard saleUserId > 0, !isAlreadyBound else { return }
|
||||
try await api.saleUserAcceptBind(saleUserId: saleUserId)
|
||||
}
|
||||
|
||||
/// 处理绑定错误,识别已绑定状态。
|
||||
func handleBindError(_ message: String) {
|
||||
errorMessage = message
|
||||
if message.contains("已绑定") {
|
||||
isAlreadyBound = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
//
|
||||
// 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
|
||||
|
||||
/// 重新加载当前门店下的合作获客员。
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,130 @@
|
||||
//
|
||||
// CooperationOrderListViewModel.swift
|
||||
// suixinkan
|
||||
//
|
||||
// Created by Codex on 2026/6/29.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
|
||||
/// 合作订单列表 ViewModel,管理获客线索与获客订单双 Tab 分页。
|
||||
@MainActor
|
||||
final class CooperationOrderListViewModel: ObservableObject {
|
||||
@Published var selectedTab = 0
|
||||
@Published var searchText = ""
|
||||
@Published var leads: [ReferralLead] = []
|
||||
@Published var orders: [AcquisitionOrder] = []
|
||||
@Published var isLoadingMore = false
|
||||
@Published var canLoadMore = false
|
||||
@Published private(set) var hasLoadedLeadsOnce = false
|
||||
@Published private(set) var hasLoadedOrdersOnce = false
|
||||
|
||||
private var leadsPage = 1
|
||||
private var ordersPage = 1
|
||||
private var leadsTotal = 0
|
||||
private var ordersTotal = 0
|
||||
private var isReloading = false
|
||||
private let pageSize = 10
|
||||
|
||||
/// 切换 Tab 并触发对应列表刷新。
|
||||
func onTabSelected(_ index: Int) {
|
||||
guard selectedTab != index else { return }
|
||||
selectedTab = index
|
||||
}
|
||||
|
||||
/// 刷新当前 Tab 列表。
|
||||
func refreshCurrentTab(api: CooperationOrderServing) async {
|
||||
if selectedTab == 0 {
|
||||
await refreshLeads(api: api)
|
||||
} else {
|
||||
await refreshOrders(api: api)
|
||||
}
|
||||
}
|
||||
|
||||
/// 刷新获客线索列表。
|
||||
func refreshLeads(api: CooperationOrderServing) async {
|
||||
guard !isReloading else { return }
|
||||
isReloading = true
|
||||
defer { isReloading = false }
|
||||
leadsPage = 1
|
||||
isLoadingMore = false
|
||||
await loadLeads(api: api)
|
||||
}
|
||||
|
||||
/// 刷新获客订单列表。
|
||||
func refreshOrders(api: CooperationOrderServing) async {
|
||||
guard !isReloading else { return }
|
||||
isReloading = true
|
||||
defer { isReloading = false }
|
||||
ordersPage = 1
|
||||
isLoadingMore = false
|
||||
await loadOrders(api: api)
|
||||
}
|
||||
|
||||
/// 加载更多当前 Tab 数据。
|
||||
func loadMore(api: CooperationOrderServing) async {
|
||||
guard !isReloading, !isLoadingMore, canLoadMore else { return }
|
||||
isLoadingMore = true
|
||||
if selectedTab == 0 {
|
||||
leadsPage += 1
|
||||
await loadLeads(api: api)
|
||||
} else {
|
||||
ordersPage += 1
|
||||
await loadOrders(api: api)
|
||||
}
|
||||
}
|
||||
|
||||
/// 按关键词搜索获客订单。
|
||||
func searchOrders(api: CooperationOrderServing) async {
|
||||
guard selectedTab == 1 else { return }
|
||||
await refreshOrders(api: api)
|
||||
}
|
||||
|
||||
private func loadLeads(api: CooperationOrderServing) async {
|
||||
do {
|
||||
let data = try await api.saleUserReferralLeads(page: leadsPage, pageSize: pageSize)
|
||||
leadsTotal = data.total
|
||||
if leadsPage == 1 {
|
||||
leads = data.list
|
||||
} else {
|
||||
leads.append(contentsOf: data.list)
|
||||
}
|
||||
canLoadMore = leads.count < leadsTotal
|
||||
} catch {
|
||||
if leadsPage == 1, !hasLoadedLeadsOnce {
|
||||
leads = []
|
||||
}
|
||||
}
|
||||
if leadsPage == 1 {
|
||||
hasLoadedLeadsOnce = true
|
||||
}
|
||||
isLoadingMore = false
|
||||
}
|
||||
|
||||
private func loadOrders(api: CooperationOrderServing) async {
|
||||
do {
|
||||
let keyword = searchText.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let data = try await api.saleUserAcquisitionOrders(
|
||||
keyword: keyword.isEmpty ? nil : keyword,
|
||||
page: ordersPage,
|
||||
pageSize: pageSize
|
||||
)
|
||||
ordersTotal = data.total
|
||||
if ordersPage == 1 {
|
||||
orders = data.list
|
||||
} else {
|
||||
orders.append(contentsOf: data.list)
|
||||
}
|
||||
canLoadMore = orders.count < ordersTotal
|
||||
} catch {
|
||||
if ordersPage == 1, !hasLoadedOrdersOnce {
|
||||
orders = []
|
||||
}
|
||||
}
|
||||
if ordersPage == 1 {
|
||||
hasLoadedOrdersOnce = true
|
||||
}
|
||||
isLoadingMore = false
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user