完善风险地图定位与标记详情

This commit is contained in:
2026-07-09 12:47:47 +08:00
parent 42aca73588
commit 2970f1514b
5 changed files with 697 additions and 113 deletions

View File

@ -4,6 +4,7 @@
//
import CoreLocation
import MapKit
import XCTest
@testable import suixinkan
@ -345,7 +346,7 @@ final class WildPhotographerReportTests: XCTestCase {
XCTAssertEqual(response.markers.last?.handleStatus?.displayText, WildReportStatus.processing.rawValue)
}
func testMarkerDetailAPISendsRequestBodyAndDecodesGreenDetail() async throws {
func testMarkerDetailAPISendsGETQueryAndDecodesGreenDetail() async throws {
let json = Data("""
{
"code": 100000,
@ -381,15 +382,16 @@ final class WildPhotographerReportTests: XCTestCase {
))
let request = try XCTUnwrap(session.requests.first)
XCTAssertEqual(request.httpMethod, "POST")
XCTAssertEqual(request.httpMethod, "GET")
XCTAssertEqual(request.url?.path, "/api/yf-handset-app/photog/report/marker-detail")
let bodyData = try XCTUnwrap(request.httpBody)
let body = try XCTUnwrap(JSONSerialization.jsonObject(with: bodyData) as? [String: Any])
XCTAssertEqual(body["scenic_id"] as? Int, 128)
XCTAssertEqual(body["marker_type"] as? String, "green")
XCTAssertEqual(body["id"] as? Int, 901)
XCTAssertEqual(body["latitude"] as? Double, 43.3779)
XCTAssertEqual(body["longitude"] as? Double, 84.0217)
XCTAssertNil(request.httpBody)
let components = try XCTUnwrap(URLComponents(url: try XCTUnwrap(request.url), resolvingAgainstBaseURL: false))
let queryItems = Dictionary(uniqueKeysWithValues: (components.queryItems ?? []).map { ($0.name, $0.value) })
XCTAssertEqual(queryItems["scenic_id"], "128")
XCTAssertEqual(queryItems["marker_type"], "green")
XCTAssertEqual(queryItems["id"], "901")
XCTAssertEqual(queryItems["latitude"], "43.3779")
XCTAssertEqual(queryItems["longitude"], "84.0217")
XCTAssertEqual(response.name, "")
XCTAssertEqual(response.storeName, "")
XCTAssertTrue(response.online)
@ -801,8 +803,6 @@ final class WildPhotographerReportTests: XCTestCase {
func testRiskMapViewModelRejectsInvalidScenicID() async {
let viewModel = WildReportRiskMapViewModel()
let api = MockWildPhotographerReportAPI()
var messages: [String] = []
viewModel.onShowMessage = { messages.append($0) }
await viewModel.loadInitial(
api: api,
@ -811,7 +811,7 @@ final class WildPhotographerReportTests: XCTestCase {
)
XCTAssertTrue(api.riskMapRequests.isEmpty)
XCTAssertEqual(messages.last, "")
XCTAssertEqual(viewModel.errorMessage, "")
}
func testRiskMapViewModelLoadsWithLocationAndMapsMarkerTypes() async {
@ -862,6 +862,27 @@ final class WildPhotographerReportTests: XCTestCase {
XCTAssertFalse(viewModel.markers.contains { $0.kind == .selfLocation })
}
func testRiskMapViewModelFocusCurrentLocationSelectsSelfMarker() async {
let viewModel = WildReportRiskMapViewModel()
let api = MockWildPhotographerReportAPI()
api.riskMapResponses = [makeRiskMapResponse()]
await viewModel.loadInitial(
api: api,
locationProvider: MockRiskMapLocationProvider(.success(latitude: 43.3779, longitude: 84.0217)),
scenicId: 128
)
let redMarker = try! XCTUnwrap(viewModel.markers.first { $0.kind == .wildPhotographer })
await viewModel.selectMarker(redMarker)
let didFocus = viewModel.focusCurrentLocation()
XCTAssertTrue(didFocus)
XCTAssertEqual(viewModel.selectedMarker?.kind, .selfLocation)
XCTAssertEqual(viewModel.region.center.latitude, 43.3779, accuracy: 0.000001)
XCTAssertEqual(viewModel.region.center.longitude, 84.0217, accuracy: 0.000001)
XCTAssertTrue(api.markerDetailRequests.isEmpty)
}
func testRiskMapViewModelLoadsMarkerDetailAndUpdatesSelectedClue() async {
let viewModel = WildReportRiskMapViewModel()
let api = MockWildPhotographerReportAPI()
@ -899,13 +920,56 @@ final class WildPhotographerReportTests: XCTestCase {
XCTAssertEqual(viewModel.selectedClue?.detail, "")
}
func testRiskMapViewModelMapsProcessingMarkerDetailForBottomCard() async {
let viewModel = WildReportRiskMapViewModel()
let api = MockWildPhotographerReportAPI()
api.riskMapResponses = [makeRiskMapResponse()]
api.markerDetailResponses = [
WildReportMarkerDetailResponse(
markerType: "yellow",
id: 33,
clueId: "202679-0039",
title: "",
statusTag: "",
latitude: "32.3774100",
longitude: "119.3979350",
distanceM: 7068,
reportTypeText: "",
desc: "",
reporterName: "",
reporterPhone: "121****1212",
createdAt: "2026-07-09 11:37:26",
evidences: [
WildReportDetailEvidence(fileType: 1, fileTypeText: "", fileURL: "https://example.com/one.jpg"),
WildReportDetailEvidence(fileType: 1, fileTypeText: "图片", fileURL: "https://example.com/two.jpg")
]
)
]
await viewModel.loadInitial(
api: api,
locationProvider: MockRiskMapLocationProvider(.success(latitude: 32.429943033854165, longitude: 119.44032552083333)),
scenicId: 128
)
let yellowMarker = try! XCTUnwrap(viewModel.markers.first { $0.kind == .processingClue })
await viewModel.selectMarker(yellowMarker, api: api, scenicId: 128)
XCTAssertEqual(api.markerDetailRequests.first?.markerType, "yellow")
XCTAssertEqual(viewModel.selectedClue?.id, "2026年7月9日-0039")
XCTAssertEqual(viewModel.selectedClue?.statusText, "正在处理中")
XCTAssertEqual(viewModel.selectedClue?.reporterName, "游客")
XCTAssertEqual(viewModel.selectedClue?.reporterPhone, "121****1212")
XCTAssertEqual(viewModel.selectedClue?.reportContents.first?.content, "色地方噶是的法规")
XCTAssertEqual(viewModel.selectedClue?.images, ["https://example.com/one.jpg", "https://example.com/two.jpg"])
XCTAssertEqual(viewModel.selectedClue?.processingStarted, true)
}
func testRiskMapViewModelMarkerDetailFailureKeepsSummary() async {
let viewModel = WildReportRiskMapViewModel()
let api = MockWildPhotographerReportAPI()
api.riskMapResponses = [makeRiskMapResponse()]
api.markerDetailError = URLError(.badServerResponse)
var messages: [String] = []
viewModel.onShowMessage = { messages.append($0) }
await viewModel.loadInitial(
api: api,
locationProvider: MockRiskMapLocationProvider(.success(latitude: 43.3779, longitude: 84.0217)),
@ -916,7 +980,7 @@ final class WildPhotographerReportTests: XCTestCase {
await viewModel.selectMarker(redMarker, api: api, scenicId: 128)
XCTAssertEqual(viewModel.selectedClue?.summary, "疑似打野")
XCTAssertEqual(messages.last, URLError(.badServerResponse).localizedDescription)
XCTAssertEqual(viewModel.errorMessage, URLError(.badServerResponse).localizedDescription)
}
func testDetailViewModelLoadsRemoteDetailWhenServerIDExists() async {