Files
suixinkan_uikit/suixinkan/Features/Orders/Utils/MainTabScanHandler.swift

205 lines
7.4 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// MainTabScanHandler.swift
// suixinkan
//
import CoreLocation
import UIKit
/// Tab Android `MainTabViewModel.signIn`
@MainActor
final class MainTabScanHandler: NSObject, CLLocationManagerDelegate {
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 locationManager = CLLocationManager()
private var locationContinuation: ((Result<CLLocationCoordinate2D, Error>) -> Void)?
private(set) var pendingMultiVerify: MultiVerifyParseData?
init(api: OrderAPI) {
self.api = api
super.init()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
}
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 {
let status = locationManager.authorizationStatus
guard status == .authorizedWhenInUse || status == .authorizedAlways else {
locationManager.requestWhenInUseAuthorization()
onShowMessage?("缺少定位权限,功能无法进行")
return
}
do {
let coordinate = try await requestLocation()
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 {
onShowMessage?(error.localizedDescription)
}
}
private func requestLocation() async throws -> CLLocationCoordinate2D {
try await withCheckedThrowingContinuation { continuation in
locationContinuation = { result in
switch result {
case .success(let coordinate):
continuation.resume(returning: coordinate)
case .failure(let error):
continuation.resume(throwing: error)
}
}
locationManager.requestLocation()
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
locationContinuation?(.success(location.coordinate))
locationContinuation = nil
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
locationContinuation?(.failure(error))
locationContinuation = nil
}
}
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)
}
}