新增门店订单与核销管理列表,对齐 Android 订单能力并完善账号级缓存。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
141
suixinkan/Features/Orders/ViewModels/WriteOffListViewModel.swift
Normal file
141
suixinkan/Features/Orders/ViewModels/WriteOffListViewModel.swift
Normal file
@ -0,0 +1,141 @@
|
||||
//
|
||||
// WriteOffListViewModel.swift
|
||||
// suixinkan
|
||||
//
|
||||
// Created by Codex on 2026/6/29.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
|
||||
@MainActor
|
||||
/// 核销管理页 ViewModel,对齐 Android WriteOffListViewModel。
|
||||
final class WriteOffListViewModel: ObservableObject {
|
||||
@Published var searchPhone = ""
|
||||
@Published var selectedStatus = 0
|
||||
@Published var filterStartDate: Date?
|
||||
@Published var filterEndDate: Date?
|
||||
@Published private(set) var orders: [WriteOffOrderItem] = []
|
||||
@Published private(set) var loading = false
|
||||
@Published private(set) var loadingMore = false
|
||||
@Published private(set) var isVerifying = false
|
||||
@Published private(set) var total = 0
|
||||
@Published private(set) var page = 1
|
||||
@Published private(set) var hasMore = false
|
||||
|
||||
private let pageSize = 20
|
||||
|
||||
/// 返回去除首尾空白后的手机号搜索值。
|
||||
var normalizedPhone: String? {
|
||||
let text = searchPhone.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
return text.isEmpty ? nil : text
|
||||
}
|
||||
|
||||
/// 刷新核销列表。
|
||||
func reload(api: OrderServing, scenicId: Int?, storeId: Int? = nil, showLoading: Bool = true) async throws {
|
||||
guard let scenicId else {
|
||||
orders = []
|
||||
total = 0
|
||||
page = 1
|
||||
hasMore = false
|
||||
return
|
||||
}
|
||||
|
||||
if showLoading { loading = true }
|
||||
defer { if showLoading { loading = false } }
|
||||
|
||||
let result = try await api.writeOffList(
|
||||
scenicId: scenicId,
|
||||
storeId: storeId,
|
||||
page: 1,
|
||||
pageSize: pageSize,
|
||||
orderStatus: orderStatusQuery,
|
||||
orderVerifyStatus: verifyStatusQuery,
|
||||
startTime: OrderDateRangeFormatter.queryValue(from: filterStartDate),
|
||||
endTime: OrderDateRangeFormatter.queryValue(from: filterEndDate),
|
||||
userPhone: normalizedPhone
|
||||
)
|
||||
orders = result.list
|
||||
total = result.total
|
||||
page = 1
|
||||
hasMore = orders.count < result.total && !result.list.isEmpty
|
||||
}
|
||||
|
||||
/// 加载下一页。
|
||||
func loadMore(api: OrderServing, scenicId: Int?, storeId: Int? = nil) async throws {
|
||||
guard !loadingMore, hasMore, let scenicId else { return }
|
||||
loadingMore = true
|
||||
defer { loadingMore = false }
|
||||
|
||||
let nextPage = page + 1
|
||||
let result = try await api.writeOffList(
|
||||
scenicId: scenicId,
|
||||
storeId: storeId,
|
||||
page: nextPage,
|
||||
pageSize: pageSize,
|
||||
orderStatus: orderStatusQuery,
|
||||
orderVerifyStatus: verifyStatusQuery,
|
||||
startTime: OrderDateRangeFormatter.queryValue(from: filterStartDate),
|
||||
endTime: OrderDateRangeFormatter.queryValue(from: filterEndDate),
|
||||
userPhone: normalizedPhone
|
||||
)
|
||||
orders.append(contentsOf: result.list)
|
||||
total = result.total
|
||||
page = nextPage
|
||||
hasMore = orders.count < result.total && !result.list.isEmpty
|
||||
}
|
||||
|
||||
/// 核销订单并刷新列表。
|
||||
func verify(api: OrderServing, scenicId: Int, storeId: Int? = nil, orderNumber: String) async throws {
|
||||
guard !isVerifying else { return }
|
||||
isVerifying = true
|
||||
defer { isVerifying = false }
|
||||
|
||||
try await api.writeOff(orderNumber: orderNumber)
|
||||
try await reload(api: api, scenicId: scenicId, storeId: storeId, showLoading: false)
|
||||
}
|
||||
|
||||
/// 解析扫码结果并返回当前列表中的匹配订单。
|
||||
func matchedWriteOffOrder(for rawCode: String) -> (orderNumber: String, matched: WriteOffOrderItem?)? {
|
||||
guard let orderNumber = OrderNumberParser.parse(rawCode) else { return nil }
|
||||
let matched = orders.first {
|
||||
$0.orderNumber.caseInsensitiveCompare(orderNumber) == .orderedSame
|
||||
}
|
||||
return (matched?.orderNumber ?? orderNumber, matched)
|
||||
}
|
||||
|
||||
/// 根据订单号查找当前列表中的订单。
|
||||
func writeOffOrder(matching orderNumber: String) -> WriteOffOrderItem? {
|
||||
orders.first { $0.orderNumber.caseInsensitiveCompare(orderNumber) == .orderedSame }
|
||||
}
|
||||
|
||||
/// 判断订单是否仍可核销。
|
||||
func canVerify(_ item: WriteOffOrderItem) -> Bool {
|
||||
let status = displayVerificationStatus(for: item)
|
||||
return !status.contains("已核销") && !status.contains("已退款") && !status.contains("已完成")
|
||||
}
|
||||
|
||||
/// 返回核销状态展示文案。
|
||||
func displayVerificationStatus(for item: WriteOffOrderItem) -> String {
|
||||
let text = item.orderVerificationStatus.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
return text.isEmpty ? "待核销" : text
|
||||
}
|
||||
|
||||
private var orderStatusQuery: Int? {
|
||||
switch selectedStatus {
|
||||
case 18, 30:
|
||||
return selectedStatus
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
private var verifyStatusQuery: Int? {
|
||||
switch selectedStatus {
|
||||
case 1, 2:
|
||||
return selectedStatus
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user