Fix location report parsing and center map on user location immediately.

Decode numeric staff_id from the report API and auto-center the map when the first user location update arrives.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-07 12:01:46 +08:00
parent cfcd3eee6f
commit 9899a2ccb3
4 changed files with 80 additions and 3 deletions

View File

@ -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
} }
} }

View File

@ -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)

View File

@ -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
}
} }

View File

@ -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}}