Sync order detail and scanner verification

This commit is contained in:
2026-06-22 17:03:27 +08:00
parent 0b83a73509
commit c2652b83c4
15 changed files with 1456 additions and 54 deletions

View File

@ -0,0 +1,71 @@
//
// OrderDetailViewModel.swift
// suixinkan
//
// Created by Codex on 2026/6/22.
//
import Foundation
import Observation
@MainActor
@Observable
/// ViewModel
final class OrderDetailViewModel {
private(set) var detail: StoreOrderDetailResponse?
private(set) var loading = false
private(set) var errorMessage: String?
private(set) var contextMessage: String?
/// 使
var display: StoreOrderDetailDisplay {
if let detail {
return StoreOrderDetailDisplay(detail: detail)
}
return StoreOrderDetailDisplay(item: item)
}
///
var projectInfo: StoreOrderProjectInfo? {
detail?.multiTravel?.projectInfo
}
///
var shootingList: [StoreOrderShootingListItem] {
detail?.multiTravel?.shootingList ?? []
}
private let item: OrderEntity
/// ViewModel
init(item: OrderEntity) {
self.item = item
}
/// ID
func load(api: OrderServing, fallbackStoreId: Int?) async {
guard detail == nil, !loading else { return }
guard let storeId = item.storeId ?? fallbackStoreId, storeId > 0 else {
contextMessage = "缺少门店上下文,当前展示订单摘要。"
return
}
loading = true
errorMessage = nil
contextMessage = nil
defer { loading = false }
do {
detail = try await api.storeOrderDetail(storeId: storeId, orderNumber: item.orderNumber)
} catch {
errorMessage = error.localizedDescription
contextMessage = "详情加载失败,当前展示订单摘要。"
}
}
///
func clearError() {
errorMessage = nil
}
}

View File

@ -39,12 +39,12 @@ final class OrdersViewModel {
}
///
func reload(api: OrderServing, scenicId: Int?, roleId: Int?, showLoading: Bool = true) async throws {
func reload(api: OrderServing, scenicId: Int?, storeId: Int? = nil, 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)
try await reloadWriteOffOrders(api: api, scenicId: scenicId, storeId: storeId, showLoading: showLoading)
}
}
@ -103,7 +103,7 @@ final class OrdersViewModel {
}
///
func reloadWriteOffOrders(api: OrderServing, scenicId: Int?, showLoading: Bool = true) async throws {
func reloadWriteOffOrders(api: OrderServing, scenicId: Int?, storeId: Int? = nil, showLoading: Bool = true) async throws {
guard let scenicId else {
writeOffOrders = []
writeOffTotal = 0
@ -115,7 +115,7 @@ final class OrdersViewModel {
if showLoading { loading = true }
defer { if showLoading { loading = false } }
let result = try await api.writeOffList(scenicId: scenicId, page: 1, pageSize: pageSize)
let result = try await api.writeOffList(scenicId: scenicId, storeId: storeId, page: 1, pageSize: pageSize)
writeOffOrders = result.list
writeOffTotal = result.total
writeOffPage = 1
@ -123,13 +123,13 @@ final class OrdersViewModel {
}
///
func loadMoreWriteOffOrders(api: OrderServing, scenicId: Int?) async throws {
func loadMoreWriteOffOrders(api: OrderServing, scenicId: Int?, storeId: Int? = nil) 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)
let result = try await api.writeOffList(scenicId: scenicId, storeId: storeId, page: nextPage, pageSize: pageSize)
writeOffOrders.append(contentsOf: result.list)
writeOffTotal = result.total
writeOffPage = nextPage
@ -137,7 +137,7 @@ final class OrdersViewModel {
}
///
func verify(api: OrderServing, scenicId: Int, orderNumber: String) async throws {
func verify(api: OrderServing, scenicId: Int, storeId: Int? = nil, orderNumber: String) async throws {
guard !isVerifying else { return }
isVerifying = true
@ -148,13 +148,31 @@ final class OrdersViewModel {
}
try await api.writeOff(orderNumber: orderNumber)
let refreshed = try await api.writeOffList(scenicId: scenicId, page: 1, pageSize: pageSize)
let refreshed = try await api.writeOffList(scenicId: scenicId, storeId: storeId, page: 1, pageSize: pageSize)
writeOffOrders = refreshed.list
writeOffTotal = refreshed.total
writeOffPage = 1
writeOffHasMore = writeOffOrders.count < refreshed.total && !refreshed.list.isEmpty
}
///
func matchedWriteOffOrder(for rawCode: String) -> (orderNumber: String, matched: WriteOffOrderItem?)? {
guard let orderNumber = OrderNumberParser.parse(rawCode) else {
return nil
}
let matched = writeOffOrders.first {
$0.orderNumber.caseInsensitiveCompare(orderNumber) == .orderedSame
}
return (matched?.orderNumber ?? orderNumber, matched)
}
///
func writeOffOrder(matching orderNumber: String) -> WriteOffOrderItem? {
writeOffOrders.first {
$0.orderNumber.caseInsensitiveCompare(orderNumber) == .orderedSame
}
}
///
func markVerifyingForTests(orderNumber: String) {
isVerifying = true