31 changed files with 776 additions and 17 deletions
@ -0,0 +1,74 @@ |
|||
using DotNetCore.CAP.Persistence; |
|||
using LINGYUN.Abp.EventBus.CAP; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Options; |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.BackgroundWorkers; |
|||
using Volo.Abp.Threading; |
|||
|
|||
namespace DotNetCore.CAP.Processor |
|||
{ |
|||
/// <summary>
|
|||
/// 过期消息清理任务
|
|||
/// </summary>
|
|||
public class AbpCapExpiresMessageCleanupBackgroundWorker : AsyncPeriodicBackgroundWorkerBase |
|||
{ |
|||
/// <summary>
|
|||
/// 过期消息清理配置
|
|||
/// </summary>
|
|||
protected MessageCleanupOptions Options { get; } |
|||
/// <summary>
|
|||
/// Initializer
|
|||
/// </summary>
|
|||
protected IStorageInitializer Initializer { get; } |
|||
/// <summary>
|
|||
/// Storage
|
|||
/// </summary>
|
|||
protected IDataStorage Storage{ get; } |
|||
/// <summary>
|
|||
/// 创建过期消息清理任务
|
|||
/// </summary>
|
|||
/// <param name="timer"></param>
|
|||
/// <param name="storage"></param>
|
|||
/// <param name="initializer"></param>
|
|||
/// <param name="options"></param>
|
|||
/// <param name="serviceScopeFactory"></param>
|
|||
public AbpCapExpiresMessageCleanupBackgroundWorker( |
|||
AbpTimer timer, |
|||
IDataStorage storage, |
|||
IStorageInitializer initializer, |
|||
IOptions<MessageCleanupOptions> options, |
|||
IServiceScopeFactory serviceScopeFactory) |
|||
: base(timer, serviceScopeFactory) |
|||
{ |
|||
Storage = storage; |
|||
Options = options.Value; |
|||
Initializer = initializer; |
|||
|
|||
timer.Period = Options.Interval; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 异步执行任务
|
|||
/// </summary>
|
|||
/// <param name="workerContext"></param>
|
|||
/// <returns></returns>
|
|||
protected override async Task DoWorkAsync(PeriodicBackgroundWorkerContext workerContext) |
|||
{ |
|||
var tables = new[] |
|||
{ |
|||
Initializer.GetPublishedTableName(), |
|||
Initializer.GetReceivedTableName() |
|||
}; |
|||
|
|||
foreach (var table in tables) |
|||
{ |
|||
Logger.LogDebug($"Collecting expired data from table: {table}"); |
|||
var time = DateTime.Now; |
|||
await Storage.DeleteExpiresAsync(table, time, Options.ItemBatch); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,115 @@ |
|||
using DotNetCore.CAP.Internal; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Logging; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace DotNetCore.CAP.Processor |
|||
{ |
|||
/// <summary>
|
|||
/// CapProcessingServer
|
|||
/// </summary>
|
|||
public class AbpCapProcessingServer : IProcessingServer |
|||
{ |
|||
private readonly CancellationTokenSource _cts; |
|||
private readonly ILogger _logger; |
|||
private readonly ILoggerFactory _loggerFactory; |
|||
private readonly IServiceProvider _provider; |
|||
|
|||
private Task _compositeTask; |
|||
private ProcessingContext _context; |
|||
private bool _disposed; |
|||
/// <summary>
|
|||
/// CapProcessingServer
|
|||
/// </summary>
|
|||
/// <param name="logger"></param>
|
|||
/// <param name="loggerFactory"></param>
|
|||
/// <param name="provider"></param>
|
|||
public AbpCapProcessingServer( |
|||
ILogger<AbpCapProcessingServer> logger, |
|||
ILoggerFactory loggerFactory, |
|||
IServiceProvider provider) |
|||
{ |
|||
_logger = logger; |
|||
_loggerFactory = loggerFactory; |
|||
_provider = provider; |
|||
_cts = new CancellationTokenSource(); |
|||
} |
|||
/// <summary>
|
|||
/// Start
|
|||
/// </summary>
|
|||
public void Start() |
|||
{ |
|||
_logger.LogInformation("Starting the processing server."); |
|||
|
|||
_context = new ProcessingContext(_provider, _cts.Token); |
|||
|
|||
var processorTasks = GetProcessors() |
|||
.Select(InfiniteRetry) |
|||
.Select(p => p.ProcessAsync(_context)); |
|||
_compositeTask = Task.WhenAll(processorTasks); |
|||
} |
|||
/// <summary>
|
|||
/// Pulse
|
|||
/// </summary>
|
|||
public void Pulse() |
|||
{ |
|||
_logger.LogTrace("Pulsing the processor."); |
|||
} |
|||
/// <summary>
|
|||
/// Dispose
|
|||
/// </summary>
|
|||
public void Dispose() |
|||
{ |
|||
if (_disposed) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
try |
|||
{ |
|||
_disposed = true; |
|||
|
|||
_logger.LogInformation("Shutting down the processing server..."); |
|||
_cts.Cancel(); |
|||
|
|||
_compositeTask?.Wait((int)TimeSpan.FromSeconds(10).TotalMilliseconds); |
|||
} |
|||
catch (AggregateException ex) |
|||
{ |
|||
var innerEx = ex.InnerExceptions[0]; |
|||
if (!(innerEx is OperationCanceledException)) |
|||
{ |
|||
_logger.LogWarning(innerEx, $"Expected an OperationCanceledException, but found '{innerEx.Message}'."); |
|||
} |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
_logger.LogWarning(ex, "An exception was occured when disposing."); |
|||
} |
|||
finally |
|||
{ |
|||
_logger.LogInformation("### CAP shutdown!"); |
|||
} |
|||
} |
|||
|
|||
private IProcessor InfiniteRetry(IProcessor inner) |
|||
{ |
|||
return new InfiniteRetryProcessor(inner, _loggerFactory); |
|||
} |
|||
|
|||
private IProcessor[] GetProcessors() |
|||
{ |
|||
var returnedProcessors = new List<IProcessor> |
|||
{ |
|||
_provider.GetRequiredService<TransportCheckProcessor>(), |
|||
_provider.GetRequiredService<MessageNeedToRetryProcessor>(), |
|||
}; |
|||
|
|||
return returnedProcessors.ToArray(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
namespace LINGYUN.Abp.EventBus.CAP |
|||
{ |
|||
/// <summary>
|
|||
/// 过期消息清理配置项
|
|||
/// </summary>
|
|||
public class MessageCleanupOptions |
|||
{ |
|||
/// <summary>
|
|||
/// 批量清理数量
|
|||
/// default: 1000
|
|||
/// </summary>
|
|||
public int ItemBatch { get; set; } = 1000; |
|||
/// <summary>
|
|||
/// 执行间隔(ms)
|
|||
/// default: 3600000 (1 hours)
|
|||
/// </summary>
|
|||
public int Interval { get; set; } = 3600000; |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\LINGYUN.Abp.Location\LINGYUN.Abp.Location.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,15 @@ |
|||
using Newtonsoft.Json; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
|
|||
namespace LINGYUN.Abp.Location.Baidu.Http |
|||
{ |
|||
public class BaiduInverseLocationResponse : BaiduLocationResponse |
|||
{ |
|||
[JsonProperty("formatted_address")] |
|||
public string Address { get; set; } |
|||
|
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
|
|||
namespace LINGYUN.Abp.Location.Baidu.Http |
|||
{ |
|||
public class BaiduLocationHttpClient |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
namespace LINGYUN.Abp.Location.Baidu.Http |
|||
{ |
|||
public abstract class BaiduLocationResponse |
|||
{ |
|||
public int Status { get; set; } |
|||
|
|||
public Location Location { get; set; } |
|||
|
|||
public bool IsSuccess() |
|||
{ |
|||
return Status == 0; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
namespace LINGYUN.Abp.Location.Baidu.Http |
|||
{ |
|||
public class BaiduPositiveLocationResponse : BaiduLocationResponse |
|||
{ |
|||
public int Precise { get; set; } |
|||
public int Confidence { get; set; } |
|||
public int Comprehension { get; set; } |
|||
public string Level { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
namespace LINGYUN.Abp.Location.Baidu.Http |
|||
{ |
|||
public class Location |
|||
{ |
|||
public double Lat { get; set; } |
|||
public double Lng { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Volo.Abp.Core" Version="2.8.0" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,8 @@ |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace LINGYUN.Abp.Location |
|||
{ |
|||
public class AbpLocationModule : AbpModule |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
namespace LINGYUN.Abp.Location |
|||
{ |
|||
public interface ILocationResolveProvider |
|||
{ |
|||
PositiveLocation GetPositiveLocation(string address); |
|||
|
|||
InverseLocation GetInverseLocation(double lat, double lng); |
|||
} |
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
namespace LINGYUN.Abp.Location |
|||
{ |
|||
/// <summary>
|
|||
/// 逆地址
|
|||
/// </summary>
|
|||
public class InverseLocation |
|||
{ |
|||
/// <summary>
|
|||
/// 详细地址
|
|||
/// </summary>
|
|||
public string Address { get; set; } |
|||
/// <summary>
|
|||
/// 国家
|
|||
/// </summary>
|
|||
public string Country { get; set; } |
|||
/// <summary>
|
|||
/// 省份
|
|||
/// </summary>
|
|||
public string Province { get; set; } |
|||
/// <summary>
|
|||
/// 城市
|
|||
/// </summary>
|
|||
public string City { get; set; } |
|||
/// <summary>
|
|||
/// 区县
|
|||
/// </summary>
|
|||
public string District { get; set; } |
|||
/// <summary>
|
|||
/// 街道
|
|||
/// </summary>
|
|||
public string Street { get; set; } |
|||
/// <summary>
|
|||
/// adcode
|
|||
/// </summary>
|
|||
public string AdCode { get; set; } |
|||
/// <summary>
|
|||
/// 乡镇
|
|||
/// </summary>
|
|||
public string Town { get; set; } |
|||
/// <summary>
|
|||
/// 门牌号
|
|||
/// </summary>
|
|||
public string Number { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,97 @@ |
|||
using System; |
|||
|
|||
namespace LINGYUN.Abp.Location |
|||
{ |
|||
public abstract class Location |
|||
{ |
|||
/// <summary>
|
|||
/// 地球半径(米)
|
|||
/// </summary>
|
|||
public const double EARTH_RADIUS = 6378137; |
|||
/// <summary>
|
|||
/// 纬度
|
|||
/// </summary>
|
|||
public double Latitude { get; set; } |
|||
/// <summary>
|
|||
/// 经度
|
|||
/// </summary>
|
|||
public double Longitude { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 计算两个位置的距离,返回两点的距离,单位 米
|
|||
/// 该公式为GOOGLE提供,误差小于0.2米
|
|||
/// </summary>
|
|||
/// <param name="location">参与计算的位置信息</param>
|
|||
/// <returns>返回两个位置的距离</returns>
|
|||
public double CalcDistance(Location location) |
|||
{ |
|||
return CalcDistance(this, location); |
|||
} |
|||
/// <summary>
|
|||
/// 计算两个位置的距离,返回两点的距离,单位 米
|
|||
/// 该公式为GOOGLE提供,误差小于0.2米
|
|||
/// </summary>
|
|||
/// <param name="location1">参与计算的位置信息</param>
|
|||
/// <param name="location2">参与计算的位置信息</param>
|
|||
/// <returns>返回两个位置的距离</returns>
|
|||
public static double CalcDistance(Location location1, Location location2) |
|||
{ |
|||
double radLat1 = Rad(location1.Latitude); |
|||
double radLng1 = Rad(location1.Longitude); |
|||
double radLat2 = Rad(location2.Latitude); |
|||
double radLng2 = Rad(location2.Longitude); |
|||
double a = radLat1 - radLat2; |
|||
double b = radLng1 - radLng2; |
|||
double result = 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin(a / 2), 2) + Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Pow(Math.Sin(b / 2), 2))); |
|||
result *= EARTH_RADIUS; |
|||
return result; |
|||
} |
|||
/// <summary>
|
|||
/// 计算位置的偏移距离
|
|||
/// </summary>
|
|||
/// <param name="location">参与计算的位置</param>
|
|||
/// <param name="distance">位置偏移量,单位 米</param>
|
|||
/// <returns></returns>
|
|||
public static Position CalcOffsetDistance(Location location, double distance) |
|||
{ |
|||
double dlng = 2 * Math.Asin(Math.Sin(distance / (2 * EARTH_RADIUS)) / Math.Cos(Rad(location.Latitude))); |
|||
dlng = Deg(dlng); |
|||
double dlat = distance / EARTH_RADIUS; |
|||
dlat = Deg(dlat); |
|||
double leftTopLat = location.Latitude + dlat; |
|||
double leftTopLng = location.Longitude - dlng; |
|||
|
|||
double leftBottomLat = location.Latitude - dlat; |
|||
double leftBottomLng = location.Longitude - dlng; |
|||
|
|||
double rightTopLat = location.Latitude + dlat; |
|||
double rightTopLng = location.Longitude + dlng; |
|||
|
|||
double rightBottomLat = location.Latitude - dlat; |
|||
double rightBottomLng = location.Longitude + dlng; |
|||
|
|||
return new Position(leftTopLat, leftBottomLat, leftTopLng, leftBottomLng, |
|||
rightTopLat, rightBottomLat, rightTopLng, rightBottomLng); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 角度转换为弧度
|
|||
/// </summary>
|
|||
/// <param name="d"></param>
|
|||
/// <returns></returns>
|
|||
public static double Rad(double d) |
|||
{ |
|||
return d * Math.PI / 180d; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 弧度转换为角度
|
|||
/// </summary>
|
|||
/// <param name="d"></param>
|
|||
/// <returns></returns>
|
|||
public static double Deg(double d) |
|||
{ |
|||
return d * (180 / Math.PI); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
namespace LINGYUN.Abp.Location |
|||
{ |
|||
/// <summary>
|
|||
/// 位置量
|
|||
/// </summary>
|
|||
public class Position |
|||
{ |
|||
/// <summary>
|
|||
/// 左上纬度
|
|||
/// </summary>
|
|||
public double LeftTopLatitude { get; } |
|||
/// <summary>
|
|||
/// 左上经度
|
|||
/// </summary>
|
|||
public double LeftTopLongitude { get; } |
|||
/// <summary>
|
|||
/// 左下纬度
|
|||
/// </summary>
|
|||
public double LeftBottomLatitude { get; } |
|||
/// <summary>
|
|||
/// 左下经度
|
|||
/// </summary>
|
|||
public double LeftBottomLongitude { get; } |
|||
|
|||
/// <summary>
|
|||
/// 右上纬度
|
|||
/// </summary>
|
|||
public double RightTopLatitude { get; } |
|||
/// <summary>
|
|||
/// 右上经度
|
|||
/// </summary>
|
|||
public double RightTopLongitude { get; } |
|||
/// <summary>
|
|||
/// 右下纬度
|
|||
/// </summary>
|
|||
public double RightBottomLatitude { get; } |
|||
/// <summary>
|
|||
/// 右下经度
|
|||
/// </summary>
|
|||
public double RightBottomLongitude { get; } |
|||
|
|||
internal Position(double leftTopLat, double leftBottomLat, double leftTopLng, double leftBottomLng, |
|||
double rightTopLat, double rightBottomLat, double rightTopLng, double rightBottomLng) |
|||
{ |
|||
LeftTopLatitude = leftTopLat; |
|||
LeftBottomLatitude = leftBottomLat; |
|||
LeftTopLongitude = leftTopLng; |
|||
LeftBottomLongitude = leftBottomLng; |
|||
RightTopLatitude = rightTopLat; |
|||
RightTopLongitude = rightTopLng; |
|||
RightBottomLatitude = rightBottomLat; |
|||
RightBottomLongitude = rightBottomLng; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
namespace LINGYUN.Abp.Location |
|||
{ |
|||
/// <summary>
|
|||
/// 正地址
|
|||
/// </summary>
|
|||
public class PositiveLocation : Location |
|||
{ |
|||
/// <summary>
|
|||
/// 附加信息
|
|||
/// </summary>
|
|||
public int Precise { get; set; } |
|||
/// <summary>
|
|||
/// 绝对精度
|
|||
/// </summary>
|
|||
public int Confidence { get; set; } |
|||
/// <summary>
|
|||
/// 理解程度
|
|||
/// 分值范围0-100
|
|||
/// 分值越大,服务对地址理解程度越高
|
|||
/// </summary>
|
|||
public int Pomprehension { get; set; } |
|||
/// <summary>
|
|||
/// 能精确理解的地址类型
|
|||
/// </summary>
|
|||
public string Level { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,57 @@ |
|||
<template> |
|||
<div> |
|||
<el-row justify="center"> |
|||
<el-col :span="4"> |
|||
<label>{{ $t('AbpUiMultiTenancy.Tenant') }}</label> |
|||
</el-col> |
|||
<el-col :span="16"> |
|||
<label>{{ value }}</label> |
|||
</el-col> |
|||
<el-col :span="4"> |
|||
<el-link |
|||
type="info" |
|||
@click="handleSwitchTenant" |
|||
> |
|||
{{ $t('AbpUiMultiTenancy.SwitchTenant') }} |
|||
</el-link> |
|||
</el-col> |
|||
</el-row> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import { Component, Prop, Vue } from 'vue-property-decorator' |
|||
import TenantService from '@/api/tenant' |
|||
import { setTenant, removeTenant } from '@/utils/sessions' |
|||
|
|||
@Component({ |
|||
name: 'TenantSelect' |
|||
}) |
|||
export default class extends Vue { |
|||
@Prop({ default: '' }) |
|||
private value?: string |
|||
|
|||
private handleSwitchTenant() { |
|||
this.$prompt(this.$t('AbpUiMultiTenancy.SwitchTenantHint').toString(), |
|||
this.$t('AbpUiMultiTenancy.SwitchTenant').toString(), { |
|||
showInput: true |
|||
}).then((val: any) => { |
|||
removeTenant() |
|||
if (val.value) { |
|||
TenantService.getTenantByName(val.value).then(tenant => { |
|||
if (tenant.success) { |
|||
setTenant(tenant.tenantId) |
|||
this.$emit('input', tenant.name) |
|||
} else { |
|||
this.$message.warning(this.$t('login.tenantIsNotAvailable', { name: val.value }).toString()) |
|||
} |
|||
}) |
|||
} else { |
|||
this.$emit('input', '') |
|||
} |
|||
}).catch(() => { |
|||
console.log() |
|||
}) |
|||
} |
|||
} |
|||
</script> |
|||
Loading…
Reference in new issue