From 15469c5164431beee00ebe66da3ed3019ac83947 Mon Sep 17 00:00:00 2001 From: zpc Date: Mon, 18 Aug 2025 12:58:01 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=85=BE=E8=AE=AF=E5=9C=B0?= =?UTF-8?q?=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/WebApiController.cs | 144 +++++++++++++++++- .../Controllers/WxOpenController.cs | 6 +- ZR.Admin.WebApi/Program.cs | 4 + ZR.Admin.WebApi/appsettings.json | 3 + ZR.Common/Model/TencentMapDto.cs | 122 +++++++++++++++ ZR.Common/TencentMapService.cs | 130 ++++++++++++++++ 6 files changed, 405 insertions(+), 4 deletions(-) create mode 100644 ZR.Common/Model/TencentMapDto.cs create mode 100644 ZR.Common/TencentMapService.cs diff --git a/ZR.Admin.WebApi/Controllers/WebApiController.cs b/ZR.Admin.WebApi/Controllers/WebApiController.cs index 67786b1..18707bb 100644 --- a/ZR.Admin.WebApi/Controllers/WebApiController.cs +++ b/ZR.Admin.WebApi/Controllers/WebApiController.cs @@ -7,6 +7,11 @@ using System.Web; using Org.BouncyCastle.Utilities; using System.Net; +using ZR.Common; +using ZR.Model.Dto; +using Infrastructure.Model; +using System.Threading.Tasks; +using ZR.Common.Model; namespace ZR.Admin.WebApi.Controllers { @@ -18,6 +23,143 @@ namespace ZR.Admin.WebApi.Controllers [ApiExplorerSettings(GroupName = "webapi")] public class WebApiController : BaseController { - + private readonly TencentMapService _tencentMapService; + + public WebApiController(TencentMapService tencentMapService) + { + _tencentMapService = tencentMapService; + } + + /// + /// 转换 GPS 经纬度到腾讯地图坐标 + /// + /// 坐标转换请求参数 + /// 转换后的坐标 + [HttpPost] + [Route("GetLocationTranslate")] + public async Task GetLocationTranslate([FromBody] CoordinateTranslateRequest request) + { + try + { + if (request == null || string.IsNullOrWhiteSpace(request.Locations)) + { + return ToResponse(ResultCode.CUSTOM_ERROR, "坐标点不能为空"); + } + + var result = await _tencentMapService.GetLocationTranslateAsync(request.Locations, request.Type); + return SUCCESS(result); + } + catch (Exception ex) + { + return ToResponse(ResultCode.CUSTOM_ERROR, ex.Message); + } + } + + /// + /// 根据坐标获取地址信息 + /// + /// 地理编码请求参数 + /// 地址信息 + [HttpPost] + [Route("GetLocationGeocoder")] + public async Task GetLocationGeocoder([FromBody] GeocoderRequest request) + { + try + { + if (request == null || string.IsNullOrWhiteSpace(request.Location)) + { + return ToResponse(ResultCode.CUSTOM_ERROR, "坐标点不能为空"); + } + + var result = await _tencentMapService.GetLocationGeocoderAsync(request.Location); + return SUCCESS(result); + } + catch (Exception ex) + { + return ToResponse(ResultCode.CUSTOM_ERROR, ex.Message); + } + } + + /// + /// 批量转换GPS坐标并获取地址 + /// + /// 坐标转换请求参数 + /// 转换后的坐标和地址信息 + [HttpPost] + [Route("GetLocationTranslateAndGeocoder")] + public async Task GetLocationTranslateAndGeocoder([FromBody] CoordinateTranslateRequest request) + { + try + { + if (request == null || string.IsNullOrWhiteSpace(request.Locations)) + { + return ToResponse(ResultCode.CUSTOM_ERROR, "坐标点不能为空"); + } + + var result = await _tencentMapService.GetLocationTranslateAndGeocoderAsync(request.Locations); + return SUCCESS(new + { + Location = result.Location, + Address = result.Address + }); + } + catch (Exception ex) + { + return ToResponse(ResultCode.CUSTOM_ERROR, ex.Message); + } + } + + /// + /// 转换 GPS 经纬度到腾讯地图坐标 (GET方式) + /// + /// 坐标点,格式:lat,lng;lat,lng + /// 转换类型,默认1表示GPS坐标转腾讯坐标 + /// 转换后的坐标 + [HttpGet] + [Route("/webapi/GetLocationTranslate")] + [AllowAnonymous] + public async Task GetLocationTranslateGet([FromQuery] string locations, [FromQuery] int type = 1) + { + try + { + if (string.IsNullOrWhiteSpace(locations)) + { + return ToResponse(ResultCode.CUSTOM_ERROR, "坐标点不能为空"); + } + + var result = await _tencentMapService.GetLocationTranslateAsync(locations, type); + return SUCCESS(result); + } + catch (Exception ex) + { + return ToResponse(ResultCode.CUSTOM_ERROR, ex.Message); + } + } + + /// + /// 根据坐标获取地址信息 (GET方式) + /// + /// 坐标点,格式:lat,lng + /// 地址信息 + [HttpGet] + [Route("/webapi/GetLocationGeocoder")] + [AllowAnonymous] + public async Task GetLocationGeocoderGet([FromQuery] string location) + { + try + { + if (string.IsNullOrWhiteSpace(location)) + { + return ToResponse(ResultCode.CUSTOM_ERROR, "坐标点不能为空"); + } + + var result = await _tencentMapService.GetLocationGeocoderAsync(location); + return SUCCESS(result); + } + catch (Exception ex) + { + return ToResponse(ResultCode.CUSTOM_ERROR, ex.Message); + } + } } } diff --git a/ZR.Admin.WebApi/Controllers/WxOpenController.cs b/ZR.Admin.WebApi/Controllers/WxOpenController.cs index 67fb8c6..8acf97c 100644 --- a/ZR.Admin.WebApi/Controllers/WxOpenController.cs +++ b/ZR.Admin.WebApi/Controllers/WxOpenController.cs @@ -5,7 +5,7 @@ using SKIT.FlurlHttpClient.Wechat.Api.Models; using System.Web; - + namespace ZR.Admin.WebApi.Controllers { /// @@ -16,11 +16,11 @@ namespace ZR.Admin.WebApi.Controllers public class WxOpenController : BaseController { private readonly WechatApiClient _client; - + public WxOpenController(WechatApiClient client) { _client = client; - + } diff --git a/ZR.Admin.WebApi/Program.cs b/ZR.Admin.WebApi/Program.cs index 8b25e9d..8d3ea75 100644 --- a/ZR.Admin.WebApi/Program.cs +++ b/ZR.Admin.WebApi/Program.cs @@ -84,6 +84,10 @@ if (!string.IsNullOrEmpty(GaoDeKey)) { GeoCodeService.ApiKey = GaoDeKey; } + +// 注册腾讯地图服务 +builder.Services.AddHttpClient(); +builder.Services.AddSingleton(); builder.Services.AddMvc(options => { options.Filters.Add(typeof(GlobalActionMonitor));//全局注册 diff --git a/ZR.Admin.WebApi/appsettings.json b/ZR.Admin.WebApi/appsettings.json index dfd5c45..67078bd 100644 --- a/ZR.Admin.WebApi/appsettings.json +++ b/ZR.Admin.WebApi/appsettings.json @@ -125,5 +125,8 @@ "tablePrefix": "sys_", //"表前缀(生成类名不会包含表前缀,多个用逗号分隔)", "vuePath": "", //前端代码存储路径eg:D:\Work\ZRAdmin-Vue3 "uniappPath": "D:\\Work" //h5前端代码存储路径 + }, + "TencentMap": { + "Key": "2DYBZ-V4N3W-VQ4RA-Y22V5-BXA2E-53FYV" //腾讯地图key } } diff --git a/ZR.Common/Model/TencentMapDto.cs b/ZR.Common/Model/TencentMapDto.cs new file mode 100644 index 0000000..67a7813 --- /dev/null +++ b/ZR.Common/Model/TencentMapDto.cs @@ -0,0 +1,122 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace ZR.Common.Model +{ + /// + /// 腾讯地图坐标对象 + /// + public class MapLocation + { + /// + /// 纬度 + /// + [JsonPropertyName("lat")] + public double Lat { get; set; } + + /// + /// 经度 + /// + [JsonPropertyName("lng")] + public double Lng { get; set; } + } + + /// + /// 腾讯地图API响应对象 + /// + public class MapApiResponse + { + /// + /// 状态码 + /// + [JsonPropertyName("status")] + public int Status { get; set; } + + /// + /// 状态信息 + /// + [JsonPropertyName("message")] + public string Message { get; set; } + + /// + /// 请求ID + /// + [JsonPropertyName("request_id")] + public string RequestId { get; set; } + + /// + /// 坐标列表 + /// + [JsonPropertyName("locations")] + public List Locations { get; set; } + } + + /// + /// 腾讯地图地理编码结果 + /// + public class MapGeocoderResult + { + /// + /// 地址 + /// + [JsonPropertyName("address")] + public string Address { get; set; } + } + + /// + /// 腾讯地图地理编码API响应 + /// + public class MapGeocoderApiResponse + { + /// + /// 状态码 + /// + [JsonPropertyName("status")] + public int Status { get; set; } + + /// + /// 状态信息 + /// + [JsonPropertyName("message")] + public string Message { get; set; } + + /// + /// 请求ID + /// + [JsonPropertyName("request_id")] + public string RequestId { get; set; } + + /// + /// 地理编码结果 + /// + [JsonPropertyName("result")] + public MapGeocoderResult Result { get; set; } + } + + /// + /// 坐标转换请求参数 + /// + public class CoordinateTranslateRequest + { + /// + /// 坐标点,格式:lat,lng;lat,lng + /// + public string Locations { get; set; } + + /// + /// 转换类型:1-GPS坐标转腾讯坐标 + /// + public int Type { get; set; } = 1; + } + + /// + /// 地理编码请求参数 + /// + public class GeocoderRequest + { + /// + /// 坐标点,格式:lat,lng + /// + public string Location { get; set; } + } +} diff --git a/ZR.Common/TencentMapService.cs b/ZR.Common/TencentMapService.cs new file mode 100644 index 0000000..dfc7896 --- /dev/null +++ b/ZR.Common/TencentMapService.cs @@ -0,0 +1,130 @@ +using Infrastructure; + +using System; +using System.Net.Http; +using System.Text.Json; +using System.Threading.Tasks; + +using ZR.Common.Model; + +namespace ZR.Common +{ + /// + /// 腾讯地图服务 + /// + public class TencentMapService + { + private readonly HttpClient _httpClient; + private readonly string _apiKey = AppSettings.GetConfig("TencentMap:KEY"); + private const string BaseUrl = "https://apis.map.qq.com/"; + + public TencentMapService(HttpClient httpClient) + { + _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient)); + + } + + /// + /// 转换 GPS 经纬度到腾讯地图坐标 + /// + /// 坐标点,格式:lat,lng;lat,lng + /// 转换类型,默认1表示GPS坐标转腾讯坐标 + /// 转换后的坐标 + public async Task GetLocationTranslateAsync(string locations, int type = 1) + { + if (string.IsNullOrWhiteSpace(locations)) + { + throw new ArgumentException("坐标点不能为空", nameof(locations)); + } + + var url = $"{BaseUrl}ws/coord/v1/translate?locations={locations}&type={type}&key={_apiKey}"; + + try + { + var response = await _httpClient.GetAsync(url); + response.EnsureSuccessStatusCode(); + + var content = await response.Content.ReadAsStringAsync(); + var mapResponse = JsonSerializer.Deserialize(content, new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true + }); + + if (mapResponse?.Status == 0 && mapResponse.Locations?.Count > 0) + { + return mapResponse.Locations[0]; + } + else + { + throw new Exception($"坐标转换失败: {mapResponse?.Message}"); + } + } + catch (HttpRequestException ex) + { + throw new Exception("请求腾讯地图API失败", ex); + } + catch (JsonException ex) + { + throw new Exception("解析腾讯地图API响应失败", ex); + } + } + + /// + /// 根据转换后的经纬度获取地址 + /// + /// 坐标点,格式:lat,lng + /// 地址信息 + public async Task GetLocationGeocoderAsync(string location) + { + if (string.IsNullOrWhiteSpace(location)) + { + throw new ArgumentException("坐标点不能为空", nameof(location)); + } + + var url = $"{BaseUrl}ws/geocoder/v1/?location={location}&key={_apiKey}"; + + try + { + var response = await _httpClient.GetAsync(url); + response.EnsureSuccessStatusCode(); + + var content = await response.Content.ReadAsStringAsync(); + var geocoderResponse = JsonSerializer.Deserialize(content, new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true + }); + + if (geocoderResponse?.Status == 0 && geocoderResponse.Result != null) + { + return geocoderResponse.Result.Address; + } + else + { + throw new Exception($"地理编码失败: {geocoderResponse?.Message}"); + } + } + catch (HttpRequestException ex) + { + throw new Exception("请求腾讯地图API失败", ex); + } + catch (JsonException ex) + { + throw new Exception("解析腾讯地图API响应失败", ex); + } + } + + /// + /// 批量转换GPS坐标并获取地址 + /// + /// 坐标点,格式:lat,lng;lat,lng + /// 转换后的坐标和地址信息 + public async Task<(MapLocation Location, string Address)> GetLocationTranslateAndGeocoderAsync(string locations) + { + var translatedLocation = await GetLocationTranslateAsync(locations); + var locationString = $"{translatedLocation.Lat},{translatedLocation.Lng}"; + var address = await GetLocationGeocoderAsync(locationString); + + return (translatedLocation, address); + } + } +}