// // 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 } } }