修复位置上报解析并立即居中到用户位置
This commit is contained in:
@ -34,6 +34,37 @@ struct LocationReportResponse: Decodable, Sendable {
|
|||||||
case staffId = "staff_id"
|
case staffId = "staff_id"
|
||||||
case expired
|
case expired
|
||||||
case status
|
case status
|
||||||
|
case storeUserId = "store_user_id"
|
||||||
|
}
|
||||||
|
|
||||||
|
init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
staffId = Self.decodeFlexibleString(from: container, forKey: .staffId)
|
||||||
|
expired = try container.decodeIfPresent(Int64.self, forKey: .expired) ?? 0
|
||||||
|
status = try container.decodeIfPresent(Int.self, forKey: .status) ?? 0
|
||||||
|
}
|
||||||
|
|
||||||
|
init(staffId: String = "", expired: Int64 = 0, status: Int = 0) {
|
||||||
|
self.staffId = staffId
|
||||||
|
self.expired = expired
|
||||||
|
self.status = status
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func decodeFlexibleString(
|
||||||
|
from container: KeyedDecodingContainer<CodingKeys>,
|
||||||
|
forKey key: CodingKeys,
|
||||||
|
defaultValue: String = ""
|
||||||
|
) -> String {
|
||||||
|
if let string = try? container.decode(String.self, forKey: key) {
|
||||||
|
return string
|
||||||
|
}
|
||||||
|
if let intValue = try? container.decode(Int.self, forKey: key) {
|
||||||
|
return String(intValue)
|
||||||
|
}
|
||||||
|
if let int64Value = try? container.decode(Int64.self, forKey: key) {
|
||||||
|
return String(int64Value)
|
||||||
|
}
|
||||||
|
return defaultValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -82,8 +82,8 @@ final class LocationReportViewController: BaseViewController {
|
|||||||
mapControls.onZoomIn = { [weak self] in self?.mapContainer.zoomIn() }
|
mapControls.onZoomIn = { [weak self] in self?.mapContainer.zoomIn() }
|
||||||
mapControls.onZoomOut = { [weak self] in self?.mapContainer.zoomOut() }
|
mapControls.onZoomOut = { [weak self] in self?.mapContainer.zoomOut() }
|
||||||
mapControls.onRelocate = { [weak self] in
|
mapControls.onRelocate = { [weak self] in
|
||||||
self?.viewModel.startLocation()
|
|
||||||
self?.mapContainer.centerOnUserLocation()
|
self?.mapContainer.centerOnUserLocation()
|
||||||
|
self?.viewModel.startLocation()
|
||||||
}
|
}
|
||||||
mapContainer.onMapTap = { [weak self] coordinate in
|
mapContainer.onMapTap = { [weak self] coordinate in
|
||||||
self?.viewModel.setMarkerLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
|
self?.viewModel.setMarkerLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
|
||||||
@ -105,6 +105,7 @@ final class LocationReportViewController: BaseViewController {
|
|||||||
onlineButton.addTarget(self, action: #selector(onlineTapped), for: .touchUpInside)
|
onlineButton.addTarget(self, action: #selector(onlineTapped), for: .touchUpInside)
|
||||||
|
|
||||||
viewModel.restoreStateIfNeeded()
|
viewModel.restoreStateIfNeeded()
|
||||||
|
mapContainer.enableInitialUserLocationCentering()
|
||||||
requestLocationIfNeeded()
|
requestLocationIfNeeded()
|
||||||
applyViewModel()
|
applyViewModel()
|
||||||
}
|
}
|
||||||
@ -113,6 +114,7 @@ final class LocationReportViewController: BaseViewController {
|
|||||||
Task {
|
Task {
|
||||||
do {
|
do {
|
||||||
try await LocationProvider.shared.ensureLocationPermission()
|
try await LocationProvider.shared.ensureLocationPermission()
|
||||||
|
mapContainer.enableInitialUserLocationCentering()
|
||||||
viewModel.startLocation()
|
viewModel.startLocation()
|
||||||
} catch {
|
} catch {
|
||||||
showToast((error as? LocalizedError)?.errorDescription ?? error.localizedDescription)
|
showToast((error as? LocalizedError)?.errorDescription ?? error.localizedDescription)
|
||||||
|
|||||||
@ -294,6 +294,7 @@ final class LocationReportMapView: UIView, MAMapViewDelegate {
|
|||||||
|
|
||||||
let mapView: MAMapView
|
let mapView: MAMapView
|
||||||
private var markerAnnotation: MAPointAnnotation?
|
private var markerAnnotation: MAPointAnnotation?
|
||||||
|
private var shouldCenterOnNextUserLocation = false
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
_ = AMapBootstrap.configureIfNeeded()
|
_ = AMapBootstrap.configureIfNeeded()
|
||||||
@ -314,9 +315,14 @@ final class LocationReportMapView: UIView, MAMapViewDelegate {
|
|||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 进入页面后,在首次拿到用户位置时将地图居中(不持续跟随,便于手动拖动)。
|
||||||
|
func enableInitialUserLocationCentering() {
|
||||||
|
shouldCenterOnNextUserLocation = true
|
||||||
|
centerOnUserLocationIfNeeded()
|
||||||
|
}
|
||||||
|
|
||||||
func centerOnUserLocation() {
|
func centerOnUserLocation() {
|
||||||
let coordinate = mapView.userLocation.location?.coordinate
|
guard let coordinate = validUserCoordinate else { return }
|
||||||
guard let coordinate, CLLocationCoordinate2DIsValid(coordinate) else { return }
|
|
||||||
setCenter(coordinate)
|
setCenter(coordinate)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,7 +351,25 @@ final class LocationReportMapView: UIView, MAMapViewDelegate {
|
|||||||
mapView.addAnnotation(annotation)
|
mapView.addAnnotation(annotation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mapView(_ mapView: MAMapView!, didUpdate userLocation: MAUserLocation!, updatingLocation: Bool) {
|
||||||
|
guard updatingLocation else { return }
|
||||||
|
centerOnUserLocationIfNeeded()
|
||||||
|
}
|
||||||
|
|
||||||
func mapView(_ mapView: MAMapView!, didSingleTappedAt coordinate: CLLocationCoordinate2D) {
|
func mapView(_ mapView: MAMapView!, didSingleTappedAt coordinate: CLLocationCoordinate2D) {
|
||||||
onMapTap?(coordinate)
|
onMapTap?(coordinate)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var validUserCoordinate: CLLocationCoordinate2D? {
|
||||||
|
let coordinate = mapView.userLocation.location?.coordinate
|
||||||
|
guard let coordinate, CLLocationCoordinate2DIsValid(coordinate) else { return nil }
|
||||||
|
guard coordinate.latitude != 0 || coordinate.longitude != 0 else { return nil }
|
||||||
|
return coordinate
|
||||||
|
}
|
||||||
|
|
||||||
|
private func centerOnUserLocationIfNeeded() {
|
||||||
|
guard shouldCenterOnNextUserLocation, let coordinate = validUserCoordinate else { return }
|
||||||
|
setCenter(coordinate, animated: false)
|
||||||
|
shouldCenterOnNextUserLocation = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,6 +26,26 @@ final class LocationReportServiceTests: XCTestCase {
|
|||||||
super.tearDown()
|
super.tearDown()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testReportLocationDecodesNumericStaffId() async throws {
|
||||||
|
let reportJSON = """
|
||||||
|
{"code":100000,"msg":"success","data":{"staff_id":732,"expired":1783403917,"status":1,"store_user_id":732}}
|
||||||
|
""".data(using: .utf8)!
|
||||||
|
let api = HomeAPI(client: APIClient(environment: .testing, session: MockURLSession(responses: [reportJSON])))
|
||||||
|
let stateStore = HomeLocationStateStore(store: appStore)
|
||||||
|
let service = LocationReportService(appStore: appStore, locationStateStore: stateStore)
|
||||||
|
|
||||||
|
let result = try await service.reportWithCoordinates(
|
||||||
|
api: api,
|
||||||
|
latitude: 32.429921061197916,
|
||||||
|
longitude: 119.44032958984376,
|
||||||
|
address: "测试地址",
|
||||||
|
type: 1
|
||||||
|
)
|
||||||
|
|
||||||
|
XCTAssertTrue(result.shouldShowSuccessDialog)
|
||||||
|
XCTAssertTrue(stateStore.isOnline)
|
||||||
|
}
|
||||||
|
|
||||||
func testReportWithCoordinatesType2UsesProvidedLocation() async throws {
|
func testReportWithCoordinatesType2UsesProvidedLocation() async throws {
|
||||||
let reportJSON = """
|
let reportJSON = """
|
||||||
{"code":100000,"msg":"success","data":{"staff_id":"staff-1","expired":0,"status":1}}
|
{"code":100000,"msg":"success","data":{"staff_id":"staff-1","expired":0,"status":1}}
|
||||||
|
|||||||
Reference in New Issue
Block a user