// // MainTabScanHandler.swift // suixinkan // import UIKit /// 主 Tab 中间扫码按钮结果处理,对齐 Android `MainTabViewModel.signIn`。 @MainActor final class MainTabScanHandler { var onShowMessage: ((String) -> Void)? var onShowSignIn: ((OrderSignInResponse) -> Void)? var onShowWriteOff: ((WriteOffOrderResponse) -> Void)? var onMultiVerifyPending: ((MultiVerifyParseData) -> Void)? var onShowMultiVerifySheet: (([MultiTravelScenicSpotEntity], MultiTravelScenicSpotEntity?) -> Void)? var onNavigateBindAcquirer: ((Int) -> Void)? private let api: OrderAPI private let locationProvider: any LocationProviding private(set) var pendingMultiVerify: MultiVerifyParseData? init(api: OrderAPI, locationProvider: any LocationProviding = LocationProvider.shared) { self.api = api self.locationProvider = locationProvider } func handleScanResult(_ scanResult: String) async { guard !scanResult.isEmpty else { onShowMessage?("请扫描正确的二维码") return } guard let parsed = QRCodeScanResult.parse(scanResult) else { onShowMessage?("请扫描正确的二维码") return } switch parsed.method { case "check_in": await performCheckIn(scanResult: scanResult) case "order_verify": if AppStore.shared.currentAppRole == .storeAdmin { await performStoreVerify(parsed: parsed) } else { await performPhotographerVerify(jsonBody: parsed.rawJSON) } case "multi_verify": guard !parsed.orderNumber.isEmpty, parsed.userId > 0, parsed.timeLong > 0, !parsed.checkSum.isEmpty else { onShowMessage?("请扫描正确的多点位核销码") return } let pending = MultiVerifyParseData( orderNumber: parsed.orderNumber, userId: parsed.userId, time: parsed.timeLong, checkSum: parsed.checkSum ) pendingMultiVerify = pending onMultiVerifyPending?(pending) await fetchSpotsForMultiVerify(pending: pending) case SaleUserQrParser.methodSaleUserBind: if let id = SaleUserQrParser.parseSaleUserId(scanResult), id > 0 { onNavigateBindAcquirer?(id) } else { onShowMessage?("请扫描正确的获客员二维码") } default: onShowMessage?("未知二维码,请检查后重试") } } func confirmMultiVerify(pending: MultiVerifyParseData, spot: MultiTravelScenicSpotEntity) async { do { let response = try await api.multiTravelOrderVerify( MultiTravelOrderVerifyRequest( orderNumber: pending.orderNumber, userId: pending.userId, time: pending.time, checkSum: pending.checkSum, scenicSpotId: spot.scenicSpotId ) ) onShowSignIn?(response) } catch { onShowMessage?(error.localizedDescription) } } private func performCheckIn(scanResult: String) async { guard var json = parseJSONObject(scanResult) else { onShowMessage?("请扫描正确的二维码") return } json["scenic_id"] = String(AppStore.shared.currentScenicId) guard let body = serializeJSON(json) else { return } do { let response = try await api.orderCheckIn(jsonBody: body) onShowSignIn?(response) } catch { onShowMessage?(error.localizedDescription) } } private func performPhotographerVerify(jsonBody: String) async { do { let response = try await api.orderVerify(jsonBody: jsonBody) onShowWriteOff?(response) } catch { onShowMessage?(error.localizedDescription) } } private func performStoreVerify(parsed: QRCodeScanResult) async { guard parsed.userId > 0, !parsed.orderNumber.isEmpty, !parsed.time.isEmpty else { onShowMessage?("请扫描正确的核销码") return } let storeId = AppStore.shared.currentStoreId guard storeId > 0 else { onShowMessage?("店铺信息异常,请先选择店铺") return } do { let response = try await api.storeOrderVerify( StoreOrderVerifyRequest( userId: parsed.userId, orderNumber: parsed.orderNumber, time: parsed.time, storeId: storeId ) ) onShowWriteOff?(response) } catch { onShowMessage?(error.localizedDescription) } } private func fetchSpotsForMultiVerify(pending: MultiVerifyParseData) async { do { let coordinate = try await locationProvider.requestCoordinate() let response = try await api.multiTravelScenicSpotList( orderNumber: pending.orderNumber, lat: coordinate.latitude, lng: coordinate.longitude ) let spots = response.entityList if spots.isEmpty { onShowMessage?("暂无可核销的打卡点") } else { onShowMultiVerifySheet?(spots, spots.first) } } catch LocationProviderError.permissionDenied { onShowMessage?(OrderLocationError.permissionDenied.errorDescription ?? "缺少定位权限,功能无法进行") } catch { onShowMessage?((error as? LocalizedError)?.errorDescription ?? error.localizedDescription) } } } private extension MainTabScanHandler { func parseJSONObject(_ text: String) -> [String: Any]? { guard let data = text.data(using: .utf8) else { return nil } return try? JSONSerialization.jsonObject(with: data) as? [String: Any] } func serializeJSON(_ json: [String: Any]) -> String? { guard let data = try? JSONSerialization.data(withJSONObject: json) else { return nil } return String(data: data, encoding: .utf8) } }