迁移合作订单完整能力,并统一 AppRoleCode 角色权限与首页菜单展示。
新增 CooperationOrder 模块(双 Tab 列表、获客员绑定、主 Tab 扫码)、订单来源/带客单绑定及配套 API 测试;同步引入 roleCode 权限匹配与相关单元测试。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@ -31,6 +31,16 @@ final class OrdersViewModel: ObservableObject {
|
||||
@Published private(set) var writeOffPage = 1
|
||||
@Published private(set) var writeOffHasMore = false
|
||||
|
||||
@Published var orderSourcePeople: [OrderSourcePerson] = []
|
||||
@Published var orderSourceLeads: [String: [OrderSourceLead]] = [:]
|
||||
@Published var orderSourceSelections: [String: OrderSourceSelection] = [:]
|
||||
@Published var loadingOrderSourceLeadsFor: String?
|
||||
|
||||
private var loadingOrderSourcePeople = false
|
||||
|
||||
static let orderTypePhotographerFollow = 11
|
||||
static let orderTypePhotographerFollowOfflineScan = 14
|
||||
|
||||
/// 返回去除首尾空白后的手机号搜索值。
|
||||
var normalizedPhone: String? {
|
||||
let text = searchPhone.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
@ -38,17 +48,17 @@ final class OrdersViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
/// 根据当前子入口刷新对应列表。
|
||||
func reload(api: OrderServing, scenicId: Int?, storeId: Int? = nil, roleId: Int?, showLoading: Bool = true) async throws {
|
||||
func reload(api: OrderServing, scenicId: Int?, storeId: Int? = nil, appRole: AppRoleCode?, showLoading: Bool = true) async throws {
|
||||
switch selectedEntry {
|
||||
case .storeOrders:
|
||||
try await reloadStoreOrders(api: api, scenicId: scenicId, roleId: roleId, showLoading: showLoading)
|
||||
try await reloadStoreOrders(api: api, scenicId: scenicId, appRole: appRole, showLoading: showLoading)
|
||||
case .verificationOrders:
|
||||
try await reloadWriteOffOrders(api: api, scenicId: scenicId, storeId: storeId, showLoading: showLoading)
|
||||
}
|
||||
}
|
||||
|
||||
/// 刷新订单管理列表,缺少景区时清空旧数据。
|
||||
func reloadStoreOrders(api: OrderServing, scenicId: Int?, roleId: Int?, showLoading: Bool = true) async throws {
|
||||
func reloadStoreOrders(api: OrderServing, scenicId: Int?, appRole: AppRoleCode?, showLoading: Bool = true) async throws {
|
||||
guard let scenicId else {
|
||||
storeOrders = []
|
||||
storeTotal = 0
|
||||
@ -69,16 +79,17 @@ final class OrdersViewModel: ObservableObject {
|
||||
startTime: startTimeQuery,
|
||||
endTime: endTimeQuery,
|
||||
isRefined: refinedQuery,
|
||||
isScenicAdmin: roleId == 53
|
||||
isScenicAdmin: appRole?.isScenicAdmin == true
|
||||
)
|
||||
storeOrders = result.list
|
||||
storeTotal = result.total
|
||||
storePage = 1
|
||||
storeHasMore = storeOrders.count < result.total && !result.list.isEmpty
|
||||
syncOrderSourceSelections(from: result.list)
|
||||
}
|
||||
|
||||
/// 加载订单管理下一页。
|
||||
func loadMoreStoreOrders(api: OrderServing, scenicId: Int?, roleId: Int?) async throws {
|
||||
func loadMoreStoreOrders(api: OrderServing, scenicId: Int?, appRole: AppRoleCode?) async throws {
|
||||
guard !loadingMore, storeHasMore, let scenicId else { return }
|
||||
loadingMore = true
|
||||
defer { loadingMore = false }
|
||||
@ -93,7 +104,7 @@ final class OrdersViewModel: ObservableObject {
|
||||
startTime: startTimeQuery,
|
||||
endTime: endTimeQuery,
|
||||
isRefined: refinedQuery,
|
||||
isScenicAdmin: roleId == 53
|
||||
isScenicAdmin: appRole?.isScenicAdmin == true
|
||||
)
|
||||
storeOrders.append(contentsOf: result.list)
|
||||
storeTotal = result.total
|
||||
@ -154,6 +165,81 @@ final class OrdersViewModel: ObservableObject {
|
||||
writeOffHasMore = writeOffOrders.count < refreshed.total && !refreshed.list.isEmpty
|
||||
}
|
||||
|
||||
/// 判断订单卡片是否展示订单来源入口。
|
||||
func shouldShowOrderSource(order: OrderEntity, appRole: AppRoleCode?) -> Bool {
|
||||
guard !Self.isScenicAdminReadOnly(appRole: appRole) else { return false }
|
||||
return order.orderType == Self.orderTypePhotographerFollow
|
||||
|| order.orderType == Self.orderTypePhotographerFollowOfflineScan
|
||||
}
|
||||
|
||||
/// 景区管理员只读模式,不可操作订单来源。
|
||||
static func isScenicAdminReadOnly(appRole: AppRoleCode?) -> Bool {
|
||||
appRole?.isScenicAdmin == true
|
||||
}
|
||||
|
||||
/// 获取订单已选中的订单来源。
|
||||
func getOrderSourceSelection(for order: OrderEntity) -> OrderSourceSelection? {
|
||||
orderSourceSelections[order.orderNumber] ?? order.toBoundOrderSourceSelection()
|
||||
}
|
||||
|
||||
/// 从列表数据同步已绑定订单来源。
|
||||
func syncOrderSourceSelections(from orders: [OrderEntity]) {
|
||||
var updated = orderSourceSelections
|
||||
for order in orders {
|
||||
if let selection = order.toBoundOrderSourceSelection() {
|
||||
updated[order.orderNumber] = selection
|
||||
}
|
||||
}
|
||||
orderSourceSelections = updated
|
||||
}
|
||||
|
||||
/// 打开订单来源 Sheet 前预加载获客员列表。
|
||||
func prepareOrderSourceSheet(api: CooperationOrderServing, storeId: Int?) async {
|
||||
orderSourceLeads = [:]
|
||||
await loadOrderSourcePeople(api: api, storeId: storeId)
|
||||
}
|
||||
|
||||
/// 加载合作获客员列表供订单来源选择。
|
||||
func loadOrderSourcePeople(api: CooperationOrderServing, storeId: Int?) async {
|
||||
if loadingOrderSourcePeople { return }
|
||||
loadingOrderSourcePeople = true
|
||||
defer { loadingOrderSourcePeople = false }
|
||||
do {
|
||||
let storeParam = storeId.flatMap { $0 > 0 ? $0 : nil }
|
||||
let data = try await api.cooperativeSalers(storeId: storeParam, page: 1, pageSize: 50)
|
||||
orderSourcePeople = data.list.map { $0.toOrderSourcePerson() }
|
||||
} catch {
|
||||
orderSourcePeople = []
|
||||
}
|
||||
}
|
||||
|
||||
/// 加载指定获客员的可绑定带客单。
|
||||
func loadOrderSourceLeads(api: CooperationOrderServing, person: OrderSourcePerson) async {
|
||||
if loadingOrderSourceLeadsFor == person.key { return }
|
||||
loadingOrderSourceLeadsFor = person.key
|
||||
defer { loadingOrderSourceLeadsFor = nil }
|
||||
guard let saleUserId = Int(person.key) else { return }
|
||||
do {
|
||||
let data = try await api.saleUserReferralOrders(saleUserId: saleUserId, page: 1, pageSize: 50)
|
||||
orderSourceLeads[person.key] = data.list.map { $0.toOrderSourceLead() }
|
||||
} catch {
|
||||
orderSourceLeads[person.key] = []
|
||||
}
|
||||
}
|
||||
|
||||
/// 绑定订单来源带客单。
|
||||
func bindOrderSource(
|
||||
api: CooperationOrderServing,
|
||||
orderNumber: String,
|
||||
selection: OrderSourceSelection
|
||||
) async throws {
|
||||
try await api.saleUserBindReferralOrder(
|
||||
orderNumber: orderNumber,
|
||||
referralOrderNo: selection.lead.key
|
||||
)
|
||||
orderSourceSelections[orderNumber] = selection
|
||||
}
|
||||
|
||||
/// 解析扫码结果并返回当前核销列表中的匹配订单。
|
||||
func matchedWriteOffOrder(for rawCode: String) -> (orderNumber: String, matched: WriteOffOrderItem?)? {
|
||||
guard let orderNumber = OrderNumberParser.parse(rawCode) else {
|
||||
|
||||
Reference in New Issue
Block a user