完善风险地图定位与标记详情
This commit is contained in:
@ -87,9 +87,9 @@ final class WildPhotographerReportAPI: WildPhotographerReportServing {
|
||||
func markerDetail(_ request: WildReportMarkerDetailRequest) async throws -> WildReportMarkerDetailResponse {
|
||||
try await client.send(
|
||||
APIRequest(
|
||||
method: .post,
|
||||
method: .get,
|
||||
path: "/api/yf-handset-app/photog/report/marker-detail",
|
||||
body: request
|
||||
queryItems: request.queryItems
|
||||
)
|
||||
)
|
||||
}
|
||||
@ -148,7 +148,7 @@ struct WildReportRiskMapRequest: Encodable, Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
/// 风险地图标记详情接口请求体。
|
||||
/// 风险地图标记详情接口请求参数。
|
||||
struct WildReportMarkerDetailRequest: Encodable, Equatable {
|
||||
let scenicId: Int
|
||||
let markerType: String
|
||||
@ -156,6 +156,21 @@ struct WildReportMarkerDetailRequest: Encodable, Equatable {
|
||||
let latitude: Double?
|
||||
let longitude: Double?
|
||||
|
||||
var queryItems: [URLQueryItem] {
|
||||
var items = [
|
||||
URLQueryItem(name: "scenic_id", value: String(scenicId)),
|
||||
URLQueryItem(name: "marker_type", value: markerType),
|
||||
URLQueryItem(name: "id", value: String(id))
|
||||
]
|
||||
if let latitude {
|
||||
items.append(URLQueryItem(name: "latitude", value: String(latitude)))
|
||||
}
|
||||
if let longitude {
|
||||
items.append(URLQueryItem(name: "longitude", value: String(longitude)))
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case scenicId = "scenic_id"
|
||||
case markerType = "marker_type"
|
||||
|
||||
@ -1185,7 +1185,9 @@ struct WildReportRiskMapMarkerDTO: Decodable, Equatable, Hashable {
|
||||
struct WildReportMarkerDetailResponse: Decodable, Equatable, Hashable {
|
||||
let markerType: String
|
||||
let id: Int
|
||||
let clueId: String
|
||||
let title: String
|
||||
let statusTag: String
|
||||
let tag: String
|
||||
let name: String
|
||||
let avatar: String
|
||||
@ -1210,7 +1212,9 @@ struct WildReportMarkerDetailResponse: Decodable, Equatable, Hashable {
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case markerType = "marker_type"
|
||||
case id
|
||||
case clueId = "clue_id"
|
||||
case title
|
||||
case statusTag = "status_tag"
|
||||
case tag
|
||||
case name
|
||||
case avatar
|
||||
@ -1237,7 +1241,9 @@ struct WildReportMarkerDetailResponse: Decodable, Equatable, Hashable {
|
||||
init(
|
||||
markerType: String,
|
||||
id: Int,
|
||||
clueId: String = "",
|
||||
title: String = "",
|
||||
statusTag: String = "",
|
||||
tag: String = "",
|
||||
name: String = "",
|
||||
avatar: String = "",
|
||||
@ -1261,7 +1267,9 @@ struct WildReportMarkerDetailResponse: Decodable, Equatable, Hashable {
|
||||
) {
|
||||
self.markerType = markerType
|
||||
self.id = id
|
||||
self.clueId = clueId
|
||||
self.title = title
|
||||
self.statusTag = statusTag
|
||||
self.tag = tag
|
||||
self.name = name
|
||||
self.avatar = avatar
|
||||
@ -1288,7 +1296,9 @@ struct WildReportMarkerDetailResponse: Decodable, Equatable, Hashable {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
markerType = try container.decodeIfPresent(String.self, forKey: .markerType) ?? ""
|
||||
id = try container.decodeIfPresent(Int.self, forKey: .id) ?? 0
|
||||
clueId = try container.decodeIfPresent(String.self, forKey: .clueId) ?? ""
|
||||
title = try container.decodeIfPresent(String.self, forKey: .title) ?? ""
|
||||
statusTag = try container.decodeIfPresent(String.self, forKey: .statusTag) ?? ""
|
||||
tag = try container.decodeIfPresent(String.self, forKey: .tag) ?? ""
|
||||
name = try container.decodeIfPresent(String.self, forKey: .name) ?? ""
|
||||
avatar = try container.decodeIfPresent(String.self, forKey: .avatar) ?? ""
|
||||
|
||||
@ -1018,7 +1018,6 @@ final class WildReportRiskMapViewModel {
|
||||
private(set) var markers: [WildReportMapMarker]
|
||||
private(set) var scenicAreaName: String
|
||||
private(set) var selectedMarkerID: String?
|
||||
private(set) var toastMessage: String?
|
||||
private(set) var isLoading = false
|
||||
private(set) var isLoadingDetail = false
|
||||
private(set) var errorMessage: String?
|
||||
@ -1027,7 +1026,6 @@ final class WildReportRiskMapViewModel {
|
||||
private(set) var currentCoordinate: CLLocationCoordinate2D?
|
||||
|
||||
var onStateChange: (() -> Void)?
|
||||
var onShowMessage: ((String) -> Void)?
|
||||
|
||||
init() {
|
||||
self.markers = []
|
||||
@ -1090,7 +1088,7 @@ final class WildReportRiskMapViewModel {
|
||||
mergeDetail(detail, intoMarkerID: marker.id)
|
||||
loadedDetailMarkerIDs.insert(marker.id)
|
||||
} catch {
|
||||
showToast(error.localizedDescription)
|
||||
errorMessage = error.localizedDescription
|
||||
}
|
||||
isLoadingDetail = false
|
||||
notifyStateChange()
|
||||
@ -1114,6 +1112,19 @@ final class WildReportRiskMapViewModel {
|
||||
return marker
|
||||
}
|
||||
|
||||
/// 将地图快速移动到已加载的当前位置标记。
|
||||
@discardableResult
|
||||
func focusCurrentLocation() -> Bool {
|
||||
guard let marker = markers.first(where: { $0.kind == .selfLocation }) else { return false }
|
||||
selectedMarkerID = marker.id
|
||||
region = MKCoordinateRegion(
|
||||
center: marker.coordinate,
|
||||
span: MKCoordinateSpan(latitudeDelta: 0.018, longitudeDelta: 0.018)
|
||||
)
|
||||
notifyStateChange()
|
||||
return true
|
||||
}
|
||||
|
||||
/// 将地图居中到当前位置标记。
|
||||
func refreshLocation(
|
||||
api: any WildPhotographerReportServing,
|
||||
@ -1132,21 +1143,12 @@ final class WildReportRiskMapViewModel {
|
||||
|
||||
/// 生成线索分享提示。
|
||||
func shareSelectedClue() {
|
||||
guard let clue = selectedClue else { return }
|
||||
let title = clue.type == .red ? "线索 ID:\(clue.id)" : clue.displayTitle
|
||||
showToast("已生成\(title)的分享信息,可发送给他人查看。")
|
||||
_ = selectedClue
|
||||
}
|
||||
|
||||
/// 生成图片预览提示。
|
||||
func showImagePreview(_ url: String) {
|
||||
_ = url
|
||||
showToast("暂不支持预览图片")
|
||||
}
|
||||
|
||||
private func showToast(_ message: String) {
|
||||
toastMessage = message
|
||||
onShowMessage?(message)
|
||||
notifyStateChange()
|
||||
}
|
||||
|
||||
private func loadRiskMap(
|
||||
@ -1159,7 +1161,7 @@ final class WildReportRiskMapViewModel {
|
||||
let resolvedScenicId = scenicId ?? AppStore.shared.currentScenicId
|
||||
guard resolvedScenicId >= 1 else {
|
||||
errorMessage = "请先选择景区后再查看风险地图"
|
||||
showToast(errorMessage ?? "")
|
||||
notifyStateChange()
|
||||
return
|
||||
}
|
||||
|
||||
@ -1170,8 +1172,7 @@ final class WildReportRiskMapViewModel {
|
||||
scenicId: resolvedScenicId,
|
||||
scenicName: scenicName,
|
||||
coordinate: coordinate,
|
||||
selectCurrentLocation: selectCurrentLocation,
|
||||
showsLocationRefreshToast: coordinate != nil
|
||||
selectCurrentLocation: selectCurrentLocation
|
||||
)
|
||||
}
|
||||
|
||||
@ -1184,8 +1185,7 @@ final class WildReportRiskMapViewModel {
|
||||
scenicId: Int,
|
||||
scenicName: String?,
|
||||
coordinate: CLLocationCoordinate2D?,
|
||||
selectCurrentLocation: Bool,
|
||||
showsLocationRefreshToast: Bool
|
||||
selectCurrentLocation: Bool
|
||||
) async {
|
||||
isLoading = true
|
||||
errorMessage = nil
|
||||
@ -1210,12 +1210,8 @@ final class WildReportRiskMapViewModel {
|
||||
} else if selectedMarker == nil {
|
||||
selectedMarkerID = markers.first?.id
|
||||
}
|
||||
if showsLocationRefreshToast {
|
||||
showToast("已更新附近风险点位")
|
||||
}
|
||||
} catch {
|
||||
errorMessage = error.localizedDescription
|
||||
showToast(error.localizedDescription)
|
||||
}
|
||||
|
||||
isLoading = false
|
||||
@ -1354,7 +1350,8 @@ final class WildReportRiskMapViewModel {
|
||||
else { return }
|
||||
|
||||
let markerType = WildReportRiskMarkerType(rawValue: detail.markerType.nonEmpty ?? oldClue.type.rawValue)
|
||||
let statusText = detail.handleStatusText.nonEmpty
|
||||
let statusText = detail.statusTag.nonEmpty
|
||||
?? detail.handleStatusText.nonEmpty
|
||||
?? detail.handleStatus?.displayText
|
||||
?? oldClue.statusText
|
||||
let reportContents = !detail.reportContents.isEmpty
|
||||
@ -1362,7 +1359,7 @@ final class WildReportRiskMapViewModel {
|
||||
: (detail.desc.nonEmpty.map { [WildReportRadarReportContent(time: detail.createdAt, content: $0)] } ?? oldClue.reportContents)
|
||||
let imageURLs = detail.evidences.filter(\.isImage).map(\.fileURL)
|
||||
let clue = WildReportRadarActiveClue(
|
||||
id: String(detail.id > 0 ? detail.id : Int(oldClue.id) ?? 0),
|
||||
id: detail.clueId.nonEmpty ?? String(detail.id > 0 ? detail.id : Int(oldClue.id) ?? 0),
|
||||
type: markerType.radarType,
|
||||
displayTitle: detail.title.nonEmpty ?? oldClue.displayTitle,
|
||||
statusText: statusText,
|
||||
|
||||
Reference in New Issue
Block a user