// // OrdersViewModel.swift // suixinkan // // Created by Codex on 2026/6/22. // import Foundation import Observation @MainActor @Observable /// 订单页面 ViewModel,管理订单列表、核销列表、筛选条件和手动核销流程。 final class OrdersViewModel { var selectedEntry: OrdersEntry = .storeOrders var selectedStatus = 0 var searchPhone = "" var filterStartDate: Date? var filterEndDate: Date? private(set) var loading = false private(set) var loadingMore = false private(set) var isVerifying = false private(set) var currentVerifyingOrderNumber: String? private(set) var storeOrders: [OrderEntity] = [] private(set) var storeTotal = 0 private(set) var storePage = 1 private(set) var storeHasMore = false private(set) var writeOffOrders: [WriteOffOrderItem] = [] private(set) var writeOffTotal = 0 private(set) var writeOffPage = 1 private(set) var writeOffHasMore = false /// 返回去除首尾空白后的手机号搜索值。 var normalizedPhone: String? { let text = searchPhone.trimmingCharacters(in: .whitespacesAndNewlines) return text.isEmpty ? nil : text } /// 根据当前子入口刷新对应列表。 func reload(api: OrderServing, scenicId: Int?, roleId: Int?, showLoading: Bool = true) async throws { switch selectedEntry { case .storeOrders: try await reloadStoreOrders(api: api, scenicId: scenicId, roleId: roleId, showLoading: showLoading) case .verificationOrders: try await reloadWriteOffOrders(api: api, scenicId: scenicId, showLoading: showLoading) } } /// 刷新订单管理列表,缺少景区时清空旧数据。 func reloadStoreOrders(api: OrderServing, scenicId: Int?, roleId: Int?, showLoading: Bool = true) async throws { guard let scenicId else { storeOrders = [] storeTotal = 0 storePage = 1 storeHasMore = false return } if showLoading { loading = true } defer { if showLoading { loading = false } } let result = try await api.orderList( scenicId: scenicId, page: 1, pageSize: pageSize, orderStatus: orderStatusQuery, userPhone: normalizedPhone, startTime: startTimeQuery, endTime: endTimeQuery, isRefined: refinedQuery, isScenicAdmin: roleId == 53 ) storeOrders = result.list storeTotal = result.total storePage = 1 storeHasMore = storeOrders.count < result.total && !result.list.isEmpty } /// 加载订单管理下一页。 func loadMoreStoreOrders(api: OrderServing, scenicId: Int?, roleId: Int?) async throws { guard !loadingMore, storeHasMore, let scenicId else { return } loadingMore = true defer { loadingMore = false } let nextPage = storePage + 1 let result = try await api.orderList( scenicId: scenicId, page: nextPage, pageSize: pageSize, orderStatus: orderStatusQuery, userPhone: normalizedPhone, startTime: startTimeQuery, endTime: endTimeQuery, isRefined: refinedQuery, isScenicAdmin: roleId == 53 ) storeOrders.append(contentsOf: result.list) storeTotal = result.total storePage = nextPage storeHasMore = storeOrders.count < result.total && !result.list.isEmpty } /// 刷新核销订单列表,缺少景区时清空旧数据。 func reloadWriteOffOrders(api: OrderServing, scenicId: Int?, showLoading: Bool = true) async throws { guard let scenicId else { writeOffOrders = [] writeOffTotal = 0 writeOffPage = 1 writeOffHasMore = false return } if showLoading { loading = true } defer { if showLoading { loading = false } } let result = try await api.writeOffList(scenicId: scenicId, page: 1, pageSize: pageSize) writeOffOrders = result.list writeOffTotal = result.total writeOffPage = 1 writeOffHasMore = writeOffOrders.count < result.total && !result.list.isEmpty } /// 加载核销订单下一页。 func loadMoreWriteOffOrders(api: OrderServing, scenicId: Int?) async throws { guard !loadingMore, writeOffHasMore, let scenicId else { return } loadingMore = true defer { loadingMore = false } let nextPage = writeOffPage + 1 let result = try await api.writeOffList(scenicId: scenicId, page: nextPage, pageSize: pageSize) writeOffOrders.append(contentsOf: result.list) writeOffTotal = result.total writeOffPage = nextPage writeOffHasMore = writeOffOrders.count < result.total && !result.list.isEmpty } /// 手动核销订单,并在成功后刷新核销列表。 func verify(api: OrderServing, scenicId: Int, orderNumber: String) async throws { guard !isVerifying else { return } isVerifying = true currentVerifyingOrderNumber = orderNumber defer { isVerifying = false currentVerifyingOrderNumber = nil } try await api.writeOff(orderNumber: orderNumber) let refreshed = try await api.writeOffList(scenicId: scenicId, page: 1, pageSize: pageSize) writeOffOrders = refreshed.list writeOffTotal = refreshed.total writeOffPage = 1 writeOffHasMore = writeOffOrders.count < refreshed.total && !refreshed.list.isEmpty } /// 用于测试重复提交场景的内部状态设置。 func markVerifyingForTests(orderNumber: String) { isVerifying = true currentVerifyingOrderNumber = orderNumber } private let pageSize = 20 private var orderStatusQuery: Int? { selectedStatus > 0 ? selectedStatus : nil } private var startTimeQuery: String? { filterStartDate.map { Self.dayFormatter.string(from: $0) } } private var endTimeQuery: String? { filterEndDate.map { Self.dayFormatter.string(from: $0) } } private var refinedQuery: Int? { switch selectedStatus { case -1: return 1 case -2: return 2 default: return nil } } private static let dayFormatter: DateFormatter = { let formatter = DateFormatter() formatter.calendar = Calendar(identifier: .gregorian) formatter.locale = Locale(identifier: "en_US_POSIX") formatter.dateFormat = "yyyy-MM-dd" return formatter }() }