65 lines
2.8 KiB
C#
65 lines
2.8 KiB
C#
using MediatR;
|
|
using Microsoft.AspNetCore.Http;
|
|
using TakeoutSaaS.Application.App.Stores;
|
|
using TakeoutSaaS.Application.App.Stores.Dto;
|
|
using TakeoutSaaS.Application.App.Stores.Queries;
|
|
using TakeoutSaaS.Application.App.Stores.Services;
|
|
using TakeoutSaaS.Domain.Stores.Repositories;
|
|
using TakeoutSaaS.Shared.Abstractions.Constants;
|
|
using TakeoutSaaS.Shared.Abstractions.Exceptions;
|
|
using TakeoutSaaS.Shared.Abstractions.Tenancy;
|
|
|
|
namespace TakeoutSaaS.Application.App.Stores.Handlers;
|
|
|
|
/// <summary>
|
|
/// 配送范围检测查询处理器。
|
|
/// </summary>
|
|
public sealed class CheckStoreDeliveryZoneQueryHandler(
|
|
IStoreRepository storeRepository,
|
|
ITenantProvider tenantProvider,
|
|
IHttpContextAccessor httpContextAccessor,
|
|
IDeliveryZoneService deliveryZoneService)
|
|
: IRequestHandler<CheckStoreDeliveryZoneQuery, StoreDeliveryCheckResultDto>
|
|
{
|
|
/// <inheritdoc />
|
|
public async Task<StoreDeliveryCheckResultDto> Handle(CheckStoreDeliveryZoneQuery request, CancellationToken cancellationToken)
|
|
{
|
|
// 1. 校验门店存在
|
|
var ignoreTenantFilter = StoreTenantAccess.ShouldIgnoreTenantFilter(httpContextAccessor);
|
|
var tenantId = ignoreTenantFilter ? 0 : tenantProvider.GetCurrentTenantId();
|
|
var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId, cancellationToken);
|
|
if (store is null)
|
|
{
|
|
throw new BusinessException(ErrorCodes.NotFound, "门店不存在");
|
|
}
|
|
|
|
// 2. (空行后) 执行配送范围判断
|
|
var zones = await storeRepository.GetDeliveryZonesAsync(request.StoreId, tenantId, cancellationToken);
|
|
var result = deliveryZoneService.CheckPointInZones(zones, request.Longitude, request.Latitude);
|
|
|
|
// 3. (空行后) 计算距离
|
|
if (store.Longitude.HasValue && store.Latitude.HasValue)
|
|
{
|
|
var distance = CalculateDistanceKm(store.Latitude.Value, store.Longitude.Value, request.Latitude, request.Longitude);
|
|
result = result with { Distance = (decimal)Math.Round(distance, 2, MidpointRounding.AwayFromZero) };
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static double CalculateDistanceKm(double latitude1, double longitude1, double latitude2, double longitude2)
|
|
{
|
|
const double earthRadius = 6371000d;
|
|
var latRad1 = DegreesToRadians(latitude1);
|
|
var latRad2 = DegreesToRadians(latitude2);
|
|
var deltaLat = DegreesToRadians(latitude2 - latitude1);
|
|
var deltaLon = DegreesToRadians(longitude2 - longitude1);
|
|
var sinLat = Math.Sin(deltaLat / 2);
|
|
var sinLon = Math.Sin(deltaLon / 2);
|
|
var a = sinLat * sinLat + Math.Cos(latRad1) * Math.Cos(latRad2) * sinLon * sinLon;
|
|
var c = 2 * Math.Asin(Math.Min(1, Math.Sqrt(a)));
|
|
return earthRadius * c / 1000d;
|
|
}
|
|
|
|
private static double DegreesToRadians(double degrees) => degrees * (Math.PI / 180d);
|
|
}
|