diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..ad7bae2f --- /dev/null +++ b/.editorconfig @@ -0,0 +1,77 @@ +# Top-most EditorConfig file +root = true + +# All files +[*] +charset = utf-8 +end_of_line = crlf +insert_final_newline = true +trim_trailing_whitespace = true + +# C# files +[*.cs] +indent_style = space +indent_size = 4 + +# CS8618 表示在定义非空属性时,没有在构造函数、初始化器或默认值中对其进行初始化。 +dotnet_diagnostic.cs8618.severity = none +# CS8618 表示方法的返回类型的可空性与目标委托的不匹配。 +dotnet_diagnostic.cs8613.severity = none +# CS1591 表示缺少XML注释 +dotnet_diagnostic.cs1591.severity = none + +# 新行前的成员初始化 +csharp_new_line_before_members_in_object_initializers = true +# 使用 var 关键字 +csharp_style_var_for_built_in_types = true:suggestion +csharp_style_var_when_type_is_apparent = true:suggestion +csharp_style_var_elsewhere = true:suggestion +# 命名约定 +dotnet_naming_rule.private_members_should_be_camel_case.severity = suggestion +dotnet_naming_rule.private_members_should_be_camel_case.symbols = private_members +dotnet_naming_rule.private_members_should_be_camel_case.style = camel_case + +dotnet_naming_symbols.private_members.applicable_accessibilities = private +dotnet_naming_symbols.private_members.applicable_kinds = field +dotnet_naming_symbols.private_members.required_modifiers = readonly + +dotnet_naming_style.camel_case.capitalization = camel_case +dotnet_naming_style.camel_case.required_prefix = _ +dotnet_naming_style.camel_case.required_suffix = + +# 空格和换行 +csharp_space_after_cast = true +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_around_binary_operators = before_and_after +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_before_open_square_bracket = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_empty_method_call_parentheses = false +csharp_space_between_empty_method_declaration_parentheses = false + +# 花括号 +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_anonymous_types = true + +# 缩进规则 +csharp_indent_case_contents = true +csharp_indent_block_contents = true +csharp_indent_braces = false + +# 其他设置 +dotnet_sort_system_directives_first = true +dotnet_separate_import_directive_groups = false + +# resharper兼容 +# 对象初始化收缩问题 https://youtrack.jetbrains.com/issue/RSRP-486359 +resharper_wrap_object_and_collection_initializer_style = chop_always +# 条件表达式花括号收缩问题 +resharper_csharp_case_block_braces = next_line_shifted_2 +resharper_indent_braces_inside_statement_conditions = false \ No newline at end of file diff --git a/.gitignore b/.gitignore index d53fbc8a..96708268 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ ## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. +## files generated by popular Visual Studio add-ons.. # User-specific files *.suo @@ -189,3 +189,4 @@ UpgradeLog*.htm FakesAssemblies/ logs/ /.vs +.idea/ diff --git a/SJZY.Track.Api.sln b/SJZY.Track.Api.sln index 0c457eb0..598973c0 100644 --- a/SJZY.Track.Api.sln +++ b/SJZY.Track.Api.sln @@ -23,6 +23,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "solution items", "solution common.props = common.props NuGet.Config = NuGet.Config .gitignore = .gitignore + .editorconfig = .editorconfig EndProjectSection EndProject Global diff --git a/SJZY.Track.Api.sln.DotSettings b/SJZY.Track.Api.sln.DotSettings index 2363a683..55bb2ed6 100644 --- a/SJZY.Track.Api.sln.DotSettings +++ b/SJZY.Track.Api.sln.DotSettings @@ -1,2 +1,3 @@ - + + True True \ No newline at end of file diff --git a/common.props b/common.props index f66ce331..9c763b60 100644 --- a/common.props +++ b/common.props @@ -2,7 +2,6 @@ enable enable - $(NoWarn);CS1591;CS0436;NU1803 diff --git a/src/SJZY.Track.Api/Program.cs b/src/SJZY.Track.Api/Program.cs index b1ac2cbf..8d7f64af 100644 --- a/src/SJZY.Track.Api/Program.cs +++ b/src/SJZY.Track.Api/Program.cs @@ -24,4 +24,4 @@ try catch (Exception ex) { Console.WriteLine($"项目启动失败,异常信息:{ex}"); -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Api/Properties/launchSettings.json b/src/SJZY.Track.Api/Properties/launchSettings.json index cba7d693..58c7579f 100644 --- a/src/SJZY.Track.Api/Properties/launchSettings.json +++ b/src/SJZY.Track.Api/Properties/launchSettings.json @@ -4,12 +4,12 @@ "commandName": "Project", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development", - "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "SJZY.Expand.ABP.Core;SkyAPM.Agent.AspNetCore", + "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "SJZY.Expand.ABP.Core", "SKYWALKING__SERVICENAME": "Track" }, "dotnetRunMessages": true, - "applicationUrl": "http://*:5054" + "applicationUrl": "http://*:5056" } }, "$schema": "https://json.schemastore.org/launchsettings.json" -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Api/SjzyTrackApiModule.cs b/src/SJZY.Track.Api/SjzyTrackApiModule.cs index 13d9633a..6ec66034 100644 --- a/src/SJZY.Track.Api/SjzyTrackApiModule.cs +++ b/src/SJZY.Track.Api/SjzyTrackApiModule.cs @@ -1,4 +1,4 @@ -using FluentValidation.AspNetCore; +using FluentValidation.AspNetCore; using Microsoft.AspNetCore.Mvc; using SJZY.Expand.ABP.Core; using SJZY.Expand.ABP.Core.Cors; @@ -9,6 +9,7 @@ using SJZY.Expand.ABP.Core.Prometheus; using SJZY.Expand.ABP.Core.Redis; using SJZY.Expand.ABP.Core.Swagger; using SJZY.Track.Application; +using SJZY.Track.Application.HostServices; using SJZY.Track.Repository; using Volo.Abp; using Volo.Abp.AspNetCore.Mvc; @@ -20,69 +21,70 @@ using Volo.Abp.Modularity; [assembly: HostingStartup(typeof(HostingStartup))] -namespace SJZY.Track.Api +namespace SJZY.Track.Api; + +[DependsOn( + typeof(AbpAutofacModule), + typeof(SjzyAbpCodeModule), + typeof(AbpAspNetCoreMvcModule), + typeof(AbpAspNetCoreSerilogModule), + typeof(SjzyTrackApplicationModule), + typeof(SjzyTrackRepositoryModule) +)] +public class SjzyTrackApiModule : AbpModule { - [DependsOn( - typeof(AbpAutofacModule), - typeof(SjzyAbpCodeModule), - typeof(AbpAspNetCoreMvcModule), - typeof(AbpAspNetCoreSerilogModule), - typeof(SjzyTrackApplicationModule), - typeof(SjzyTrackRepositoryModule) - )] - public class SjzyTrackApiModule : AbpModule + public override void ConfigureServices(ServiceConfigurationContext context) { - public override void ConfigureServices(ServiceConfigurationContext context) + var environment = context.Services.GetHostingEnvironment(); + var configuration = context.Services.GetConfiguration(); + context.Services.AddSwagger(); + + //过滤器相关配置 + context.Services.AddMvc(options => { - var environment = context.Services.GetHostingEnvironment(); - var configuration = context.Services.GetConfiguration(); - context.Services.AddSwagger(); + options.Filters.AddService(); + options.Filters.AddService(); + options.Filters.AddService(); + }).AddNewtonsoftJson(); - //过滤器相关配置 - context.Services.AddMvc(options => - { - options.Filters.AddService(); - options.Filters.AddService(); - options.Filters.AddService(); - }).AddNewtonsoftJson(); + context.Services.AddFluentValidationAutoValidation().AddFluentValidationClientsideAdapters(); - context.Services.AddFluentValidationAutoValidation().AddFluentValidationClientsideAdapters(); - - //Json格式化全局处理 - context.Services.Configure(options => - { - options.SerializerSettings.ContractResolver = - new Newtonsoft.Json.Serialization. - CamelCasePropertyNamesContractResolver(); //.DefaultContractResolver(); - options.SerializerSettings.Converters.Add(new DateTimeJsonConverter("yyyy-MM-dd HH:mm:ss")); - options.SerializerSettings.Converters.Add(new LongJsonConverter()); - }); - - Configure(options => options.OutputDateTimeFormat = "yyyy-MM-dd HH:mm:ss"); - Configure(options => { options.IsEnabled = false; }); - - context.Services.AddRedis(); - } - - public override void OnApplicationInitialization(ApplicationInitializationContext context) + //Json格式化全局处理 + context.Services.Configure(options => { - var app = context.GetApplicationBuilder(); - var env = context.GetEnvironment(); + options.SerializerSettings.ContractResolver = + new Newtonsoft.Json.Serialization. + CamelCasePropertyNamesContractResolver(); //.DefaultContractResolver(); + options.SerializerSettings.Converters.Add(new DateTimeJsonConverter("yyyy-MM-dd HH:mm:ss")); + options.SerializerSettings.Converters.Add(new LongJsonConverter()); + }); - if (env.IsDevelopment()) - app.UseDeveloperExceptionPage(); + Configure(options => options.OutputDateTimeFormat = "yyyy-MM-dd HH:mm:ss"); + Configure(options => { options.IsEnabled = false; }); - app.UseRequestCulture(); - app.UseRouting(); - app.UseCorsPolicy(); - app.UseConfiguredEndpoints(); - app.UseAbpSwaggerUI(env); - app.UseAbpSerilogEnrichers(); - app.UsePrometheus(); + context.Services.AddRedis(); + context.Services.AddHostedService(); + } - #region 启动提示 + public override void OnApplicationInitialization(ApplicationInitializationContext context) + { + var app = context.GetApplicationBuilder(); + var env = context.GetEnvironment(); - Console.WriteLine($@" + if (env.IsDevelopment()) + app.UseDeveloperExceptionPage(); + + app.UseRequestCulture(); + app.UseRouting(); + app.UseCorsPolicy(); + app.UseConfiguredEndpoints(); + app.UseAbpSwaggerUI(env); + app.UseAbpSerilogEnrichers(); + app.UsePrometheus(); + + #region 启动提示 + + Console.WriteLine($@" +-------------------------------------------------------+ | | | | @@ -93,7 +95,6 @@ namespace SJZY.Track.Api +-------------------------------------------------------+ "); - #endregion - } + #endregion } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Api/appsettings.json b/src/SJZY.Track.Api/appsettings.json index d69cb0c1..beb55965 100644 --- a/src/SJZY.Track.Api/appsettings.json +++ b/src/SJZY.Track.Api/appsettings.json @@ -1,13 +1,17 @@ { "Configuration": { - "UseLocalConfiguration": false, //是否使用本地配置文件 - "ConfiguraFileName": "appsettings.Development.json", //指定配置文件名称,开启UseLocalConfiguration时生效 + "UseLocalConfiguration": false, + //是否使用本地配置文件 + "ConfiguraFileName": "appsettings.Development.json", + //指定配置文件名称,开启UseLocalConfiguration时生效 "Apollo": { "AppId": "SJZY.Track.Configuration", "Env": "DEV", - "Namespace": "Test", - "MetaServer": "http://apollo-service-test-apollo-configservice.apollo.svc.cluster.local:8080", - "ConfigServer": [ "http://apollo-service-test-apollo-configservice.apollo.svc.cluster.local:8080" ] + "Namespace": "test", + "MetaServer": "https://apollo.test.shijizhongyun.com", + "ConfigServer": [ + "https://apollo.test.shijizhongyun.com" + ] } }, "Kestrel": { @@ -17,4 +21,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/AreaCacheEntry.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/AreaCacheEntry.cs new file mode 100644 index 00000000..c4de4ba6 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/AreaCacheEntry.cs @@ -0,0 +1,29 @@ +namespace SJZY.Track.Application.Contract.Dtos.Forewarning; + +public class AreaCacheEntry +{ + /// + /// 国家或地区 + /// + public string Country { get; set; } = null!; + + /// + /// 省份 + /// + public string? Province { get; set; } + + /// + /// 城市 + /// + public string? City { get; set; } + + /// + /// 开始邮编 + /// + public string? LeftPostcode { get; set; } + + /// + /// 截止邮编 + /// + public string? RightPostcode { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/CreateWarningInput.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/CreateWarningInput.cs new file mode 100644 index 00000000..51da4575 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/CreateWarningInput.cs @@ -0,0 +1,29 @@ +namespace SJZY.Track.Application.Contract.Dtos.Forewarning; + +public class CreateWarningInput +{ + /// + /// 模板名称 + /// + public string Name { get; set; } = null!; + + /// + /// 子系统id + /// + public int SubSystemId { get; set; } + + /// + /// 客户id + /// + public int CustomerId { get; set; } + + /// + /// 轨迹状态跨度列表 + /// + public List TrackStatusSpans { get; set; } = new(); + + /// + /// 预警因素列表。 + /// + public List WarningFactors { get; set; } = new(); +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/EditWarningOutput.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/EditWarningOutput.cs new file mode 100644 index 00000000..0e1a5131 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/EditWarningOutput.cs @@ -0,0 +1,45 @@ +namespace SJZY.Track.Application.Contract.Dtos.Forewarning; + +public class EditWarningOutput +{ + /// + /// 模板名称 + /// + public string Name { get; set; } = null!; + + /// + /// 子系统id + /// + public int SubSystemId { get; set; } + + /// + /// 客户id + /// + public int CustomerId { get; set; } + + /// + /// 轨迹状态列表 + /// + public List TrackStatusSpans { get; set; } = new(); + + /// + /// 预警因素列表。 + /// + public List WarningFactors { get; set; } = new(); +} + +public class WarningNotifyWithIdDto : WarningNotifyDto +{ + /// + /// 通知id + /// + public int Id { get; set; } +} + +public class WarningFactorWithIdDto : WarningFactorDto +{ + /// + /// 因素id + /// + public int Id { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/ForewarningRuleCacheEntry.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/ForewarningRuleCacheEntry.cs new file mode 100644 index 00000000..76a31a74 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/ForewarningRuleCacheEntry.cs @@ -0,0 +1,69 @@ +namespace SJZY.Track.Application.Contract.Dtos.Forewarning; + +public class ForewarningRuleCacheEntry +{ + /// + /// 自增主键 + /// + public int Id { get; set; } + + /// + /// 预警id + /// + public int WarningId { get; set; } + + /// + /// 时效(小时) e.g. 24 + /// + public float TotalTimeSpan { get; set; } + + /// + /// 提醒的时间(小时) e.g. 9 10 11.. + /// + public float WarnTimeSpan { get; set; } + + /// + /// 提醒次数 e.g. 3 2 1 + /// + public int WarnCount { get; set; } + + /// + /// 起始轨迹状态id + /// + public int StartTrackStatusId { get; set; } + + /// + /// 终止轨迹状态id + /// + public int EndTrackStatusId { get; set; } + + /// + /// 货物类型 + /// + public string? CargoType { get; set; } + + /// + /// 月份 + /// + public List? Months { get; set; } + + /// + /// 区域 + /// + public List? Areas { get; set; } + + /// + /// 是否中转 + /// + public bool? IsTransit { get; set; } + + /// + /// 起运港口 + /// + public string? LeavePort { get; set; } + + /// + /// 产品编码 + /// + public string? ProductCode { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/ModifyTimeSpanInput.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/ModifyTimeSpanInput.cs new file mode 100644 index 00000000..53df5f8b --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/ModifyTimeSpanInput.cs @@ -0,0 +1,14 @@ +namespace SJZY.Track.Application.Contract.Dtos.Forewarning; + +public class ModifyTimeSpanInput +{ + /// + /// 预警id + /// + public int WarningId { get; set; } + + /// + /// 规则详情中的时效相关信息 + /// + public List Items { get; set; } = new(); +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/RuleAreaBaseInfo.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/RuleAreaBaseInfo.cs new file mode 100644 index 00000000..ee217da3 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/RuleAreaBaseInfo.cs @@ -0,0 +1,17 @@ +namespace SJZY.Track.Application.Contract.Dtos.Forewarning; + +public class RuleAreaBaseInfo +{ + public RuleAreaBaseInfo() + { + } + + public RuleAreaBaseInfo(int systemId, int customerId) + { + SystemId = systemId; + CustomerId = customerId; + } + + public int SystemId { get; set; } + public int CustomerId { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/UpdateWarningInput.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/UpdateWarningInput.cs new file mode 100644 index 00000000..c8db8908 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/UpdateWarningInput.cs @@ -0,0 +1,37 @@ +namespace SJZY.Track.Application.Contract.Dtos.Forewarning; + +public class UpdateWarningInput +{ + /// + /// 预警id + /// + public int Id { get; set; } + + /// + /// 模板名称 + /// + public string Name { get; set; } = null!; + + /// + /// 通知列表 + /// + public List Notifies { get; set; } = new(); +} + +public class NotifyDto +{ + /// + /// 通知id + /// + public int Id { get; set; } + + /// + /// 通知人 + /// + public List NotifyUsers { get; set; } + + /// + /// 通知方式(1站内信,2飞书) + /// + public List NotifyModes { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningDto.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningDto.cs new file mode 100644 index 00000000..b7249b2a --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningDto.cs @@ -0,0 +1,28 @@ +namespace SJZY.Track.Application.Contract.Dtos.Forewarning; + +public class WarningDto +{ + /// + /// 当前轨迹状态 + /// + public int TrackStatusId { get; set; } + + /// + /// 子系统id + /// + public int SubSystemId { get; set; } + + /// + /// 客户id + /// + public int CustomerId { get; set; } + + public List Orders { get; set; } = new(); + + + public override string ToString() + { + return $"子系统:{SubSystemId},客户:{CustomerId},订单:{Orders.Select(x => x.Id) + .JoinAsString(",")},发生轨迹状态{TrackStatusId}"; + } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningFactorDto.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningFactorDto.cs new file mode 100644 index 00000000..9045c6ac --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningFactorDto.cs @@ -0,0 +1,14 @@ +namespace SJZY.Track.Application.Contract.Dtos.Forewarning; + +public class WarningFactorDto +{ + /// + /// 因素类型(1表示货物类型,2表示月份,3表示分区或区域,4指示货物是否中转,5表示起运港口,6表示销售产品) + /// + public int FactorType { get; set; } + + /// + /// 因素值(直接传json数组) + /// + public List FactorValue { get; set; } = new(); +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningNitifyDto.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningNitifyDto.cs new file mode 100644 index 00000000..995a76f2 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningNitifyDto.cs @@ -0,0 +1,47 @@ +namespace SJZY.Track.Application.Contract.Dtos.Forewarning; + +public class WarningNotifyDto +{ + /// + /// 起始轨迹状态id + /// + public int StartTrackStatusId { get; set; } + + /// + /// 终止轨迹状态id + /// + public int EndTrackStatusId { get; set; } + + /// + /// 起始轨迹状态 + /// + public string StartTrackStatus { get; set; } = null!; + + /// + /// 终止轨迹状态 + /// + public string EndTrackStatus { get; set; } = null!; + + /// + /// 通知人 + /// + public List NotifyUsers { get; set; } + + /// + /// 通知方式(1站内信,2飞书) + /// + public List NotifyModes { get; set; } +} + +public class NotifyUser +{ + /// + /// 用户id + /// + public int UserId { get; set; } + + /// + /// 用户名 + /// + public string UserName { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningNotifyCacheEntry.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningNotifyCacheEntry.cs new file mode 100644 index 00000000..feb0de06 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningNotifyCacheEntry.cs @@ -0,0 +1,39 @@ +namespace SJZY.Track.Application.Contract.Dtos.Forewarning; + +public class WarningNotifyCacheEntry +{ + public WarningNotifyCacheEntry(int ruleId, int orderId, int counter) + { + RuleId = ruleId; + OrderId = orderId; + Counter = counter; + } + + public WarningNotifyCacheEntry(string notifyValue) + { + var values = notifyValue.Split('_'); + RuleId = int.Parse(values[0]); + OrderId = int.Parse(values[1]); + Counter = int.Parse(values[2]); + } + + /// + /// 规则id + /// + public int RuleId { get; set; } + + /// + /// 订单id + /// + public int OrderId { get; set; } + + /// + /// 预警次数(第几次) + /// + public int Counter { get; set; } + + public override string ToString() + { + return $"{RuleId}_{OrderId}_{Counter}"; + } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningOrderDto.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningOrderDto.cs new file mode 100644 index 00000000..0fa46590 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningOrderDto.cs @@ -0,0 +1,52 @@ +namespace SJZY.Track.Application.Contract.Dtos.Forewarning; + +public class WarningOrderDto +{ + /// + /// 订单id + /// + public int Id { get; set; } + + /// + /// 订单号 + /// + public string OrderNo { get; set; } = null!; + + /// + /// 轨迹发生时间 + /// + public DateTime TrackTime { get; set; } + + public string? CargoType { get; set; } + + public int Month { get; set; } + + public bool? IsTransit { get; set; } + + /// + /// 起运港 + /// + public string? LeavePort { get; set; } + + public string? ProductCode { get; set; } + + /// + /// 目的城市 + /// + public string ArrivalCity { get; set; } = null!; + + /// + /// 目的国家 + /// + public string ArrivalCountry { get; set; } = null!; + + /// + /// 到达邮编 + /// + public string? ArrivalPostCode { get; set; } + + /// + /// 到达州省 + /// + public string? ArrivalProvince { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningTimeSpanDto.cs b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningTimeSpanDto.cs new file mode 100644 index 00000000..45795909 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/Forewarning/WarningTimeSpanDto.cs @@ -0,0 +1,27 @@ +namespace SJZY.Track.Application.Contract.Dtos.Forewarning; + +/// +/// 预警规则时效 +/// +public class WarningTimeSpanDto +{ + /// + /// 预警规则id + /// + public int Id { get; set; } + + /// + /// 时效 + /// + public float TotalTimeSpan { get; set; } + + /// + /// 提醒时效 + /// + public float WarnTimeSpan { get; set; } + + /// + /// 提醒次数 + /// + public int WarnCount { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/BatchDeleteTrackByEsIdInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/BatchDeleteTrackByEsIdInput.cs new file mode 100644 index 00000000..681b3b75 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/BatchDeleteTrackByEsIdInput.cs @@ -0,0 +1,13 @@ +using System.ComponentModel.DataAnnotations; + +namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; + +public class BatchDeleteTrackByEsIdInput +{ + + /// + /// 轨迹内容es id,必填 + /// + [MaxLength(500)] + public List TrackContentEsIds { get; set; } = new(); +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/BatchDeleteTrackInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/BatchDeleteTrackInput.cs index 0a79e008..9d3db0a5 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/BatchDeleteTrackInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/BatchDeleteTrackInput.cs @@ -1,12 +1,23 @@ -using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations; namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; public class BatchDeleteTrackInput : OrderNosInfo { /// - /// 轨迹code,必填 + /// 轨迹标识符集合,必填 /// [Required] - public List TrackCodes { get; set; } = new(); -} \ No newline at end of file + [MaxLength(500)] + public List TrackIdentifiers { get; set; } = new(); + + /// + /// 重复的情况下,用什么字段比较 + /// + public string? CompareFields { get; set; } + + /// + /// 重复的情况下,比较值 + /// + public object? CompareValue { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/BatchUpsertTrackInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/BatchUpsertTrackInput.cs index 1c90e3a9..bd7a5c2f 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/BatchUpsertTrackInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/BatchUpsertTrackInput.cs @@ -1,4 +1,4 @@ -using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations; namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; @@ -27,12 +27,122 @@ public class BatchUpsertTrackInput : OrderNosInfo /// 轨迹发生时间 /// [Required] - public DateTime? TrackTime { get; set; } + public DateTime TrackTime { get; set; } + + /// + /// 更改后的轨迹发生时间,无需更改保持为空 + /// + public DateTime? NewTrackTime { get; set; } /// /// 轨迹发生时区 /// + // [Required] + // [Range(-12, 12)] + public float TrackTimeZone { get; set; } + + /// + /// 客户是否可见 + /// + [Obsolete("废弃的,请使用IsExternal")] + public bool IsVisibility { get; set; } + + /// + /// 是否对外(可选的) + /// 如果未填则按照【轨迹内容】中的【是否可见】做为默认值 + /// + public bool? IsExternal { get; set; } + + /// + /// 数据来源:1外部服务商创建,2内部系统创建,3人工创建 + /// 批量新增时使用指定轨迹来源,更新时无需指定 + /// [Required] + public int Source { get; set; } + + /// + /// 轨迹备注 + /// + public string? Remarks { get; set; } + + /// + /// 附件集合 + /// + public List? Files { get; set; } + + /// + /// 轨迹内容,若为空则取轨迹内容表中该轨迹Code对应的轨迹内容 + /// + public string? Content { get; set; } + + /// + /// 轨迹内容英文,若为空则取轨迹内容表中该轨迹Code对应的轨迹英文内容 + /// + public string? EnStatus { get; set; } + + /// + /// 轨迹发生地(城市) + /// + public string? TrackPlaceCity { get; set; } + + /// + /// 轨迹发生地(城市)Id + /// + public int? TrackPlaceCityId { get; set; } + + /// + /// 轨迹发生地(省/州) + /// + public string? TrackPlaceProvince { get; set; } + + /// + ///轨迹发生地(省/州)Id + /// + public int? TrackPlaceProvinceId { get; set; } + + /// + /// 轨迹发生地(国家/地区) + /// + public string? TrackPlaceNation { get; set; } + + /// + /// 轨迹发生地(国家/地区)Id + /// + public int? TrackPlaceNationId { get; set; } + + /// + /// 轨迹发生地邮编 + /// + public string? TrackPlacePostcode { get; set; } + + /// + /// 预计到达时间 + /// + public DateTime? EstimatedDeliveryDate { get; set; } + + /// + /// 目的地时区 + /// [Range(-12, 12)] - public float? TrackTimeZone { get; set; } -} \ No newline at end of file + public float? DestinationTimeZone { get; set; } + + /// + /// 重复的情况下,用什么比较 + /// + public string? CompareFields { get; set; } + + /// + /// 扩展信息字段,用与轨迹推送的附加字段 + /// + public string? Extra { get; set; } + + /// + /// 是否强制推送 + /// + public bool ForcedPush { get; set; } + + /// + /// 指定是否推送 + /// + public bool IsToMq { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/DeleteOrderInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/DeleteOrderInput.cs index bff3df6e..ef4139e4 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/DeleteOrderInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/DeleteOrderInput.cs @@ -1,4 +1,4 @@ -using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations; namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; @@ -9,8 +9,22 @@ public class DeleteOrderInput : OrderNoInfo public class DeleteTrackInput : OrderNoInfo { /// - /// 轨迹code + /// 轨迹标识符集合,为支持esid删除,所以非必填 /// - [Required] - public List TrackCodes { get; set; } = new(); -} \ No newline at end of file + public List? TrackIdentifiers { get; set; } = new(); + + /// + /// 轨迹ESId集合,非必填,如果有优先级最高 + /// + public List? EsIds { get; set; } + + /// + /// 重复的情况下,用什么字段比较 + /// + public string? CompareFields { get; set; } + + /// + /// 重复的情况下,比较值 + /// + public object? CompareValue { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/FileItemDto.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/FileItemDto.cs new file mode 100644 index 00000000..d39bf488 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/FileItemDto.cs @@ -0,0 +1,19 @@ +namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; + +public class FileItemDto +{ + /// + /// 文件osskey + /// + public string OssKey { get; set; } + + /// + /// 文件名称 + /// + public string FileName { get; set; } + + /// + /// 文件下载地址 + /// + public string? DownloadUrl { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetDetailTimelineInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetDetailTimelineInput.cs new file mode 100644 index 00000000..21ec867c --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetDetailTimelineInput.cs @@ -0,0 +1,19 @@ +namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; + +public class GetDetailTimelineInput +{ + /// + /// 订单编号 + /// + public string OrderNumber { get; set; } + + /// + /// 订单所属子系统id + /// + public int SystemId { get; set; } + + /// + /// 当前用户登陆子系统id + /// + public int CurrenUserSystemId { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetDetailTimelineOutput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetDetailTimelineOutput.cs new file mode 100644 index 00000000..4441323c --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetDetailTimelineOutput.cs @@ -0,0 +1,92 @@ +namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; + +public class GetDetailTimelineOutput +{ + /// + /// 轨迹编码 + /// + public string TrackCode { get; set; } + + /// + /// 轨迹内容 + /// + public string Content { get; set; } + + /// + /// 轨迹英文内容 + /// + public string EnContent { get; set; } + + /// + /// 轨迹发生时间 + /// + public long TrackTime { get; set; } + + /// + /// 轨迹时间前缀 + /// + public string TrackTimePrefix { get; set; } + + /// + /// 轨迹发生时区 + /// + public string TrackTimeZone { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } + + /// + /// 文件 osskey 集合 + /// + public List Files { get; set; } + + /// + /// 是否高亮 + /// + public bool IsHighlight { get; set; } + + /// + /// 是否显示悬停效果 + /// + public bool IsShowHover { get; set; } + + /// + /// 轨迹发生地 + /// + public string TrackPlace { get; set; } + + /// + /// 轨迹发生地(城市) + /// + public string? TrackPlaceCity { get; set; } + + /// + /// 轨迹发生地(省/州) + /// + public string? TrackPlaceProvince { get; set; } + + /// + /// 轨迹发生地(国家/地区) + /// + public string? TrackPlaceNation { get; set; } +} + +public class TrackFileItem +{ + /// + /// 文件osskey + /// + public string OssKey { get; set; } + + /// + /// 文件名称 + /// + public string FileName { get; set; } + + /// + /// 文件url + /// + public string Url { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetOrderDetailsInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetOrderDetailsInput.cs index edba26df..7aab1d65 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetOrderDetailsInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetOrderDetailsInput.cs @@ -1,25 +1,12 @@ -namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; +namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; -public class GetOrderDetailsInput +public class TrackOrderDetailDto { - /// - /// 轨迹订单id - /// - public int OrderId { get; set; } - /// /// 子系统id /// public int SubSystemId { get; set; } - /// - /// 轨迹模板Id - /// - public List? TrackTemplateIds { get; set; } = new List(); -} - -public class TrackOrderDetailDto -{ /// /// Id es主键 /// @@ -43,7 +30,7 @@ public class TrackOrderDetailDto /// /// 轨迹代码 /// - public string? Code { get; set; } + public string Code { get; set; } /// /// 轨迹内容 @@ -56,9 +43,9 @@ public class TrackOrderDetailDto public string? EnContent { get; set; } /// - /// 服务商 + /// 服务商代码 /// - public string? ServiceProviderName { get; set; } + public string? ServiceProviderCode { get; set; } /// /// 原轨迹内容 @@ -86,9 +73,10 @@ public class TrackOrderDetailDto public float TrackTimeZoneValue { get; set; } /// - /// 是否可删 + /// 客户是否可见 /// - public bool IsCanDelete { get; set; } + [Obsolete("废弃的,请使用IsExternal")] + public bool IsVisibility { get; set; } /// /// 是否对外 @@ -104,4 +92,49 @@ public class TrackOrderDetailDto /// 创建人 /// public string? CreateUser { get; set; } -} \ No newline at end of file + + /// + /// 数据来源:1外部服务商创建,2内部系统创建,3人工创建 + /// + public int Source { get; set; } + + /// + /// 备注 + /// + public string? Remarks { get; set; } + + /// + /// 附件集合 + /// + public List? Files { get; set; } + + /// + /// 轨迹发生地(城市) + /// + public string? TrackPlaceCity { get; set; } + + /// + /// 轨迹发生地(省/州) + /// + public string? TrackPlaceProvince { get; set; } + + /// + /// 轨迹发生地(国家/地区) + /// + public string? TrackPlaceNation { get; set; } + + /// + /// 轨迹发生地邮编 + /// + public string? TrackPlacePostcode { get; set; } + + /// + /// 预计到达时间 + /// + public DateTime? EstimatedDeliveryDate { get; set; } + + /// + /// 目的地时区 + /// + public float? DestinationTimeZone { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetPageTrackOrderInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetPageTrackOrderInput.cs index d9c87ab0..324e9c48 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetPageTrackOrderInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetPageTrackOrderInput.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; +namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; public class GetPageTrackOrderInput : PageInfoInput { @@ -73,16 +73,6 @@ public class TrackOrderDto /// public string? OrderNumber { get; set; } - /// - /// 轨迹模版 - /// - public string? TrackTemplateNames { get; set; } - - /// - /// 轨迹模板Id数组 - /// - public List? TrackTemplateIds { get; set; } - /// /// 客户简称 /// @@ -162,4 +152,19 @@ public class TrackOrderDto ///// 问题描述名称 ///// //public string? ProblemDescriptionName { get; set; } -} \ No newline at end of file + + /// + /// 预计到达时间 + /// + public DateTime? EstimatedDeliveryDate { get; set; } + + /// + /// 目的地时区 + /// + public float? DestinationTimeZone { get; set; } + + /// + /// 第三方单号,服务商-轨迹0000000、轨迹服务商-0000000 + /// + public string? ThirdPartyOrderNumber { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetPageTrackTemplateListInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetPageTrackTemplateListInput.cs new file mode 100644 index 00000000..a591adf7 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetPageTrackTemplateListInput.cs @@ -0,0 +1,29 @@ +namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; + +public class GetPageTrackTemplateListInput : PageInfoInput +{ + /// + /// 子系统id + /// + public int SubSystemId { get; set; } + + /// + /// 客户id + /// + public int? CustomerId { get; set; } + + /// + /// 模版分类 + /// + public int? TemplateType { get; set; } + + /// + /// 模板code + /// + public string? TemplateCode { get; set; } + + /// + /// 关键字 + /// + public string? KeyWord { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetTrackInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetTrackInput.cs index 8fa3dec0..44df6107 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetTrackInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetTrackInput.cs @@ -1,26 +1,33 @@ -using System.ComponentModel.DataAnnotations; - namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; +/// +/// 支持模板,传入时区补正,按轨迹发生时间升序降序 +/// public class GetTrackInput : OrderNosInfo { + private float? _timeZone; + /// /// 时区 +8 +8.25 -8.5 -9 /// 不传默认+8 /// - private float? _timeZone; - - public float? TimeZone - { - get => _timeZone ?? 8; - set => _timeZone = value; - } + public float? TimeZone { get => _timeZone ?? 8; set => _timeZone = value; } /// - /// 排序方式 + /// 排序方式,默认按轨迹发生时间降序 /// - [Required] - public SortMethod SortMethod { get; set; } + public SortMethod? SortMethod { get; set; } +} + +/// +/// 不支持模板,无时区补正,按轨迹发生时间升序降序 +/// +public class GetTrackInputV2 : OrderNosInfo +{ + /// + /// 排序方式,默认按轨迹发生时间降序 + /// + public SortMethod? SortMethod { get; set; } } public enum SortMethod @@ -28,15 +35,20 @@ public enum SortMethod /// /// 按轨迹发生时间排序 /// - ByTrackTime, + ByTrackTime = 0, /// /// 按轨迹发生时间降序 /// - ByTrackTimeDesc, + ByTrackTimeDesc = 1, /// - /// 按订单模板排序 + /// 模板排序+轨迹发生时间 /// - ByTemplate -} \ No newline at end of file + ByTemplateAndTrackTime = 2, + + /// + /// 模板排序+轨迹发生时间 + /// + ByTemplateAndTrackTimeDesc = 3 +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetTrackOutput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetTrackOutput.cs index dcafe452..e03a46f0 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetTrackOutput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetTrackOutput.cs @@ -7,16 +7,111 @@ public class GetTrackOutput /// public string OrderNo { get; set; } = null!; + /// + /// 轨迹明细列表 + /// public List TrackDetails { get; set; } = new(); } public class TrackDetail { + public string EsId { get; set; } = null!; public string Code { get; set; } = null!; public string Status { get; set; } = null!; public string? Content { get; set; } + public string? EnContent { get; set; } public string? OriginContent { get; set; } public string Location { get; set; } = null!; + + /// + /// 发生时间 + /// public DateTime Time { get; set; } - public float TimeZone { get; set; } -} \ No newline at end of file + + /// + /// 轨迹时区 + /// + public float? TimeZone { get; set; } + + /// + /// 是否对外 + /// + [Obsolete("废弃的,请使用IsExternal")] + public bool IsDisplay { get; set; } + + /// + /// 客户是否可见 + /// + [Obsolete("废弃的,请使用IsExternal")] + public bool IsVisibility { get; set; } + + /// + /// 是否对外 + /// + public bool IsExternal { get; set; } + + /// + /// 数据来源:1外部服务商创建,2内部系统创建,3人工创建 + /// + public int Source { get; set; } + + /// + /// 备注 + /// + public string? Remarks { get; set; } + + /// + /// 附件集合 + /// + public List? Files { get; set; } + + /// + /// 轨迹发生地(城市) + /// + public string? TrackPlaceCity { get; set; } + + /// + /// 轨迹发生地(城市)Id + /// + public int? TrackPlaceCityId { get; set; } + + /// + /// 轨迹发生地(省/州) + /// + public string? TrackPlaceProvince { get; set; } + + /// + /// 轨迹发生地(省/州)Id + /// + public int? TrackPlaceProvinceId { get; set; } + + /// + /// 轨迹发生地(国家/地区) + /// + public string? TrackPlaceNation { get; set; } + + /// + /// 轨迹发生地(国家/地区)Id + /// + public int? TrackPlaceNationId { get; set; } + + /// + /// 轨迹发生地邮编 + /// + public string? TrackPlacePostcode { get; set; } + + /// + /// 预计到达时间 + /// + public DateTime? EstimatedDeliveryDate { get; set; } + + /// + /// 目的地时区 + /// + public float? DestinationTimeZone { get; set; } + + /// + /// 扩展信息字段,用与轨迹推送的附加字段 + /// + public string? Extra { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetTrackTemplateListInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetTrackTemplateListInput.cs new file mode 100644 index 00000000..e1c04282 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetTrackTemplateListInput.cs @@ -0,0 +1,24 @@ +namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; + +public class GetTrackTemplateListInput +{ + /// + /// 子系统id + /// + public int SubSystemId { get; set; } + + /// + /// 客户id + /// + public int? CustomerId { get; set; } + + /// + /// 模版分类 + /// + public int? TemplateType { get; set; } + + /// + /// 模板code + /// + public string? TemplateCode { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/LinkOrderInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/LinkOrderInput.cs index da8b3110..28b17b97 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/LinkOrderInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/LinkOrderInput.cs @@ -1,9 +1,16 @@ -using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations; namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; public class LinkOrderInput { + /// + /// 子系统id + /// + [Required] + [Range(1, int.MaxValue)] + public int SubSystemId { get; set; } + /// /// false解绑,true关联 /// @@ -22,6 +29,13 @@ public class LinkOrderInput [Required] public string OrderNo { get; set; } = null!; + /// + /// 关联子系统id + /// + [Required] + [Range(1, int.MaxValue)] + public int LinkSubSystemId { get; set; } + /// /// 关联单类型 /// @@ -32,4 +46,4 @@ public class LinkOrderInput /// 关联的单号 /// public List LinkOrderNos { get; set; } = new(); -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/OrderNoInfo.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/OrderNoInfo.cs index 3ec49a17..e62cb1b4 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/OrderNoInfo.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/OrderNoInfo.cs @@ -1,9 +1,19 @@ -using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations; namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; +/// +/// 子系统id+订单类型+订单号 确定唯一订单 +/// public class OrderNoInfo { + /// + /// 子系统id + /// + [Required] + [Range(1, int.MaxValue)] + public int SubSystemId { get; set; } + /// /// 订单类型,必填 /// @@ -21,6 +31,13 @@ public class OrderNoInfo public class OrderNosInfo { + /// + /// 子系统id + /// + [Required] + [Range(1, int.MaxValue)] + public int SubSystemId { get; set; } + /// /// 订单类型 /// @@ -32,5 +49,6 @@ public class OrderNosInfo /// 订单号 /// [Required] + [MaxLength(500)] public List OrderNos { get; set; } = new(); -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/PushTrackInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/PushTrackInput.cs index 5eaff31e..bc5b6cae 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/PushTrackInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/PushTrackInput.cs @@ -1,4 +1,4 @@ -using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations; namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; @@ -9,4 +9,14 @@ public class PushTrackInput : OrderNosInfo /// [Required] public string TrackCode { get; set; } = null!; -} \ No newline at end of file + + /// + /// 重复的情况下,用什么字段比较 + /// + public string? CompareFields { get; set; } + + /// + /// 重复的情况下,比较值 + /// + public object? CompareValue { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/QueryTrackPullMappingsInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/QueryTrackPullMappingsInput.cs index ed0e9da4..7c29d75b 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/QueryTrackPullMappingsInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/QueryTrackPullMappingsInput.cs @@ -1,60 +1,53 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; -namespace SJZY.Track.Application.Contract.Dtos.ProvideServices +/// +/// 查询轨迹推送映射关系入参 +/// +public class QueryTrackPullMappingsInput { /// - /// 查询轨迹推送映射关系入参 + /// 子系统id /// - public class QueryTrackPullMappingsInput - { - /// - /// 子系统id - /// - public int SubsystemsId { get; set; } - - /// - /// 客户id - /// - public int CustomerId { get; set; } - } + public int SubsystemsId { get; set; } /// - /// 查询轨迹推送映射关系返参项 + /// 客户id /// - public class QueryTrackPullMappingsInfo - { - /// - /// 轨迹代码 - /// - public string? Code { get; set; } - - /// - /// 订单类型 - /// - public int OrderType { get; set; } - - /// - /// 服务商轨迹代码 - /// - public string? ServiceCode { get; set; } - - /// - /// 服务商轨迹状态 - /// - public string? Status { get; set; } - - /// - /// 服务商轨迹内容 - /// - public string? Content { get; set; } - - /// - /// 服务商轨迹内容英文 - /// - public string? ContentEn { get; set; } - } + public int CustomerId { get; set; } +} + +/// +/// 查询轨迹推送映射关系返参项 +/// +public class QueryTrackPullMappingsInfo +{ + /// + /// 轨迹代码 + /// + public string? Code { get; set; } + + /// + /// 订单类型 + /// + public int OrderType { get; set; } + + /// + /// 服务商轨迹代码 + /// + public string? ServiceCode { get; set; } + + /// + /// 服务商轨迹状态 + /// + public string? Status { get; set; } + + /// + /// 服务商轨迹内容 + /// + public string? Content { get; set; } + + /// + /// 服务商轨迹内容英文 + /// + public string? ContentEn { get; set; } } diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/RefreshTrackInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/RefreshTrackInput.cs index 4e6e2955..6197fe26 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/RefreshTrackInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/RefreshTrackInput.cs @@ -1,9 +1,14 @@ -namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; +namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; public class RefreshTrackInput { + /// + /// 子系统id + /// + public int SubSystemId { get; set; } + /// /// 订单号 /// public List OrderNos { get; set; } = new(); -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/TrackIdentifierDto.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/TrackIdentifierDto.cs new file mode 100644 index 00000000..993de61c --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/TrackIdentifierDto.cs @@ -0,0 +1,21 @@ +using System.ComponentModel.DataAnnotations; + +namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; + +/// +/// 轨迹标识符,用于唯一标识一个轨迹 +/// +public sealed class TrackIdentifierDto +{ + /// + /// 轨迹code + /// + [Required] + public string TrackCode { get; set; } + + /// + /// 轨迹发生时间 + /// + [Required] + public DateTime TrackTime { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/TrackTemplateContentDto.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/TrackTemplateContentDto.cs new file mode 100644 index 00000000..ffabeb90 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/TrackTemplateContentDto.cs @@ -0,0 +1,52 @@ +namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; + +public class TrackTemplateOutput +{ + /// + /// 模版名称 + /// + public string TemplateName { get; set; } + + /// + /// 模版code + /// + public string TemplateCode { get; set; } + + /// + /// 模版内容 + /// + public List TemplateContents { get; set; } +} + +public class TemplateContentDto +{ + /// + /// 轨迹code + /// + public string Code { get; set; } + + /// + /// 轨迹内容中文 + /// + public string ContentCn { get; set; } + + /// + /// 轨迹内容中文 + /// + public string ContentEn { get; set; } + + /// + /// 轨迹状态 + /// + public string Status { get; set; } + + /// + /// 轨迹节点 + /// + public string Node { get; set; } + + /// + /// 排序键 + /// + public int Sort { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpdateOrderInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpdateOrderInput.cs index ebb47f17..a37ab135 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpdateOrderInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpdateOrderInput.cs @@ -43,12 +43,79 @@ public class UpdateOrderInput : OrderNoInfo public string LeaveCity { get; set; } = null!; /// - /// 订单模板(传全量) + /// 货物类型 /// - public List Templates { get; set; } = new(); + public string? CargoType { get; set; } + + /// + /// 是否转运 + /// + public bool? IsTransit { get; set; } + + /// + /// 产品编码 + /// + public string? ProductCode { get; set; } + + /// + /// 预计到达时间 + /// + public DateTime? EstimatedDeliveryDate { get; set; } + + /// + /// 目的地时区 + /// + public float? DestinationTimeZone { get; set; } + + /// + /// 拉取配置信息 + /// + public List? PullConfigInfos { get; set; } /// /// 订单航班信息 /// public List FlightInfos { get; set; } = new(); -} \ No newline at end of file + + + /// + /// 模板code + /// + public List? TemplateCodes { get; set; } +} + +public class PullConfigInfo +{ + /// + /// 服务商code + /// + [Required] + public string ServiceCode { get; set; } + + /// + /// api服务商订单号(第三方单号) + /// + public string? OrderNo { get; set; } + + /// + /// 开始轨迹code + /// + public string? StartCode { get; set; } + + /// + /// 结束轨迹code + /// + public string? EndCode { get; set; } + + /// + /// 静默多久后拉取(小时) + /// + [Range(0, 24 * 7)] + public int SilenceTime { get; set; } + + /// + /// 结束多久后停止拉取(小时) + /// + [Range(0, 24 * 7)] + public int StopTime { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpdateOrderStatusInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpdateOrderStatusInput.cs index c05d79ee..9d1e330b 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpdateOrderStatusInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpdateOrderStatusInput.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; +namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; public class UpdateOrderStatusInput { @@ -8,4 +8,4 @@ public class UpdateOrderStatusInput /// 订单是否完成 /// public bool IsCompleted { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpdateServiceProviderPullConfigsInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpdateServiceProviderPullConfigsInput.cs new file mode 100644 index 00000000..fd0dca43 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpdateServiceProviderPullConfigsInput.cs @@ -0,0 +1,6 @@ +namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; + +public class UpdateOrderPullConfigsInput : OrderNosInfo +{ + public PullConfigInfo Config { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpsertOrderInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpsertOrderInput.cs index 4293ccc0..628a6155 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpsertOrderInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpsertOrderInput.cs @@ -7,23 +7,12 @@ public class UpsertOrderInput : UpdateOrderInput /// /// 客户id /// - [Required] public int CustomId { get; set; } -} - -public class OrderTemplateInfo -{ - /// - /// 模板id - /// - [Required] - [Range(1, Int32.MaxValue)] - public int TemplateId { get; set; } /// - /// 服务商id + /// 当前操作人 /// - public int? ServiceProviderId { get; set; } + public int OptionUserId { get; set; } } public class OrderFlightInfo @@ -40,4 +29,4 @@ public class OrderFlightInfo /// [Required] public DateTime FlightDate { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpsertTrackInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpsertTrackInput.cs index ce97f715..961841a6 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpsertTrackInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpsertTrackInput.cs @@ -1,4 +1,4 @@ -using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations; namespace SJZY.Track.Application.Contract.Dtos.ProvideServices; @@ -9,6 +9,11 @@ public class UpsertTrackInput : OrderNoInfo /// public bool IsAdd { get; set; } + /// + /// 轨迹唯一标识(可选) + /// + public string? EsId { get; set; } + /// /// 轨迹内容代码 /// @@ -27,12 +32,126 @@ public class UpsertTrackInput : OrderNoInfo /// 轨迹发生时间 /// [Required] - public DateTime? TrackTime { get; set; } + public DateTime TrackTime { get; set; } + + /// + /// 更改后的轨迹发生时间,无需更改保持为空 + /// + public DateTime? NewTrackTime { get; set; } /// /// 轨迹发生时区 /// - [Required] - [Range(-12, 12)] + // [Required] + // [Range(-12, 12)] public float? TrackTimeZone { get; set; } -} \ No newline at end of file + + /// + /// 客户是否可见 + /// + [Obsolete("废弃的,请使用IsExternal")] + public bool IsVisibility { get; set; } + + /// + /// 是否对外(可选的) + /// 如果未填则按照【轨迹内容】中的【是否可见】做为默认值 + /// + public bool? IsExternal { get; set; } + + /// + /// 数据来源:1外部服务商创建,2内部系统创建,3人工创建 + /// + [Required] + public int Source { get; set; } + + /// + /// 轨迹备注 + /// + public string? Remarks { get; set; } + + /// + /// 附件集合 + /// + public List? Files { get; set; } + + /// + /// 轨迹内容,若为空则取轨迹内容表中该轨迹Code对应的轨迹内容 + /// + public string? Content { get; set; } + + /// + /// 轨迹内容英文,若为空则取轨迹内容表中该轨迹Code对应的轨迹英文内容 + /// + public string? EnStatus { get; set; } + + /// + /// 轨迹发生地(城市) + /// + public string? TrackPlaceCity { get; set; } + + /// + /// 轨迹发生地(城市)Id + /// + public int? TrackPlaceCityId { get; set; } + + /// + /// 轨迹发生地(省/州) + /// + public string? TrackPlaceProvince { get; set; } + + /// + /// 轨迹发生地(省/州)Id + /// + public int? TrackPlaceProvinceId { get; set; } + + /// + /// 轨迹发生地(国家/地区) + /// + public string? TrackPlaceNation { get; set; } + + /// + /// 轨迹发生地(国家/地区)Id + /// + public int? TrackPlaceNationId { get; set; } + + /// + /// 轨迹发生地邮编 + /// + public string? TrackPlacePostcode { get; set; } + + /// + /// 预计到达时间 + /// + public DateTime? EstimatedDeliveryDate { get; set; } + + /// + /// 目的地时区 + /// + [Range(-12, 12)] + public float? DestinationTimeZone { get; set; } + + /// + /// 当前操作人 + /// + public int OptionUserId { get; set; } + + /// + /// 重复的情况下,用什么比较 + /// + public string? CompareFields { get; set; } + + /// + /// 扩展信息字段,用与轨迹推送的附加字段 + /// + public string? Extra { get; set; } + + /// + /// 是否强制推送 + /// + public bool ForcedPush { get; set; } + + /// + /// 指定是否推送 + /// + public bool IsToMq { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackContents/EditTrackContentInput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/EditTrackContentInput.cs index 8a99f816..8b1aca31 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackContents/EditTrackContentInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/EditTrackContentInput.cs @@ -1,98 +1,137 @@ -namespace SJZY.Track.Application.Contract.Dtos.TrackContents +namespace SJZY.Track.Application.Contract.Dtos.TrackContents; + +public class EditTrackContentInput { - public class EditTrackContentInput - { - /// - /// Id - /// - public int Id { get; set; } + /// + /// Id + /// + public int Id { get; set; } - /// - /// 操作类型 - /// - public OptionType Options { get; set; } + /// + /// 操作类型 + /// + public OptionType Options { get; set; } - /// - /// 子系统id - /// - public int SubSystemId { get; set; } + /// + /// 子系统id + /// + public int SubSystemId { get; set; } - /// - /// 所属轨迹状态id - /// - public int TrackStatusId { get; set; } + /// + /// 所属轨迹状态id + /// + public int? TrackStatusId { get; set; } - /// - /// 轨迹内容代码 - /// - public string? Code { get; set; } + /// + /// 轨迹内容代码 + /// + public string? Code { get; set; } - /// - /// 轨迹内容 - /// - public string? Content { get; set; } + /// + /// 轨迹内容 + /// + public string? Content { get; set; } - /// - /// 轨迹内容英文 - /// - public string? EnContent { get; set; } + /// + /// 轨迹内容英文 + /// + public string? EnContent { get; set; } - /// - /// 轨迹标记id - /// - public int TrackFlagId { get; set; } - } + /// + /// 轨迹标记id + /// + public int[]? TrackFlagIds { get; set; } - public class GetTrackContentDetailDto - { - /// - /// Id - /// - public int Id { get; set; } + /// + /// 是否对外 + /// + public bool IsExternal { get; set; } - /// - /// 子系统id - /// - public int SubSystemId { get; set; } + /// + /// 是否可重复 + /// + public bool IsRepeatable { get; set; } - /// - /// 子系统 - /// - public string SubSystem { get; set; } + /// + /// 是否允许手动修改 + /// + public bool IsAllowManuallyUpdate { get; set; } - /// - /// 所属轨迹状态id - /// - public int TrackStatusId { get; set; } + /// + /// 是否允许手动创建 + /// + public bool IsAllowManuallyCreate { get; set; } +} - /// - /// 所属轨迹状态 - /// - public string TrackStatus { get; set; } +public class GetTrackContentDetailDto +{ + /// + /// Id + /// + public int Id { get; set; } - /// - /// 轨迹内容代码 - /// - public string Code { get; set; } + /// + /// 子系统id + /// + public int SubSystemId { get; set; } - /// - /// 轨迹内容 - /// - public string Content { get; set; } + /// + /// 子系统 + /// + public string SubSystem { get; set; } - /// - /// 轨迹内容英文 - /// - public string EnContent { get; set; } + /// + /// 所属轨迹状态id + /// + public int TrackStatusId { get; set; } - /// - /// 轨迹标记id - /// - public int? TrackFlagId { get; set; } + /// + /// 所属轨迹状态 + /// + public string TrackStatus { get; set; } - /// - /// 轨迹标记 - /// - public string TrackFlag { get; set; } - } -} \ No newline at end of file + /// + /// 轨迹内容代码 + /// + public string Code { get; set; } + + /// + /// 轨迹内容 + /// + public string Content { get; set; } + + /// + /// 轨迹内容英文 + /// + public string EnContent { get; set; } + + /// + /// 轨迹标记id + /// + public string? TrackFlagId { get; set; } + + /// + /// 轨迹标记ids + /// + public List? TrackFlagIds { get; set; } + + /// + /// 是否对外 + /// + public bool IsExternal { get; set; } + + /// + /// 是否可重复 + /// + public bool IsRepeatable { get; set; } + + /// + /// 是否允许手动修改 + /// + public bool IsAllowManuallyUpdate { get; set; } + + /// + /// 是否允许手动创建 + /// + public bool IsAllowManuallyCreate { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackContents/EditTrackContentMapInput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/EditTrackContentMapInput.cs index e207654d..b556cb20 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackContents/EditTrackContentMapInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/EditTrackContentMapInput.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Application.Contract.Dtos.TrackContents; +namespace SJZY.Track.Application.Contract.Dtos.TrackContents; public class EditTrackContentMapInput { @@ -38,4 +38,4 @@ public class EditTrackContentMapInput /// 源轨迹内容id /// public int? TrackContentId { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetAvailableContentInput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetAvailableContentInput.cs new file mode 100644 index 00000000..39ae0073 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetAvailableContentInput.cs @@ -0,0 +1,27 @@ +namespace SJZY.Track.Application.Contract.Dtos.TrackContents; + +public class GetAvailableContentInput +{ + /// + /// 子系统id + /// + public int SystemId { get; set; } + + /// + /// 订单号 + /// + public string? OrderNo { get; set; } + + /// + /// 操作类型 1=创建 2=修改 3=删除 4=推送 + /// + public TrackOptionType TrackOptionType { get; set; } +} + +public enum TrackOptionType +{ + 创建 = 1, + 修改 = 2, + 删除 = 3, + 推送 = 4, +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetAvailableContentOutput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetAvailableContentOutput.cs new file mode 100644 index 00000000..7af80b7c --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetAvailableContentOutput.cs @@ -0,0 +1,104 @@ +using SJZY.Track.Application.Contract.Dtos.ProvideServices; + +namespace SJZY.Track.Application.Contract.Dtos.TrackContents; + +public class GetAvailableContentOutput +{ + /// + /// Id + /// + public int Id { get; set; } + + /// + /// 轨迹内容代码 + /// + public string Code { get; set; } + + /// + /// 轨迹内容 + /// + public string Content { get; set; } + + /// + /// 轨迹内容英文 + /// + public string EnContent { get; set; } + + /// + /// 是否对外 + /// + public bool IsExternal { get; set; } + + /// + /// 轨迹来源 + /// + public int? Source { get; set; } + + /// + /// 轨迹发生地 + /// + public string? TrackPlace { get; set; } + + /// + /// 轨迹发生时间 + /// + public DateTime? TrackTime { get; set; } + + /// + /// 轨迹发生时区 + /// + public float? TrackTimeZone { get; set; } + + /// + /// 时区的值 + /// + public float? TrackTimeZoneValue { get; set; } + + /// + /// 备注 + /// + public string? Remarks { get; set; } + + /// + /// 轨迹发生地(城市) + /// + public string? TrackPlaceCity { get; set; } + public int? TrackPlaceCityId { get; set; } + + /// + /// 轨迹发生地(省/州) + /// + public string? TrackPlaceProvince { get; set; } + public int? TrackPlaceProvinceId { get; set; } + + /// + /// 轨迹发生地(国家/地区) + /// + public string? TrackPlaceNation { get; set; } + public int? TrackPlaceNationId { get; set; } + + /// + /// 轨迹发生地邮编 + /// + public string? TrackPlacePostcode { get; set; } + + /// + /// 预计到达时间 + /// + public DateTime? EstimatedDeliveryDate { get; set; } + + /// + /// 目的地时区 + /// + public float? DestinationTimeZone { get; set; } + + /// + /// 附件文件集合 + /// + public List? FileItems { get; set; } + + /// + /// 客户是否可见 + /// + public bool IsVisibility { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetContentDetailInput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetContentDetailInput.cs new file mode 100644 index 00000000..d61d19bb --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetContentDetailInput.cs @@ -0,0 +1,29 @@ +namespace SJZY.Track.Application.Contract.Dtos.TrackContents; + +public class GetContentDetailInput +{ + /// + /// 子系统编号 + /// + public int SystemId { get; set; } + + /// + /// 订单号 + /// + public string OrderNumber { get; set; } + + /// + /// 订单类型 + /// + public int OrderType { get; set; } + + /// + /// 轨迹code + /// + public string TrackCode { get; set; } + + /// + /// 轨迹发生时间 + /// + public DateTime TrackTime { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetContentDetailOutput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetContentDetailOutput.cs new file mode 100644 index 00000000..ea58971c --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetContentDetailOutput.cs @@ -0,0 +1,192 @@ +namespace SJZY.Track.Application.Contract.Dtos.TrackContents; + +public class GetContentDetailOutput +{ + /// + /// 子系统 + /// + public int SubSystemId { get; set; } + + /// + /// 订单Id + /// + public int OrderId { get; set; } + + /// + /// 订单号 + /// + public string OrderNo { get; set; } = null!; + + /// + /// 索引名称 + /// + public string IndexName { get; set; } = null!; + + /// + /// 订单类型(主数据枚举TrackOrderType) + /// + public int OrderType { get; set; } + + /// + /// 轨迹状态 + /// + public string TrackStatus { get; set; } + + /// + /// 轨迹状态code + /// + public string TrackStatusCode { get; set; } + + /// + /// 轨迹内容代码 + /// + public string TrackCode { get; set; } + + /// + /// 轨迹内容 + /// + public string TrackContent { get; set; } + + /// + /// 轨迹内容英文 + /// + public string TrackEnContent { get; set; } + + /// + /// 服务商code + /// + public string ServiceProviderCode { get; set; } + + /// + /// 原轨迹内容 + /// + public string? OriginTrackContent { get; set; } + + /// + /// 原轨迹报文hash(刷新轨迹重复性校验使用) + /// + public string OriginTrackDataHash { get; set; } = null!; + + /// + /// 轨迹发生地 + /// + public string TrackPlace { get; set; } + + /// + /// 轨迹发生时间 + /// + public DateTime TrackTime { get; set; } + + /// + /// 轨迹发生时区 + /// + public float TrackTimeZone { get; set; } + + /// + /// 转化后的轨迹发生时间 + /// + public DateTime ZeroTrackTime { get; set; } + + /// + /// 创建人 + /// + public string CreateUser { get; set; } + + /// + /// 创建时间 + /// + public DateTime CreateTime { get; set; } + + /// + /// 修改人 + /// + public string UpdateUser { get; set; } + + /// + /// 修改时间 + /// + public DateTime? UpdateTime { get; set; } + + /// + /// 客户是否可见 + /// + public bool IsVisibility { get; set; } + + /// + /// 数据来源:1外部服务商创建,2内部系统创建,3人工创建 + /// + public int Source { get; set; } + + /// + /// 备注 + /// + public string? Remarks { get; set; } + + /// + /// 附件集合 + /// + public List? Files { get; set; } + + /// + /// 轨迹发生地(城市) + /// + public string? TrackPlaceCity { get; set; } + + /// + /// 轨迹发生地(城市)Id + /// + public int? TrackPlaceCityId { get; set; } + + /// + /// 轨迹发生地(省/州) + /// + public string? TrackPlaceProvince { get; set; } + + /// + ///轨迹发生地(省/州)Id + /// + public int? TrackPlaceProvinceId { get; set; } + + /// + /// 轨迹发生地(国家/地区) + /// + public string? TrackPlaceNation { get; set; } + + /// + /// 轨迹发生地(国家/地区)Id + /// + public int? TrackPlaceNationId { get; set; } + + /// + /// 轨迹发生地邮编 + /// + public string? TrackPlacePostcode { get; set; } + + /// + /// 预计签收时间 + /// + public DateTime? EstimatedDeliveryDate { get; set; } + + /// + /// 签收地时区 + /// + public float? DestinationTimeZone { get; set; } +} + +public class FileItem +{ + /// + /// 文件osskey + /// + public string OssKey { get; set; } + + /// + /// 文件名称 + /// + public string FileName { get; set; } + + /// + /// 路径 + /// + public string Url { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetPageTrackContentInput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetPageTrackContentInput.cs index b6aa4a90..1d5cceac 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetPageTrackContentInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetPageTrackContentInput.cs @@ -1,88 +1,107 @@ -namespace SJZY.Track.Application.Contract.Dtos.TrackContents +namespace SJZY.Track.Application.Contract.Dtos.TrackContents; + +public class GetPageTrackContentInput : PageInfoInput { - public class GetPageTrackContentInput : PageInfoInput - { - /// - /// 子系统id - /// - public int SubSystemId { get; set; } + /// + /// 子系统id + /// + public int SubSystemId { get; set; } - /// - /// 关键字 - /// - public string? Keywords { get; set; } + /// + /// 关键字 + /// + public string? Keywords { get; set; } - /// - /// 轨迹状态id - /// - public int TrackStatusId { get; set; } + /// + /// 轨迹状态id + /// + public int TrackStatusId { get; set; } - /// - /// 选中的轨迹内容id - /// - public List? SelectIds { get; set; } - } + /// + /// 选中的轨迹内容id + /// + public List? SelectIds { get; set; } +} - public class GetTrackContentListDto - { - /// - /// Id - /// - public int Id { get; set; } +public class GetTrackContentListDto +{ + /// + /// Id + /// + public int Id { get; set; } - /// - /// 子系统 - /// - public string SubSystem { get; set; } + /// + /// 子系统 + /// + public string SubSystem { get; set; } - /// - /// 轨迹内容代码 - /// - public string Code { get; set; } + /// + /// 轨迹内容代码 + /// + public string Code { get; set; } - /// - /// 轨迹内容 - /// - public string Content { get; set; } + /// + /// 轨迹内容 + /// + public string Content { get; set; } - /// - /// 轨迹内容英文 - /// - public string EnContent { get; set; } + /// + /// 轨迹内容英文 + /// + public string EnContent { get; set; } - /// - /// 所属状态 - /// - public string TrackStatus { get; set; } + /// + /// 所属状态 + /// + public string TrackStatus { get; set; } - /// - /// 所属节点 - /// - public string Node { get; set; } + /// + /// 所属节点 + /// + public string Node { get; set; } - /// - /// 轨迹标记 - /// - public string TrackFlag { get; set; } + /// + /// 轨迹标记 + /// + public string TrackFlag { get; set; } - /// - /// 创建时间 - /// - public DateTime? CreateTime { get; set; } + /// + /// 是否对外 + /// + public bool IsExternal { get; set; } - /// - /// 创建人 - /// - public string CreateUser { get; set; } + /// + /// 创建时间 + /// + public DateTime? CreateTime { get; set; } - /// - /// 修改时间 - /// - public DateTime? UpdateTime { get; set; } + /// + /// 创建人 + /// + public string CreateUser { get; set; } - /// - /// 修改人 - /// - public string UpdateUser { get; set; } - } -} \ No newline at end of file + /// + /// 修改时间 + /// + public DateTime? UpdateTime { get; set; } + + /// + /// 修改人 + /// + public string UpdateUser { get; set; } + + /// + /// 是否可重复 + /// + public bool IsRepeatable { get; set; } + + /// + /// 是否允许手动修改 + /// + public bool IsAllowManuallyUpdate { get; set; } + + /// + /// 是否允许手动创建 + /// + public bool IsAllowManuallyCreate { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetTrackContentByCodeInput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetTrackContentByCodeInput.cs new file mode 100644 index 00000000..8f7b1c85 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetTrackContentByCodeInput.cs @@ -0,0 +1,14 @@ +namespace SJZY.Track.Application.Contract.Dtos.TrackContents; + +public class GetTrackContentByCodeInput +{ + /// + /// 子系统id + /// + public int SystemId { get; set; } + + /// + /// 轨迹内容code + /// + public string Code { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetTrackContentByCodeOutput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetTrackContentByCodeOutput.cs new file mode 100644 index 00000000..e584522d --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackContents/GetTrackContentByCodeOutput.cs @@ -0,0 +1,19 @@ +namespace SJZY.Track.Application.Contract.Dtos.TrackContents; + +public class GetTrackContentByCodeOutput +{ + /// + /// 中文内容 + /// + public string Content { get; set; } + + /// + /// 英文内容 + /// + public string EnContent { get; set; } + + /// + /// 是否对外 + /// + public bool IsExternal { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackFlags/EditTrackFlagInput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackFlags/EditTrackFlagInput.cs index 49bb942a..5ec2434c 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackFlags/EditTrackFlagInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackFlags/EditTrackFlagInput.cs @@ -1,68 +1,67 @@ -namespace SJZY.Track.Application.Contract.Dtos.TrackFlags +namespace SJZY.Track.Application.Contract.Dtos.TrackFlags; + +public class EditTrackFlagInput { - public class EditTrackFlagInput - { - /// - /// 操作类型 - /// - public OptionType Options { get; set; } + /// + /// 操作类型 + /// + public OptionType Options { get; set; } - /// - /// Id - /// - public int Id { get; set; } + /// + /// Id + /// + public int Id { get; set; } - /// - /// 子系统id - /// - public int SubSystemId { get; set; } + /// + /// 子系统id + /// + public int SubSystemId { get; set; } - /// - /// 标记 - /// - public string? Flag { get; set; } + /// + /// 标记 + /// + public string? Flag { get; set; } - /// - /// 代码 - /// - public string? Code { get; set; } + /// + /// 代码 + /// + public string? Code { get; set; } - ///// - ///// 是否完结 - ///// - //public bool IsFinish { get; set; } - } + /// + /// 是否广播 + /// + public bool IsToMq { get; set; } +} - public class GetTrackFlagDetailDto - { - /// - /// Id - /// - public int Id { get; set; } +public class GetTrackFlagDetailDto +{ + /// + /// Id + /// + public int Id { get; set; } - /// - /// 子系统id - /// - public int SubSystemId { get; set; } + /// + /// 子系统id + /// + public int SubSystemId { get; set; } - /// - /// 子系统 - /// - public string SubSystem { get; set; } + /// + /// 子系统 + /// + public string SubSystem { get; set; } - /// - /// 代码 - /// - public string Code { get; set; } + /// + /// 代码 + /// + public string Code { get; set; } - /// - /// - /// - public string Flag { get; set; } + /// + /// 标记 + /// + public string Flag { get; set; } - ///// - ///// 是否完结 - ///// - //public bool IsFinish { get; set; } - } -} \ No newline at end of file + /// + /// 是否广播 + /// + public bool IsToMq { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackFlags/GetTrackFlagListDto.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackFlags/GetTrackFlagListDto.cs index 505536e1..bc422fbb 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackFlags/GetTrackFlagListDto.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackFlags/GetTrackFlagListDto.cs @@ -1,68 +1,67 @@ -namespace SJZY.Track.Application.Contract.Dtos.TrackFlags +namespace SJZY.Track.Application.Contract.Dtos.TrackFlags; + +public class GetTrackFlagListDto { - public class GetTrackFlagListDto - { - /// - /// Id - /// - public int Id { get; set; } + /// + /// Id + /// + public int Id { get; set; } - /// - /// 子系统 - /// - public string SubSystem { get; set; } + /// + /// 子系统 + /// + public string SubSystem { get; set; } - /// - /// 代码 - /// - public string Code { get; set; } + /// + /// 代码 + /// + public string Code { get; set; } - /// - /// 标记 - /// - public string Flag { get; set; } + /// + /// 标记 + /// + public string Flag { get; set; } - ///// - ///// 是否完结 - ///// - //public bool IsFinish { get; set; } + /// + /// 是否广播 + /// + public bool IsToMq { get; set; } - /// - /// 创建时间 - /// - public DateTime? CreateTime { get; set; } + /// + /// 创建时间 + /// + public DateTime? CreateTime { get; set; } - /// - /// 创建人 - /// - public string CreateUser { get; set; } + /// + /// 创建人 + /// + public string CreateUser { get; set; } - /// - /// 修改时间 - /// - public DateTime? UpdateTime { get; set; } + /// + /// 修改时间 + /// + public DateTime? UpdateTime { get; set; } - /// - /// 修改人 - /// - public string UpdateUser { get; set; } - } + /// + /// 修改人 + /// + public string UpdateUser { get; set; } +} - public class GetPageTrackFlagInput : PageInfoInput - { - /// - /// 子系统id - /// - public int SubSystemId { get; set; } +public class GetPageTrackFlagInput : PageInfoInput +{ + /// + /// 子系统id + /// + public int SubSystemId { get; set; } - /// - /// 选中的轨迹标记id - /// - public List? SelectIds { get; set; } + /// + /// 选中的轨迹标记id + /// + public List? SelectIds { get; set; } - /// - /// 关键字 - /// - public string? Keywords { get; set; } - } -} \ No newline at end of file + /// + /// 关键字 + /// + public string? Keywords { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackNode/TrackNodeInput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackNode/TrackNodeInput.cs new file mode 100644 index 00000000..557a7206 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackNode/TrackNodeInput.cs @@ -0,0 +1,29 @@ +namespace SJZY.Track.Application.Contract.Dtos.TrackNode; + +public class EditTrackNodeInput +{ + /// + /// 操作类型 + /// + public OptionType Options { get; set; } + + /// + /// 轨迹节点id,创建不用填 + /// + public long Id { get; set; } + + /// + /// 系统id + /// + public int? SubSystemId { get; set; } + + /// + /// 节点名称 + /// + public string? NodeName { get; set; } + + /// + /// 节点英文名称 + /// + public string? NodeEnName { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackOrder/GetTrackCounterOutput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackOrder/GetTrackCounterOutput.cs index e330fabb..f52c7156 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackOrder/GetTrackCounterOutput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackOrder/GetTrackCounterOutput.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Application.Contract.Dtos.TrackOrder; +namespace SJZY.Track.Application.Contract.Dtos.TrackOrder; public class GetTrackCounterOutput { @@ -16,4 +16,4 @@ public class GetTrackCounterOutput /// 预警数 /// public int WarnCount { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackOrder/TrackPushRecordItem.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackOrder/TrackPushRecordItem.cs index f01d9869..1050f2ea 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackOrder/TrackPushRecordItem.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackOrder/TrackPushRecordItem.cs @@ -1,5 +1,5 @@ -namespace SJZY.Track.Application.Contract.Dtos.TrackOrder; +namespace SJZY.Track.Application.Contract.Dtos.TrackOrder; public class TrackPushRecordItem { -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackOrder/TrackPushRecordOutput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackOrder/TrackPushRecordOutput.cs index bc136ca0..0dbf4bc9 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackOrder/TrackPushRecordOutput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackOrder/TrackPushRecordOutput.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Application.Contract.Dtos.TrackOrder; +namespace SJZY.Track.Application.Contract.Dtos.TrackOrder; public class TrackPushRecordOutput { @@ -72,4 +72,4 @@ public class TrackPushRecordOutput /// 创建时间 public DateTime CreateTime { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackPull/EditTrackPullConfigInput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackPull/EditTrackPullConfigInput.cs index f60beeb4..1e4b08ee 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackPull/EditTrackPullConfigInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackPull/EditTrackPullConfigInput.cs @@ -1,33 +1,13 @@ -namespace SJZY.Track.Application.Contract.Dtos.TrackPull; +namespace SJZY.Track.Application.Contract.Dtos.TrackPull; public class EditTrackPullConfigInput { - public int? Id { get; set; } - /// /// 操作类型 /// public OptionTypeNoNull Options { get; set; } - /// - /// 拉取轨迹订单号 - /// - public string? OrderNoName { get; set; } - - /// - /// 返参解析对象 - /// - public int? ParseMethod { get; set; } - - /// - /// 定时任务(分钟) - /// - public int? PullInterval { get; set; } - - /// - /// 服务商id - /// - public int? ServiceProviderId { get; set; } + public int? Id { get; set; } /// /// 子系统id @@ -35,42 +15,62 @@ public class EditTrackPullConfigInput public int? SubSystemId { get; set; } /// - /// 拉取轨迹时区 + /// 服务商id /// - public string? TrackTimeZoneName { get; set; } + public int? ServiceProviderId { get; set; } /// - /// 拉取轨迹内容代码 + /// 服务商拉取频率(分钟) /// - public string? TrackContentCodeName { get; set; } + public int PullInterval { get; set; } /// - /// 拉取轨迹内容 + /// 解析方式,1取接口通返参映射后的,2取服务商原返参 /// - public string? TrackContentName { get; set; } - - /// - /// 拉取轨迹发生地 - /// - public string? TrackPlaceName { get; set; } - - /// - /// 拉取轨迹状态 - /// - public string? TrackStatusName { get; set; } - - /// - /// 拉取轨迹发生时间 - /// - public string? TrackTimeName { get; set; } + public int ParseMethod { get; set; } /// /// 订单路径 /// public string? OrderPath { get; set; } + /// + /// 单号参数名 + /// + public string? OrderNoName { get; set; } + /// /// 轨迹明细路径 /// public string? TrackDetailsPath { get; set; } -} \ No newline at end of file + + /// + /// 轨迹状态参数名 + /// + public string? TrackStatusName { get; set; } + + /// + /// 轨迹代码参数名 + /// + public string? TrackContentCodeName { get; set; } + + /// + /// 轨迹内容参数名 + /// + public string? TrackContentName { get; set; } + + /// + /// 轨迹发生地参数名 + /// + public string? TrackPlaceName { get; set; } + + /// + /// 轨迹发生时间参数名 + /// + public string? TrackTimeName { get; set; } + + /// + /// 轨迹时区参数名 + /// + public string? TrackTimeZoneName { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackPull/EditTrackPullContentInput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackPull/EditTrackPullContentInput.cs index 1342b38b..a4d9e0f8 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackPull/EditTrackPullContentInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackPull/EditTrackPullContentInput.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Application.Contract.Dtos.TrackPull; +namespace SJZY.Track.Application.Contract.Dtos.TrackPull; public class EditTrackPullContentInput { @@ -9,21 +9,11 @@ public class EditTrackPullContentInput public int? Id { get; set; } - /// - /// 服务商轨迹代码参数值 - /// - public string? TrackContentCodeValue { get; set; } - /// /// 轨迹内容id /// public int? TrackContentId { get; set; } - /// - /// 服务商轨迹内容参数值 - /// - public string? TrackContentValue { get; set; } - /// /// 拉取轨迹关键字(正向) /// @@ -47,15 +37,10 @@ public class EditTrackPullContentInput /// /// 服务商轨迹状态参数值 /// - public string? TrackStatusValue { get; set; } + public List? TrackStatusValues { get; set; } /// - /// 轨迹时区GMT + /// 兜底轨迹时区发生地 /// - public double? TrackTimeZone { get; set; } - - /// - /// 是否完结 - /// - public bool IsCompleted { get; set; } -} \ No newline at end of file + public int? TrackTimePlaceValue { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackPullContentConfigDto.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackPullContentConfigDto.cs index 771b328c..da3fecdc 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackPullContentConfigDto.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackPullContentConfigDto.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Application.Contract.Dtos.TrackPull; +namespace SJZY.Track.Application.Contract.Dtos.TrackPull; public class TrackPullContentConfigDto { @@ -10,27 +10,17 @@ public class TrackPullContentConfigDto /// /// 服务商轨迹状态参数值 /// - public string? TrackStatusValue { get; set; } + public List TrackStatusValues { get; set; } = new(); /// - /// 服务商轨迹代码参数值 + /// 轨迹关键词(正向) /// - public string? TrackContentCodeValue { get; set; } + public List TrackKeywords { get; set; } = new(); /// - /// 服务商轨迹内容参数值 + /// 轨迹关键词(反向) /// - public string? TrackContentValue { get; set; } - - /// - /// 轨迹关键词(正向),多个逗分隔 - /// - public string? TrackKeyword { get; set; } - - /// - /// 轨迹关键词(反向),多个逗分隔 - /// - public string? TrackKeywordReverse { get; set; } + public List TrackKeywordReverses { get; set; } = new(); /// /// 轨迹发生地参数值(主数据枚举) @@ -38,12 +28,7 @@ public class TrackPullContentConfigDto public int? TrackPlaceValue { get; set; } /// - /// 轨迹时区GMT值 + /// 轨迹时区发生地参数值 /// - public float? TrackTimeZoneValue { get; set; } - - /// - /// 订单是否完成(由轨迹刷新配置决定) - /// - public bool IsCompleted { get; set; } -} \ No newline at end of file + public int? TrackZonePlaceValue { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackPullParamConfigDto.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackPullParamConfigDto.cs index 79af5185..f64cdead 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackPullParamConfigDto.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackPullParamConfigDto.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Application.Contract.Dtos.TrackPull; +namespace SJZY.Track.Application.Contract.Dtos.TrackPull; public class TrackPullParamConfigDto { @@ -46,4 +46,9 @@ public class TrackPullParamConfigDto /// 轨迹明细数组路径 /// public string TrackDetailsPath { get; set; } = null!; -} \ No newline at end of file + + /// + /// 轨迹内容代码 + /// + public string? TrackContentCode { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackPullParamWithContentConfigDto.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackPullParamWithContentConfigDto.cs index fe807cb0..e105248b 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackPullParamWithContentConfigDto.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackPullParamWithContentConfigDto.cs @@ -1,8 +1,8 @@ namespace SJZY.Track.Application.Contract.Dtos.TrackPull; -public class TrackPullParamWithContentConfigDto +public class TrackPullParamsWithContentDto { public TrackPullParamConfigDto ParamConfig { get; set; } = new(); public List ContentConfigs { get; set; } = new(); -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackPullPayload.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackPullPayload.cs new file mode 100644 index 00000000..3165361a --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackPullPayload.cs @@ -0,0 +1,9 @@ +namespace SJZY.Track.Application.Contract.Dtos.TrackPull; + +public class TrackPullPayload +{ + /// + /// 订单号 + /// + public string OrderNo { get; set; } = null!; +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackRefreshAttach.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackRefreshAttach.cs index a527dd47..5f6894e1 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackRefreshAttach.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackRefreshAttach.cs @@ -1,24 +1,18 @@ -namespace SJZY.Track.Application.Contract.Dtos.TrackPull; +namespace SJZY.Track.Application.Contract.Dtos.TrackPull; public class TrackRefreshAttach { - public TrackRefreshAttach(int serviceProviderId, string serviceProviderName, int subSystemId, int orderType) + public TrackRefreshAttach(string serviceProviderCode, int subSystemId, int orderType) { - ServiceProviderId = serviceProviderId; - ServiceProviderName = serviceProviderName; + ServiceProviderCode = serviceProviderCode; SubSystemId = subSystemId; OrderType = orderType; } /// - /// 服务商id + /// 服务商code /// - public int ServiceProviderId { get; set; } - - /// - /// 服务商name - /// - public string ServiceProviderName { get; set; } + public string ServiceProviderCode { get; set; } /// /// 订单类型(主数据枚举TrackOrderType) @@ -29,4 +23,4 @@ public class TrackRefreshAttach /// 子系统id /// public int SubSystemId { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackRefreshContext.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackRefreshContext.cs index d7e67a39..89e55afe 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackRefreshContext.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackRefreshContext.cs @@ -18,9 +18,9 @@ public class TrackRefreshContext public string OrderNo { get; set; } = null!; /// - /// 服务商 + /// 服务商代码 /// - public string ServiceProviderName { get; set; } = null!; + public string ServiceProviderCode { get; set; } = null!; /// /// 客户id @@ -31,4 +31,4 @@ public class TrackRefreshContext /// 子系统id /// public int SubSystemId { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackPush/EditTrackPushConfigInput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackPush/EditTrackPushConfigInput.cs index b4ed8f6e..9d7c58d9 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackPush/EditTrackPushConfigInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackPush/EditTrackPushConfigInput.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Application.Contract.Dtos.TrackPush; +namespace SJZY.Track.Application.Contract.Dtos.TrackPush; public class EditTrackPushConfigInput { @@ -20,14 +20,9 @@ public class EditTrackPushConfigInput public OptionTypeNoNull Options { get; set; } /// - /// 推送轨迹订单号 + /// 服务商code /// - public string? OrderNoName { get; set; } - - /// - /// 服务商id - /// - public int? ServiceProviderId { get; set; } + public string? ServiceProviderCode { get; set; } /// /// 子系统id @@ -48,4 +43,24 @@ public class EditTrackPushConfigInput /// 是否全量推送 /// public bool? IsAllPush { get; set; } -} \ No newline at end of file + + /// + /// 是否全量推送 + /// + public bool? IsAllPushWithLatest { get; set; } + + /// + /// 时间格式枚举 + /// + public int? DateTimeFormatType { get; set; } = 0; + + /// + /// 日期时间格式模板 + /// + public string? DateTimeFormat { get; set; } + + /// + /// 时区格式格式模板 + /// + public string? TimezoneFormat { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackPush/EditTrackPushContentInput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackPush/EditTrackPushContentInput.cs index 62fa7cda..d8d4621a 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackPush/EditTrackPushContentInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackPush/EditTrackPushContentInput.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Application.Contract.Dtos.TrackPush; +namespace SJZY.Track.Application.Contract.Dtos.TrackPush; public class EditTrackPushContentInput { @@ -63,4 +63,4 @@ public class EditTrackPushContentInput /// 轨迹时区GMT /// public double? TrackTimeZone { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackPush/SortTrackPushContentInput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackPush/SortTrackPushContentInput.cs index ed095f3e..e7c21f14 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackPush/SortTrackPushContentInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackPush/SortTrackPushContentInput.cs @@ -1,4 +1,4 @@ -using SJZY.Expand.ABP.Core.PublicMethords; +using SJZY.Expand.ABP.Core.PublicMethords; namespace SJZY.Track.Application.Contract.Dtos.TrackPush; @@ -8,4 +8,4 @@ public class SortTrackPushContentInput /// 排序信息 /// public List SortInfo { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushAfterUpdateOrderDto.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushAfterUpdateOrderDto.cs index 3e6ca93d..0fbbbbd6 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushAfterUpdateOrderDto.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushAfterUpdateOrderDto.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Application.Contract.Dtos.TrackPush; +namespace SJZY.Track.Application.Contract.Dtos.TrackPush; public class TrackPushAfterUpdateOrderDto { @@ -26,4 +26,4 @@ public class TrackPushAfterUpdateOrderDto /// 问题描述 /// public string? Message { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushContentConfigDto.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushContentConfigDto.cs index c2bcf867..7c1c1568 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushContentConfigDto.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushContentConfigDto.cs @@ -17,6 +17,11 @@ public class TrackPushContentConfigDto /// public bool IsAllPush { get; set; } + /// + /// 是否全量推送(最新轨迹) + /// + public bool IsAllPushWithLatest { get; set; } + /// /// 是否支持删除 /// @@ -70,5 +75,21 @@ public class TrackPushContentConfigDto /// /// 扩展字段参数值 /// + [Obsolete("废弃属性,调整为从轨迹明细扩展中获取扩展值填入")] public string? ExpandFieldsValue { get; set; } -} \ No newline at end of file + + /// + /// 时间格式枚举 + /// + public int DateTimeFormatType { get; set; } + + /// + /// 日期时间格式模板 + /// + public string? DateTimeFormat { get; set; } + + /// + /// 时区格式格式模板 + /// + public string? TimezoneFormat { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushContentDto.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushContentDto.cs new file mode 100644 index 00000000..dab24a5e --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushContentDto.cs @@ -0,0 +1,36 @@ +namespace SJZY.Track.Application.Contract.Dtos.TrackPush; + +public class TrackPushContentDto +{ + public int Id { get; set; } + + /// + /// 轨迹代码 + /// + public string Code { get; set; } + + /// + /// 推送单号类型 + /// + public int OrderType { get; set; } + + /// + /// 服务商轨迹代码 + /// + public string ServiceCode { get; set; } + + /// + /// 服务商轨迹状态 + /// + public string Status { get; set; } + + /// + /// 服务商轨迹内容 + /// + public string Content { get; set; } + + /// + /// 服务商轨迹内容英文 + /// + public string ContentEn { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushInput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushInput.cs index bc1d10bc..eae08b81 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushInput.cs @@ -1,10 +1,11 @@ -namespace SJZY.Track.Application.Contract.Dtos.TrackPush; +namespace SJZY.Track.Application.Contract.Dtos.TrackPush; public class TrackPushInput { public string OrderNo { get; set; } = null!; - public List Data { get; set; } = new(); + //原TrackItem,为了扩展字段入参变更为字典 + public List> Data { get; set; } = new(); public string Log { get; set; } } @@ -13,19 +14,8 @@ public class TrackUpdateInput { public string OrderNo { get; set; } = null!; - public List Data { get; set; } = new(); + //原TrackItem,为了扩展字段入参变更为字典 + public List> Data { get; set; } = new(); public string Log { get; set; } } - -public class TrackItem -{ - public string Location { get; set; } = null!; - public DateTime Date { get; set; } - public double TimeZone { get; set; } - public string? Description { get; set; } - public string? DescriptionCn { get; set; } - public string? Code { get; set; } - public string? Status { get; set; } - public string? Extra { get; set; } -} \ No newline at end of file diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushRecordDto.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushRecordDto.cs new file mode 100644 index 00000000..a2d88e3b --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackPush/TrackPushRecordDto.cs @@ -0,0 +1,90 @@ +namespace SJZY.Track.Application.Contract.Dtos.TrackPush; + +public class TrackPushRecordDto +{ + /// + /// 子系统代码 + /// + public string SubSystemCode { get; set; } + + /// + /// 是否为手动推送 + /// + public bool IsManualPush { get; set; } + + /// + /// 推送时间 + /// + public DateTime PushTime { get; set; } + + /// + /// 操作人 + /// + public string? OperationMan { get; set; } + + /// + /// 订单号 + /// + public string OrderNo { get; set; } = null!; + + /// + /// 接口通请求Id + /// 在请求接口通前被拦截,就不会有请求Id + /// + public Guid? RequestId { get; set; } + + /// + /// 信息 + /// + public string Message { get; set; } = null!; + + /// + /// 操作类型 + /// + public string OptionType { get; set; } = null!; + + /// + /// 轨迹状态 + /// + public string TrackStatus { get; set; } = null!; + + /// + /// 轨迹内容代码 + /// + public string TrackCode { get; set; } = null!; + + /// + /// 轨迹内容 + /// + public string TrackContent { get; set; } = null!; + + /// + /// 轨迹发生地 + /// + public string TrackPlace { get; set; } = null!; + + /// + /// 轨迹发生时间 + /// + public DateTime TrackTime { get; set; } + + /// + /// 轨迹发生时区 + /// + public float TrackTimeZone { get; set; } + + /// + /// 是否成功 + /// + public bool IsSuccess { get; set; } + + /// + /// 推送内容(json) + /// + public string PushContent { get; set; } = null!; + + /// + /// 轨迹的额外新 + /// + public string? Extra { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackStatus/EditTrackStatusInput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackStatus/EditTrackStatusInput.cs index 61a9d98e..e5efd4c1 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackStatus/EditTrackStatusInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackStatus/EditTrackStatusInput.cs @@ -1,40 +1,49 @@ -namespace SJZY.Track.Application.Contract.Dtos.TrackStatus +namespace SJZY.Track.Application.Contract.Dtos.TrackStatus; + +public class EditTrackStatusInput { - public class EditTrackStatusInput - { - /// - /// Id - /// - public int Id { get; set; } + /// + /// Id + /// + public int Id { get; set; } - /// - /// 操作类型 - /// - public OptionType Options { get; set; } + /// + /// 操作类型 + /// + public OptionType Options { get; set; } - /// - /// 子系统id - /// - public int SubSystemId { get; set; } + /// + /// 子系统id + /// + public int SubSystemId { get; set; } - /// - /// 所属节点id - /// - public int NodeId { get; set; } + /// + /// 所属节点id + /// + public int NodeId { get; set; } - /// - /// 轨迹状态代码 - /// - public string? Code { get; set; } + /// + /// 轨迹状态代码 + /// + public string? Code { get; set; } - /// - /// 轨迹状态 - /// - public string? TrackStatus { get; set; } + /// + /// 轨迹状态 + /// + public string? TrackStatus { get; set; } - /// - /// 轨迹状态英文 - /// - public string? EntrackStatus { get; set; } - } -} \ No newline at end of file + /// + /// 轨迹状态英文 + /// + public string? EnTrackStatus { get; set; } + + /// + /// 是否完结 + /// + public bool IsCompleted { get; set; } + + /// + /// 是否广播 + /// + public bool IsToMq { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackStatus/GetTrackStatusDetailDto.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackStatus/GetTrackStatusDetailDto.cs index fe39c418..228b013c 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackStatus/GetTrackStatusDetailDto.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackStatus/GetTrackStatusDetailDto.cs @@ -1,40 +1,54 @@ -namespace SJZY.Track.Application.Contract.Dtos.TrackStatus +namespace SJZY.Track.Application.Contract.Dtos.TrackStatus; + +public class GetTrackStatusDetailDto { - public class GetTrackStatusDetailDto - { - /// - /// Id - /// - public int Id { get; set; } + /// + /// Id + /// + public int Id { get; set; } - /// - /// 子系统id - /// - public int SubSystemId { get; set; } + /// + /// 子系统id + /// + public int SubSystemId { get; set; } - /// - /// 子系统 - /// - public string SubSystem { get; set; } + /// + /// 子系统 + /// + public string SubSystem { get; set; } - /// - /// 节点id - /// - public int NodeId { get; set; } + /// + /// 节点id + /// + public int NodeId { get; set; } - /// - /// 所属轨迹状态 - /// - public string TrackStatus { get; set; } + /// + /// 所属轨迹状态 + /// + public string TrackStatus { get; set; } - /// - /// 轨迹状态代码 - /// - public string Code { get; set; } + /// + /// 轨迹状态代码 + /// + public string Code { get; set; } - /// - /// 轨迹内容英文 - /// - public string EntrackStatus { get; set; } - } -} \ No newline at end of file + /// + /// 轨迹内容英文 + /// + public string EnTrackStatus { get; set; } + + /// + /// 节点名称 + /// + public string? NodeName { get; set; } + + /// + /// 是否完结 + /// + public bool IsCompleted { get; set; } + + /// + /// 是否广播 + /// + public bool IsToMq { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackStatus/GetTrackStatusListDto.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackStatus/GetTrackStatusListDto.cs index c505aa72..e0410ee0 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackStatus/GetTrackStatusListDto.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackStatus/GetTrackStatusListDto.cs @@ -1,74 +1,82 @@ -namespace SJZY.Track.Application.Contract.Dtos.TrackStatus +namespace SJZY.Track.Application.Contract.Dtos.TrackStatus; + +public class GetTrackStatusListDto { - public class GetTrackStatusListDto - { - /// - /// Id - /// - public int Id { get; set; } + /// + /// Id + /// + public int Id { get; set; } - /// - /// 子系统 - /// - public string SubSystem { get; set; } + /// + /// 子系统 + /// + public string SubSystem { get; set; } - /// - /// 所属节点 - /// - public string Node { get; set; } + /// + /// 所属节点 + /// + public string Node { get; set; } - /// - /// 所属轨迹状态 - /// - public string TrackStatus { get; set; } + /// + /// 所属轨迹状态 + /// + public string TrackStatus { get; set; } - /// - /// 轨迹状态代码 - /// - public string Code { get; set; } + /// + /// 轨迹状态代码 + /// + public string Code { get; set; } - /// - /// 轨迹内容英文 - /// - public string EntrackStatus { get; set; } + /// + /// 轨迹内容英文 + /// + public string EnTrackStatus { get; set; } - /// - /// 创建人 - /// - public string CreateUser { get; set; } + /// + /// 是否完结 + /// + public bool IsCompleted { get; set; } - /// - /// 创建时间 - /// - public DateTime? CreateTime { get; set; } + /// + /// 是否广播 + /// + public bool IsToMq { get; set; } - /// - /// 修改人 - /// - public string UpdateUser { get; set; } + /// + /// 创建人 + /// + public string CreateUser { get; set; } - /// - /// 修改时间 - /// - public DateTime? UpdateTime { get; set; } - } + /// + /// 创建时间 + /// + public DateTime? CreateTime { get; set; } + /// + /// 修改人 + /// + public string UpdateUser { get; set; } - public class GetPageTrackStatusInput : PageInfoInput - { - /// - /// 子系统id - /// - public int SubSystemId { get; set; } + /// + /// 修改时间 + /// + public DateTime? UpdateTime { get; set; } +} - /// - /// 关键字 - /// - public string? Keywords { get; set; } +public class GetPagedTrackStatusInput : PageInfoInput +{ + /// + /// 子系统id + /// + public int SubSystemId { get; set; } - /// - /// 选中的轨迹状态id - /// - public List? SelectIds { get; set;} - } -} \ No newline at end of file + /// + /// 关键字 + /// + public string? Keywords { get; set; } + + /// + /// 选中的轨迹状态id + /// + public List? SelectIds { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackStatus/QueryTrackNodeRequest.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackStatus/QueryTrackNodeRequest.cs new file mode 100644 index 00000000..b22e14a1 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackStatus/QueryTrackNodeRequest.cs @@ -0,0 +1,14 @@ +namespace SJZY.Track.Application.Contract.Dtos.TrackStatus; + +public class QueryTrackNodeRequest : PageInfoInput +{ + /// + /// 关键字,节点中文和英文 + /// + public string? KeyWord { get; set; } + + /// + /// 子系统id + /// + public long? SystemId { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackTemplates/EditTrackTemplateContentInput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackTemplates/EditTrackTemplateContentInput.cs index 62ae5922..e990ce39 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackTemplates/EditTrackTemplateContentInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackTemplates/EditTrackTemplateContentInput.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Application.Contract.Dtos.TrackTemplates; +namespace SJZY.Track.Application.Contract.Dtos.TrackTemplates; /// public class EditTrackTemplateContentInput @@ -11,16 +11,6 @@ public class EditTrackTemplateContentInput /// public int? Id { get; set; } - /// - /// 是否可删 - /// - public bool? IsCanDelete { get; set; } - - /// - /// 是否对外 - /// - public bool? IsExternal { get; set; } - /// /// 轨迹内容id /// @@ -30,4 +20,4 @@ public class EditTrackTemplateContentInput /// 轨迹模板id /// public int? TrackTemplateId { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackTemplates/GetPageTrackTemplateInput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackTemplates/GetPageTrackTemplateInput.cs index 27d3dfc3..32c44f61 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackTemplates/GetPageTrackTemplateInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackTemplates/GetPageTrackTemplateInput.cs @@ -1,28 +1,27 @@ -namespace SJZY.Track.Application.Contract.Dtos.TrackTemplates +namespace SJZY.Track.Application.Contract.Dtos.TrackTemplates; + +/// +/// 获取轨迹模版分页输入 +/// +public class GetPageTrackTemplateInput : PageInfoInput { /// - /// 获取轨迹模版分页输入 + /// 子系统id /// - public class GetPageTrackTemplateInput : PageInfoInput - { - /// - /// 子系统id - /// - public int SubSystemId { get; set; } + public int SubSystemId { get; set; } - /// - /// 关键字 - /// - public string? Keywords { get; set; } + /// + /// 关键字 + /// + public string? Keywords { get; set; } - ///// - ///// 轨迹模版id,轨迹映射的查询使用 - ///// - //public int TrackTemplateId { get; set; } + ///// + ///// 轨迹模版id,轨迹映射的查询使用 + ///// + //public int TrackTemplateId { get; set; } - /// - /// 选中的轨迹模版id - /// - public List? SelectIds { get; set; } - } -} \ No newline at end of file + /// + /// 选中的轨迹模版id + /// + public List? SelectIds { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackTemplates/GetTrackDetailDto.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackTemplates/GetTrackDetailDto.cs index 51fc9c20..ca3e1777 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackTemplates/GetTrackDetailDto.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackTemplates/GetTrackDetailDto.cs @@ -1,110 +1,114 @@ -namespace SJZY.Track.Application.Contract.Dtos.TrackTemplates +namespace SJZY.Track.Application.Contract.Dtos.TrackTemplates; + +/// +/// 获取轨迹模版详情 +/// +public class GetTrackTemplateDetailDto { /// - /// 获取轨迹模版详情 + /// Id /// - public class GetTrackTemplateDetailDto - { - /// - /// Id - /// - public int Id { get; set; } - - /// - /// 子系统id - /// - public int SubSystemId { get; set; } - - /// - /// 子系统 - /// - public string SubSystem { get; set; } - - /// - /// 模版名称 - /// - public string Name { get; set; } - - /// - /// 模版代码 - /// - public string Code { get; set; } - - /// - /// 显示原轨迹 - /// - public bool ShowOrigin { get; set; } - } + public int Id { get; set; } /// - /// 获取轨迹模版列表 + /// 子系统id /// - public class GetTrackTemplateListDto - { - /// - /// 轨迹模版id - /// - public int Id { get; set; } - - /// - /// 模板名称 - /// - public string Name { set; get; } - - /// - /// 模版代码 - /// - public string Code { get; set; } - - /// - /// 所属子系统 - /// - public string SubSystem { set; get; } - - /// - /// 子系统id - /// - public int SubSystemId { set; get; } - - /// - /// 创建时间 - /// - public DateTime CreateTime { get; set; } - } + public int SubSystemId { get; set; } /// - /// 编辑轨迹模版 + /// 子系统 /// - public class EditTrackTemplateInput - { - /// - /// Id - /// - public int Id { set; get; } + public string SubSystem { get; set; } - /// - /// 操作类型 - /// - public OptionType Options { get; set; } + /// + /// 模版名称 + /// + public string Name { get; set; } - /// - /// 子系统id - /// - public int SubSystemId { set; get; } + /// + /// 模版代码 + /// + public string Code { get; set; } - /// - /// 模板名称 - /// - public string? Name { set; get; } + /// + /// 显示原轨迹 + /// + public bool ShowOrigin { get; set; } +} - /// - /// 模板代码 - /// - public string? Code { set; get; } +/// +/// 获取轨迹模版列表 +/// +public class GetTrackTemplateListDto +{ + /// + /// 轨迹模版id + /// + public int Id { get; set; } - /// - /// 显示原轨迹 - /// - public bool ShowOrigin { get; set; } - } -} \ No newline at end of file + /// + /// 模板名称 + /// + public string Name { set; get; } + + /// + /// 模版代码 + /// + public string Code { get; set; } + + /// + /// 所属子系统 + /// + public string SubSystem { set; get; } + + /// + /// 子系统id + /// + public int SubSystemId { set; get; } + + /// + /// 创建时间 + /// + public DateTime CreateTime { get; set; } +} + +/// +/// 编辑轨迹模版 +/// +public class EditTrackTemplateInput +{ + /// + /// Id + /// + public int Id { set; get; } + + /// + /// 操作类型 + /// + public OptionType Options { get; set; } + + /// + /// 子系统id + /// + public int SubSystemId { set; get; } + + /// + /// 模板名称 + /// + public string? Name { set; get; } + + /// + /// 模板代码 + /// + public string? Code { set; get; } + + /// + /// 分类id + /// + public int CategoryId { get; set; } + + /// + /// 客户id + /// + public int CustomerId { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackTemplates/SortTrackTemplateContentInput.cs b/src/SJZY.Track.Application.Contract/Dtos/TrackTemplates/SortTrackTemplateContentInput.cs index 0dbd5155..06c52f37 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackTemplates/SortTrackTemplateContentInput.cs +++ b/src/SJZY.Track.Application.Contract/Dtos/TrackTemplates/SortTrackTemplateContentInput.cs @@ -1,4 +1,4 @@ -using SJZY.Expand.ABP.Core.PublicMethords; +using SJZY.Expand.ABP.Core.PublicMethords; namespace SJZY.Track.Application.Contract.Dtos.TrackTemplates; @@ -8,4 +8,4 @@ public class SortTrackTemplateContentInput /// 排序信息 /// public List SortInfo { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application.Contract/Events/ClearRulCacheEvent.cs b/src/SJZY.Track.Application.Contract/Events/ClearRulCacheEvent.cs new file mode 100644 index 00000000..54ec00e9 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Events/ClearRulCacheEvent.cs @@ -0,0 +1,8 @@ +using SJZY.Track.Application.Contract.Dtos.Forewarning; + +namespace SJZY.Track.Application.Contract.Events; + +public class ClearRulCacheEvent +{ + public List Items { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Events/ModifyWarningEvent.cs b/src/SJZY.Track.Application.Contract/Events/ModifyWarningEvent.cs new file mode 100644 index 00000000..d5ba00e7 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Events/ModifyWarningEvent.cs @@ -0,0 +1,22 @@ +namespace SJZY.Track.Application.Contract.Events; + +/// +/// redis 的发布订阅事件 +/// +public class ModifyWarningEvent : RedisEvent +{ + public string Key { get; set; } +} + +public class RedisEvent : IRedisEvent +{ + public string EventType { get; set; } +} + +/// +/// 简单的事件接口,后续可以根据需要扩展 +/// +public interface IRedisEvent +{ + string EventType { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Events/OrderIdentifier.cs b/src/SJZY.Track.Application.Contract/Events/OrderIdentifier.cs index 158e64b1..09bccd14 100644 --- a/src/SJZY.Track.Application.Contract/Events/OrderIdentifier.cs +++ b/src/SJZY.Track.Application.Contract/Events/OrderIdentifier.cs @@ -2,9 +2,18 @@ namespace SJZY.Track.Application.Contract.Events; public struct OrderIdentifier { + /// + /// 订单id + /// public int OrderId { get; set; } - public string OrderNo { get; set; } - public int OrderType { get; set; } - public int CustomId { get; set; } -} \ No newline at end of file + /// + /// 订单号 + /// + public string OrderNo { get; set; } + + /// + /// 订单类型 + /// + public int OrderType { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Events/PushWarningEvent.cs b/src/SJZY.Track.Application.Contract/Events/PushWarningEvent.cs new file mode 100644 index 00000000..a6601102 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Events/PushWarningEvent.cs @@ -0,0 +1,6 @@ +namespace SJZY.Track.Application.Contract.Events; + +public class PushWarningEvent +{ + public int PageSize { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Events/TrackChangeAfterUpdateOrderEvent.cs b/src/SJZY.Track.Application.Contract/Events/TrackChangeAfterUpdateOrderEvent.cs index a59c31c8..90c807d0 100644 --- a/src/SJZY.Track.Application.Contract/Events/TrackChangeAfterUpdateOrderEvent.cs +++ b/src/SJZY.Track.Application.Contract/Events/TrackChangeAfterUpdateOrderEvent.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Application.Contract.Events; +namespace SJZY.Track.Application.Contract.Events; public class TrackChangeAfterUpdateOrderEvent { @@ -8,7 +8,7 @@ public class TrackChangeAfterUpdateOrderEvent public int[] OrderIds { get; set; } = null!; /// - /// 这条轨迹是否意味着完成(只有刷新会设为true) + /// 这条轨迹是否意味着订单已完成 /// public bool IsCompleted { get; set; } @@ -36,4 +36,19 @@ public class TrackChangeAfterUpdateOrderEvent /// 轨迹时区 /// public float TrackTimeZone { get; set; } -} \ No newline at end of file + + /// + /// 时区缺失和发生地缺失标记,1表示时区,2表示发生地,3表示两种 + /// + public int DeficiencyTagValue { get; set; } + + /// + /// 预计到达时间 + /// + public DateTime? EstimatedDeliveryDate { get; set; } + + /// + /// 签收地时区 + /// + public float? DestinationTimeZone { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Events/TrackChangeEto.cs b/src/SJZY.Track.Application.Contract/Events/TrackChangeEto.cs new file mode 100644 index 00000000..804ad6d5 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Events/TrackChangeEto.cs @@ -0,0 +1,142 @@ +using SJZY.Track.Application.Contract.Dtos.ProvideServices; + +namespace SJZY.Track.Application.Contract.Events; + +public class TrackChangeEto +{ + /// + /// 操作类型:1新增,2删除,3修改 + /// + public int Option { get; set; } + + /// + /// 子系统id + /// + public int SubSystemId { get; set; } + + /// + /// 单号 + /// + public string OrderNo { get; set; } + + /// + /// 客户id + /// + public int CustomId { get; set; } + + /// + /// 订单id + /// + public OrderIdentifier[] OrderIdentifiers { get; set; } = null!; + + /// + /// 操作人 + /// + public string? OperationMan { get; set; } + + /// + /// 轨迹内容代码 + /// + public string TrackCode { get; set; } = null!; + + /// + /// 轨迹内容 + /// + public string? Content { get; set; } + + /// + /// 轨迹内容英文 + /// + public string? EnStatus { get; set; } + + /// + /// 轨迹状态代码 + /// + public string TrackStatusCode { get; set; } + + /// + /// 轨迹发生地 + /// + public string TrackPlace { get; set; } = null!; + + /// + /// 轨迹发生时间 + /// + public DateTime TrackTime { get; set; } + + /// + /// 轨迹发生地时区 + /// + public float TrackTimeZone { get; set; } + + /// + /// 客户是否可见 + /// + [Obsolete("废弃的,请使用IsExternal")] + public bool IsVisibility { get; set; } + + /// + /// 是否对外 + /// + public bool IsExternal { get; set; } + + /// + /// 数据来源:1外部服务商创建,2内部系统创建,3人工创建 + /// + public int Source { get; set; } + + /// + /// 轨迹备注 + /// + public string? Remarks { get; set; } + + /// + /// 附件集合 + /// + public List? Files { get; set; } + + /// + /// 轨迹发生地(城市) + /// + public string? TrackPlaceCity { get; set; } + + /// + /// 轨迹发生地(城市)Id + /// + public int? TrackPlaceCityId { get; set; } + + /// + /// 轨迹发生地(省/州) + /// + public string? TrackPlaceProvince { get; set; } + + /// + ///轨迹发生地(省/州)Id + /// + public int? TrackPlaceProvinceId { get; set; } + + /// + /// 轨迹发生地(国家/地区) + /// + public string? TrackPlaceNation { get; set; } + + /// + /// 轨迹发生地(国家/地区)Id + /// + public int? TrackPlaceNationId { get; set; } + + /// + /// 轨迹发生地邮编 + /// + public string? TrackPlacePostcode { get; set; } + + /// + /// 预计到达时间 + /// + public DateTime? EstimatedDeliveryDate { get; set; } + + /// + /// 扩展信息字段,用与轨迹推送的附加字段 + /// + public string? Extra { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Events/TrackDeleteEvent.cs b/src/SJZY.Track.Application.Contract/Events/TrackDeleteEvent.cs index 73b4d0ac..6fa3c346 100644 --- a/src/SJZY.Track.Application.Contract/Events/TrackDeleteEvent.cs +++ b/src/SJZY.Track.Application.Contract/Events/TrackDeleteEvent.cs @@ -1,4 +1,6 @@ -namespace SJZY.Track.Application.Contract.Events; +using SJZY.Track.Application.Contract.Dtos.ProvideServices; + +namespace SJZY.Track.Application.Contract.Events; public class TrackDeleteEvent { @@ -7,23 +9,49 @@ public class TrackDeleteEvent /// public int SubSystemId { get; set; } + /// + /// es中的id + /// + public string[]? EsIds { get; set; } + /// /// 订单ids /// public int[] OrderIds { get; set; } = null!; /// - /// 轨迹代码 + /// 重复的情况下,用什么字段比较 /// - public List TrackCodes { get; set; } = null!; + public string? CompareFields { get; set; } + + /// + /// 重复的情况下,比较值 + /// + public object? CompareValue { get; set; } + + /// + /// 轨迹标识符 + /// + public List? TrackIdentifiers { get; set; } /// /// 操作人 /// public string? OperationMan { get; set; } + /// + /// 操作人姓名 + /// + public int OperationManId { get; set; } + /// /// 已经处理过的订单 /// public List Visited { get; set; } = new(); -} \ No newline at end of file + + public override string ToString() + { + return $"[TrackDelete by {OperationMan}] SubSystemId: {SubSystemId}, OrderIds: {string.Join(",", + OrderIds)}, TrackCodes: {string.Join(",", TrackIdentifiers.Select(x=>x.TrackCode))}"; + } +} diff --git a/src/SJZY.Track.Application.Contract/Events/TrackInsertForNotMappedEvent.cs b/src/SJZY.Track.Application.Contract/Events/TrackInsertForNotMappedEvent.cs deleted file mode 100644 index 8ab3f2ae..00000000 --- a/src/SJZY.Track.Application.Contract/Events/TrackInsertForNotMappedEvent.cs +++ /dev/null @@ -1,49 +0,0 @@ -namespace SJZY.Track.Application.Contract.Events; - -public class TrackInsertForNotMappedEvent -{ - /// - /// 订单id - /// - public int OrderId { get; set; } - - /// - /// 订单类型 - /// - public int OrderType { get; set; } - - /// - /// 订单号 - /// - public string OrderNo { get; set; } = null!; - - /// - /// 服务商 - /// - public string ServiceProviderName { get; set; } = null!; - - /// - /// 原轨迹内容 - /// - public string? OriginTrackContent { get; set; } - - /// - /// 原轨迹报文 - /// - public string? OriginTrackData { get; set; } - - /// - /// 轨迹发生地 - /// - public string TrackPlace { get; set; } = null!; - - /// - /// 轨迹发生时间 - /// - public DateTime TrackTime { get; set; } - - /// - /// 轨迹发生时区 - /// - public float TrackTimeZone { get; set; } -} \ No newline at end of file diff --git a/src/SJZY.Track.Application.Contract/Events/TrackPushCompletedEvent.cs b/src/SJZY.Track.Application.Contract/Events/TrackPushCompletedEvent.cs new file mode 100644 index 00000000..c7f4801d --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Events/TrackPushCompletedEvent.cs @@ -0,0 +1,88 @@ +namespace SJZY.Track.Application.Contract.Events; + +/// +/// 轨迹推送广播模型 +/// +public class TrackPushCompletedEvent +{ + /// + /// 是否为手动推送 + /// + public bool IsManualPush { get; set; } + + /// + /// 推送时间 + /// + public DateTime PushTime { get; set; } + + /// + /// 操作人 + /// + public string? OperationMan { get; set; } + + /// + /// 订单号 + /// + public string OrderNo { get; set; } = null!; + + /// + /// 接口通请求Id + /// 在请求接口通前被拦截,就不会有请求Id + /// + public Guid? RequestId { get; set; } + + /// + /// 信息 + /// + public string Message { get; set; } = null!; + + /// + /// 操作类型 + /// + public string OptionType { get; set; } = null!; + + /// + /// 轨迹状态 + /// + public string TrackStatus { get; set; } = null!; + + /// + /// 轨迹内容代码 + /// + public string TrackCode { get; set; } = null!; + + /// + /// 轨迹内容 + /// + public string TrackContent { get; set; } = null!; + + /// + /// 轨迹发生地 + /// + public string TrackPlace { get; set; } = null!; + + /// + /// 轨迹发生时间 + /// + public DateTime TrackTime { get; set; } + + /// + /// 轨迹发生时区 + /// + public float TrackTimeZone { get; set; } + + /// + /// 是否成功 + /// + public bool IsSuccess { get; set; } + + /// + /// 推送内容(json) + /// + public string PushContent { get; set; } = null!; + + /// + /// 轨迹的额外新 + /// + public string? Extra { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Events/TrackPushEvent.cs b/src/SJZY.Track.Application.Contract/Events/TrackPushEvent.cs index b2724e3d..9be77fbc 100644 --- a/src/SJZY.Track.Application.Contract/Events/TrackPushEvent.cs +++ b/src/SJZY.Track.Application.Contract/Events/TrackPushEvent.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Application.Contract.Events; +namespace SJZY.Track.Application.Contract.Events; public class TrackPushEvent { @@ -12,6 +12,11 @@ public class TrackPushEvent /// public int SubSystemId { get; set; } + /// + /// 子系统代码 + /// + public string SubSystemCode { get; set; } + /// /// 客户id /// @@ -36,6 +41,16 @@ public class TrackPushEvent /// 系统推送信息 /// public SystemPushStruct SystemPushInfo { get; set; } + + /// + /// 是否强制推送 + /// + public bool ForcedPush { get; set; } + + /// + /// 是否发送到mq + /// + public bool IsToMq { get; set; } } public struct SystemPushStruct @@ -64,4 +79,14 @@ public struct SystemPushStruct /// 轨迹发生时区 /// public float TrackTimeZone { get; set; } -} \ No newline at end of file + + /// + /// 重复的情况下,用什么比较 + /// + public string? CompareFields { get; set; } + + /// + /// 扩展信息字段,用与轨迹推送的附加字段 + /// + public string? Extra { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Events/TrackRefreshStruct.cs b/src/SJZY.Track.Application.Contract/Events/TrackRefreshStruct.cs index 62bcf4a2..4e73f046 100644 --- a/src/SJZY.Track.Application.Contract/Events/TrackRefreshStruct.cs +++ b/src/SJZY.Track.Application.Contract/Events/TrackRefreshStruct.cs @@ -3,9 +3,9 @@ namespace SJZY.Track.Application.Contract.Events; public struct TrackRefreshStruct { /// - /// 服务商 + /// 服务商code /// - public string? ServiceProviderName { get; set; } + public string? ServiceProviderCode { get; set; } /// /// 原轨迹内容 @@ -13,13 +13,7 @@ public struct TrackRefreshStruct public string? OriginTrackContent { get; set; } /// - /// 原轨迹报文 + /// 原轨迹报文hash(刷新轨迹重复性校验使用) /// - public string? OriginTrackData { get; set; } - - /// - /// 表示订单是否完成(只由轨迹刷新配置决定) - /// tips:能够使得IsCompleted为true的点,全局只有一个:轨迹刷新 - /// - public bool IsCompleted { get; set; } -} \ No newline at end of file + public string? OriginTrackDataHash { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/Events/TrackUpsertEvent.cs b/src/SJZY.Track.Application.Contract/Events/TrackUpsertEvent.cs index 905060ea..182672cb 100644 --- a/src/SJZY.Track.Application.Contract/Events/TrackUpsertEvent.cs +++ b/src/SJZY.Track.Application.Contract/Events/TrackUpsertEvent.cs @@ -1,22 +1,39 @@ -namespace SJZY.Track.Application.Contract.Events; +using SJZY.Track.Application.Contract.Dtos.ProvideServices; + +namespace SJZY.Track.Application.Contract.Events; public class TrackUpsertEvent { /// - /// 子系统id(操作的订单都是相同子系统下的) + /// 子系统id /// public int SubSystemId { get; set; } + /// + /// 客户id + /// + public int CustomId { get; set; } + /// /// 订单id /// public OrderIdentifier[] OrderIdentifiers { get; set; } = null!; + /// + /// 轨迹唯一标识(用于单个订单更新单条轨迹,如果有的话优先级最高) + /// + public string? EsId { get; set; } + /// /// 操作人(null则默认系统) /// public string? OperationMan { get; set; } + /// + /// 操作人id + /// + public int OperationManId { get; set; } + /// /// true新增,false更新 /// @@ -37,6 +54,11 @@ public class TrackUpsertEvent /// public DateTime TrackTime { get; set; } + /// + /// 更改后的轨迹发生时间,无需更改保持为空 + /// + public DateTime? NewTrackTime { get; set; } + /// /// 轨迹发生时区 /// @@ -48,4 +70,112 @@ public class TrackUpsertEvent public List Visited { get; set; } = new(); public TrackRefreshStruct TrackRefreshData { get; set; } -} \ No newline at end of file + + /// + /// 客户是否可见 + /// + [Obsolete("废弃的,请使用IsExternal")] + public bool IsVisibility { get; set; } + + /// + /// 是否对外 + /// + public bool? IsExternal { get; set; } + + /// + /// 数据来源:1外部服务商创建,2内部系统创建,3人工创建 + /// + public int Source { get; set; } + + /// + /// 轨迹备注 + /// + public string? Remarks { get; set; } + + /// + /// 附件集合 + /// + public List? Files { get; set; } + + /// + /// 轨迹内容,若为空则取轨迹内容表中该轨迹Code对应的轨迹内容 + /// + public string? Content { get; set; } + + /// + /// 轨迹内容英文,若为空则取轨迹内容表中该轨迹Code对应的轨迹英文内容 + /// + public string? EnStatus { get; set; } + + /// + /// 轨迹发生地(城市) + /// + public string? TrackPlaceCity { get; set; } + + /// + /// 轨迹发生地(城市)Id + /// + public int? TrackPlaceCityId { get; set; } + + /// + /// 轨迹发生地(省/州) + /// + public string? TrackPlaceProvince { get; set; } + + /// + ///轨迹发生地(省/州)Id + /// + public int? TrackPlaceProvinceId { get; set; } + + /// + /// 轨迹发生地(国家/地区) + /// + public string? TrackPlaceNation { get; set; } + + /// + /// 轨迹发生地(国家/地区)Id + /// + public int? TrackPlaceNationId { get; set; } + + /// + /// 轨迹发生地邮编 + /// + public string? TrackPlacePostcode { get; set; } + + /// + /// 预计到达时间 + /// + public DateTime? EstimatedDeliveryDate { get; set; } + + /// + /// 目的地时区 + /// + public float? DestinationTimeZone { get; set; } + + /// + /// 重复的情况下,用什么比较 + /// + public string? CompareFields { get; set; } + + /// + /// 扩展信息字段,用与轨迹推送的附加字段 + /// + public string? Extra { get; set; } + + /// + /// 是否强制推送 + /// + public bool ForcedPush { get; set; } + + /// + /// 指定是否推送 + /// + public bool IsToMq { get; set; } + + public override string ToString() + { + return + $"[{(IsAdd ? "TrackInsert" : "TrackUpdate")} by {OperationMan}] SubSystemId: {SubSystemId}, OrderIds: {string.Join(",", + OrderIdentifiers.Select(x => x.OrderId))}, TrackCode: {TrackCode}, TrackPlace: {TrackPlace}, TrackTime: {TrackTime}"; + } +} diff --git a/src/SJZY.Track.Application.Contract/Events/TrackUpsertForRefreshEvent.cs b/src/SJZY.Track.Application.Contract/Events/TrackUpsertForRefreshEvent.cs deleted file mode 100644 index 7069903a..00000000 --- a/src/SJZY.Track.Application.Contract/Events/TrackUpsertForRefreshEvent.cs +++ /dev/null @@ -1,94 +0,0 @@ -namespace SJZY.Track.Application.Contract.Events; - -public class TrackUpsertForRefreshEvent -{ - /// - /// 子系统id(操作的订单都是相同子系统下的) - /// - public int SubSystemId { get; set; } - - /// - /// 订单 - /// - public OrderIdentifier OrderIdentifiers { get; set; } - - /// - /// 服务商 - /// - public string? ServiceProviderName { get; set; } - - /// - /// 原轨迹内容 - /// - public string? OriginTrackContent { get; set; } - - /// - /// 原轨迹报文 - /// - public string? OriginTrackData { get; set; } - - /// - /// 表示订单是否完成(只由轨迹刷新配置决定) - /// tips:能够使得IsCompleted为true的点,全局只有一个:轨迹刷新 - /// - public bool IsCompleted { get; set; } - - /// - /// 轨迹内容代码 - /// - public string TrackCode { get; set; } = null!; - - /// - /// 轨迹发生地 - /// - public string TrackPlace { get; set; } = null!; - - /// - /// 轨迹发生时间 - /// - public DateTime TrackTime { get; set; } - - /// - /// 轨迹发生时区 - /// - public float TrackTimeZone { get; set; } -} - -public class TrackHandledDto -{ - /// - /// 原轨迹内容 - /// - public string? OriginTrackContent { get; set; } - - /// - /// 原轨迹报文 - /// - public string? OriginTrackData { get; set; } - - /// - /// 表示订单是否完成(只由轨迹刷新配置决定) - /// tips:能够使得IsCompleted为true的点,全局只有一个:轨迹刷新 - /// - public bool? IsCompleted { get; set; } - - /// - /// 轨迹内容代码 - /// - public string? TrackCode { get; set; } - - /// - /// 轨迹发生地 - /// - public string? TrackPlace { get; set; } - - /// - /// 轨迹发生时间 - /// - public DateTime? TrackTime { get; set; } - - /// - /// 轨迹发生时区 - /// - public float? TrackTimeZone { get; set; } -} \ No newline at end of file diff --git a/src/SJZY.Track.Application.Contract/Events/TrackWarningCalcEvent.cs b/src/SJZY.Track.Application.Contract/Events/TrackWarningCalcEvent.cs new file mode 100644 index 00000000..f2031f12 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Events/TrackWarningCalcEvent.cs @@ -0,0 +1,29 @@ +namespace SJZY.Track.Application.Contract.Events; + +public class TrackWarningCalcEvent +{ + /// + /// 子系统id + /// + public int SubSystemId { get; set; } + + /// + /// 客户id + /// + public int CustomId { get; set; } + + /// + /// 轨迹状态Id + /// + public int TrackStatusId { get; set; } + + /// + /// 订单id + /// + public int[] OrderIds { get; set; } + + /// + /// 轨迹发生时间 + /// + public DateTime TrackTime { get; set; } +} diff --git a/src/SJZY.Track.Application.Contract/GlobalUsings.cs b/src/SJZY.Track.Application.Contract/GlobalUsings.cs index 99b0e5e1..5845e7a0 100644 --- a/src/SJZY.Track.Application.Contract/GlobalUsings.cs +++ b/src/SJZY.Track.Application.Contract/GlobalUsings.cs @@ -1,4 +1,4 @@ -// Global using directives +// Global using directives global using SJZY.Expand.ABP.Common.Enums; -global using SJZY.Expand.ABP.Core.Common.Dto; \ No newline at end of file +global using SJZY.Expand.ABP.Core.Common.Dto; diff --git a/src/SJZY.Track.Application.Contract/SJZY.Track.Application.Contract.csproj b/src/SJZY.Track.Application.Contract/SJZY.Track.Application.Contract.csproj index 7a7f7902..f0778d54 100644 --- a/src/SJZY.Track.Application.Contract/SJZY.Track.Application.Contract.csproj +++ b/src/SJZY.Track.Application.Contract/SJZY.Track.Application.Contract.csproj @@ -5,7 +5,7 @@ net7.0 True - 7.0.2 + 7.0.14 True diff --git a/src/SJZY.Track.Application.Contract/Services/IBroadcastingService.cs b/src/SJZY.Track.Application.Contract/Services/IBroadcastingService.cs new file mode 100644 index 00000000..238f015b --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Services/IBroadcastingService.cs @@ -0,0 +1,37 @@ +using SJZY.Track.Application.Contract.Dtos.TrackPush; +using SJZY.Track.Application.Contract.Events; +using Volo.Abp.DependencyInjection; + +namespace SJZY.Track.Application.Contract.Services; + +public interface IBroadcastingService : ITransientDependency +{ + /// + /// 轨迹变更广播(新增/修改) + /// + /// + /// + /// + /// + void TrackChangePublicTopic(TrackUpsertEvent eto,bool contentIsExternal, string subSystemCode, string trackStatusCode); + + /// + /// 轨迹变更广播(删除) + /// + /// + /// + /// + void TrackChangePublicTopic(TrackChangeEto eto, string subSystemCode); + + /// + /// 轨迹推送完成广播(推送完成回调) + /// + /// + void TrackPushCompletedPublicTopic(TrackPushRecordDto log); + + /// + /// 轨迹推送失败广播(推送前置被拦截,或调用接口通失败) + /// + /// + void TrackPushFailedPubilcTopic(TrackPushRecordDto log); +} diff --git a/src/SJZY.Track.Application.Contract/Services/IForewarningCacheService.cs b/src/SJZY.Track.Application.Contract/Services/IForewarningCacheService.cs new file mode 100644 index 00000000..4ed849d3 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Services/IForewarningCacheService.cs @@ -0,0 +1,35 @@ +using SJZY.Track.Application.Contract.Dtos.Forewarning; +using SJZY.Track.Application.Contract.Events; + +namespace SJZY.Track.Application.Contract.Services; + +public interface IForewarningCacheService +{ + /// + /// 获取预警规则,如果没有则返回null + /// + /// 子系统id + /// 客户id + /// + Task?> GetRulesAsync(int subSystemId, int customerId); + + /// + /// 重置本地缓存 + /// + /// + Task Clear(ClearRulCacheEvent @event); + + /// + /// 清除redis 缓存 + /// + /// + Task ClearRedisByAreaId(int areaId); + + /// + /// 清除redis 缓存 + /// + /// 子系统id + /// 客户id + /// + Task ClearRedisBySystemIdAndCustomer(int subSystemId, int customerId); +} diff --git a/src/SJZY.Track.Application.Contract/Services/IForewarningNotifyService.cs b/src/SJZY.Track.Application.Contract/Services/IForewarningNotifyService.cs new file mode 100644 index 00000000..07b792ac --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Services/IForewarningNotifyService.cs @@ -0,0 +1,22 @@ +using SJZY.Track.Application.Contract.Dtos.Forewarning; + +namespace SJZY.Track.Application.Contract.Services; + +/// +/// 预警通知服务接口定义。 +/// 提供创建、删除预警通知和发送通知的功能。 +/// +public interface IForewarningNotifyService +{ + /// + /// 创建预警通知。 + /// + /// 预警订单模型。 + /// 创建操作的结果,以整数形式返回。 + Task WarningCalculateAsync(WarningDto order); + + /// + /// 发送通知。 + /// + Task SendNotificationAsync(int subSystemId); +} diff --git a/src/SJZY.Track.Application.Contract/Services/IKpiAreaCacheService.cs b/src/SJZY.Track.Application.Contract/Services/IKpiAreaCacheService.cs new file mode 100644 index 00000000..4e15278f --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Services/IKpiAreaCacheService.cs @@ -0,0 +1,5 @@ +namespace SJZY.Track.Application.Contract.Services; + +public interface IKpiAreaCacheService +{ +} diff --git a/src/SJZY.Track.Application.Contract/Services/ITrackContentService.cs b/src/SJZY.Track.Application.Contract/Services/ITrackContentService.cs index 08ce5194..b24b807c 100644 --- a/src/SJZY.Track.Application.Contract/Services/ITrackContentService.cs +++ b/src/SJZY.Track.Application.Contract/Services/ITrackContentService.cs @@ -1,5 +1,5 @@ -namespace SJZY.Track.Application.Contract.Services; +namespace SJZY.Track.Application.Contract.Services; public interface ITrackContentService { -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application.Contract/Services/ITrackFlagService.cs b/src/SJZY.Track.Application.Contract/Services/ITrackFlagService.cs index a7d780b9..4527823d 100644 --- a/src/SJZY.Track.Application.Contract/Services/ITrackFlagService.cs +++ b/src/SJZY.Track.Application.Contract/Services/ITrackFlagService.cs @@ -1,5 +1,5 @@ -namespace SJZY.Track.Application.Contract.Services; +namespace SJZY.Track.Application.Contract.Services; public interface ITrackFlagService { -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application.Contract/Services/ITrackPullCacheService.cs b/src/SJZY.Track.Application.Contract/Services/ITrackPullCacheService.cs index e98a6be8..308cd8ff 100644 --- a/src/SJZY.Track.Application.Contract/Services/ITrackPullCacheService.cs +++ b/src/SJZY.Track.Application.Contract/Services/ITrackPullCacheService.cs @@ -1,34 +1,24 @@ -using SJZY.Track.Application.Contract.Dtos.TrackPull; +using SJZY.Track.Application.Contract.Dtos.TrackPull; namespace SJZY.Track.Application.Contract.Services; public interface ITrackPullCacheService { - string TrackPullKey(int subSystemId, int serviceProviderId); - string TrackPullContentKey(int subSystemId, int serviceProviderId); - - /// - /// 获取所有拉取配置 - /// - /// - Task> GetAllPullConfigsAsync(); + string TrackPullKey(int subSystemId, string serviceProviderCode); /// /// 获取服务商拉取配置 /// /// 子系统id - /// 服务商id + /// 服务商code /// - Task - GetPullParamWithContentConfigAsync(int subSystemId, int serviceProviderId); + Task + GetPullParamsWithContentAsync(int subSystemId, string serviceProviderCode); /// /// 设置拉取配置缓存 /// /// - /// 子系统id - /// 服务商id /// - Task SetPullConfigAsync(int? id = null, int? subSystemId = null, - int? serviceProviderId = null); -} \ No newline at end of file + Task SetPullConfigAsync(int id); +} diff --git a/src/SJZY.Track.Application.Contract/Services/ITrackPushCacheService.cs b/src/SJZY.Track.Application.Contract/Services/ITrackPushCacheService.cs index d243a7a0..a7fb056a 100644 --- a/src/SJZY.Track.Application.Contract/Services/ITrackPushCacheService.cs +++ b/src/SJZY.Track.Application.Contract/Services/ITrackPushCacheService.cs @@ -1,4 +1,4 @@ -using SJZY.Track.Application.Contract.Dtos.TrackPush; +using SJZY.Track.Application.Contract.Dtos.TrackPush; namespace SJZY.Track.Application.Contract.Services; @@ -19,4 +19,4 @@ public interface ITrackPushCacheService /// /// Task?> SetPushContentConfigsAsync(int subSystemId, int customId); -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application.Contract/Services/ITrackPushConfigService.cs b/src/SJZY.Track.Application.Contract/Services/ITrackPushConfigService.cs index e191f6bb..214ba4f1 100644 --- a/src/SJZY.Track.Application.Contract/Services/ITrackPushConfigService.cs +++ b/src/SJZY.Track.Application.Contract/Services/ITrackPushConfigService.cs @@ -1,20 +1,15 @@ -using SJZY.Track.Application.Contract.Dtos.ProvideServices; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using SJZY.Track.Application.Contract.Dtos.ProvideServices; using Volo.Abp; -namespace SJZY.Track.Application.Contract.Services +namespace SJZY.Track.Application.Contract.Services; + +public interface ITrackPushConfigService : IRemoteService { - public interface ITrackPushConfigService : IRemoteService - { - /// - /// 查询轨迹推送配置关系 - /// - /// - /// - Task QueryTrackPullMappingsAsync(QueryTrackPullMappingsInput input); - } + /// + /// 查询轨迹推送配置关系 + /// + /// + /// + Task>> QueryTrackPullMappingsAsync( + QueryTrackPullMappingsInput input); } diff --git a/src/SJZY.Track.Application.Contract/Services/ITrackService.cs b/src/SJZY.Track.Application.Contract/Services/ITrackService.cs deleted file mode 100644 index 904f834d..00000000 --- a/src/SJZY.Track.Application.Contract/Services/ITrackService.cs +++ /dev/null @@ -1,35 +0,0 @@ -using SJZY.Track.Application.Contract.Dtos.ProvideServices; -using Volo.Abp; - -namespace SJZY.Track.Application.Contract.Services; - -public interface ITrackService : IRemoteService -{ - /// - /// 新增/更新订单轨迹接口 - /// - /// - /// - Task UpsertTrackAsync(UpsertTrackInput input); - - /// - /// 删除轨迹 - /// - /// - /// - Task DeleteTrackAsync(DeleteTrackInput input); - - /// - /// 批量删除轨迹 - /// - /// - /// - Task BatchDeleteTrackAsync(BatchDeleteTrackInput input); - - /// - /// 根据订单号获取轨迹 - /// - /// - /// - Task QueryAsync(GetTrackInput input); -} \ No newline at end of file diff --git a/src/SJZY.Track.Application.Contract/Services/ITrackStatusService.cs b/src/SJZY.Track.Application.Contract/Services/ITrackStatusService.cs index b350cb93..fc85abb7 100644 --- a/src/SJZY.Track.Application.Contract/Services/ITrackStatusService.cs +++ b/src/SJZY.Track.Application.Contract/Services/ITrackStatusService.cs @@ -1,5 +1,5 @@ -namespace SJZY.Track.Application.Contract.Services; +namespace SJZY.Track.Application.Contract.Services; public interface ITrackStatusService { -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application.Contract/Services/IOrderService.cs b/src/SJZY.Track.Application.Contract/Services/ProvideServices/IOrderService.cs similarity index 50% rename from src/SJZY.Track.Application.Contract/Services/IOrderService.cs rename to src/SJZY.Track.Application.Contract/Services/ProvideServices/IOrderService.cs index adff3b24..8f469cde 100644 --- a/src/SJZY.Track.Application.Contract/Services/IOrderService.cs +++ b/src/SJZY.Track.Application.Contract/Services/ProvideServices/IOrderService.cs @@ -1,7 +1,7 @@ -using SJZY.Track.Application.Contract.Dtos.ProvideServices; +using SJZY.Track.Application.Contract.Dtos.ProvideServices; using Volo.Abp; -namespace SJZY.Track.Application.Contract.Services; +namespace SJZY.Track.Application.Contract.Services.ProvideServices; public interface IOrderService : IRemoteService { @@ -10,14 +10,14 @@ public interface IOrderService : IRemoteService /// /// /// - Task UpsertAsync(UpsertOrderInput input); + Task> UpsertAsync(UpsertOrderInput input); /// /// 删除订单 /// /// /// - Task DeleteOrderAsync(DeleteOrderInput input); + Task> DeleteOrderAsync(DeleteOrderInput input); /// /// 关联订单 @@ -25,4 +25,11 @@ public interface IOrderService : IRemoteService /// /// Task LinkOrderAsync(LinkOrderInput input); -} \ No newline at end of file + + /// + /// 修改服务商拉取信息 + /// + /// + /// + public Task UpdateOrderPullConfigsAsync(UpdateOrderPullConfigsInput input); +} diff --git a/src/SJZY.Track.Application.Contract/Services/ProvideServices/ITrackPullService.cs b/src/SJZY.Track.Application.Contract/Services/ProvideServices/ITrackPullService.cs new file mode 100644 index 00000000..744f195f --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Services/ProvideServices/ITrackPullService.cs @@ -0,0 +1,14 @@ +using SJZY.Track.Application.Contract.Dtos.ProvideServices; +using Volo.Abp; + +namespace SJZY.Track.Application.Contract.Services.ProvideServices; + +public interface ITrackPullService : IRemoteService +{ + /// + /// 刷新轨迹 + /// + /// + /// + public Task RefreshTrackAsync(RefreshTrackInput input); +} diff --git a/src/SJZY.Track.Application.Contract/Services/ProvideServices/ITrackPushService.cs b/src/SJZY.Track.Application.Contract/Services/ProvideServices/ITrackPushService.cs new file mode 100644 index 00000000..b7029aa6 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Services/ProvideServices/ITrackPushService.cs @@ -0,0 +1,31 @@ +using SJZY.Track.Application.Contract.Dtos.ProvideServices; +using SJZY.Track.Application.Contract.Dtos.TrackOrder; +using SJZY.Track.Application.Contract.Dtos.TrackPush; +using Volo.Abp; + +namespace SJZY.Track.Application.Contract.Services.ProvideServices; + +public interface ITrackPushService : IRemoteService +{ + /// + /// 推送轨迹 + /// + /// + /// + public Task PushTrackAsync(PushTrackInput input); + + /// + /// 获取轨迹推送内容 + /// + /// + /// 子系统id + /// 客户id + public Task>> GetTrackPushContentListAsync(int subSystemId, int customerId); + + /// + /// 获取轨迹推送记录 + /// + /// + /// + public Task>> GetTrackPushRecordsAsync(OrderNoInfo input); +} diff --git a/src/SJZY.Track.Application.Contract/Services/ProvideServices/ITrackService.cs b/src/SJZY.Track.Application.Contract/Services/ProvideServices/ITrackService.cs new file mode 100644 index 00000000..0921c05d --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Services/ProvideServices/ITrackService.cs @@ -0,0 +1,51 @@ +using SJZY.Track.Application.Contract.Dtos.ProvideServices; +using Volo.Abp; + +namespace SJZY.Track.Application.Contract.Services.ProvideServices; + +public interface ITrackService : IRemoteService +{ + /// + /// 新增/更新订单轨迹接口 + /// + /// + /// + Task UpsertTrackAsync(UpsertTrackInput input); + + /// + /// 批量新增/更新订单轨迹接口 + /// + /// + /// + Task BatchUpsertTrackAsync(BatchUpsertTrackInput input); + + /// + /// 删除轨迹 + /// + /// + /// + Task DeleteTrackAsync(DeleteTrackInput input); + + /// + /// 批量删除轨迹 + /// + /// + /// + Task BatchDeleteTrackAsync(BatchDeleteTrackInput input); + + /// + /// 根据订单号获取轨迹 + /// 支持模板,传入时区补正,按轨迹发生时间升序降序 + /// + /// + /// + Task>> QueryAsync(GetTrackInput input); + + /// + /// 根据订单号获取轨迹 + /// 不支持模板,无时区补正,可按轨迹发生时间升序降序 + /// + /// + /// + Task>> QueryV2Async(GetTrackInputV2 input); +} diff --git a/src/SJZY.Track.Application.Contract/Services/ProvideServices/ITrackTemplateService.cs b/src/SJZY.Track.Application.Contract/Services/ProvideServices/ITrackTemplateService.cs new file mode 100644 index 00000000..d6e10e87 --- /dev/null +++ b/src/SJZY.Track.Application.Contract/Services/ProvideServices/ITrackTemplateService.cs @@ -0,0 +1,7 @@ +using Volo.Abp; + +namespace SJZY.Track.Application.Contract.Services.ProvideServices; + +public interface ITrackTemplateService : IRemoteService +{ +} diff --git a/src/SJZY.Track.Application.Contract/SjzyTrackApplicationContractModule.cs b/src/SJZY.Track.Application.Contract/SjzyTrackApplicationContractModule.cs index 0da04423..9a69109c 100644 --- a/src/SJZY.Track.Application.Contract/SjzyTrackApplicationContractModule.cs +++ b/src/SJZY.Track.Application.Contract/SjzyTrackApplicationContractModule.cs @@ -1,4 +1,4 @@ -using Volo.Abp.Modularity; +using Volo.Abp.Modularity; namespace SJZY.Track.Application.Contract; @@ -7,4 +7,4 @@ public class SjzyTrackApplicationContractModule : AbpModule public override void PreConfigureServices(ServiceConfigurationContext context) { } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/AutoMapper/ForewarningMapperProfile.cs b/src/SJZY.Track.Application/AutoMapper/ForewarningMapperProfile.cs new file mode 100644 index 00000000..2ac133b5 --- /dev/null +++ b/src/SJZY.Track.Application/AutoMapper/ForewarningMapperProfile.cs @@ -0,0 +1,39 @@ +using AutoMapper; +using SJZY.Track.Application.Contract.Dtos.Forewarning; +using SJZY.Track.Domain.Aggregates.ForewarningAggregate; +using SJZY.Track.Domain.Aggregates.KPIAreaAggregate; +using SJZY.Track.Domain.Dtos.Forewarning; +using Volo.Abp.AutoMapper; + +namespace SJZY.Track.Application.AutoMapper; + +public class ForewarningMapperProfile : Profile +{ + public ForewarningMapperProfile() + { + CreateMap(MemberList.None) + .Ignore(x => x.WarningFactors); + CreateMap(MemberList.None); + CreateMap(MemberList.None); + CreateMap(MemberList.None) + .ForMember(dest => dest.CountryCode, opt => opt.MapFrom(src => src.CountryCode)) + .ForMember(dest => dest.CountryName, opt => opt.MapFrom(src => src.CountryName)) + .ForMember(dest => dest.Province, opt => opt.MapFrom(src => src.Province)) + .ForMember(dest => dest.City, opt => opt.MapFrom(src => src.City)) + .ForMember(dest => dest.LeftPostcode, opt => opt.MapFrom(src => src.LeftPostCode)) + .ForMember(dest => dest.RightPostcode, opt => opt.MapFrom(src => src.RightPostCode)) + .ForMember(dest => dest.AreaId, opt => opt.MapFrom(src => src.AreaId)); + + CreateMap(MemberList.None) + .ForMember(dest => dest.SubSystemId, opt => opt.MapFrom(src => src.SystemId)) + .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Name)); + + CreateMap(MemberList.None) + .ForMember(dest => dest.CountryCode, opt => opt.MapFrom(src => src.CountryCode)) + .ForMember(dest => dest.CountryName, opt => opt.MapFrom(src => src.CountryName)) + .ForMember(dest => dest.Province, opt => opt.MapFrom(src => src.Province)) + .ForMember(dest => dest.City, opt => opt.MapFrom(src => src.City)) + .ForMember(dest => dest.LeftPostcode, opt => opt.MapFrom(src => src.LeftPostCode)) + .ForMember(dest => dest.RightPostcode, opt => opt.MapFrom(src => src.RightPostCode)); + } +} diff --git a/src/SJZY.Track.Application/AutoMapper/OrderAutoMapperProfile.cs b/src/SJZY.Track.Application/AutoMapper/OrderAutoMapperProfile.cs index dbe6b8f6..0ec4b79a 100644 --- a/src/SJZY.Track.Application/AutoMapper/OrderAutoMapperProfile.cs +++ b/src/SJZY.Track.Application/AutoMapper/OrderAutoMapperProfile.cs @@ -1,4 +1,4 @@ -using AutoMapper; +using AutoMapper; using SJZY.Expand.ABP.Core.PublicMethords; using SJZY.Track.Application.Contract.Dtos.ProvideServices; using SJZY.Track.Application.Contract.Dtos.TrackOrder; @@ -18,17 +18,10 @@ public class OrderAutoMapperProfile : Profile CreateMap(MemberList.None); CreateMap(MemberList.None); - CreateMap(MemberList.None) - .ForMember(dest => dest.ServiceProviderId, opt => opt.MapFrom(m => m.ServiceProviderId ?? 0)) - .ForMember(dest => dest.TrackTemplateId, opt => opt.MapFrom(m => m.TemplateId)); CreateMap(MemberList.None); CreateMap(MemberList.None); - CreateMap(MemberList.None) - .ForMember(dest => dest.OrderTypeName, - opt => opt.MapFrom(source => GetEnumDescription(2, source.OrderType))) - .ForMember(dest => dest.QuestionTypeName, - opt => opt.MapFrom(source => GetEnumDescription(1, source.QuestionType))); + CreateMap(MemberList.None); CreateMap, UnifyPageResultDto>(MemberList.None); CreateMap(MemberList.None).Ignore(dest => dest.TrackTimeZone) @@ -36,6 +29,7 @@ public class OrderAutoMapperProfile : Profile .ForMember(dest => dest.Content, opt => opt.MapFrom(m => m.TrackContent)) .ForMember(dest => dest.EnContent, opt => opt.MapFrom(m => m.TrackEnContent)) .ForMember(dest => dest.TrackTimeZoneValue, opt => opt.MapFrom(m => m.TrackTimeZone)); + CreateMap(MemberList.None); CreateMap(MemberList.None); } @@ -51,7 +45,7 @@ public class OrderAutoMapperProfile : Profile string enumDescription = string.Empty; if (type == 1) { - TrackProblemType trackProblem = (TrackProblemType)value; // 将int值转换为枚举 + TrackProblemType trackProblem = (TrackProblemType) value; // 将int值转换为枚举 if (trackProblem.GetDescription().IsNullOrWhiteSpace()) enumDescription = ""; else @@ -59,7 +53,7 @@ public class OrderAutoMapperProfile : Profile } else { - OrderType orderType = (OrderType)value; // 将int值转换为枚举 + OrderType orderType = (OrderType) value; // 将int值转换为枚举 if (orderType.GetDescription().IsNullOrWhiteSpace()) enumDescription = ""; else @@ -68,4 +62,4 @@ public class OrderAutoMapperProfile : Profile return enumDescription; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/AutoMapper/TrackAutoMapperProfile.cs b/src/SJZY.Track.Application/AutoMapper/TrackAutoMapperProfile.cs index b9c185d7..cac245bd 100644 --- a/src/SJZY.Track.Application/AutoMapper/TrackAutoMapperProfile.cs +++ b/src/SJZY.Track.Application/AutoMapper/TrackAutoMapperProfile.cs @@ -1,13 +1,13 @@ -using AutoMapper; +using AutoMapper; using SJZY.Track.Application.Contract.Dtos.ProvideServices; using SJZY.Track.Application.Contract.Events; namespace SJZY.Track.Application.AutoMapper; -public class TrackAutoMapperProfile:Profile +public class TrackAutoMapperProfile : Profile { public TrackAutoMapperProfile() { CreateMap(MemberList.None); } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/AutoMapper/TrackContentAutoMapperProfile.cs b/src/SJZY.Track.Application/AutoMapper/TrackContentAutoMapperProfile.cs index bf20809b..a161314e 100644 --- a/src/SJZY.Track.Application/AutoMapper/TrackContentAutoMapperProfile.cs +++ b/src/SJZY.Track.Application/AutoMapper/TrackContentAutoMapperProfile.cs @@ -1,21 +1,25 @@ -using AutoMapper; +using AutoMapper; using SJZY.Track.Application.Contract.Dtos.TrackContents; using SJZY.Track.Domain.Aggregates.TrackContentAggregate; +using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; using SJZY.Track.Domain.Dtos.TrackContents; -namespace SJZY.Track.Application.AutoMapper +namespace SJZY.Track.Application.AutoMapper; + +public class TrackContentAutoMapperProfile : Profile { - public class TrackContentAutoMapperProfile : Profile + public TrackContentAutoMapperProfile() { - public TrackContentAutoMapperProfile() - { - CreateMap(MemberList.None); - CreateMap(MemberList.None); - CreateMap(MemberList.None); - CreateMap(MemberList.None); - CreateMap, UnifyPageResultDto>( - MemberList.None); - CreateMap(MemberList.None); - } + CreateMap(MemberList.None); + CreateMap(MemberList.None); + CreateMap(MemberList.None); + CreateMap(MemberList.None); + CreateMap, UnifyPageResultDto>( + MemberList.None); + CreateMap(MemberList.None); + + CreateMap(MemberList.None).ReverseMap(); + CreateMap< SJZY.Track.Domain.Aggregates.TrackDetailsAggregate.FileItem, SJZY.Track.Application.Contract.Dtos.TrackContents.FileItem>(MemberList.None).ReverseMap(); + } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/AutoMapper/TrackFlagAutoMapperProfile.cs b/src/SJZY.Track.Application/AutoMapper/TrackFlagAutoMapperProfile.cs index bf72f035..be324306 100644 --- a/src/SJZY.Track.Application/AutoMapper/TrackFlagAutoMapperProfile.cs +++ b/src/SJZY.Track.Application/AutoMapper/TrackFlagAutoMapperProfile.cs @@ -1,21 +1,20 @@ -using AutoMapper; +using AutoMapper; using SJZY.Track.Application.Contract.Dtos.TrackFlags; using SJZY.Track.Domain.Aggregates.TrackFlagAggregate; using SJZY.Track.Domain.Dtos.TrackFlags; -namespace SJZY.Track.Application.AutoMapper +namespace SJZY.Track.Application.AutoMapper; + +public class TrackFlagAutoMapperProfile : Profile { - public class TrackFlagAutoMapperProfile : Profile + public TrackFlagAutoMapperProfile() { - public TrackFlagAutoMapperProfile() - { - CreateMap(MemberList.None) - .ForMember(dest => dest.Name, opt => opt.MapFrom(source => source.Flag)); - //.ForMember(dest => dest.IsCompleted, opt => opt.MapFrom(source => source.IsFinish)); - CreateMap(MemberList.None); - CreateMap(MemberList.None); - CreateMap, UnifyPageResultDto>(MemberList.None); - CreateMap(MemberList.None); - } + CreateMap(MemberList.None) + .ForMember(dest => dest.Name, opt => opt.MapFrom(source => source.Flag)); + //.ForMember(dest => dest.IsCompleted, opt => opt.MapFrom(source => source.IsFinish)); + CreateMap(MemberList.None); + CreateMap(MemberList.None); + CreateMap, UnifyPageResultDto>(MemberList.None); + CreateMap(MemberList.None); } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/AutoMapper/TrackNodeMapperProfile.cs b/src/SJZY.Track.Application/AutoMapper/TrackNodeMapperProfile.cs new file mode 100644 index 00000000..5de329ac --- /dev/null +++ b/src/SJZY.Track.Application/AutoMapper/TrackNodeMapperProfile.cs @@ -0,0 +1,19 @@ +using AutoMapper; +using SJZY.Track.Application.Contract.Dtos.TrackNode; +using SJZY.Track.Application.Contract.Dtos.TrackStatus; +using SJZY.Track.Domain.Aggregates.TrackNodeAggregate; +using SJZY.Track.Domain.Dtos.TrackNode; + +namespace SJZY.Track.Application.AutoMapper; + +public class TrackNodeMapperProfile : Profile +{ + public TrackNodeMapperProfile() + { + CreateMap(); + CreateMap(MemberList.None) + .ForMember(val => val.NodeName, opt => opt.MapFrom(src => src.NodeName)) + .ForMember(val => val.NodeEnName, opt => opt.MapFrom(src => src.NodeEnName)) + .ForMember(val => val.SubSystemId, opt => opt.MapFrom(src => src.SubSystemId)); + } +} diff --git a/src/SJZY.Track.Application/AutoMapper/TrackPullAutoMapperProfile.cs b/src/SJZY.Track.Application/AutoMapper/TrackPullAutoMapperProfile.cs index c2409eea..ad6f1aff 100644 --- a/src/SJZY.Track.Application/AutoMapper/TrackPullAutoMapperProfile.cs +++ b/src/SJZY.Track.Application/AutoMapper/TrackPullAutoMapperProfile.cs @@ -1,8 +1,9 @@ -using AutoMapper; +using AutoMapper; +using SJZY.Track.Application.Contract.Dtos.ProvideServices; using SJZY.Track.Application.Contract.Dtos.TrackPull; using SJZY.Track.Domain.Aggregates.TrackPullAggregate; +using SJZY.Track.Domain.Dtos.Order; using SJZY.Track.Domain.Dtos.TrackPull; -using Volo.Abp.AutoMapper; namespace SJZY.Track.Application.AutoMapper; @@ -11,12 +12,18 @@ public class TrackPullAutoMapperProfile : Profile public TrackPullAutoMapperProfile() { CreateMap(MemberList.None); - CreateMap(MemberList.None).Ignore(dest => dest.Id) - .ForMember(dest => dest.IsPush, opt => opt.MapFrom(source => false)); CreateMap(MemberList.None) - .ForMember(dest => dest.TrackKeyword, opt => opt.MapFrom(src => string.Join(',', src.TrackKeywords))) - .ForMember(dest => dest.TrackKeywordReverse, opt => opt.MapFrom(src => string.Join(',', src.TrackKeywordReverses))); + .ForMember(dest => dest.TrackStatusValue, + opt => opt.MapFrom(src => string.Join(',', src.TrackStatusValues ?? Enumerable.Empty()))) + .ForMember(dest => dest.TrackKeyword, + opt => opt.MapFrom(src => string.Join(',', src.TrackKeywords ?? Enumerable.Empty()))) + .ForMember(dest => dest.TrackKeywordReverse, + opt => opt.MapFrom(src => string.Join(',', src.TrackKeywordReverses ?? Enumerable.Empty()))) + .ForMember(dest => dest.TrackZonePlaceValue, opt => opt.MapFrom(src => src.TrackTimePlaceValue)); CreateMap(MemberList.None); + CreateMap(MemberList.None); + + CreateMap(MemberList.None); } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/AutoMapper/TrackPushAutoMapperProfile.cs b/src/SJZY.Track.Application/AutoMapper/TrackPushAutoMapperProfile.cs index 213d7872..fe654d77 100644 --- a/src/SJZY.Track.Application/AutoMapper/TrackPushAutoMapperProfile.cs +++ b/src/SJZY.Track.Application/AutoMapper/TrackPushAutoMapperProfile.cs @@ -1,9 +1,7 @@ -using AutoMapper; +using AutoMapper; using SJZY.Track.Application.Contract.Dtos.TrackPush; -using SJZY.Track.Domain.Aggregates.TrackPullAggregate; using SJZY.Track.Domain.Aggregates.TrackPushAggregate; using SJZY.Track.Domain.Dtos.TrackPush; -using Volo.Abp.AutoMapper; namespace SJZY.Track.Application.AutoMapper; @@ -11,10 +9,12 @@ public class TrackPushAutoMapperProfile : Profile { public TrackPushAutoMapperProfile() { - CreateMap(MemberList.None); - CreateMap(MemberList.None).Ignore(dest => dest.Id) - .ForMember(dest => dest.IsPush, opt => opt.MapFrom(source => true)); + CreateMap(MemberList.None) + .ForMember(val => val.DateTimeFormatType, opt => opt.MapFrom(src => src.DateTimeFormatType)) + .ForMember(val => val.DateTimeFormat, opt => opt.MapFrom(src => src.DateTimeFormat)) + .ForMember(val => val.TimezoneFormat, opt => opt.MapFrom(src => src.TimezoneFormat)); + CreateMap(MemberList.None); CreateMap(MemberList.None); } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/AutoMapper/TrackPushConfigAutoMapperProfile.cs b/src/SJZY.Track.Application/AutoMapper/TrackPushConfigAutoMapperProfile.cs index 7cb8ccd2..f6141b70 100644 --- a/src/SJZY.Track.Application/AutoMapper/TrackPushConfigAutoMapperProfile.cs +++ b/src/SJZY.Track.Application/AutoMapper/TrackPushConfigAutoMapperProfile.cs @@ -1,22 +1,17 @@ using AutoMapper; using SJZY.Track.Application.Contract.Dtos.ProvideServices; using SJZY.Track.Application.Contract.Dtos.TrackPush; -using SJZY.Track.Domain.Aggregates.TrackPushAggregate; using SJZY.Track.Domain.Dtos.TrackPush; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SJZY.Track.Application.AutoMapper +namespace SJZY.Track.Application.AutoMapper; + +public class TrackPushConfigAutoMapperProfile : Profile { - public class TrackPushConfigAutoMapperProfile : Profile + public TrackPushConfigAutoMapperProfile() { - public TrackPushConfigAutoMapperProfile() - { - CreateMap(MemberList.None); - CreateMap(MemberList.None); - } + CreateMap(MemberList.None); + CreateMap(MemberList.None); + + CreateMap(MemberList.None); } } diff --git a/src/SJZY.Track.Application/AutoMapper/TrackStatusAutoMapperProfile.cs b/src/SJZY.Track.Application/AutoMapper/TrackStatusAutoMapperProfile.cs index 49796f47..f8bb4d05 100644 --- a/src/SJZY.Track.Application/AutoMapper/TrackStatusAutoMapperProfile.cs +++ b/src/SJZY.Track.Application/AutoMapper/TrackStatusAutoMapperProfile.cs @@ -1,24 +1,23 @@ -using AutoMapper; +using AutoMapper; using SJZY.Track.Application.Contract.Dtos.TrackStatus; using SJZY.Track.Domain.Aggregates.TrackStatusAggregate; using SJZY.Track.Domain.Dtos.TrackStatus; -namespace SJZY.Track.Application.AutoMapper +namespace SJZY.Track.Application.AutoMapper; + +public class TrackStatusAutoMapperProfile : Profile { - public class TrackStatusAutoMapperProfile : Profile + public TrackStatusAutoMapperProfile() { - public TrackStatusAutoMapperProfile() - { - CreateMap(MemberList.None) - //层级不一致的场景 - .ForMember(dest => dest.Status, opt => opt.MapFrom(source => source.TrackStatus)) - .ForMember(dest => dest.EnStatus, opt => opt.MapFrom(source => source.EntrackStatus)) - .ForMember(dest => dest.Node, opt => opt.MapFrom(source => source.NodeId)); - CreateMap(MemberList.None); - CreateMap(MemberList.None); - CreateMap(MemberList.None); - CreateMap, UnifyPageResultDto>(MemberList - .None); - } + CreateMap(MemberList.None) + //层级不一致的场景 + .ForMember(dest => dest.Status, opt => opt.MapFrom(source => source.TrackStatus)) + .ForMember(dest => dest.EnStatus, opt => opt.MapFrom(source => source.EnTrackStatus)) + .ForMember(dest => dest.Node, opt => opt.MapFrom(source => source.NodeId)); + CreateMap(MemberList.None); + CreateMap(MemberList.None); + CreateMap(MemberList.None); + CreateMap, UnifyPageResultDto>(MemberList + .None); } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/AutoMapper/TrackTemplateAutoMapperProfile.cs b/src/SJZY.Track.Application/AutoMapper/TrackTemplateAutoMapperProfile.cs index 36f0e498..f6e6b53b 100644 --- a/src/SJZY.Track.Application/AutoMapper/TrackTemplateAutoMapperProfile.cs +++ b/src/SJZY.Track.Application/AutoMapper/TrackTemplateAutoMapperProfile.cs @@ -1,4 +1,5 @@ using AutoMapper; +using SJZY.Track.Application.Contract.Dtos.ProvideServices; using SJZY.Track.Application.Contract.Dtos.TrackTemplates; using SJZY.Track.Domain.Aggregates.TrackTemplateAggregate; using SJZY.Track.Domain.Dtos.TrackTemplate; @@ -19,5 +20,11 @@ public class TrackTemplateAutoMapperProfile : Profile CreateMap(MemberList.None); CreateMap, UnifyPageResultDto>(MemberList .None); + CreateMap(MemberList.None); + CreateMap, UnifyPageResultDto>(MemberList.None); + + CreateMap(MemberList.None); + CreateMap(MemberList.None); + CreateMap(MemberList.None); } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/CAP/CAPFilter.cs b/src/SJZY.Track.Application/CAP/CAPFilter.cs index 036c1e34..0decb640 100644 --- a/src/SJZY.Track.Application/CAP/CAPFilter.cs +++ b/src/SJZY.Track.Application/CAP/CAPFilter.cs @@ -1,17 +1,13 @@ -using System.Security.Cryptography; -using System.Text; using DotNetCore.CAP.Filter; using SJZY.Expand.ABP.Core; using SJZY.Expand.ABP.Core.Logger; using SJZY.Expand.ABP.Core.PublicMethords; -using SJZY.Track.Domain.Consts; +using SJZY.Track.Application.Helpers; namespace SJZY.Track.Application.CAP; public class CapFilter : SubscribeFilter { - const string ErrorCode = "Error599"; - /// /// 执行前 /// @@ -21,11 +17,7 @@ public class CapFilter : SubscribeFilter { // 轨迹新增、更新要做幂等 if (!context.DeliverMessage.Headers["cap-msg-name"] - .IsIn(GlobalConst.TrackUpsertSubscribe, GlobalConst.TrackManualPushSubscribe)) - { - return; - } - + .IsIn(GlobalConst.TrackUpsertSubscribe, GlobalConst.TrackManualPushSubscribe)) return; var argumentJsonStr = context.Arguments.ToJson(); if (!string.IsNullOrEmpty(argumentJsonStr)) @@ -33,13 +25,13 @@ public class CapFilter : SubscribeFilter context.DeliverMessage.Headers.TryGetValue("sjzy-arguments-hash", out var hash); if (hash.IsNullOrEmpty()) // 计算参数hash { - hash = GetHash(argumentJsonStr); + hash = StringHelper.GetHash(argumentJsonStr); context.DeliverMessage.Headers["sjzy-arguments-hash"] = hash; } - if (await RedisHelper.Client.ExistsAsync($"CapExecuteFilter:{hash}")) + if (await RedisHelper.Client.ExistsAsync($"CapExecuteFilter:{hash}{DateTime.Now:G}")) { - throw new BusinessException(ErrorCode, $"检测到重复消费,消费参数:{argumentJsonStr}"); + throw new BusinessException(GlobalConst.CapNoRetryErrorCode, $"检测到重复消费,消费参数:{argumentJsonStr}"); } } } @@ -49,7 +41,7 @@ public class CapFilter : SubscribeFilter context.DeliverMessage.Headers.TryGetValue("sjzy-arguments-hash", out var hash); if (!hash.IsNullOrEmpty()) { - await RedisHelper.Client.SetAsync($"CapExecuteFilter:{hash}", 1, TimeSpan.FromMinutes(10).Seconds); + await RedisHelper.Client.SetAsync($"CapExecuteFilter:{hash}{DateTime.Now:G}", 1, TimeSpan.FromMinutes(3)); } } @@ -62,10 +54,10 @@ public class CapFilter : SubscribeFilter { context.DeliverMessage.Headers.TryGetValue("cap-msg-id", out var messageId); - if (context.Exception is BusinessException ex && ex.Code == ErrorCode) + if (context.Exception is BusinessException ex && ex.Code == GlobalConst.CapNoRetryErrorCode) { - context.ExceptionHandled = true; // 幂等不做重试 - LogHelper.Warn(ex.ToString()); + context.ExceptionHandled = true; + LogHelper.Warn(ex.ToString(), true); } else { @@ -76,22 +68,4 @@ public class CapFilter : SubscribeFilter return Task.CompletedTask; } - - - /// 获取字符串的hash值 - /// - /// - public static string GetHash(string str) - { - // 将字符串转换为字节 - byte[] data = Encoding.UTF8.GetBytes(str); - - // 创建SHA256实例 - using SHA256 sha256 = SHA256.Create(); - // 计算哈希值 - byte[] hash = sha256.ComputeHash(data); - - // 将哈希值转换为16进制字符串 - return BitConverter.ToString(hash); - } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs index c8f184ae..e3a98037 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackChangeAfterUpdateOrderEventHandler.cs @@ -1,8 +1,7 @@ -using DotNetCore.CAP; +using DotNetCore.CAP; +using SJZY.Expand.ABP.Core.Logger; using SJZY.Track.Application.Contract.Events; using SJZY.Track.Domain.Aggregates.OrderAggregate; -using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; -using SJZY.Track.Domain.Consts; using Volo.Abp.DependencyInjection; namespace SJZY.Track.Application.CAP.EventHandlers; @@ -10,31 +9,22 @@ namespace SJZY.Track.Application.CAP.EventHandlers; public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICapSubscribe { private readonly IOrderRepository _orderRepository; - private readonly ITrackDetailsRepository _trackDetailsRepository; - public TrackChangeAfterUpdateOrderEventHandler(IOrderRepository orderRepository, - ITrackDetailsRepository trackDetailsRepository) + public TrackChangeAfterUpdateOrderEventHandler(IOrderRepository orderRepository) { _orderRepository = orderRepository; - _trackDetailsRepository = trackDetailsRepository; } [CapSubscribe(GlobalConst.TrackChangeAfterUpdateOrderSubscribe)] public async Task ConsumerAsync(TrackChangeAfterUpdateOrderEvent @event) { - var orders = await _orderRepository.GetListAsync(x => @event.OrderIds.Contains(x.Id), - x => new OrderEntity - { - Id = x.Id, - IsCompleted = x.IsCompleted, - LatestTrackContent = x.LatestTrackContent, - LatestTrackEnContent = x.LatestTrackEnContent, - LatestTrackPlace = x.LatestTrackPlace, - LatestTrackTime = x.LatestTrackTime, - LatestTrackTimeZone = x.LatestTrackTimeZone, - }); + var orders = await GetOrdersAsync(@event.OrderIds); - if (orders.Count == 0) return; + if (orders.Count == 0) + { + LogHelper.Warn($"没有找到订单信息:{@event.OrderIds.JoinAsString(",")},无法更新轨迹信息"); + return; + } var updateOrders = new List(); foreach (var order in orders) @@ -49,6 +39,12 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa } } + // 执行轨迹兜底时 时区缺失和发生地缺失标记,1表示时区,2表示发生地,3表示两种 + if (@event.DeficiencyTagValue is > 0 and <= 3) + { + order.DeficiencyTag = @event.DeficiencyTagValue; + } + if (!order.IsCompleted) { order.IsCompleted = @event.IsCompleted; @@ -59,13 +55,46 @@ public class TrackChangeAfterUpdateOrderEventHandler : ITransientDependency, ICa order.LatestTrackPlace = @event.TrackPlace; order.LatestTrackTime = @event.TrackTime; order.LatestTrackTimeZone = @event.TrackTimeZone; + //当【预计签收时间】【签收地时区】同时存在时则更新主表 + if (@event.EstimatedDeliveryDate.HasValue && @event.DestinationTimeZone.HasValue) + { + order.EstimatedDeliveryDate = @event.EstimatedDeliveryDate.Value; + order.DestinationTimeZone = @event.DestinationTimeZone.Value; + } + updateOrders.Add(order); } await _orderRepository.UpdateRangeAsync(updateOrders, x => new + { + x.IsCompleted, + x.LatestTrackContent, + x.LatestTrackEnContent, + x.LatestTrackPlace, + x.LatestTrackTime, + x.LatestTrackTimeZone, + x.DeficiencyTag, + x.EstimatedDeliveryDate, + x.DestinationTimeZone + } + ); + } + + private async Task> GetOrdersAsync(int[] orderIds) + { + return await _orderRepository.GetListAsync(order => orderIds.Contains(order.Id), order => new OrderEntity { - x.IsCompleted, x.LatestTrackContent, x.LatestTrackEnContent, x.LatestTrackPlace, x.LatestTrackTime, - x.LatestTrackTimeZone + Id = order.Id, + + // 轨迹 + IsCompleted = order.IsCompleted, + LatestTrackContent = order.LatestTrackContent, + LatestTrackEnContent = order.LatestTrackEnContent, + LatestTrackPlace = order.LatestTrackPlace, + LatestTrackTime = order.LatestTrackTime, + LatestTrackTimeZone = order.LatestTrackTimeZone, + DestinationTimeZone = order.DestinationTimeZone, + EstimatedDeliveryDate = order.EstimatedDeliveryDate, }); } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackDeleteEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackDeleteEventHandler.cs index ae24d7e3..5ce98e81 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackDeleteEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackDeleteEventHandler.cs @@ -1,10 +1,15 @@ -using DotNetCore.CAP; +using System.Collections.Immutable; +using System.Text.Json; +using DotNetCore.CAP; using SJZY.Expand.ABP.Core.Logger; using SJZY.Expand.ABP.Core.PublicMethords; +using SJZY.Track.Application.Contract.Dtos.ProvideServices; using SJZY.Track.Application.Contract.Events; +using SJZY.Track.Application.Contract.Services; +using SJZY.Track.Application.Helpers; using SJZY.Track.Domain.Aggregates.OrderAggregate; using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; -using SJZY.Track.Domain.Consts; +using SJZY.Track.Domain.Enums; using SJZY.Track.Domain.Queries; using Volo.Abp.DependencyInjection; @@ -12,33 +17,44 @@ namespace SJZY.Track.Application.CAP.EventHandlers; public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe { + private readonly ICapPublisher _capPublisher; + private readonly IOrderOperationRecordEsRepository _orderOperationRecordEsRepository; private readonly IOrderRepository _orderRepository; private readonly IProvideQueries _provideQueries; - private readonly ICapPublisher _capPublisher; - private readonly ITrackDetailsRepository _trackDetailsRepository; + private readonly ITrackDetailsEsRepository _trackDetailsEsRepository; + private readonly IBroadcastingService _broadcastingService; public TrackDeleteEventHandler(IProvideQueries provideQueries, - IOrderRepository orderRepository, ICapPublisher capPublisher, ITrackDetailsRepository trackDetailsRepository) + IOrderRepository orderRepository, ICapPublisher capPublisher, + ITrackDetailsEsRepository trackDetailsEsRepository, + IOrderOperationRecordEsRepository orderOperationRecordEsRepository, + IBroadcastingService broadcastingService) { _provideQueries = provideQueries; _orderRepository = orderRepository; _capPublisher = capPublisher; - _trackDetailsRepository = trackDetailsRepository; + _trackDetailsEsRepository = trackDetailsEsRepository; + _orderOperationRecordEsRepository = orderOperationRecordEsRepository; + _broadcastingService = broadcastingService; } [CapSubscribe(GlobalConst.TrackDeleteSubscribe, Group = GlobalConst.TrackDeleteSubscribe)] public async Task ConsumerAsync(TrackDeleteEvent @event) { - var dup = @event.Visited.Intersect(@event.OrderIds).ToArray(); - if (dup.Any()) - { - LogHelper.Error($"删除轨迹时,发现循环依赖:{dup.JoinAsString(",")}"); - return; - } + if (!CanDelete(@event)) return; - await DeleteTrackAsync(@event); + var trackList = await DeleteTrackAsync(@event); + + //当轨迹删除,根据轨迹标记/状态上IsToMq选择进行广播 + if (trackList.Count != 0) + _ = PublicTrackTopicAsync(@event, trackList); // 根据订单关联关系异步向下刷(异步) + await DownByOrderLink(@event); + } + + private async Task DownByOrderLink(TrackDeleteEvent @event) + { var linkedOrders = await _orderRepository.GetLinkedOrdersAsync(@event.OrderIds); foreach (var orderId in @event.OrderIds) { @@ -47,22 +63,29 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe { var nextEvent = @event.DeepCopy(); nextEvent.Visited.AddRange(@event.OrderIds); - nextEvent.TrackCodes = @event.TrackCodes; + nextEvent.TrackIdentifiers = @event.TrackIdentifiers; nextEvent.SubSystemId = group.Key; // 不同子系统需要做内容映射 if (@event.SubSystemId != nextEvent.SubSystemId) { - var mapCodes = await _provideQueries - .MapTrackCodesAsync(@event.SubSystemId, nextEvent.SubSystemId, @event.TrackCodes.ToArray()); + var codeMaps = await _provideQueries + .GetTrackCodeMapsAsync(@event.SubSystemId, nextEvent.SubSystemId, + @event.TrackIdentifiers.Select(x => x.TrackCode).ToArray()); - if (mapCodes.Count == 0) + if (codeMaps.Count == 0) { - //throw new BusinessException(message: "订单跨子系统,未配置内容映射,请联系管理员"); + LogHelper.Warn($"订单跨子系统,未配置内容映射,请联系管理员:{@event}", true); continue; } - nextEvent.TrackCodes = mapCodes; + //映射轨迹code + foreach (var trackIdentity in nextEvent.TrackIdentifiers) + { + var match = codeMaps.FirstOrDefault(x => x.MapTrackContentCode == trackIdentity.TrackCode); + if (match == null) continue; + trackIdentity.TrackCode = match.TrackContentCode; + } } var identifiers = group.Select(x => x.OrderId).ToList(); @@ -82,14 +105,110 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe } } - private async Task DeleteTrackAsync(TrackDeleteEvent @event) + private bool CanDelete(TrackDeleteEvent @event) { - // 删除轨迹(删的是同子系统下的单,所以code是统一的) - var tracks = await _trackDetailsRepository.GetLatestListAsync(@event.OrderIds, @event.TrackCodes); + if (@event.OrderIds == null) + return true; - await _trackDetailsRepository.DeleteTrackAsync(@event.OrderIds, @event.TrackCodes); + // 订单循环关联检测 + var dup = @event.Visited.Intersect(@event.OrderIds).ToArray(); + if (dup.Any()) + { + LogHelper.Warn($"删除轨迹时,发现循环依赖:{dup.JoinAsString(",")}", true); + return false; + } - var orders = await _orderRepository.GetListAsync(x => @event.OrderIds.Contains(x.Id), + return true; + } + + private async Task> DeleteTrackAsync(TrackDeleteEvent @event) + { + List orderIds; + List tracks; + List deleteTracks; + if (@event.EsIds != null && @event.EsIds.Any()) //根据明确的esid进行删除 + { + deleteTracks = await _trackDetailsEsRepository.GetDataByIds(@event.EsIds); + orderIds = deleteTracks.Select(m => m.OrderId).Distinct().ToList(); + @event.OrderIds = orderIds.ToArray(); + @event.TrackIdentifiers = deleteTracks.Select(x => new TrackIdentifierDto + { + TrackCode = x.TrackCode, + TrackTime = x.TrackTime + }).ToList(); + + // 外部api获取的轨迹不允许删除 + if (deleteTracks.Any(m => m.Source == TrackSourceEnum.ExternalServiceProvide.GetHashCode())) + return deleteTracks; + + //查出订单下的所有轨迹,以供后面回退使用 + tracks = await _trackDetailsEsRepository.GetListAsync(@event.OrderIds); + + // 删除轨迹 + foreach (var item in deleteTracks) + { + await _trackDetailsEsRepository.DeleteTrackByIdAsync(item.Id, item.IndexName); + } + + //清理已经删除过的esid + @event.EsIds = Array.Empty(); + } + else //原有逻辑,根据轨迹code和订单进行删除 + { + //根据订单查询出所有的轨迹,查所有是因为主单上需要进行回退更新 + tracks = await _trackDetailsEsRepository.GetListAsync(@event.OrderIds); + + //比较字段为空则使用时间来作为额外的标识key + if (string.IsNullOrWhiteSpace(@event.CompareFields)) + { + //构建标识符集合 + var ids = @event.TrackIdentifiers.Select(x => $"{x.TrackCode}{x.TrackTime:G}").ToHashSet(); + //根据标识符选出要删除的轨迹明细 + deleteTracks = tracks.Where(x => ids.Contains($"{x.TrackCode}{x.TrackTime:G}")).ToList(); + } + //否则则使用比较字段,使用扩展字段中的内容进行比较 + else + { + var codes = @event.TrackIdentifiers.Select(x => x.TrackCode).ToImmutableHashSet(); + deleteTracks = tracks + .Where(x => + { + if (!codes.Contains(x.TrackCode)) + return false; + + if (string.IsNullOrWhiteSpace(x.Extra)) + { + throw new BusinessException(message: $"当前轨迹不存在扩展信息,无法利用扩展字段:{@event.CompareFields}"); + } + + var extraDict = TextJsonHelper.DeserializeToDictionary(x.Extra); + if (extraDict == null || !extraDict.TryGetValue(@event.CompareFields, out var compareValue)) + { + throw new BusinessException(message: $"请检查拓展字段,为什么找不到比较字段:{@event.CompareFields}"); + } + + return TextJsonHelper.EqJsonElement(compareValue, @event.CompareValue); + }) + .ToList(); + } + + + if (deleteTracks.Count == 0) return deleteTracks; + + foreach (var track in deleteTracks) + { + await _trackDetailsEsRepository.DeleteTrackByIdAsync(track.Id, track.IndexName); + } + + //从被删除轨迹寻找订单id,稍后会更新订单主表 + orderIds = deleteTracks.Select(m => m.OrderId).Distinct().ToList(); + } + + //排除掉已经删除的轨迹 + var deleteTrackIds = deleteTracks.Select(m => m.Id).ToList(); + tracks = tracks.Where(x => !deleteTrackIds.Contains(x.Id)).ToList(); + + var orders = await _orderRepository.GetListAsync(x => orderIds.Contains(x.Id), x => new OrderEntity { Id = x.Id, @@ -98,13 +217,16 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe LatestTrackPlace = x.LatestTrackPlace, LatestTrackTime = x.LatestTrackTime, LatestTrackTimeZone = x.LatestTrackTimeZone, + EstimatedDeliveryDate = x.EstimatedDeliveryDate, + DestinationTimeZone = x.DestinationTimeZone }); - - if (orders.Count == 0) return; + if (orders.Count == 0) return tracks; foreach (var order in orders) { - var track = tracks.FirstOrDefault(x => x.OrderId == order.Id); + //找到最新的轨迹数据 + var track = tracks?.OrderByDescending(x => x.TrackTime) + .FirstOrDefault(x => x.OrderId == order.Id); // 删除全部轨迹导致的重置行为 if (track == default) @@ -123,13 +245,123 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe order.LatestTrackPlace = track.TrackPlace; order.LatestTrackTime = track.TrackTime; order.LatestTrackTimeZone = track.TrackTimeZone; + order.EstimatedDeliveryDate = track.EstimatedDeliveryDate; + order.DestinationTimeZone = track.DestinationTimeZone; } } - await _orderRepository.UpdateRangeAsync(orders, x => new + //更新订单上冗余轨迹明细的字段 + await _orderRepository.UpdateRangeAsync(orders, + x => new + { + x.LatestTrackContent, + x.LatestTrackEnContent, + x.LatestTrackPlace, + x.LatestTrackTime, + x.LatestTrackTimeZone, + x.EstimatedDeliveryDate, + x.DestinationTimeZone + }); + + //批量写入订单操作日志 + _ = _orderOperationRecordEsRepository.AddManyAsync(orders.Select(order => new OrderOperationRecordIndex { - x.LatestTrackContent, x.LatestTrackEnContent, x.LatestTrackPlace, x.LatestTrackTime, - x.LatestTrackTimeZone - }); + OrderId = order.Id, + OrderNo = order.OrderNo, + OptionType = OrderOperationType.删除轨迹.ToString(), + Content = deleteTracks.Where(m => m.OrderId == order.Id).ToList().ToJson(), + CreateUserId = @event.OperationManId, + CreateUserName = @event.OperationMan ?? "", + CreateTime = DateTime.Now + }).ToList()); + + return deleteTracks; } -} \ No newline at end of file + + private async Task PublicTrackTopicAsync(TrackDeleteEvent @event, List trackList) + { + var systemIds = trackList.Select(x => x.SubSystemId).Distinct().ToArray(); + var trackCodes = trackList.Select(x => x.TrackCode).Distinct().ToArray(); + + //从轨迹内容中查询出标记是否需要mq广播 + var contentList = await _provideQueries.GetTrackContentsAsync(systemIds, trackCodes); + var toMqDict = contentList + .ToDictionary(x => x.SubSystemId + x.TrackContentCode, y => y.IsToMq); + + //选出需要广播的轨迹,并按code和订单号分组 + var trackGroup = trackList + .Where(x => toMqDict[x.SubSystemId + x.TrackCode]) + .GroupBy(m => new + { + m.TrackCode, + m.OrderNo + }) + .ToList(); + if (trackGroup.Count == 0) return; + + //增加延时确保写盘成功 + await Task.Delay(1000); + foreach (var dataItem in trackGroup) + { + var item = dataItem.First(); + var content = contentList.First(m => m.TrackContentCode == item.TrackCode); + + // _broadcastingService.TrackChangePublicTopic(track, + // dataItem.Select(m => new OrderIdentifier + // { + // OrderId = m.OrderId, + // OrderNo = m.OrderNo, + // OrderType = m.OrderType + // }).ToArray(), + // item.TrackCode, + // item.TrackStatusCode, + // content.SubSystemCode + // ); + + //将每个订单的每个轨迹的删除变更发布 + foreach (var track in dataItem) + { + _broadcastingService.TrackChangePublicTopic(new TrackChangeEto + { + EstimatedDeliveryDate = track.EstimatedDeliveryDate, + TrackPlacePostcode = track.TrackPlacePostcode, + TrackPlaceNation = track.TrackPlaceNation, + TrackPlaceNationId = track.TrackPlaceNationId, + TrackPlaceProvince = track.TrackPlaceProvince, + TrackPlaceProvinceId = track.TrackPlaceProvinceId, + TrackPlaceCity = track.TrackPlaceCity, + TrackPlaceCityId = track.TrackPlaceCityId, + Files = track.Files?.Select(x => new FileItemDto() + { + FileName = x.FileName, + OssKey = x.OssKey + }).ToList(), + Remarks = track.Remarks, + Source = track.Source, + IsVisibility = track.IsVisibility, + IsExternal = track.IsExternal, + TrackTimeZone = track.TrackTimeZone, + TrackTime = track.TrackTime, + TrackPlace = track.TrackPlace, + TrackStatusCode = track.TrackStatusCode, + EnStatus = track.TrackEnContent, + Content = track.TrackContent, + TrackCode = track.TrackCode, + OperationMan = @event.OperationMan, + OrderNo = track.OrderNo, + OrderIdentifiers = new[] + { + new OrderIdentifier() + { + OrderId = track.OrderId, + OrderNo = track.OrderNo, + OrderType = track.OrderType + } + }, + SubSystemId = @event.SubSystemId, + Extra = track.Extra + }, content.SubSystemCode); + } + } + } +} diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackInsertForNotMappedEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackInsertForNotMappedEventHandler.cs deleted file mode 100644 index b2f59331..00000000 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackInsertForNotMappedEventHandler.cs +++ /dev/null @@ -1,50 +0,0 @@ -using DotNetCore.CAP; -using SJZY.Track.Application.Contract.Events; -using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; -using SJZY.Track.Domain.Consts; -using Volo.Abp.DependencyInjection; - -namespace SJZY.Track.Application.CAP.EventHandlers; - -public class TrackInsertForNotMappedEventHandler : ITransientDependency, ICapSubscribe -{ - private readonly ITrackDetailsRepository _trackDetailsRepository; - - public TrackInsertForNotMappedEventHandler(ITrackDetailsRepository trackDetailsRepository) - { - _trackDetailsRepository = trackDetailsRepository; - } - - [CapSubscribe(GlobalConst.TrackInsertForNotMappedEventSubscribe)] - public async Task ConsumerAsync(TrackInsertForNotMappedEvent @event) - { - if (await _trackDetailsRepository.AnyAsync(@event.OrderId, @event.TrackTime)) - { - return; - } - - // 新增服务商轨迹到es - var track = new TrackDetailsIndex - { - IndexName = $"{GlobalConst.TrackIndex}-{DateTime.Now:yyyy.MM.dd}", - OrderId = @event.OrderId, - OrderNo = @event.OrderNo, - OrderType = @event.OrderType, - TrackPlace = @event.TrackPlace, - TrackTime = @event.TrackTime, - TrackTimeZone = @event.TrackTimeZone, - ServiceProviderName = @event.ServiceProviderName, - OriginTrackContent = @event.OriginTrackContent, - OriginTrackData = @event.OriginTrackData, - CreateUser = GlobalConst.SystemUser, - CreateTime = DateTime.Now - }; - track.TrackCode = GlobalConst.EmptyString; - track.TrackStatus = GlobalConst.EmptyString; - track.TrackContent = GlobalConst.EmptyString; - track.TrackEnContent = GlobalConst.EmptyString; - track.ZeroTrackTime = track.TrackTime.Subtract(TimeSpan.FromHours(track.TrackTimeZone)); - - await _trackDetailsRepository.AddAsync(track); - } -} \ No newline at end of file diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushCompletedEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushCompletedEventHandler.cs deleted file mode 100644 index 4658aa44..00000000 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushCompletedEventHandler.cs +++ /dev/null @@ -1,101 +0,0 @@ -using DotNetCore.CAP; -using Newtonsoft.Json; -using SJZY.InterfaceRelay.Application.Contracts; -using SJZY.Track.Application.Contract.Dtos.TrackPush; -using SJZY.Track.Application.Helpers; -using SJZY.Track.Domain.Aggregates.OrderAggregate; -using SJZY.Track.Domain.Aggregates.TrackPushAggregate; -using SJZY.Track.Domain.Consts; -using SJZY.Track.Domain.Enums; -using Volo.Abp.DependencyInjection; - -namespace SJZY.Track.Application.CAP.EventHandlers; - -public class TrackPushCompletedEventHandler : ITransientDependency, ICapSubscribe -{ - private readonly ITrackPushRecordsRepository _trackPushRecordsRepository; - private readonly IOrderRepository _orderRepository; - - public TrackPushCompletedEventHandler(ITrackPushRecordsRepository trackPushRecordsRepository, - IOrderRepository orderRepository) - { - _trackPushRecordsRepository = trackPushRecordsRepository; - _orderRepository = orderRepository; - } - - [CapSubscribe(GlobalConst.TrackPushCompletedSubscribe, Group = GlobalConst.TrackPushSubscribe)] - public async Task ConsumerAsync(InterfaceRelayForwardReplayEvent @event) - { - string logStr = null; - var optionType = Base64Helper.DeSerialize(@event.Attach); - if (optionType == OptionType.新增.ToString()) - { - logStr = JsonConvert.DeserializeObject(@event.RequestParams)!.Log; - } - else if (optionType == OptionType.修改.ToString()) - { - logStr = JsonConvert.DeserializeObject(@event.RequestParams)!.Log; - } - - if (logStr.IsNullOrEmpty()) throw new InvalidOperationException(); - var log = JsonConvert.DeserializeObject(logStr!); - - if (log == null) throw new BusinessException(message: "轨迹推送返回结果解析异常"); - log.IsSuccess = @event.IsSuccess; - log.Message = @event.Message; - log.RequestId = @event.RequestId; - - // 往es 写推送日志 - await _trackPushRecordsRepository.AddAsync(log); - - // if (!log.IsSuccess) - // { - // // 重试过程中不会去更新订单主表 - // if (@event.RetryNum < 3) - // { - // @event.RetryNum++; - // await _capPublisher.PublishAsync(GlobalConst.TrackPushSubscribe, @event); - // return; - // } - // } - - // 同步去更新订单主表 - await TrackPushAfterUpdateOrderAsync(log); - } - - private async Task TrackPushAfterUpdateOrderAsync(TrackPushRecordIndex log) - { - // tips:只有新增会影响推送进度? - if (log.OptionType != OptionType.新增.ToString()) return; - - var order = new OrderEntity - { - Id = log.OrderId - }; - - /* - * 异常:最近一条推送是失败 - */ - if (!log.IsSuccess) - { - order.QuestionType = (int)TrackProblemType.Error; - order.LatestPushError = log.Message; - await _orderRepository.UpdateColumnAsync(order, x => new - { - x.QuestionType, x.LatestPushError - }); - } - else - { - // 还原成正常态 - order.QuestionType = (int)TrackProblemType.None; - order.LatestPushError = null; - order.LatestPushTrackCode = log.TrackCode; - order.LatestPushTime = log.CreateTime; - await _orderRepository.UpdateColumnAsync(order, x => new - { - x.LatestPushTrackCode, x.LatestPushTime, x.QuestionType, x.LatestPushError - }); - } - } -} \ No newline at end of file diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs index 734246eb..cd792aa6 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs @@ -1,4 +1,7 @@ -using DotNetCore.CAP; +using System.Collections.Immutable; +using System.Text.Json; +using DotNetCore.CAP; +using Microsoft.Extensions.Options; using Newtonsoft.Json; using SJZY.Expand.ABP.Core.PublicMethords; using SJZY.InterfaceRelay.Application.Contracts; @@ -6,10 +9,11 @@ using SJZY.Track.Application.Contract.Dtos.TrackPush; using SJZY.Track.Application.Contract.Events; using SJZY.Track.Application.Contract.Services; using SJZY.Track.Application.Helpers; +using SJZY.Track.Application.Options; +using SJZY.Track.Application.Track2InterfaceRelay; using SJZY.Track.Domain.Aggregates.OrderAggregate; using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; using SJZY.Track.Domain.Aggregates.TrackPushAggregate; -using SJZY.Track.Domain.Consts; using SJZY.Track.Domain.Enums; using Volo.Abp.DependencyInjection; using Volo.Abp.Http.Client.DynamicProxying; @@ -19,22 +23,30 @@ namespace SJZY.Track.Application.CAP.EventHandlers; public class TrackPushEventHandler : ITransientDependency, ICapSubscribe { private readonly IHttpClientProxy _httpClientProxy; + private readonly IOptionsMonitor _options; private readonly IOrderRepository _orderRepository; private readonly ITrackPushCacheService _trackPushCacheService; - private readonly ITrackDetailsRepository _trackDetailsRepository; - private readonly ITrackPushRecordsRepository _trackPushRecordsRepository; - private List _pushConfigs; - private List _orders; + private readonly ITrackPushRecordEsRepository _trackPushRecordEsRepository; + private readonly ITrackDetailsEsRepository _trackDetailsEsRepository; + private readonly IBroadcastingService _broadcastingService; + private List _orders = null!; + private List _pushConfigs = null!; public TrackPushEventHandler(IHttpClientProxy httpClientProxy, - IOrderRepository orderRepository, ITrackPushCacheService trackPushCacheService, - ITrackDetailsRepository trackDetailsRepository, ITrackPushRecordsRepository trackPushRecordsRepository) + IOrderRepository orderRepository, + ITrackPushCacheService trackPushCacheService, + ITrackPushRecordEsRepository trackPushRecordEsRepository, + IOptionsMonitor options, + IBroadcastingService broadcastingService, + ITrackDetailsEsRepository trackDetailsEsRepository) { _httpClientProxy = httpClientProxy; _orderRepository = orderRepository; _trackPushCacheService = trackPushCacheService; - _trackDetailsRepository = trackDetailsRepository; - _trackPushRecordsRepository = trackPushRecordsRepository; + _trackPushRecordEsRepository = trackPushRecordEsRepository; + _options = options; + _broadcastingService = broadcastingService; + _trackDetailsEsRepository = trackDetailsEsRepository; } [CapSubscribe(GlobalConst.TrackPushSubscribe, Group = GlobalConst.TrackPushSubscribe)] @@ -43,17 +55,32 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe { var pushConfigs = await _trackPushCacheService.GetPushContentConfigsAsync(@event.SubSystemId, @event.CustomId); if (pushConfigs == null || pushConfigs.Count == 0) return; + if (pushConfigs.First().ServiceProviderCode.IsNullOrWhiteSpace()) + { + throw new BusinessException(GlobalConst.CapNoRetryErrorCode, $"该客户{@event.CustomId}未关联服务商,无法推送"); + } + _pushConfigs = pushConfigs; var orders = await _orderRepository.GetListAsync(x => - @event.OrderIds.Contains(x.Id), x => new OrderEntity - { - Id = x.Id, OrderNo = x.OrderNo, LatestPushTrackCode = x.LatestPushTrackCode, - OrderType = x.OrderType - }); + @event.OrderIds.Contains(x.Id), + x => new OrderEntity + { + Id = x.Id, + OrderNo = x.OrderNo, + LatestPushTrackCode = x.LatestPushTrackCode, + OrderType = x.OrderType + }); if (orders.Count == 0) return; _orders = orders; + if (@event.ForcedPush) + { + //当为强制推送,会走手动推送逻辑 + await DoPushAsync(@event); + return; + } + switch (@event.OptionType) { case OptionType.无: @@ -74,100 +101,142 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe private async Task DoPushAsync(TrackPushEvent @event) { var items = new List(); - TrackPushContentConfigDto? config; - if (@event.OperationMan == null) { - foreach (var order in _orders) + if (@event.OptionType == OptionType.新增) { - if (order.QuestionType == (int)TrackProblemType.Error) continue; // 系统不推异常单,只能人工操作 - // 推送新增,需要根据上一次的推送 推断 本次推送 是否可行 - config = GetValidPushConfigAsync(_pushConfigs, order.LatestPushTrackCode, @event.TrackCode); - if (config == null) continue; - if (!config.IsAutoPush) continue; - if (config.OrderType != order.OrderType) continue; - - var log = new TrackPushRecordIndex - { - OptionType = @event.OptionType.ToString(), - OrderId = order.Id, - OrderNo = order.OrderNo, - TrackStatus = @event.SystemPushInfo.TrackStatus, - TrackCode = @event.TrackCode, - TrackContent = @event.SystemPushInfo.TrackContent, - TrackPlace = @event.SystemPushInfo.TrackPlace, - TrackTime = @event.SystemPushInfo.TrackTime, - TrackTimeZone = @event.SystemPushInfo.TrackTimeZone, - CreateUser = GlobalConst.SystemUser, - }; - var item = await BuiltPushItem(config, log); - item.Log = JsonConvert.SerializeObject(log); - items.Add(item); + await BuiltSystemPushItemsAsync(@event, items); + } + else if (@event.OptionType == OptionType.修改) + { + await BuiltManualPushItemsAsync(@event, items); } } - else //手工推送 + else { - config = _pushConfigs.FirstOrDefault(x => x.TrackCode == @event.TrackCode); - if (config == null) return; - - var tracks = await _trackDetailsRepository.GetListAsync(@event.OrderIds, @event.TrackCode); - tracks = tracks.DistinctBy(x => x.OrderId).ToList(); // 防止重复推送 - - if (tracks.Count == 0) return; // 一个能推的轨迹都不存在 - - // tips:人工推送只要能推就推了,不会校验已推和顺序问题,因为可能是更新 - foreach (var track in tracks) - { - var order = _orders.First(x => x.Id == track.OrderId); - if (config is { IsAllPush: true }) - { - // 推断 本次推送 是否可行 - config = GetValidPushConfigAsync(_pushConfigs, order.LatestPushTrackCode, @event.TrackCode); - } - - if (config == null) continue; - - var log = new TrackPushRecordIndex - { - OptionType = @event.OptionType.ToString(), - OrderId = track.OrderId, - OrderNo = order.OrderNo, - TrackStatus = track.TrackStatus, - TrackCode = @event.TrackCode, - TrackContent = track.TrackContent, - TrackPlace = track.TrackPlace, - TrackTime = track.TrackTime, - TrackTimeZone = track.TrackTimeZone, - CreateUser = @event.OperationMan, - }; - var item = await BuiltPushItem(config, log); - item.Log = JsonConvert.SerializeObject(log); - items.Add(item); - } + // 手工推送,不会校验已推和顺序问题,因为可能是更新 + await BuiltManualPushItemsAsync(@event, items); } if (items.Count == 0) return; - string asciiString = Base64Helper.SerializeObject(OptionType.新增.ToString()); - var r = await _httpClientProxy.Service.BatchForwardThenPushToQueueAsync( - InterfaceRelayConst.PushTrackInterfaceCode, - _pushConfigs.First().ServiceProviderCode, items, GlobalConst.TrackPushCompletedSubscribe, - attach: asciiString); - - if (r.Code != InterfaceRelayConst.SuccessCode) + using (Track2InterfaceRelaySubSystemContext.Use( + new Track2InterfaceRelaySubSystemContext(@event.SubSystemCode))) { - throw new BusinessException(message: $"requestId: {r.RequestId}; {r.Msg}"); + var asciiString = Base64Helper.SerializeObject(OptionType.新增.ToString()); + var serviceProviderCode = _pushConfigs.First().ServiceProviderCode; + var r = await _httpClientProxy.Service.BatchForwardThenPushToQueueAsync( + _options.CurrentValue.PushTrackInterfaceCode, + serviceProviderCode, items.Cast().ToList(), GlobalConst.TrackPushCompletedSubscribe, + attach: asciiString); + + if (r.Code != GlobalConst.SuccessCode) + { + TrackPushFailedPublicTopic($"轨迹中台调用接口通失败,RequestId: {r.RequestId}; Msg: {r.Msg}", @event, r.RequestId, + items.Cast().ToList()); + throw new BusinessException( + message: $"requestId: {r.RequestId}; serviceProviderCode:{serviceProviderCode} Msg: {r.Msg}"); + } } } - private async Task DoUpdateAsync(TrackPushEvent @event) + private async Task BuiltManualPushItemsAsync(TrackPushEvent @event, List items) { + // tips: 手工强制推送直接使用配置 var config = _pushConfigs.FirstOrDefault(x => x.TrackCode == @event.TrackCode); - if (config == null || !config.IsCanUpdate) return; - - var items = new List(); foreach (var order in _orders) { + if (config is { IsAllPush: true }) + { + // 非强制推送需要 推断 本次推送 是否可行 + if (!@event.ForcedPush) + { + config = GetValidPushConfigAsync(_pushConfigs, order.LatestPushTrackCode, @event); + } + } + + if (config == null) + { + TrackPushFailedPublicTopic("推送顺序异常,找不到有效推送配置", @event, order); + return; + } + + + //配置的类型如何和订单类型不一致则不允许推送 + if (config.OrderType != order.OrderType) + { + TrackPushFailedPublicTopic($"订单类型{order.OrderType}和配置中的订单类型[{config.OrderType}]不一致,不能推送", @event, + order); + continue; + } + + var log = new TrackPushRecordIndex + { + OptionType = @event.OptionType.ToString(), + OrderId = order.Id, + OrderNo = order.OrderNo, + TrackStatus = @event.SystemPushInfo.TrackStatus, + TrackCode = @event.TrackCode, + TrackContent = @event.SystemPushInfo.TrackContent, + TrackPlace = @event.SystemPushInfo.TrackPlace, + TrackTime = @event.SystemPushInfo.TrackTime, + TrackTimeZone = @event.SystemPushInfo.TrackTimeZone, + CreateUser = @event.OperationMan, + SubSystemCode = @event.SubSystemCode, + IsToMq = @event.IsToMq, + Extra = @event.SystemPushInfo.Extra + }; + var item = await BuiltPushItem(config, log, @event.SystemPushInfo.CompareFields); + item.Log = JsonConvert.SerializeObject(log); + items.Add(item); + } + } + + private async Task BuiltSystemPushItemsAsync(TrackPushEvent @event, List items) + { + var config = _pushConfigs.FirstOrDefault(x => x.TrackCode == @event.TrackCode); + foreach (var order in _orders) + { + if (config == null) + { + TrackPushFailedPublicTopic($"没有在推送映射配置中找到关于轨迹代码[{@event.TrackCode}]的配置", @event, order); + return; + } + + // 系统不推异常单,只能人工操作 + if (order.QuestionType == (int) TrackProblemType.Error) + { + TrackPushFailedPublicTopic("系统不推异常单,只能人工操作", @event, order); + continue; + } + + // 推送新增,需要根据上一次的推送 推断 本次推送 是否可行,为了约束顺序 + // 如果当前推送code与订单上的最后的code不一致,则考虑推送映射顺序 + if (!string.Equals(order.LatestPushTrackCode, @event.TrackCode)) + { + config = GetValidPushConfigAsync(_pushConfigs, order.LatestPushTrackCode, @event); + if (config == null) + { + TrackPushFailedPublicTopic("推送顺序异常,找不到有效推送配置", @event, order); + continue; + } + } + + // 是否自动推送 + if (!config.IsAutoPush) + { + TrackPushFailedPublicTopic("没有设置为自动推送,如果要推送请手动推送", @event, order); + continue; + } + + // 配置的类型如何和订单类型不一致则不允许推送 + if (config.OrderType != order.OrderType) + { + TrackPushFailedPublicTopic($"订单类型{order.OrderType}和配置中的订单类型[{config.OrderType}]不一致,不能推送", @event, + order); + continue; + } + var log = new TrackPushRecordIndex { OptionType = @event.OptionType.ToString(), @@ -180,6 +249,47 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe TrackTime = @event.SystemPushInfo.TrackTime, TrackTimeZone = @event.SystemPushInfo.TrackTimeZone, CreateUser = GlobalConst.SystemUser, + SubSystemCode = @event.SubSystemCode, + IsToMq = @event.IsToMq, + Extra = @event.SystemPushInfo.Extra + }; + var item = await BuiltPushItem(config, log, @event.SystemPushInfo.CompareFields); + item.Log = JsonConvert.SerializeObject(log); + items.Add(item); + } + } + + private async Task DoUpdateAsync(TrackPushEvent @event) + { + var config = _pushConfigs.FirstOrDefault(x => x.TrackCode == @event.TrackCode); + if (config == null || !config.IsCanUpdate) return; + + var items = new List(); + foreach (var order in _orders) + { + //配置的类型如何和订单类型不一致则不允许推送 + if (config.OrderType != order.OrderType) + { + TrackPushFailedPublicTopic($"订单类型{order.OrderType}和配置中的订单类型[{config.OrderType}]不一致,不能推送", @event, + order); + continue; + } + + var log = new TrackPushRecordIndex + { + OptionType = @event.OptionType.ToString(), + OrderId = order.Id, + OrderNo = order.OrderNo, + TrackStatus = @event.SystemPushInfo.TrackStatus, + TrackCode = @event.TrackCode, + TrackContent = @event.SystemPushInfo.TrackContent, + TrackPlace = @event.SystemPushInfo.TrackPlace, + TrackTime = @event.SystemPushInfo.TrackTime, + TrackTimeZone = @event.SystemPushInfo.TrackTimeZone, + CreateUser = GlobalConst.SystemUser, + SubSystemCode = @event.SubSystemCode, + IsToMq = @event.IsToMq, + Extra = @event.SystemPushInfo.Extra }; var item = BuiltUpdateItem(config, log); item.Log = JsonConvert.SerializeObject(log); @@ -188,77 +298,145 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe if (items.Count == 0) return; - string asciiString = Base64Helper.SerializeObject(OptionType.修改.ToString()); - var r = await _httpClientProxy.Service.BatchForwardThenPushToQueueAsync( - InterfaceRelayConst.TrackUpdateInterfaceCode, - _pushConfigs.First().ServiceProviderCode, items, GlobalConst.TrackPushCompletedSubscribe, - attach: asciiString); - - if (r.Code != InterfaceRelayConst.SuccessCode) + using (Track2InterfaceRelaySubSystemContext.Use( + new Track2InterfaceRelaySubSystemContext(@event.SubSystemCode))) { - throw new BusinessException(message: $"requestId: {r.RequestId}; {r.Msg}"); + var asciiString = Base64Helper.SerializeObject(OptionType.修改.ToString()); + var serviceProviderCode = _pushConfigs.First().ServiceProviderCode; + var r = await _httpClientProxy.Service.BatchForwardThenPushToQueueAsync( + _options.CurrentValue.TrackUpdateInterfaceCode, + serviceProviderCode, items.Cast().ToList(), GlobalConst.TrackPushCompletedSubscribe, + attach: asciiString); + + if (r.Code != GlobalConst.SuccessCode) + { + TrackPushFailedPublicTopic($"轨迹中台调用接口通失败,RequestId: {r.RequestId}; Msg: {r.Msg}", @event, r.RequestId, + items.Cast().ToList()); + throw new BusinessException( + message: $"requestId: {r.RequestId}; serviceProviderCode:{serviceProviderCode} Msg: {r.Msg}"); + } } } private TrackUpdateInput BuiltUpdateItem(TrackPushContentConfigDto config, TrackPushRecordIndex log) { - var track = new TrackItem - { - // 推真实的发生地和发生时间(时间是计算后的) - Location = log.TrackPlace, - Date = log.TrackTime.AddHours( - config.TrackTimeZone ?? log.TrackTimeZone - log.TrackTimeZone), - TimeZone = config.TrackTimeZone ?? log.TrackTimeZone, - Description = config.TrackEnContentValue, - DescriptionCn = config.TrackContentValue, - Code = config.TrackContentCodeValue, - Status = config.TrackStatusValue, - Extra = config.ExpandFieldsValue - }; + var trackDatetime = log.TrackTime.AddHours(config.TrackTimeZone ?? log.TrackTimeZone - log.TrackTimeZone); + var trackDateStr = DateTimeFormat(trackDatetime, config.TrackTimeZone ?? log.TrackTimeZone, config); var body = new TrackUpdateInput { - OrderNo = log.OrderNo, + OrderNo = log.OrderNo }; - body.Data.Add(track); + var dict = new Dictionary() + { + //推真实的发生地和发生时间(时间是计算后的) + { "location", log.TrackPlace }, + { "date", trackDateStr }, + { "timeZone", config.TrackTimeZone ?? log.TrackTimeZone }, + { "description", config.TrackEnContentValue }, + { "descriptionCn", config.TrackContentValue }, + { "code", config.TrackContentCodeValue }, + { "status", config.TrackStatusValue }, + { "extra", TextJsonHelper.Deserialize(log.Extra) } + }; + body.Data.Add(dict); log.PushContent = body.ToJson(); return body; } - private async Task BuiltPushItem(TrackPushContentConfigDto config, TrackPushRecordIndex log) + private async Task BuiltPushItem(TrackPushContentConfigDto config, TrackPushRecordIndex log, + string? compareFields) { - var track = new TrackItem - { - // 推真实的发生地和发生时间(时间是计算后的) - Location = log.TrackPlace, - Date = log.TrackTime.AddHours( - config.TrackTimeZone ?? log.TrackTimeZone - log.TrackTimeZone), - TimeZone = config.TrackTimeZone ?? log.TrackTimeZone, - Description = config.TrackEnContentValue, - DescriptionCn = config.TrackContentValue, - Code = config.TrackContentCodeValue, - Status = config.TrackStatusValue, - Extra = config.ExpandFieldsValue - }; + var trackDatetime = log.TrackTime.AddHours(config.TrackTimeZone ?? log.TrackTimeZone - log.TrackTimeZone); + var trackDateStr = DateTimeFormat(trackDatetime, config.TrackTimeZone ?? log.TrackTimeZone, config); var body = new TrackPushInput { OrderNo = log.OrderNo, }; - body.Data.Add(track); + var cur = new Dictionary + { + // 推真实的发生地和发生时间(时间是计算后的) + { "location", log.TrackPlace }, + { "date", trackDateStr }, + { "timeZone", config.TrackTimeZone ?? log.TrackTimeZone }, + { "description", config.TrackEnContentValue }, + { "descriptionCn", config.TrackContentValue }, + { "code", config.TrackContentCodeValue }, + { "status", config.TrackStatusValue }, + { "extra", TextJsonHelper.Deserialize(log.Extra) } + }; + body.Data.Add(cur); if (config.IsAllPush) { - var history = await _trackPushRecordsRepository.GetLatestTrackPushRecordAsync(log.OrderId); + var history = await _trackPushRecordEsRepository.GetLatestTrackPushRecordAsync(log.OrderId, true); if (history != default) { - body = JsonConvert.DeserializeObject(history.PushContent); - body!.Data.Add(track); + body = TextJsonHelper.Deserialize(history.PushContent); + + //在推送历史中,选出当前轨迹明细一致的轨迹 + var tracks = await _trackDetailsEsRepository.GetListAsync(log.OrderId); + //确定轨迹标识符 + var trackIdentifies = tracks.Select(x => + { + //寻找映射配置(转换后的code) + var code = _pushConfigs.First(y => y.TrackCode == x.TrackCode).TrackContentCodeValue; + var timeStr = DateTimeFormat(x.TrackTime, config.TrackTimeZone ?? log.TrackTimeZone, config); + return string.IsNullOrWhiteSpace(compareFields) + ? $"{code}{timeStr}" + : $"{code}{TextJsonHelper.ExtractValue(x.Extra, compareFields)}"; + } + ).ToImmutableHashSet(); + //在历史中选取在订单当前轨迹明细中的记录 + body!.Data = body.Data.Where(x => + { + var code = ((JsonElement) x["code"]!).GetString(); + var timeStr = ((JsonElement) x["date"]!).GetString(); + + if (string.IsNullOrWhiteSpace(compareFields)) + return trackIdentifies.Contains($"{code}{timeStr}"); + + if (((JsonElement) x["extra"]!).TryGetProperty(compareFields, out var comparerValueJsonElement)) + return trackIdentifies.Contains($"{code}{TextJsonHelper.GetString(comparerValueJsonElement)}"); + + return trackIdentifies.Contains($"{code}{null}"); + }).ToList(); + + + if (config.IsAllPushWithLatest) + { + //同code同比较字段保证唯一 + var old = body.Data + .Where(x => + { + //反序列化出的JsonElement和字典字符串类型做比较 + var a = ((JsonElement) x["code"]!).GetString(); + var b = cur["code"]! + .ToString(); //tips: 需要要将object类型的字符串转为string类型,否则使用的是引用比较,反序列化出的string一定和本地string引用不同 + return a == b; + }) + .WhereIf(!compareFields.IsNullOrWhiteSpace(), x => + { + if (x["extra"] == null || log.Extra == null) return false; + return TextJsonHelper.EqByJsonElementField(x["extra"]!, + TextJsonHelper.Deserialize(log.Extra), compareFields!); + }) + .FirstOrDefault(); + + if (old != null) + { + body.Data.Remove(old); + } + } + + // 添加当前要推送的轨迹 + body.Data.Add(cur); } } - log.PushContent = body.ToJson(); + log.PushContent = TextJsonHelper.Serialize(body)!; return body; } @@ -267,24 +445,104 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe /// 根据轨迹代码推断下一个(升序)要推送的内容,如果找不到或者已经是最后一个了 /// 则查询有没有可交换的推送,没有就返回null /// - /// - /// - /// - /// - TrackPushContentConfigDto? GetValidPushConfigAsync(List cache, - string? latestPushTrackCode, string? trackCode) + private static TrackPushContentConfigDto? GetValidPushConfigAsync(List cache, + string? latestPushTrackCode, TrackPushEvent @event) { + var trackCode = @event.TrackCode; var idx = cache.FindIndex(x => x.TrackCode == latestPushTrackCode); + if (@event.ForcedPush && trackCode == latestPushTrackCode) + { + //强制推送,允许重复推送当前轨迹 + return cache[idx]; + } + if (idx + 1 >= cache.Count) return default; // 推完了 // find next var matched = cache[idx + 1].TrackCode == trackCode ? cache[idx + 1] - : // find swap - cache.FirstOrDefault(x => x.TrackCode == cache[idx + 1].SwapTrackCode); + : cache.FirstOrDefault(x => x.TrackCode == cache[idx + 1].SwapTrackCode); + //没推完,可能不符合推送顺序 return matched != null && matched.TrackCode == trackCode ? matched : default; } -} \ No newline at end of file + + /// + /// 转换推送时间格式 + /// + private static string DateTimeFormat(DateTime dateTime, double timezone, TrackPushContentConfigDto config) + { + if (config.DateTimeFormatType == (int) DateTimeFormatEnum.Timestamp) + return DateTimeHelper.ConvertToUnixTimestamp(dateTime).ToString(); + + if (config.DateTimeFormatType == (int) DateTimeFormatEnum.DateTimeAndTimezone + && !string.IsNullOrEmpty(config.DateTimeFormat) + && !string.IsNullOrEmpty(config.TimezoneFormat)) + { + var zoneStr = DateTimeHelper.TimezoneFormat(timezone, config.TimezoneFormat); + var datetimeStr = DateTimeHelper.FormatDateTime(dateTime, config.DateTimeFormat); + return $"{datetimeStr} {zoneStr}"; + } + + return dateTime.ToString("yyyy-MM-ddTHH:mm:ss.fffK"); + } + + //轨迹推送失败(被拦截) + private void TrackPushFailedPublicTopic(string failedMessage, TrackPushEvent @event, OrderEntity order) + { + _broadcastingService.TrackPushFailedPubilcTopic(new TrackPushRecordDto + { + //还没请求接口通 + RequestId = null, + IsSuccess = false, + Message = failedMessage, + OperationMan = @event.OperationMan, + PushTime = DateTime.Now, + OptionType = @event.OptionType.ToString(), + IsManualPush = @event.OperationMan != null, + //还没到构建推送内容那一步就被拦截 + PushContent = string.Empty, + OrderNo = order.OrderNo, + TrackStatus = @event.SystemPushInfo.TrackStatus, + TrackContent = @event.SystemPushInfo.TrackStatus, + TrackTimeZone = @event.SystemPushInfo.TrackTimeZone, + TrackTime = @event.SystemPushInfo.TrackTime, + TrackPlace = @event.SystemPushInfo.TrackPlace, + TrackCode = @event.TrackCode, + Extra = @event.SystemPushInfo.Extra, + }); + } + + //轨迹推送失败(请求接口通) + private void TrackPushFailedPublicTopic( + string failedMessage, + TrackPushEvent @event, + Guid requestId, + List pushOrUpdateInputs) + { + foreach (var pushInput in pushOrUpdateInputs) + { + _broadcastingService.TrackPushFailedPubilcTopic(new TrackPushRecordDto + { + RequestId = requestId, + IsSuccess = false, + Message = failedMessage, + OperationMan = @event.OperationMan, + PushTime = DateTime.Now, + OptionType = @event.OptionType.ToString(), + IsManualPush = @event.OperationMan != null, + PushContent = TextJsonHelper.Serialize(pushInput), + OrderNo = pushInput.OrderNo, + TrackStatus = @event.SystemPushInfo.TrackStatus, + TrackContent = @event.SystemPushInfo.TrackStatus, + TrackTimeZone = @event.SystemPushInfo.TrackTimeZone, + TrackTime = @event.SystemPushInfo.TrackTime, + TrackPlace = @event.SystemPushInfo.TrackPlace, + TrackCode = @event.TrackCode, + Extra = @event.SystemPushInfo.Extra, + }); + } + } +} diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackRefreshEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackRefreshEventHandler.cs deleted file mode 100644 index f982343e..00000000 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackRefreshEventHandler.cs +++ /dev/null @@ -1,256 +0,0 @@ -using System.Diagnostics; -using System.Linq.Expressions; -using DotNetCore.CAP; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using SJZY.InterfaceRelay.Application.Contracts; -using SJZY.Track.Application.Contract.Dtos.TrackPull; -using SJZY.Track.Application.Contract.Events; -using SJZY.Track.Application.Contract.Services; -using SJZY.Track.Application.Helpers; -using SJZY.Track.Domain.Aggregates.OrderAggregate; -using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; -using SJZY.Track.Domain.Consts; -using SJZY.Track.Domain.Enums; -using Volo.Abp.DependencyInjection; - -namespace SJZY.Track.Application.CAP.EventHandlers; - -public class TrackRefreshEventHandler : ITransientDependency, ICapSubscribe -{ - private readonly IOrderRepository _orderRepository; - private readonly ICapPublisher _capPublisher; - private readonly ITrackPullCacheService _trackPullCacheService; - private readonly ITrackDetailsRepository _trackDetailsRepository; - - public TrackRefreshEventHandler(IOrderRepository orderRepository, - ICapPublisher capPublisher, ITrackPullCacheService trackPullCacheService, - ITrackDetailsRepository trackDetailsRepository) - { - _orderRepository = orderRepository; - _capPublisher = capPublisher; - _trackPullCacheService = trackPullCacheService; - _trackDetailsRepository = trackDetailsRepository; - } - - [CapSubscribe(GlobalConst.TrackRefreshSubscribe, Group = GlobalConst.TrackRefreshSubscribe)] - public async Task ConsumerAsync(InterfaceRelayForwardReplayEvent @event) - { - if (!@event.IsSuccess) return; - var attach = Base64Helper.DeSerialize(@event.Attach); - if (attach is null) return; - - var config = await _trackPullCacheService.GetPullParamWithContentConfigAsync(attach.SubSystemId, - attach.ServiceProviderId); - if (@event.Data == null || config == null) return; - - var data = JObject.Parse(@event.Data); - var orderToken = data[config.ParamConfig.OrderPath]; - if (orderToken is JArray orderTokens) - { - foreach (var token in orderTokens) - { - await HandleOrderAsync(token, config, attach); - } - } - else if (orderToken is JObject) - { - await HandleOrderAsync(orderToken, config, attach); - } - } - - private async Task HandleOrderAsync(JToken orderToken, TrackPullParamWithContentConfigDto paramWithContentConfig, - TrackRefreshAttach attach) - { - var paramConfig = paramWithContentConfig.ParamConfig; - var orderNo = orderToken[paramConfig.OrderNoName]?.Value(); - if (orderNo.IsNullOrWhiteSpace()) return; - - var trackToken = orderToken[paramConfig.TrackDetailsPath]; - if (trackToken is null) return; - - var order = await _orderRepository.GetFirstAsync(x => - x.OrderType == attach.OrderType && x.OrderNo == orderNo, x => new - { - x.Id, x.LatestPushTrackCode, x.CustomId - }); - if (order == default) return; - - var context = new TrackRefreshContext - { - OrderId = order.Id, - OrderType = attach.OrderType, - OrderNo = orderNo!, - ServiceProviderName = attach.ServiceProviderName, - CustomId = order.CustomId, - SubSystemId = attach.SubSystemId - }; - - - if (trackToken is JArray trackTokens) - { - foreach (var item in trackTokens) - { - await HandleTrackAsync(item, paramWithContentConfig, context); - } - } - else if (trackToken is JObject) - { - await HandleTrackAsync(trackToken, paramWithContentConfig, context); - } - } - - private async Task HandleTrackAsync(JToken trackToken, TrackPullParamWithContentConfigDto paramWithContentConfig, - TrackRefreshContext context) - { - var originTrackData = JsonConvert.SerializeObject(trackToken); - // 如果已经存在一模一样的报文了说明处理过了,直接return - if (await _trackDetailsRepository.AnyAsync(context.OrderId, originTrackData)) return; - - var paramConfig = paramWithContentConfig.ParamConfig; - var contentConfigs = paramWithContentConfig.ContentConfigs; - TrackPullContentConfigDto? matchedContentConfig = null; - - // 1、匹配轨迹代码 - if (paramConfig.TrackContentCodeName != null) - { - var trackCode = trackToken[paramConfig.TrackContentCodeName]?.Value(); - if (!trackCode.IsNullOrWhiteSpace()) - { - matchedContentConfig = contentConfigs.FirstOrDefault(x => x.TrackContentCodeValue == trackCode); - } - } - // 2、匹配轨迹状态 - else if (paramConfig.TrackStatusName != null) - { - var trackStatus = trackToken[paramConfig.TrackStatusName]?.Value(); - if (!trackStatus.IsNullOrWhiteSpace()) - { - matchedContentConfig = contentConfigs.FirstOrDefault(x => x.TrackStatusValue == trackStatus); - } - } - // 3、匹配轨迹内容 - else if (paramConfig.TrackContentName != null) - { - var trackContent = trackToken[paramConfig.TrackContentName]?.Value(); - if (!trackContent.IsNullOrWhiteSpace()) - { - Debug.Assert(trackContent != null, nameof(trackContent) + " != null"); - matchedContentConfig = contentConfigs.FirstOrDefault(x => x.TrackContentValue == trackContent); - - // 按关键字分析轨迹内容 - if (matchedContentConfig is null) - { - foreach (var contentConfig in contentConfigs) - { - foreach (var keyword in contentConfig.TrackKeyword?.Split(',') ?? Enumerable.Empty()) - { - if (trackContent.Contains(keyword, StringComparison.OrdinalIgnoreCase)) - { - matchedContentConfig = contentConfig; - break; - } - } - - if (matchedContentConfig is null) continue; - - foreach (var keyword in contentConfig.TrackKeywordReverse?.Split(',') ?? - Enumerable.Empty()) - { - if (trackContent.Contains(keyword, StringComparison.OrdinalIgnoreCase)) - { - matchedContentConfig = null; - break; - } - } - } - } - } - } - - // 轨迹发生地 - var trackPlace = paramConfig.TrackPlaceName == null - ? null - : trackToken[paramConfig.TrackPlaceName]?.Value(); - if (trackPlace.IsNullOrWhiteSpace()) - { - Expression> resultExpression = - (TrackLocationValue?)matchedContentConfig?.TrackPlaceValue switch - { - TrackLocationValue.ArrivalPort => x => x.ArrivalPort, - TrackLocationValue.ArriveCity => x => x.ArrivalCity, - TrackLocationValue.ArrivalCountry => x => x.ArrivalCountry, - TrackLocationValue.LeavePort => x => x.LeavePort, - TrackLocationValue.LeaveCity => x => x.LeaveCity, - TrackLocationValue.LeaveCountry => x => x.LeaveCountry, - _ => x => x.LeaveCountry - }; - trackPlace = await _orderRepository.GetFirstAsync(x => - x.Id == context.OrderId, resultExpression); - } - - // 轨迹发生时间 - var trackTime = paramConfig.TrackTimeName == null - ? null - : trackToken[paramConfig.TrackTimeName]?.Value(); - // 轨迹发生时区 - var trackTimeZone = paramConfig.TrackTimeZoneName == null - ? null - : trackToken[paramConfig.TrackTimeZoneName]?.Value(); - - if (matchedContentConfig is null) - { - var notMappedEvent = new TrackInsertForNotMappedEvent - { - OrderId = context.OrderId, - OrderType = context.OrderType, - OrderNo = context.OrderNo, - ServiceProviderName = context.ServiceProviderName, - OriginTrackData = JsonConvert.SerializeObject(trackToken), - TrackPlace = trackPlace ?? GlobalConst.EmptyString, - TrackTime = trackTime ?? DateTime.Now, - TrackTimeZone = trackTimeZone ?? matchedContentConfig?.TrackTimeZoneValue ?? 8 - }; - if (paramConfig.TrackContentName != null) - { - notMappedEvent.OriginTrackContent = trackToken[paramConfig.TrackContentName]?.Value(); - } - - await _capPublisher.PublishAsync(GlobalConst.TrackInsertForNotMappedEventSubscribe, notMappedEvent); - return; - } - - // 新增/更新轨迹 - var trackUpsertEvent = new TrackUpsertEvent - { - OrderIdentifiers = new[] - { - new OrderIdentifier - { - OrderId = context.OrderId, - OrderNo = context.OrderNo, - OrderType = context.OrderType, - CustomId = context.CustomId - } - }, - TrackRefreshData = new TrackRefreshStruct - { - ServiceProviderName = context.ServiceProviderName, - OriginTrackData = originTrackData, - IsCompleted = matchedContentConfig.IsCompleted, - OriginTrackContent = paramConfig.TrackContentName != null - ? trackToken[paramConfig.TrackContentName]?.Value() - : GlobalConst.EmptyString - }, - SubSystemId = context.SubSystemId, - TrackCode = matchedContentConfig.TrackContentCode, - TrackPlace = trackPlace ?? GlobalConst.EmptyString, - TrackTime = trackTime ?? DateTime.Now, - TrackTimeZone = trackTimeZone ?? matchedContentConfig.TrackTimeZoneValue ?? 8 - }; - - trackUpsertEvent.IsAdd = - !await _trackDetailsRepository.AnyByCodeAsync(context.OrderId, matchedContentConfig.TrackContentCode); - await _capPublisher.PublishAsync(GlobalConst.TrackUpsertForRefreshSubscribe, trackUpsertEvent); - } -} \ No newline at end of file diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs index 46443ffb..8a657ad2 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs @@ -1,65 +1,91 @@ -using DotNetCore.CAP; +using System.Diagnostics; +using DotNetCore.CAP; +using Microsoft.Extensions.Logging; using SJZY.Expand.ABP.Core.Logger; using SJZY.Expand.ABP.Core.PublicMethords; using SJZY.Track.Application.Contract.Events; +using SJZY.Track.Application.Contract.Services; +using SJZY.Track.Application.Helpers; using SJZY.Track.Domain.Aggregates.OrderAggregate; using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; -using SJZY.Track.Domain.Consts; +using SJZY.Track.Domain.Dtos.TrackContents; +using SJZY.Track.Domain.Enums; using SJZY.Track.Domain.Queries; using Volo.Abp.DependencyInjection; +using OrderIdentifier = SJZY.Track.Application.Contract.Events.OrderIdentifier; namespace SJZY.Track.Application.CAP.EventHandlers; public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe { + private readonly ICapPublisher _capPublisher; private readonly IOrderRepository _orderRepository; private readonly IProvideQueries _provideQueries; - private readonly ITrackDetailsRepository _trackDetailsRepository; - private readonly ICapPublisher _capPublisher; + private readonly ITrackDetailsEsRepository _trackDetailsEsRepository; + private readonly IBroadcastingService _broadcastingService; + private readonly ILogger _logger; + private readonly IOrderOperationRecordEsRepository _orderOperationRecordEsRepository; - public TrackUpsertEventHandler(IOrderRepository orderRepository, ICapPublisher capPublisher, - IProvideQueries provideQueries, ITrackDetailsRepository trackDetailsRepository) + public TrackUpsertEventHandler( + IOrderRepository orderRepository, + ICapPublisher capPublisher, + IProvideQueries provideQueries, + ITrackDetailsEsRepository trackDetailsEsRepository, + IOrderOperationRecordEsRepository orderOperationRecordEsRepository, + IBroadcastingService broadcastingService, + ILogger logger) { _orderRepository = orderRepository; _capPublisher = capPublisher; _provideQueries = provideQueries; - _trackDetailsRepository = trackDetailsRepository; + _trackDetailsEsRepository = trackDetailsEsRepository; + _orderOperationRecordEsRepository = orderOperationRecordEsRepository; + _broadcastingService = broadcastingService; + _logger = logger; } [CapSubscribe(GlobalConst.TrackUpsertSubscribe, Group = GlobalConst.TrackUpsertSubscribe)] [CapSubscribe(GlobalConst.TrackUpsertForRefreshSubscribe, Group = GlobalConst.TrackUpsertForRefreshSubscribe)] public async Task ConsumerAsync(TrackUpsertEvent @event) { - var orderIds = @event.OrderIdentifiers.Select(x => x.OrderId).ToArray(); - - var dup = @event.Visited.Intersect(orderIds).ToArray(); - if (dup.Any()) - { - LogHelper.Error($"{(@event.IsAdd ? "添加" : "修改")}轨迹时,发现循环依赖:{dup.JoinAsString(",")}"); - return; - } + if (!CanDelete(@event)) return; var canNextOrderIds = new List(); - await HandleTrackAsync(@event, canNextOrderIds); + var content = await HandleTrackAsync(@event, canNextOrderIds); + + // 处理广播事件 + if (content != null && (content.IsToMq || @event.IsToMq)) + _ = EnsureWriteAfterPublicTopicAsync(@event, content.IsExternal, content.SubSystemCode, content.TrackStatusCode); + + if (canNextOrderIds.Count == 0) return; + // 根据订单关联关系异步向下刷(异步) + await DownByOrderLink(@event, canNextOrderIds); + } + + private async Task DownByOrderLink(TrackUpsertEvent @event, List canNextOrderIds) + { // 根据订单关联关系异步向下刷(异步) var linkedOrders = await _orderRepository.GetLinkedOrdersAsync(canNextOrderIds.ToArray()); foreach (var order in @event.OrderIdentifiers) { // 理论上小包在这不会分组 foreach (var group in linkedOrders.Where(x => x.OwnerOrderId == order.OrderId) - .GroupBy(x => new { x.SubSystemId, x.CustomId })) + .GroupBy(x => new + { + x.SubSystemId, + x.CustomId // 这里按客户分组是为了后续的推送方便 + })) { var nextEvent = @event.DeepCopy(); - nextEvent.Visited.AddRange(orderIds); + nextEvent.Visited.AddRange(canNextOrderIds); nextEvent.SubSystemId = group.Key.SubSystemId; + nextEvent.CustomId = group.Key.CustomId; nextEvent.TrackRefreshData = new TrackRefreshStruct { - ServiceProviderName = @event.TrackRefreshData.ServiceProviderName, + ServiceProviderCode = @event.TrackRefreshData.ServiceProviderCode, OriginTrackContent = @event.TrackRefreshData.OriginTrackContent, - OriginTrackData = @event.TrackRefreshData.OriginTrackData, - // tips:一定要重置为false,父级订单的完成不会使得关联订单完成,关联单也必须由刷新来完成或手动设置完成!! - IsCompleted = false + OriginTrackDataHash = @event.TrackRefreshData.OriginTrackDataHash, }; // 不同子系统需要做内容映射 @@ -83,7 +109,6 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe OrderId = x.OrderId, OrderNo = x.OrderNo, OrderType = x.OrderType, - CustomId = x.CustomId }).ToList(); var idx = 0; while (idx < identifiers.Count) @@ -101,115 +126,343 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe } } - private async Task HandleTrackAsync(TrackUpsertEvent @event, List canNextOrderIds) + private bool CanDelete(TrackUpsertEvent @event) { - var orderIds = @event.OrderIdentifiers.Select(x => x.OrderId).ToArray(); - var tracks = await _trackDetailsRepository.GetListAsync(orderIds, @event.TrackCode, true); - - var newOrderIds = orderIds.Except(tracks.Select(x => x.OrderId)).ToArray(); - var trackContents = await _provideQueries.MatchTrackContentAsync(newOrderIds, @event.TrackCode); - - var insertTracks = new List(); - - foreach (var order in @event.OrderIdentifiers) + // 系统创建的轨迹不允许修改 + if (@event.Visited.IsNullOrEmpty() && @event is { OperationMan: GlobalConst.SystemUser, IsAdd: false }) { - var track = tracks.FirstOrDefault(x => x.OrderId == order.OrderId); - - if (track == null && !@event.IsAdd) continue; // 不存在不让改 - if (track != null && @event.IsAdd) continue; // 存在不让创建 - - if (track == default) - { - track = new TrackDetailsIndex - { - OrderId = order.OrderId, - OrderNo = order.OrderNo, - OrderType = order.OrderType, - TrackCode = @event.TrackCode, - TrackPlace = @event.TrackPlace, - TrackTime = @event.TrackTime, - TrackTimeZone = @event.TrackTimeZone, - ServiceProviderName = @event.TrackRefreshData.ServiceProviderName ?? GlobalConst.EmptyString, - OriginTrackContent = @event.TrackRefreshData.OriginTrackContent ?? GlobalConst.EmptyString, - OriginTrackData = @event.TrackRefreshData.OriginTrackData ?? GlobalConst.EmptyString, - IsCanDelete = false, - CreateUser = @event.OperationMan ?? GlobalConst.SystemUser, - CreateTime = DateTime.Now - }; - - // 根据轨迹code在订单模板内容中寻找匹配的 - var trackContent = trackContents.FirstOrDefault(x => x.OrderId == order.OrderId); - if (trackContent == default) - { - // 订单所绑定的模板,没有一条内容可以匹配发生的轨迹 - continue; - } - - track.TrackStatus = trackContent.Status; - track.TrackCode = trackContent.TrackCode; - track.TrackContent = trackContent.Content; - track.TrackEnContent = trackContent.EnContent; - track.IsCanDelete = trackContent.IsCanDelete; - track.ZeroTrackTime = track.TrackTime.Subtract(TimeSpan.FromHours(track.TrackTimeZone)); - - insertTracks.Add(track); - } - else - { - track.TrackPlace = @event.TrackPlace; - track.TrackTime = @event.TrackTime; - track.TrackTimeZone = @event.TrackTimeZone; - track.UpdateUser = @event.OperationMan ?? GlobalConst.SystemUser; - track.UpdateTime = DateTime.Now; - - await _trackDetailsRepository.UpdateAsync(track); - } - - canNextOrderIds.Add(order.OrderId); + LogHelper.Warn($"系统创建的轨迹不允许被修改:{@event}", true); + return false; } - if (canNextOrderIds.Count == 0) return; + var orderIds = @event.OrderIdentifiers.Select(x => x.OrderId).ToArray(); - var content = await _provideQueries.GetTrackContentAsync(@event.SubSystemId, @event.TrackCode); + var dup = @event.Visited.Intersect(orderIds).ToArray(); + if (dup.Any()) + { + LogHelper.Warn($"{(@event.IsAdd ? "添加" : "修改")}轨迹时,发现循环依赖:{dup.JoinAsString(",")}", true); + return false; + } - // 批量add to es - await _trackDetailsRepository.AddManyAsync(insertTracks); + return true; + } + + private async Task HandleTrackAsync(TrackUpsertEvent @event, List canNextOrderIds) + { + var trackContent = await _provideQueries.GetTrackContentAsync(@event.SubSystemId, @event.TrackCode); + + if (trackContent == null) + { + // 找不到轨迹内容,直接结束 + LogHelper.Warn($"找不到轨迹内容:{@event}", true); + return null; + } + + //#7001:未来潜在需求,当轨迹内容匹配预设,记录一个标记,保证下刷过程都是使用预设内容 + //虽然在引发事件之前做了判断,引发之后并不一定立即处理,在此过程中轨迹内容仍然可能被修改,所以要二次进行判断。 + //通过来源指示是否为手动操作 + var manualOperation = @event.Source == (int) TrackSourceEnum.Artificial; + //轨迹内容标识不允许手动创建的 + if (manualOperation && @event.IsAdd && trackContent.IsAllowManuallyCreate == false) return trackContent; + //轨迹内容标识不允许手动更新的 + if (manualOperation && !@event.IsAdd && trackContent.IsAllowManuallyUpdate == false) return trackContent; + + var insertTracks = await UpsertTrackAsync(@event, canNextOrderIds, trackContent); + + if (canNextOrderIds.Count == 0) return trackContent; + + if (insertTracks.Any()) + { + // 批量add to es + await _trackDetailsEsRepository.AddManyAsync(insertTracks); + + //批量写入订单操作日志 + _ = _orderOperationRecordEsRepository + .AddManyAsync(insertTracks.Select(t => BuildOrderOperationRecord(@event, t, new OrderIdentifier + { + OrderNo = t.OrderNo, + OrderId = t.OrderId + })).ToList()); + + // 添加轨迹触发订单拉取状态更新 + await _orderRepository.UpdatePullStatusToSilenceAsync(insertTracks.Select(x => x.OrderId).ToList(), + @event.TrackCode); + + // 添加轨迹触发预警计算(异步) + await _capPublisher.PublishAsync(GlobalConst.TrackWarningCalcSubscribe, new TrackWarningCalcEvent + { + SubSystemId = @event.SubSystemId, + CustomId = @event.CustomId, + OrderIds = insertTracks.Select(x => x.OrderId).ToArray(), + TrackStatusId = trackContent.TrackStatusId, + TrackTime = @event.TrackTime, + }); + } // 触发订单主表更新事件(异步) await _capPublisher.PublishAsync(GlobalConst.TrackChangeAfterUpdateOrderSubscribe, new TrackChangeAfterUpdateOrderEvent { OrderIds = canNextOrderIds.ToArray(), - IsCompleted = @event.TrackRefreshData.IsCompleted, - TrackContent = content.TrackContent, - TrackEnContent = content.TrackEnContent, + IsCompleted = trackContent.IsCompleted, + TrackContent = trackContent.TrackContent, + TrackEnContent = trackContent.TrackEnContent, TrackPlace = @event.TrackPlace, - TrackTime = @event.TrackTime, - TrackTimeZone = @event.TrackTimeZone + TrackTime = @event.NewTrackTime ?? @event.TrackTime, + TrackTimeZone = @event.TrackTimeZone, + DestinationTimeZone = @event.DestinationTimeZone, + EstimatedDeliveryDate = @event.EstimatedDeliveryDate }); // 触发轨迹推送事件(异步) - foreach (var group in @event.OrderIdentifiers - .Where(x => x.OrderId.IsIn(canNextOrderIds)) - .GroupBy(x => x.CustomId)) + var trackPushEvent = new TrackPushEvent { - var trackPushEvent = new TrackPushEvent + OptionType = @event.IsAdd ? OptionType.新增 : OptionType.修改, + SubSystemId = @event.SubSystemId, + SubSystemCode = trackContent.SubSystemCode, + CustomId = @event.CustomId, + OrderIds = canNextOrderIds.ToArray(), + TrackCode = @event.TrackCode, + SystemPushInfo = new SystemPushStruct { - OptionType = @event.IsAdd ? OptionType.新增 : OptionType.修改, - SubSystemId = @event.SubSystemId, - CustomId = group.Key, - OrderIds = group.Select(x => x.OrderId).ToArray(), - TrackCode = @event.TrackCode, - SystemPushInfo = new SystemPushStruct - { - TrackStatus = content.TrackStatus, - TrackContent = content.TrackContent, - TrackPlace = @event.TrackPlace, - TrackTime = @event.TrackTime, - TrackTimeZone = @event.TrackTimeZone - } - }; - await _capPublisher.PublishAsync(GlobalConst.TrackPushSubscribe, trackPushEvent); - } + TrackStatus = trackContent.TrackStatus, + TrackContent = trackContent.TrackContent, + TrackPlace = @event.TrackPlace, + TrackTime = @event.NewTrackTime ?? @event.TrackTime, + TrackTimeZone = @event.TrackTimeZone, + CompareFields = @event.CompareFields, + Extra = @event.Extra + }, + ForcedPush = @event.ForcedPush, + IsToMq = (trackContent.IsToMq || @event.IsToMq) + }; + await _capPublisher.PublishAsync(GlobalConst.TrackPushSubscribe, trackPushEvent); + + return trackContent; } -} \ No newline at end of file + + private async Task> UpsertTrackAsync(TrackUpsertEvent @event, List canNextOrderIds, + TrackContentVO trackContent) + { + var orderIds = @event.OrderIdentifiers.Select(x => x.OrderId).ToArray(); + + // important:轨迹code相同,时间、发生地不同的,可能存在多条!! + var tracks = await _trackDetailsEsRepository.GetListAsync(orderIds, @event.TrackCode, true); + + var insertTracks = new List(); + var updateTracks = new List(); + var operationRecords = new List(); + foreach (var order in @event.OrderIdentifiers) + { + // fast path: by update with es id case + if (!@event.IsAdd && !string.IsNullOrWhiteSpace(@event.EsId)) + { + var trackById = tracks.FirstOrDefault(x => x.Id == @event.EsId); + if (trackById != null) + { + updateTracks.Add(BuiltUpdateTrack(@event, trackById, order, trackContent)); + } + + continue; + } + + var existTracks = tracks.Where(x => x.OrderId == order.OrderId).ToList(); + + if (@event.CompareFields.IsNullOrEmpty()) + { + existTracks = existTracks.Where(x => x.TrackTime == @event.TrackTime).ToList(); + } + else + { + Debug.Assert(@event.CompareFields != null, "@event.CompareFields != null"); + var extraDict = TextJsonHelper.DeserializeToDictionary(@event.Extra); + if (extraDict == null || !extraDict.TryGetValue(@event.CompareFields, out var compareValue)) + { + throw new BusinessException(message: $"请检查拓展字段,为什么找不到比较字段:{@event.CompareFields}"); + } + + existTracks = existTracks.Where(x => + { + var oldExtraDict = TextJsonHelper.DeserializeToDictionary(x.Extra); + // tips:注意兼容性,历史轨迹的字段可能为空 + if (oldExtraDict == null || !oldExtraDict.TryGetValue(@event.CompareFields, out var oldValue)) + { + return false; + } + + return TextJsonHelper.EqJsonElement(oldValue, compareValue); + }).ToList(); + } + + var track = existTracks.FirstOrDefault(); + + if (!@event.IsAdd) + { + if (existTracks.Count > 1) + { + _logger.LogInformation("订单存在多条轨迹不允许修改:{@event}", @event); + continue; + } + + if (track == null) + { + _logger.LogInformation("订单不存在轨迹不允许修改:{@event}", @event); + continue; // 不存在不让改 + } + + updateTracks.Add(BuiltUpdateTrack(@event, track, order, trackContent)); + operationRecords.Add(BuildOrderOperationRecord(@event, track, order)); + } + else + { + // 不允许重复轨迹,跳过 + if (!trackContent.IsRepeatable && existTracks.Count > 0) + { + _logger.LogInformation("订单已经存在不允许重复的轨迹,不允许重复添加:{@event}", @event); + continue; + } + + insertTracks.Add(BuiltNewTrack(@event, order, trackContent)); + } + + canNextOrderIds.Add(order.OrderId); + } + + if (updateTracks.Any()) + { + //批量差异化更新轨迹 + await _trackDetailsEsRepository.BulkUpdateAsync(updateTracks); + //批量写入操作日志 + _ = _orderOperationRecordEsRepository.AddManyAsync(operationRecords); + } + + return insertTracks; + } + + + private TrackDetailsIndex BuiltUpdateTrack(TrackUpsertEvent @event, TrackDetailsIndex track, OrderIdentifier order, + TrackContentVO trackContent) + { + //外部轨迹,轨迹发生地,轨迹发生时间,轨迹发生时区,不允许更改 + if (track.Source != (int) TrackSourceEnum.ExternalServiceProvide) + { + track.TrackPlace = @event.TrackPlace; + track.TrackTime = @event.NewTrackTime ?? @event.TrackTime; + track.TrackTimeZone = @event.TrackTimeZone; + } + + track.ZeroTrackTime = Math.Abs(track.TrackTimeZone - GlobalConst.NoneTrackTimeZone) < 1 + ? track.TrackTime + : track.TrackTime.Subtract(TimeSpan.FromHours(track.TrackTimeZone)); + track.UpdateUser = @event.OperationMan ?? GlobalConst.SystemUser; + track.UpdateTime = DateTime.Now; + + //允许二次修改,在修改了轨迹内容后进行修改轨迹操作,如果输入的轨迹内容则以输入为准 + //跨子系统? + track.TrackContent = @event.Content ?? trackContent.TrackContent; + track.TrackEnContent = @event.EnStatus ?? trackContent.TrackEnContent; + //S06新增 + track.IsVisibility = @event.IsVisibility; + //当传入的IsExternal为空,则使用轨迹内容中的IsExternal + track.IsExternal = @event.IsExternal ?? trackContent.IsExternal; + track.Remarks = @event.Remarks ?? GlobalConst.EmptyString; + track.Files = @event.Files?.Select(x => new FileItem + { + OssKey = x.OssKey, + FileName = x.FileName + }).ToList(); + track.TrackPlaceCity = @event.TrackPlaceCity ?? GlobalConst.EmptyString; + track.TrackPlaceCityId = @event.TrackPlaceCityId ?? GlobalConst.NotExistId; + track.TrackPlaceProvince = @event.TrackPlaceProvince ?? GlobalConst.EmptyString; + track.TrackPlaceProvinceId = @event.TrackPlaceProvinceId ?? GlobalConst.NotExistId; + track.TrackPlaceNation = @event.TrackPlaceNation ?? GlobalConst.EmptyString; + track.TrackPlaceNationId = @event.TrackPlaceNationId ?? GlobalConst.NotExistId; + track.TrackPlacePostcode = @event.TrackPlacePostcode ?? GlobalConst.EmptyString; + track.DestinationTimeZone = @event.DestinationTimeZone; + track.EstimatedDeliveryDate = @event.EstimatedDeliveryDate; + track.Extra = @event.Extra; + + return track; + } + + private TrackDetailsIndex BuiltNewTrack(TrackUpsertEvent @event, OrderIdentifier order, TrackContentVO trackContent) + { + var track = new TrackDetailsIndex + { + SubSystemId = @event.SubSystemId, + OrderId = order.OrderId, + OrderNo = order.OrderNo, + OrderType = order.OrderType, + TrackCode = @event.TrackCode, + TrackPlace = @event.TrackPlace, + TrackTime = @event.NewTrackTime ?? @event.TrackTime, + TrackTimeZone = @event.TrackTimeZone, + ServiceProviderCode = @event.TrackRefreshData.ServiceProviderCode ?? GlobalConst.EmptyString, + OriginTrackContent = @event.TrackRefreshData.OriginTrackContent ?? GlobalConst.EmptyString, + OriginTrackDataHash = @event.TrackRefreshData.OriginTrackDataHash ?? GlobalConst.EmptyString, + CreateUser = @event.OperationMan ?? GlobalConst.SystemUser, + CreateTime = DateTime.Now, + //来源轨迹内容,第一次新增的时候使用轨迹内容表提供的 + TrackStatusId = trackContent.TrackStatusId, + TrackStatus = trackContent.TrackStatus, + TrackStatusCode = trackContent.TrackStatusCode, + //跨子系统? + TrackContentId = trackContent.TrackContentId, + TrackContent = @event.Content ?? trackContent.TrackContent, + TrackEnContent = @event.EnStatus ?? trackContent.TrackEnContent, + //S06新增轨迹明细字段 + IsVisibility = @event.IsVisibility, + //当传入的IsExternal为空,则使用轨迹内容中的IsExternal + IsExternal = @event.IsExternal ?? trackContent.IsExternal, + Source = @event.Source, + Remarks = @event.Remarks ?? GlobalConst.EmptyString, + Files = @event.Files?.Select(x => new FileItem + { + OssKey = x.OssKey, + FileName = x.FileName + }).ToList(), + TrackPlaceCity = @event.TrackPlaceCity ?? GlobalConst.EmptyString, + TrackPlaceCityId = @event.TrackPlaceCityId ?? GlobalConst.NotExistId, + TrackPlaceProvince = @event.TrackPlaceProvince ?? GlobalConst.EmptyString, + TrackPlaceProvinceId = @event.TrackPlaceProvinceId ?? GlobalConst.NotExistId, + TrackPlaceNation = @event.TrackPlaceNation ?? GlobalConst.EmptyString, + TrackPlaceNationId = @event.TrackPlaceNationId ?? GlobalConst.NotExistId, + TrackPlacePostcode = @event.TrackPlacePostcode ?? GlobalConst.EmptyString, + DestinationTimeZone = @event.DestinationTimeZone, + EstimatedDeliveryDate = @event.EstimatedDeliveryDate, + Extra = @event.Extra + }; + + track.ZeroTrackTime = Math.Abs(track.TrackTimeZone - GlobalConst.NoneTrackTimeZone) < 1 + ? track.TrackTime + : track.TrackTime.Subtract(TimeSpan.FromHours(track.TrackTimeZone)); + + return track; + } + + private OrderOperationRecordIndex BuildOrderOperationRecord(TrackUpsertEvent @event, TrackDetailsIndex track, OrderIdentifier order) + { + return new OrderOperationRecordIndex + { + OrderId = order.OrderId, + OrderNo = order.OrderNo, + OptionType = @event.IsAdd ? OrderOperationType.创建轨迹.ToString() : OrderOperationType.修改轨迹.ToString(), + Content = track.ToJson(), + CreateUserId = @event.OperationManId, + CreateUserName = @event.OperationMan ?? "", + CreateTime = DateTime.Now + }; + } + + private async Task EnsureWriteAfterPublicTopicAsync(TrackUpsertEvent @event, bool contentIsExternal, string subSystemCode, string statusCode) + { + //理想情况在写入之后1s会刷盘 https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-refresh.html + //增加一个版本号来确定是否真的变更了 + //没有刷盘成功事件回调 + //方案1:!!【轮询等待静默刷盘】查出版本号确实发生了变更在发送广播 + //方案2:考虑强制刷盘(对es压力大)后发送 + //方案3:采用一个较大延时,不查询直接发 + await Task.Delay(1000); + _broadcastingService.TrackChangePublicTopic(@event, contentIsExternal, subSystemCode, statusCode); + } +} diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackWarningCalcEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackWarningCalcEventHandler.cs new file mode 100644 index 00000000..0acde53b --- /dev/null +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackWarningCalcEventHandler.cs @@ -0,0 +1,76 @@ +using DotNetCore.CAP; +using SJZY.Expand.ABP.Core.Logger; +using SJZY.Track.Application.Contract.Dtos.Forewarning; +using SJZY.Track.Application.Contract.Events; +using SJZY.Track.Application.Contract.Services; +using SJZY.Track.Domain.Aggregates.OrderAggregate; +using Volo.Abp.DependencyInjection; + +namespace SJZY.Track.Application.CAP.EventHandlers; + +public class TrackWarningCalcEventHandler : ITransientDependency, ICapSubscribe +{ + private readonly IForewarningNotifyService _forewarningNotifyService; + private readonly IOrderRepository _orderRepository; + + public TrackWarningCalcEventHandler(IOrderRepository orderRepository, + IForewarningNotifyService forewarningNotifyService) + { + _orderRepository = orderRepository; + _forewarningNotifyService = forewarningNotifyService; + } + + [CapSubscribe(GlobalConst.TrackWarningCalcSubscribe)] + public async Task ConsumerAsync(TrackWarningCalcEvent @event) + { + var orders = await _orderRepository.GetListAsync(order => @event.OrderIds.Contains(order.Id), order => + new OrderEntity + { + Id = order.Id, + // 因素 + CargoType = order.CargoType, + CreateTime = order.CreateTime, + ArrivalCountry = order.ArrivalCountry, + ArrivalProvince = order.ArrivalProvince, + ArrivalCity = order.ArrivalCity, + ArrivalPostCode = order.ArrivalPostCode, + IsTransit = order.IsTransit, + LeavePort = order.LeavePort, + ProductCode = order.ProductCode, + }); + + if (orders.Count == 0) + { + LogHelper.Warn($"没有找到订单信息:{@event.OrderIds.JoinAsString(",")},无法做轨迹预警计算"); + return; + } + + // 预警计算 + await _forewarningNotifyService.WarningCalculateAsync(BuiltWarningDto(orders, @event)); + } + + private WarningDto BuiltWarningDto(List orders, TrackWarningCalcEvent @event) + { + return new WarningDto + { + TrackStatusId = @event.TrackStatusId, + SubSystemId = @event.SubSystemId, + CustomerId = @event.CustomId, + Orders = orders.Select(order => new WarningOrderDto + { + Id = order.Id, + OrderNo = order.OrderNo, + TrackTime = @event.TrackTime, + CargoType = order.CargoType, + Month = order.CreateTime.Month, + IsTransit = order.IsTransit, + LeavePort = order.LeavePort, + ProductCode = order.ProductCode, + ArrivalCountry = order.ArrivalCountry, + ArrivalProvince = order.ArrivalProvince, + ArrivalCity = order.ArrivalCity, + ArrivalPostCode = order.ArrivalPostCode, + }).ToList() + }; + } +} diff --git a/src/SJZY.Track.Application/CAP/LoggerExtensions.cs b/src/SJZY.Track.Application/CAP/LoggerExtensions.cs index 8b430825..1cefe77b 100644 --- a/src/SJZY.Track.Application/CAP/LoggerExtensions.cs +++ b/src/SJZY.Track.Application/CAP/LoggerExtensions.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging; namespace SJZY.Track.Application.CAP; @@ -86,4 +86,4 @@ internal static class LoggerExtensions { logger.LogWarning(ex, $"Expected an OperationCanceledException, but found '{ex.Message}'."); } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/CAP/MySubscribeExecutor.cs b/src/SJZY.Track.Application/CAP/MySubscribeExecutor.cs index c9ff478b..39412572 100644 --- a/src/SJZY.Track.Application/CAP/MySubscribeExecutor.cs +++ b/src/SJZY.Track.Application/CAP/MySubscribeExecutor.cs @@ -1,4 +1,4 @@ -using System.Diagnostics; +using System.Diagnostics; using System.Reflection; using DotNetCore.CAP; using DotNetCore.CAP.Diagnostics; @@ -265,4 +265,4 @@ public class MySubscribeExecutor : ISubscribeExecutor } #endregion -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/CAP/SubscriberExecutionFailedException.cs b/src/SJZY.Track.Application/CAP/SubscriberExecutionFailedException.cs index 31b183af..567f5a9e 100644 --- a/src/SJZY.Track.Application/CAP/SubscriberExecutionFailedException.cs +++ b/src/SJZY.Track.Application/CAP/SubscriberExecutionFailedException.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Application.CAP; +namespace SJZY.Track.Application.CAP; internal class SubscriberExecutionFailedException : Exception { @@ -12,4 +12,4 @@ internal class SubscriberExecutionFailedException : Exception public override string? StackTrace => _originException.StackTrace; public override string? Source => _originException.Source; -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/FodyWeavers.xml b/src/SJZY.Track.Application/FodyWeavers.xml new file mode 100644 index 00000000..510b255f --- /dev/null +++ b/src/SJZY.Track.Application/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + diff --git a/src/SJZY.Track.Application/FodyWeavers.xsd b/src/SJZY.Track.Application/FodyWeavers.xsd new file mode 100644 index 00000000..f35a69b7 --- /dev/null +++ b/src/SJZY.Track.Application/FodyWeavers.xsd @@ -0,0 +1,26 @@ + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/src/SJZY.Track.Application/GlobalUsing.cs b/src/SJZY.Track.Application/GlobalUsings.cs similarity index 69% rename from src/SJZY.Track.Application/GlobalUsing.cs rename to src/SJZY.Track.Application/GlobalUsings.cs index e4968bf8..5f9509fe 100644 --- a/src/SJZY.Track.Application/GlobalUsing.cs +++ b/src/SJZY.Track.Application/GlobalUsings.cs @@ -1,8 +1,9 @@ -global using Microsoft.AspNetCore.Mvc; +global using SJZY.Track.Domain.Consts; +global using Microsoft.AspNetCore.Mvc; global using Microsoft.Extensions.DependencyInjection; global using SJZY.Expand.ABP.Common.Enums; global using SJZY.Expand.ABP.Core.Common.Dto; +global using SJZY.Track.Domain; global using Volo.Abp; global using Volo.Abp.Application.Services; global using Volo.Abp.Validation; -global using SJZY.Track.Domain; \ No newline at end of file diff --git a/src/SJZY.Track.Application/Helpers/Base64Helper.cs b/src/SJZY.Track.Application/Helpers/Base64Helper.cs index 4cc20d25..1a94a5ac 100644 --- a/src/SJZY.Track.Application/Helpers/Base64Helper.cs +++ b/src/SJZY.Track.Application/Helpers/Base64Helper.cs @@ -1,4 +1,4 @@ -using System.Text; +using System.Text; using Newtonsoft.Json; namespace SJZY.Track.Application.Helpers; @@ -30,4 +30,4 @@ public class Base64Helper return JsonConvert.DeserializeObject(Encoding.UTF8.GetString(bytes)); } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/Helpers/DateTimeHelper.cs b/src/SJZY.Track.Application/Helpers/DateTimeHelper.cs new file mode 100644 index 00000000..dff48044 --- /dev/null +++ b/src/SJZY.Track.Application/Helpers/DateTimeHelper.cs @@ -0,0 +1,58 @@ +namespace SJZY.Track.Application.Helpers; + +public static class DateTimeHelper +{ + /// + /// convert to a Unix timestamp from a DateTime object. + /// + /// The DateTime object to convert to a Unix timestamp. + /// The Unix timestamp as a long. + public static long ConvertToUnixTimestamp(DateTime dateTime) + { + return new DateTimeOffset(dateTime).ToUnixTimeSeconds(); + } + + /// + /// Formats a DateTime object into a specified format. + /// + /// The DateTime object to format. + /// The format string. + /// The formatted date string. + public static string FormatDateTime(DateTime dateTime, string format) + { + return dateTime.ToString(format); + } + + /// + /// 时区格式化 + /// + /// + /// + /// + public static string TimezoneFormat(double timezone, string format) + { + //时区是整数丢掉浮点数部分 + return format.Replace("hh", ((int) timezone).ToString()); + } + + /// + /// 转换主数据中心类似GMT-09:00这种的时区为浮点数 + /// + /// 分区 + /// + /// + public static float? ConvertTimeZoneToFloat(string timeZone) + { + if (string.IsNullOrEmpty(timeZone) || !timeZone.StartsWith("GMT")) + { + return null; + } + + var sign = timeZone[3] == '+' ? 1 : -1; + var parts = timeZone.Substring(4).Split(':'); + var hours = int.Parse(parts[0]); + var minutes = int.Parse(parts[1]); + + return sign * (hours + minutes / 60f); + } +} diff --git a/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs b/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs new file mode 100644 index 00000000..62243800 --- /dev/null +++ b/src/SJZY.Track.Application/Helpers/ForewarningHelper.cs @@ -0,0 +1,262 @@ +using System.Dynamic; +using Nest; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using SJZY.Expand.ABP.Core.PublicMethords; +using SJZY.Track.Application.Contract.Dtos.Forewarning; +using SJZY.Track.Domain.Aggregates.ForewarningAggregate; +using SJZY.Track.Domain.Dtos.Common; +using SJZY.Track.Domain.Dtos.Forewarning; +using SJZY.Track.Domain.Enums; + +namespace SJZY.Track.Application.Helpers; + +public class ForewarningHelper +{ + /// + /// 递推分裂预警规则列表 + /// + /// + /// + /// + public static List CalcRuleList(List statusSpans, + List factors) + { + if (statusSpans.Count == 0 || factors.Count == 0) + { + throw new BusinessException(message: "轨迹状态区间或因素列表为空"); + } + + var len = statusSpans.Count * factors.Select(f => f.FactorValue.Count).Aggregate((pre, cur) => pre * cur); + if (len == 0) + { + throw new BusinessException(message: "轨迹状态区间或因素列表为空"); + } + + var rules = Enumerable.Range(0, len).Select(_ => new WarningRuleEntity()).ToList(); + + var repeat = len / statusSpans.Count; + + FillStatus(statusSpans, rules, repeat); + + foreach (var factor in factors) + { + var factorValueCount = factor.FactorValue.Count; + + // repeat梯度下降,与times成反比关系 + repeat /= factorValueCount; + var times = len / repeat / factorValueCount; + FillFactor(factor, rules, repeat, times); + } + + + return rules; + } + + private static void FillStatus(List statusSpans, List rules, int repeat) + { + var row = 0; + foreach (var span in statusSpans) + { + for (var i = 0; i < repeat; i++, row++) + { + rules[row].StartTrackStatusId = span.StartTrackStatusId; + rules[row].StartTrackStatus = span.StartTrackStatus; + rules[row].EndTrackStatusId = span.EndTrackStatusId; + rules[row].EndTrackStatus = span.EndTrackStatus; + } + } + } + + private static void FillFactor(WarningFactorDto factor, List rules, int repeat, int times) + { + var row = 0; + for (var i = 0; i < times; i++) + { + foreach (var value in factor.FactorValue.Select(JToken.FromObject)) + { + var strValue = value.ToString(); + if (strValue.IsNullOrEmpty()) + { + throw new BusinessException(message: "因素值不能为空"); + } + + for (var j = 0; j < repeat; j++, row++) + { + switch ((RuleFactorType) factor.FactorType) + { + case RuleFactorType.CargoType: + if (value.Type is not JTokenType.String) + { + throw new BusinessException(message: "货物类型只接收字符串"); + } + + rules[row].CargoType = strValue; + break; + case RuleFactorType.Months: + foreach (var item in strValue.Split("/")) + { + if (!int.TryParse(item, out var month) || month < 1 || month > 12) + { + throw new BusinessException(message: "请输入合法的月份,多个月份请以'/'连接"); + } + } + + rules[row].Months = strValue; + break; + case RuleFactorType.Area: + if (value.Type is not JTokenType.Integer) + { + throw new BusinessException(message: "分区请传id"); + } + + rules[row].AreaId = int.Parse(strValue); + break; + case RuleFactorType.IsTransit: + if (value.Type is not JTokenType.Boolean) + { + throw new BusinessException(message: "是否中转只接收bool类型"); + } + + rules[row].IsTransit = bool.Parse(strValue); + break; + case RuleFactorType.LeavePort: + if (value.Type is not JTokenType.String) + { + throw new BusinessException(message: "起运港只接收字符串"); + } + + rules[row].LeavePort = strValue; + break; + case RuleFactorType.ProductCode: + if (value.Type is not JTokenType.String) + { + throw new BusinessException(message: "产品代码只接收字符串"); + } + + rules[row].ProductCode = strValue; + break; + default: + throw new BusinessException(message: $"不支持的因素:{factor.FactorType}"); + } + } + } + } + } + + public static List MapFactorEntities(List warningFactors) + { + return warningFactors.Select(x => new WarningFactorEntity + { + Type = (RuleFactorType) x.FactorType, + Value = x.FactorValue.ToJson() + }).ToList(); + } + + public static List MapNotifyEntities(CreateWarningInput input) + { + return input.TrackStatusSpans.Select(x => new WarningNotifyEntity + { + StartTrackStatusId = x.StartTrackStatusId, + EndTrackStatusId = x.EndTrackStatusId, + NotifyMode = x.NotifyModes.JoinAsString(","), + NotifyUser = x.NotifyUsers.ToJson(), + }).ToList(); + } + + public static EditWarningOutput MapWarningSummary(WarningEntity warning, List statusList, + List areaList) + { + var statusDic = statusList.ToDictionary(x => x.Id, x => x.Name); + var areaDic = areaList.ToDictionary(x => x.Id, x => x.Name); + return new EditWarningOutput + { + Name = warning.Name, + SubSystemId = warning.SubSystemId, + CustomerId = warning.CustomerId, + TrackStatusSpans = warning.WarningNotifies.Select(x => new WarningNotifyWithIdDto + { + Id = x.Id, + StartTrackStatusId = x.StartTrackStatusId, + StartTrackStatus = statusDic.TryGetValue(x.StartTrackStatusId, out var start) ? start : "", + EndTrackStatusId = x.EndTrackStatusId, + EndTrackStatus = statusDic.TryGetValue(x.EndTrackStatusId, out var end) ? end : "", + NotifyUsers = JsonConvert.DeserializeObject>(x.NotifyUser) ?? new List(), + NotifyModes = x.NotifyMode.IsNullOrWhiteSpace() + ? new List() + : x.NotifyMode.Split(',').Select(int.Parse).ToList(), + }).ToList(), + WarningFactors = warning.WarningFactors.Select(x => + { + if (x.Type == RuleFactorType.Area) + { + var areaIds = JsonConvert.DeserializeObject>(x.Value); + return new WarningFactorWithIdDto + { + Id = x.Id, + FactorType = (int) x.Type, + FactorValue = areaIds? + .Select(area => areaDic.TryGetValue(area, out var name) ? name : area.ToString()) + .Cast().ToList() ?? new List(), + }; + } + + return new WarningFactorWithIdDto + { + Id = x.Id, + FactorType = (int) x.Type, + FactorValue = JsonConvert.DeserializeObject>(x.Value)!, + }; + }).ToList() + }; + } + + public static List DynamicCalcRuleList(List rules, List factors) + { + var dynamicList = new List(); + + foreach (var rule in rules) + { + dynamic dynamicRule = new ExpandoObject(); + var dynamicRuleDict = (IDictionary) dynamicRule; + + dynamicRuleDict[nameof(Id)] = rule.Id; + dynamicRuleDict[nameof(rule.StartTrackStatus)] = rule.StartTrackStatus; + dynamicRuleDict[nameof(rule.EndTrackStatus)] = rule.EndTrackStatus; + + foreach (var factor in factors) + { + switch (factor) + { + case RuleFactorType.CargoType: + dynamicRuleDict[nameof(rule.CargoType)] = rule.CargoType; + break; + case RuleFactorType.Months: + dynamicRuleDict[nameof(rule.Months)] = rule.Months; + break; + case RuleFactorType.Area: + dynamicRuleDict[nameof(rule.Area)] = rule.Area; + break; + case RuleFactorType.IsTransit: + dynamicRuleDict[nameof(rule.IsTransit)] = rule.IsTransit; + break; + case RuleFactorType.LeavePort: + dynamicRuleDict[nameof(rule.LeavePort)] = rule.LeavePort; + break; + case RuleFactorType.ProductCode: + dynamicRuleDict[nameof(rule.ProductCode)] = rule.ProductCode; + break; + default: + throw new BusinessException(message: $"不支持的因素:{factor}"); + } + } + + dynamicRuleDict[nameof(rule.TotalTimeSpan)] = rule.TotalTimeSpan; + dynamicRuleDict[nameof(rule.WarnTimeSpan)] = rule.WarnTimeSpan; + dynamicRuleDict[nameof(rule.WarnCount)] = rule.WarnCount; + dynamicList.Add(dynamicRule); + } + + return dynamicList; + } +} diff --git a/src/SJZY.Track.Application/Helpers/StringHelper.cs b/src/SJZY.Track.Application/Helpers/StringHelper.cs new file mode 100644 index 00000000..32fca43e --- /dev/null +++ b/src/SJZY.Track.Application/Helpers/StringHelper.cs @@ -0,0 +1,49 @@ +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; + +namespace SJZY.Track.Application.Helpers; + +public class StringHelper +{ + /// + /// 只能输入英文字符和键盘上常用的符号 + /// + /// + /// + public static bool IsValidEnglishString(string input) + { + if (string.IsNullOrEmpty(input)) + { + return false; + } + + // Regular expression to match only English letters and specified symbols + var regex = new Regex(@"^[a-zA-Z\(\)@!#$%^&*_\-+=;:""'/><,.\s]+$"); + return regex.IsMatch(input); + } + + + /// 获取字符串的hash值 + /// + /// + public static string GetHash(string str) + { + // 将字符串转换为字节 + byte[] data = Encoding.UTF8.GetBytes(str); + + // 创建SHA256实例 + using SHA256 sha256 = SHA256.Create(); + // 计算哈希值 + byte[] hash = sha256.ComputeHash(data); + + // 将哈希值转换为16进制字符串 + StringBuilder sb = new StringBuilder(); + foreach (byte b in hash) + { + sb.Append(b.ToString("x2")); + } + + return sb.ToString(); + } +} diff --git a/src/SJZY.Track.Application/Helpers/TextJsonHelper.cs b/src/SJZY.Track.Application/Helpers/TextJsonHelper.cs new file mode 100644 index 00000000..306e22e2 --- /dev/null +++ b/src/SJZY.Track.Application/Helpers/TextJsonHelper.cs @@ -0,0 +1,181 @@ +using System.Globalization; +using System.Text.Json; + +namespace SJZY.Track.Application.Helpers; + +/// +/// 针对 Text.Json 的一些辅助方法 +/// +public static class TextJsonHelper +{ + public static string? Serialize(object? obj) + { + return obj == null ? default : System.Text.Json.JsonSerializer.Serialize(obj); + } + + public static T? Deserialize(string? json) + { + return string.IsNullOrWhiteSpace(json) ? default : System.Text.Json.JsonSerializer.Deserialize(json); + } + + public static Dictionary? DeserializeToDictionary(string? dictJsonString) + { + return string.IsNullOrWhiteSpace(dictJsonString) + ? null + : System.Text.Json.JsonSerializer.Deserialize>(dictJsonString); + } + + public static JsonElement? DeserializeToJsonElement(string? dictJsonString) + { + return string.IsNullOrWhiteSpace(dictJsonString) + ? null + : System.Text.Json.JsonSerializer.Deserialize(dictJsonString); + } + + /// + /// 获取JsonElement字符串表达的值 + /// + /// + /// + public static string? GetString(object? el) + { + if (el is not JsonElement jsonElement) + return default; + return jsonElement.ValueKind switch + { + JsonValueKind.Undefined or JsonValueKind.Null => default, + JsonValueKind.True or JsonValueKind.False => jsonElement.GetBoolean().ToString(), + JsonValueKind.Object or JsonValueKind.Array or JsonValueKind.Number => jsonElement.GetRawText(), + JsonValueKind.String => jsonElement.GetString(), + _ => default + }; + } + + /// + /// 提取字典字符串中某个字段的值 + /// + /// 字典json字符串 + /// + /// + public static object? ExtractValue(string? dictString, string fieldName) + { + if (string.IsNullOrWhiteSpace(dictString)) + { + return null; + } + + var dict = System.Text.Json.JsonSerializer.Deserialize>(dictString); + if (dict == null || !dict.TryGetValue(fieldName, out var value)) + { + return null; + } + + return value; + } + + /// + /// 两个jsonElement进行比较 + /// + /// + /// + /// + public static bool EqJsonElement(object? a, object? b) + { + if (a == null && b == null) + { + return true; + } + + if (a is JsonElement aJsonElement && b is JsonElement bJsonElement) + { + return aJsonElement.ToString() == bJsonElement.ToString(); + } + + return false; + } + + /// + /// jsonElement和object之间的比较 + /// + /// + /// + /// + public static bool EqJsonElementAndObject(object? jsonElement, object? obj) + { + if (jsonElement == null && obj == null) + { + return true; + } + + if (jsonElement is JsonElement aJsonElement) + { + switch (aJsonElement.ValueKind) + { + case JsonValueKind.Undefined: + return false; + case JsonValueKind.Object: + return false; + case JsonValueKind.Array: + return false; + case JsonValueKind.String: + return string.Equals(aJsonElement.GetString(), obj as string); + case JsonValueKind.Number: + { + if (obj == null) return false; + + if (obj is int bInt) + { + var aInt = aJsonElement.GetInt32(); + return aInt == bInt; + } + + if (obj is long bLong) + { + var aLong = aJsonElement.GetInt64(); + return aLong == bLong; + } + + return false; + } + case JsonValueKind.True: + case JsonValueKind.False: + { + if (obj is bool bl) + { + return aJsonElement.GetBoolean() == bl; + } + + return false; + } + case JsonValueKind.Null: + { + return false; + } + } + } + + return false; + } + + + /// + /// 比较两个jsonElement中的的fieldName字段的值 + /// + /// + /// + /// + /// + public static bool EqByJsonElementField(object? a, object? b, string fieldName) + { + if (a is not JsonElement aJsonElement || b is not JsonElement bJsonElement) + return false; + + if (aJsonElement.TryGetProperty(fieldName, out var aValue) + && bJsonElement.TryGetProperty(fieldName, out var bValue)) + { + return aValue.ToString() == bValue.ToString(); + } + + return false; + } +} diff --git a/src/SJZY.Track.Application/HostServices/RedisHostService.cs b/src/SJZY.Track.Application/HostServices/RedisHostService.cs new file mode 100644 index 00000000..d86c9ed4 --- /dev/null +++ b/src/SJZY.Track.Application/HostServices/RedisHostService.cs @@ -0,0 +1,49 @@ +using Microsoft.Extensions.Hosting; +using SJZY.Expand.ABP.Core; +using SJZY.Track.Application.Contract.Events; +using SJZY.Track.Application.Contract.Services; + +namespace SJZY.Track.Application.HostServices; + +public class RedisHostService : IHostedService +{ + readonly IForewarningCacheService _forewarningCacheService; + + public RedisHostService(IForewarningCacheService forewarningCacheService) + { + _forewarningCacheService = forewarningCacheService; + } + + // todo:redis一旦重启,订阅的频道就会丢失,需要重新订阅 + public Task StartAsync(CancellationToken cancellationToken) + { + // 订阅频道 + RedisHelper.Client.Subscribe(GetKey(), Subscribe); + return Task.CompletedTask; + } + + public Task StopAsync(CancellationToken cancellationToken) + { + RedisHelper.Client.UnSubscribe(GetKey()); + return Task.CompletedTask; + } + + private void Subscribe(string message, object value) + { + if (value is string str) + { + // 暂时只处理一个事件,不做反序列化 + //var instance = Newtonsoft.Json.JsonConvert.DeserializeObject(value as string); + var instance = Newtonsoft.Json.JsonConvert.DeserializeObject(str); + if (instance != null) + { + _forewarningCacheService.Clear(instance); + } + } + } + + private string GetKey() + { + return $"{GlobalConst.PublishNotifyChannelKey}"; + } +} diff --git a/src/SJZY.Track.Application/Localization/Resources/en.json b/src/SJZY.Track.Application/Localization/Resources/en.json index c7d369bc..dd092982 100644 --- a/src/SJZY.Track.Application/Localization/Resources/en.json +++ b/src/SJZY.Track.Application/Localization/Resources/en.json @@ -10,6 +10,7 @@ "TrackFlagExist": "Duplicate code or flag in the current subsystem", "IsExistTrackPullConfig": "Track Pull The template has been bound. Delete the track pull before deleting the template", "IsExistTrackStatus": "The trajectory content has been bound to the trajectory status. Delete the trajectory content before deleting the trajectory status", - "IsExistTrackFlag": "The track content has been bound to the track mark. Delete the track content before deleting the track mark" + "IsExistTrackFlag": "The track content has been bound to the track mark. Delete the track content before deleting the track mark", + "IsTrackPushConfigAny": "This subsystem already has the push mapping of this customer, and it cannot be added repeatedly" } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/Localization/Resources/zh.json b/src/SJZY.Track.Application/Localization/Resources/zh.json index 38db9ebb..b33ac103 100644 --- a/src/SJZY.Track.Application/Localization/Resources/zh.json +++ b/src/SJZY.Track.Application/Localization/Resources/zh.json @@ -10,6 +10,7 @@ "TrackFlagExist": "当前子系统下代码或标记重复", "IsExistTrackPullConfig": "轨迹拉取已绑定了该模版,请先删除轨迹拉取再删除该模版", "IsExistTrackStatus": "轨迹内容已经绑定了该轨迹状态,请先删除轨迹内容后再删除该轨迹状态", - "IsExistTrackFlag": "轨迹内容已经绑定了该轨迹标记,请先删除轨迹内容后再删除该轨迹标记" + "IsExistTrackFlag": "轨迹内容已经绑定了该轨迹标记,请先删除轨迹内容后再删除该轨迹标记", + "IsTrackPushConfigAny": "这个子系统已经存在这个客户的推送映射,无法重复添加" } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/Localization/TrackLocalizationResource.cs b/src/SJZY.Track.Application/Localization/TrackLocalizationResource.cs index 70e2cea5..6be5b4e4 100644 --- a/src/SJZY.Track.Application/Localization/TrackLocalizationResource.cs +++ b/src/SJZY.Track.Application/Localization/TrackLocalizationResource.cs @@ -1,10 +1,9 @@ -using SJZY.Expand.ABP.Core.Localization; +using SJZY.Expand.ABP.Core.Localization; using Volo.Abp.Localization; -namespace SJZY.Track.Application.Localization +namespace SJZY.Track.Application.Localization; + +[InheritResource(typeof(SjzyBasicLocalization))] +public class TrackLocalizationResource { - [InheritResource(typeof(SjzyBasicLocalization))] - public class TrackLocalizationResource - { - } } diff --git a/src/SJZY.Track.Application/Options/CustomeOptions.cs b/src/SJZY.Track.Application/Options/CustomeOptions.cs deleted file mode 100644 index 39f20d96..00000000 --- a/src/SJZY.Track.Application/Options/CustomeOptions.cs +++ /dev/null @@ -1,10 +0,0 @@ -using SJZY.Expand.ABP.Core; - -namespace SJZY.Track.Application.Options -{ - public class CustomeOptions : IOptionAutoInjection - { - public int Setting1 { get; set; } - public int Setting2 { get; set; } - } -} diff --git a/src/SJZY.Track.Application/Options/InterfaceRelayParamsConfigOptions.cs b/src/SJZY.Track.Application/Options/InterfaceRelayParamsConfigOptions.cs new file mode 100644 index 00000000..e2a3d78e --- /dev/null +++ b/src/SJZY.Track.Application/Options/InterfaceRelayParamsConfigOptions.cs @@ -0,0 +1,74 @@ +namespace SJZY.Track.Application.Options; + +public class InterfaceRelayParamsConfigOptions +{ + /// + /// 订单路径 + /// + public string OrderPath { get; set; } = null!; + + /// + /// 单号参数名 + /// + public string OrderNoName { get; set; } = null!; + + /// + /// 轨迹明细路径 + /// + public string TrackDetailsPath { get; set; } = null!; + + /// + /// 轨迹代码参数名 + /// + public string TrackContentCodeName { get; set; } + + /// + /// 轨迹状态参数名 + /// + public string TrackStatusName { get; set; } + + /// + /// 轨迹内容参数名 + /// + public string TrackContentName { get; set; } + + /// + /// 轨迹发生地参数名 + /// + public string TrackPlaceName { get; set; } + + /// + /// 轨迹发生时间参数名 + /// + public string TrackTimeName { get; set; } + + /// + /// 轨迹时区参数名 + /// + public string TrackTimeZoneName { get; set; } + + /// + /// 获取轨迹接口代码 + /// + public string GetTrackInterfaceCode { get; set; } + + /// + /// 推送轨迹接口代码 + /// + public string PushTrackInterfaceCode { get; set; } + + /// + /// 推送轨迹接口Id + /// + public int PushTrackInterfaceId { get; set; } + + /// + /// 推送轨迹接口 内容项 参数别名前缀 + /// + public string PushTrackItemParamAliasPrefix { get; set; } + + /// + /// 更新轨迹接口代码 + /// + public string TrackUpdateInterfaceCode { get; set; } +} diff --git a/src/SJZY.Track.Application/Options/TrackAppOptions.cs b/src/SJZY.Track.Application/Options/TrackAppOptions.cs new file mode 100644 index 00000000..12b93bf8 --- /dev/null +++ b/src/SJZY.Track.Application/Options/TrackAppOptions.cs @@ -0,0 +1,24 @@ +namespace SJZY.Track.Application.Options; + +public class TrackAppOptions +{ + /// + /// 轨迹刷新并发度 + /// + public int TrackRefreshFetchCount { get; set; } + + /// + /// 订单拉取状态扫描间隔(秒) + /// + public int OrderPullStatusScanInterval { get; set; } + + /// + /// 轨迹兜底扫描间隔(秒) + /// + public int TrackButtomUpScanInterval { get; set; } + + /// + /// 轨迹运输时效预警通知跳转地址 + /// + public string WarningNotifyUrl { get; set; } +} diff --git a/src/SJZY.Track.Application/Rabbit/TrackPushCompletedEventHandler.cs b/src/SJZY.Track.Application/Rabbit/TrackPushCompletedEventHandler.cs new file mode 100644 index 00000000..11be63aa --- /dev/null +++ b/src/SJZY.Track.Application/Rabbit/TrackPushCompletedEventHandler.cs @@ -0,0 +1,146 @@ +using System.Text; +using BSI.Stack.Rabbit; +using BSI.Stack.Rabbit.Handler; +using Newtonsoft.Json; +using RabbitMQ.Client.Events; +using SJZY.Expand.ABP.Core.Logger; +using SJZY.InterfaceRelay.Application.Contracts; +using SJZY.Track.Application.Contract.Dtos.TrackPush; +using SJZY.Track.Application.Contract.Services; +using SJZY.Track.Application.Helpers; +using SJZY.Track.Domain.Aggregates.OrderAggregate; +using SJZY.Track.Domain.Aggregates.TrackPushAggregate; +using SJZY.Track.Domain.Enums; +using Volo.Abp.DependencyInjection; + +namespace SJZY.Track.Application.Rabbit; + +public class TrackPushCompletedEventHandler : ITransientDependency, IRabbitHandler +{ + private readonly IOrderRepository _orderRepository; + private readonly ITrackPushRecordEsRepository _trackPushRecordEsRepository; + private readonly IBroadcastingService _broadcastingService; + + public TrackPushCompletedEventHandler(IOrderRepository orderRepository, + ITrackPushRecordEsRepository trackPushRecordEsRepository, + IBroadcastingService broadcastingService) + { + _orderRepository = orderRepository; + _trackPushRecordEsRepository = trackPushRecordEsRepository; + _broadcastingService = broadcastingService; + } + + public ConsumeOptions Options() + { + return new ConsumeOptions() + { + Queue = GlobalConst.TrackPushCompletedSubscribe + }; + } + + public async Task Handle(IServiceProvider sp, BasicDeliverEventArgs args, ConsumeOptions options) + { + var msg = Encoding.UTF8.GetString(args.Body.ToArray()); + var @event = System.Text.Json.JsonSerializer.Deserialize(msg); + if (@event == null) + { + LogHelper.Warn( + $"rabbit on queue({options.Queue}) received msg can't convert to {nameof(InterfaceRelayForwardReplayEvent)}"); + return; + } + + string? logStr = null; + var optionType = Base64Helper.DeSerialize(@event.Attach); + if (optionType == OptionType.新增.ToString()) + { + logStr = JsonConvert.DeserializeObject>(@event.RequestParams)!.First().Log; + } + else if (optionType == OptionType.修改.ToString()) + { + logStr = JsonConvert.DeserializeObject>(@event.RequestParams)!.First().Log; + } + + if (logStr.IsNullOrEmpty()) throw new InvalidOperationException(); + var log = JsonConvert.DeserializeObject(logStr!); + + if (log == null) throw new BusinessException(message: "轨迹推送返回结果解析异常"); + log.IsSuccess = @event.IsSuccess; + log.Message = @event.Message; + log.RequestId = @event.RequestId; + + // 推送广播 + if (log.IsToMq) + _broadcastingService.TrackPushCompletedPublicTopic(BuildDto(log)); + + // 往es 写推送日志 + await _trackPushRecordEsRepository.AddAsync(log); + + // 同步去更新订单主表 + await TrackPushAfterUpdateOrderAsync(log); + } + + private async Task TrackPushAfterUpdateOrderAsync(TrackPushRecordIndex log) + { + // tips:只有新增会影响推送进度? + if (log.OptionType != OptionType.新增.ToString()) return; + + var order = new OrderEntity + { + Id = log.OrderId + }; + + /* + * 异常:最近一条推送是失败 + */ + if (!log.IsSuccess) + { + order.QuestionType = (int) TrackProblemType.Error; + order.LatestPushError = log.Message; + await _orderRepository.UpdateColumnAsync(order, x => new + { + x.QuestionType, + x.LatestPushError + }); + } + else + { + // 还原成正常态 + order.QuestionType = (int) TrackProblemType.None; + order.LatestPushError = null; + order.LatestPushTrackCode = log.TrackCode; + order.LatestPushTime = log.CreateTime; + await _orderRepository.UpdateColumnAsync(order, + x => new + { + x.LatestPushTrackCode, + x.LatestPushTime, + x.QuestionType, + x.LatestPushError + }); + } + } + + private TrackPushRecordDto BuildDto(TrackPushRecordIndex log) + { + return new TrackPushRecordDto + { + SubSystemCode = log.SubSystemCode, + RequestId = log.RequestId, + IsSuccess = log.IsSuccess, + Message = log.Message, + OperationMan = log.CreateUser, + PushTime = DateTime.Now, + OptionType = log.OptionType, + IsManualPush = !string.Equals(log.CreateUser, GlobalConst.SystemUser), //操作人不为系统用户,则认为是仍推送 + PushContent = log.PushContent, + OrderNo = log.OrderNo, + TrackStatus = log.TrackStatus, + TrackContent = log.TrackContent, + TrackTimeZone = log.TrackTimeZone, + TrackTime = log.TrackTime, + TrackPlace = log.TrackPlace, + TrackCode = log.TrackCode, + Extra = log.Extra + }; + } +} diff --git a/src/SJZY.Track.Application/Rabbit/TrackRefreshEventHandler.cs b/src/SJZY.Track.Application/Rabbit/TrackRefreshEventHandler.cs new file mode 100644 index 00000000..2903eb5e --- /dev/null +++ b/src/SJZY.Track.Application/Rabbit/TrackRefreshEventHandler.cs @@ -0,0 +1,336 @@ +using System.Diagnostics; +using System.Text; +using BSI.Stack.Rabbit; +using BSI.Stack.Rabbit.Handler; +using DotNetCore.CAP; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using RabbitMQ.Client.Events; +using SJZY.Expand.ABP.Core.PublicMethords; +using SJZY.InterfaceRelay.Application.Contracts; +using SJZY.Track.Application.Contract.Dtos.TrackPull; +using SJZY.Track.Application.Contract.Events; +using SJZY.Track.Application.Contract.Services; +using SJZY.Track.Application.Helpers; +using SJZY.Track.Domain.Aggregates.OrderAggregate; +using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; +using SJZY.Track.Domain.Enums; +using Volo.Abp.DependencyInjection; + +namespace SJZY.Track.Application.Rabbit; + +public class TrackRefreshEventHandler : ITransientDependency, IRabbitHandler +{ + private readonly ICapPublisher _capPublisher; + private readonly ILogger _logger; + private readonly IOrderRepository _orderRepository; + private readonly ITrackDetailsEsRepository _trackDetailsEsRepository; + private readonly ITrackPullCacheService _trackPullCacheService; + + public TrackRefreshEventHandler(IOrderRepository orderRepository, + ICapPublisher capPublisher, ITrackPullCacheService trackPullCacheService, + ITrackDetailsEsRepository trackDetailsEsRepository, + ILogger logger) + { + _orderRepository = orderRepository; + _capPublisher = capPublisher; + _trackPullCacheService = trackPullCacheService; + _trackDetailsEsRepository = trackDetailsEsRepository; + _logger = logger; + } + + public ConsumeOptions Options() + { + return new ConsumeOptions() + { + Queue = GlobalConst.TrackRefreshSubscribe, + }; + } + + public async Task Handle(IServiceProvider sp, BasicDeliverEventArgs args, ConsumeOptions options) + { + var msg = Encoding.UTF8.GetString(args.Body.ToArray()); + var @event = System.Text.Json.JsonSerializer.Deserialize(msg); + if (@event == null) + { + _logger.LogWarning( + $"rabbit on queue({options.Queue}) received msg can't convert to {nameof(InterfaceRelayForwardReplayEvent)}"); + return; + } + + await ConsumerAsync(@event); + } + + public async Task ConsumerAsync(InterfaceRelayForwardReplayEvent @event) + { + if (!@event.IsSuccess) + { + _logger.LogWarning("请求id: {@RequestId},轨迹刷新失败", @event.RequestId); + return; + } + + var attach = Base64Helper.DeSerialize(@event.Attach); + if (attach is null || @event.Data == null) + { + _logger.LogWarning("请求id: {@RequestId},轨迹消费失败,attach或data解析为空", @event.RequestId); + return; + } + + var config = await _trackPullCacheService.GetPullParamsWithContentAsync(attach.SubSystemId, + attach.ServiceProviderCode); + if (config == null) + { + _logger.LogWarning("请求id: {@RequestId},轨迹消费失败,找不到拉取配置:{@Attach}", attach.ToJson(), @event.RequestId); + return; + } + + var data = JObject.Parse(@event.Data); + + var orderToken = data.SelectToken(config.ParamConfig.OrderPath); + if (orderToken is JArray orderTokens) + { + foreach (var token in orderTokens) + { + await HandleOrderAsync(token, config, attach); + } + } + else if (orderToken is JObject) + { + await HandleOrderAsync(orderToken, config, attach); + } + } + + private async Task HandleOrderAsync(JToken orderToken, TrackPullParamsWithContentDto paramsWithContent, + TrackRefreshAttach attach) + { + var paramConfig = paramsWithContent.ParamConfig; + var orderNo = orderToken[paramConfig.OrderNoName]?.Value(); + if (orderNo.IsNullOrWhiteSpace()) return; + + var trackToken = orderToken.SelectToken(paramConfig.TrackDetailsPath); + if (trackToken is null) return; + + //回传单号可能是主单也可能是外部单号 + //通过平台code和(外部单号/主单号)查询主单 + var order = await _orderRepository.GetTrackOrderByProviderAndOrderNo(attach.ServiceProviderCode, orderNo!); + if (order == default) + { + _logger.LogError($"请求id: {attach.ToJson()},轨迹消费失败,找不到主单,平台code:{attach.ServiceProviderCode},单号:{orderNo}"); + return; + } + + var context = new TrackRefreshContext + { + OrderId = order.MainOrderId, + OrderType = attach.OrderType, + OrderNo = orderNo!, + ServiceProviderCode = attach.ServiceProviderCode, + CustomId = order.CustomId, + SubSystemId = attach.SubSystemId + }; + + + if (trackToken is JArray trackTokens) + { + foreach (var item in trackTokens) + { + await HandleTrackAsync(item, paramsWithContent, context); + } + } + else if (trackToken is JObject) + { + await HandleTrackAsync(trackToken, paramsWithContent, context); + } + } + + private async Task HandleTrackAsync(JToken trackToken, TrackPullParamsWithContentDto paramsWithContent, + TrackRefreshContext context) + { + var originTrackDataHash = StringHelper.GetHash(JsonConvert.SerializeObject(trackToken)); + // 如果已经存在一模一样的报文了说明处理过了,直接return + if (await _trackDetailsEsRepository.AnyAsync(context.OrderId, originTrackDataHash)) + { + return; + } + + var paramConfig = paramsWithContent.ParamConfig; + var contentConfigs = paramsWithContent.ContentConfigs; + TrackPullContentConfigDto? matchedContentConfig = null; + + // 轨迹内容 + var trackContent = paramConfig.TrackContentName == null + ? null + : trackToken[paramConfig.TrackContentName]?.Value(); + + // 1、匹配轨迹代码 + + // 2、匹配轨迹状态 + if (matchedContentConfig == null && !paramConfig.TrackStatusName.IsNullOrWhiteSpace()) + { + var trackStatus = trackToken[paramConfig.TrackStatusName!]?.Value(); + if (!trackStatus.IsNullOrWhiteSpace()) + { + matchedContentConfig = contentConfigs.FirstOrDefault(x => x.TrackStatusValues.Contains(trackStatus!)); + } + } + + // 3、匹配轨迹内容 + if (matchedContentConfig == null && !paramConfig.TrackContentName.IsNullOrWhiteSpace()) + { + if (!trackContent.IsNullOrWhiteSpace()) + { + Debug.Assert(trackContent != null, nameof(trackContent) + " != null"); + // 3.1 按内容直接匹配 + + // 3.2 按关键字分析轨迹内容 + foreach (var contentConfig in contentConfigs) + { + foreach (var keyword in contentConfig.TrackKeywords) + { + if (trackContent.Contains(keyword, StringComparison.OrdinalIgnoreCase)) + { + matchedContentConfig = contentConfig; + break; + } + } + + if (matchedContentConfig is null) continue; + + foreach (var keyword in contentConfig.TrackKeywordReverses) + { + if (trackContent.Contains(keyword, StringComparison.OrdinalIgnoreCase)) + { + matchedContentConfig = null; + break; + } + } + + if (matchedContentConfig is not null) break; // 找到匹配的,跳出循环 + } + } + } + + // 轨迹发生时间 + var trackTime = paramConfig.TrackTimeName == null + ? null + : trackToken[paramConfig.TrackTimeName]?.Value(); + // 轨迹发生时区 + var trackTimeZone = paramConfig.TrackTimeZoneName == null + ? null + : trackToken[paramConfig.TrackTimeZoneName]?.Value(); + // 轨迹发生地 + var trackPlace = paramConfig.TrackPlaceName == null + ? null + : trackToken[paramConfig.TrackPlaceName]?.Value(); + + + if (matchedContentConfig is null) + { + _logger.LogDebug("订单号:{OrderNo},未匹配到轨迹内容,轨迹报文:{TrackContent}", + context.OrderNo, trackToken.ToString()); + await InsertNotMappedTrackAsync(trackToken, context, trackPlace, trackTime, trackTimeZone, trackContent); + return; + } + + // 新增/更新轨迹 + var trackUpsertEvent = new TrackUpsertEvent + { + OrderIdentifiers = + new[] + { + new OrderIdentifier + { + OrderId = context.OrderId, + OrderNo = context.OrderNo, + OrderType = context.OrderType, + } + }, + TrackRefreshData = new TrackRefreshStruct + { + ServiceProviderCode = context.ServiceProviderCode, + OriginTrackDataHash = originTrackDataHash, + OriginTrackContent = trackContent ?? GlobalConst.EmptyString, + }, + SubSystemId = context.SubSystemId, + CustomId = context.CustomId, + TrackCode = matchedContentConfig.TrackContentCode, + TrackPlace = trackPlace ?? GlobalConst.EmptyString, + TrackTime = trackTime ?? DateTime.Now, + TrackTimeZone = trackTimeZone ?? GlobalConst.NoneTrackTimeZone, + IsAdd = true, + //S06新增 + IsVisibility = false, + //服务商轨迹默认不对外 + IsExternal = false, + Source = (int) TrackSourceEnum.ExternalServiceProvide, + Remarks = null, + Files = null, + Content = null, + EnStatus = null, + TrackPlaceCity = null, + TrackPlaceCityId = null, + TrackPlaceProvince = null, + TrackPlaceProvinceId = null, + TrackPlaceNation = null, + TrackPlaceNationId = null, + TrackPlacePostcode = null, + DestinationTimeZone = null, + EstimatedDeliveryDate = null, + }; + + await _capPublisher.PublishAsync(GlobalConst.TrackUpsertForRefreshSubscribe, trackUpsertEvent); + } + + private async Task InsertNotMappedTrackAsync(JToken trackToken, TrackRefreshContext context, string? trackPlace, + DateTime? trackTime, float? trackTimeZone, string? trackContent) + { + // 新增服务商轨迹到es + var track = new TrackDetailsIndex + { + IndexName = $"{GlobalConst.TrackDetailsIndex}-{DateTime.Now:yyyy.MM.dd}", + SubSystemId = context.SubSystemId, + OrderId = context.OrderId, + OrderType = context.OrderType, + OrderNo = context.OrderNo, + TrackPlace = trackPlace ?? GlobalConst.EmptyString, + TrackTime = trackTime ?? DateTime.Now, + TrackTimeZone = trackTimeZone ?? GlobalConst.NoneTrackTimeZone, + ServiceProviderCode = context.ServiceProviderCode, + OriginTrackDataHash = StringHelper.GetHash(JsonConvert.SerializeObject(trackToken)), + OriginTrackContent = trackContent ?? GlobalConst.EmptyString, + CreateUser = GlobalConst.SystemUser, + CreateTime = DateTime.Now, + //来源轨迹内容,第一次新增的时候使用轨迹内容表提供的 + TrackStatusId = GlobalConst.NotExistId, + TrackStatus = GlobalConst.EmptyString, + TrackStatusCode = GlobalConst.EmptyString, + TrackContentId = GlobalConst.NotExistId, + TrackContent = GlobalConst.EmptyString, + TrackEnContent = GlobalConst.EmptyString, + //S06新增轨迹明细字段 + IsVisibility = false, + //服务商轨迹默认不对外 + IsExternal = false, + Source = (int) TrackSourceEnum.ExternalServiceProvide, + Remarks = null, + Files = null, + TrackPlaceCity = null, + TrackPlaceCityId = null, + TrackPlaceProvince = null, + TrackPlaceProvinceId = null, + TrackPlaceNation = null, + TrackPlaceNationId = null, + TrackPlacePostcode = null, + DestinationTimeZone = null, + EstimatedDeliveryDate = null, + Extra = null + }; + + track.ZeroTrackTime = Math.Abs(track.TrackTimeZone - GlobalConst.NoneTrackTimeZone) < 1 + ? track.TrackTime + : track.TrackTime.Subtract(TimeSpan.FromHours(track.TrackTimeZone)); + + await _trackDetailsEsRepository.AddAsync(track); + } +} diff --git a/src/SJZY.Track.Application/SJZY.Track.Application.csproj b/src/SJZY.Track.Application/SJZY.Track.Application.csproj index 378f50c7..78816ec1 100644 --- a/src/SJZY.Track.Application/SJZY.Track.Application.csproj +++ b/src/SJZY.Track.Application/SJZY.Track.Application.csproj @@ -8,25 +8,28 @@ - - - - - + + + + - + - - - - - - + + + + + + + + + + diff --git a/src/SJZY.Track.Application/Services/Broadcasting/BroadcastingService.cs b/src/SJZY.Track.Application/Services/Broadcasting/BroadcastingService.cs new file mode 100644 index 00000000..9b790e89 --- /dev/null +++ b/src/SJZY.Track.Application/Services/Broadcasting/BroadcastingService.cs @@ -0,0 +1,114 @@ +using System.Text; +using BSI.Stack.Rabbit; +using SJZY.Expand.ABP.Core.PublicMethords; +using SJZY.Track.Application.Contract.Dtos.TrackPush; +using SJZY.Track.Application.Contract.Events; +using SJZY.Track.Application.Contract.Services; + +namespace SJZY.Track.Application.Services.Broadcasting; + +/// +/// 广播服务 +/// +public class BroadcastingService : IBroadcastingService +{ + private readonly RabbitClientBus _rabbitClientBus; + + public BroadcastingService(RabbitClientBus rabbitClientBus) + { + _rabbitClientBus = rabbitClientBus; + } + + /// + /// 轨迹变更广播 + /// + /// + /// 轨迹内容中的是否对外 + /// 子系统代码 + /// 轨迹状态代码 + /// + public void TrackChangePublicTopic(TrackUpsertEvent eto, bool contentIsExternal, string subSystemCode, string trackStatusCode) + { + var data = new TrackChangeEto + { + EstimatedDeliveryDate = eto.EstimatedDeliveryDate, + TrackPlacePostcode = eto.TrackPlacePostcode, + TrackPlaceNation = eto.TrackPlaceNation, + TrackPlaceNationId = eto.TrackPlaceNationId, + TrackPlaceProvince = eto.TrackPlaceProvince, + TrackPlaceProvinceId = eto.TrackPlaceProvinceId, + TrackPlaceCity = eto.TrackPlaceCity, + TrackPlaceCityId = eto.TrackPlaceCityId, + Files = eto.Files, + Remarks = eto.Remarks, + Source = eto.Source, + IsVisibility = eto.IsVisibility, + IsExternal = eto.IsExternal ?? contentIsExternal, + TrackTimeZone = eto.TrackTimeZone, + TrackTime = eto.NewTrackTime ?? eto.TrackTime, + TrackPlace = eto.TrackPlace, + TrackStatusCode = trackStatusCode, + OrderNo = eto.OrderIdentifiers.First().OrderNo, + EnStatus = eto.EnStatus, + Content = eto.Content, + TrackCode = eto.TrackCode, + OperationMan = eto.OperationMan, + OrderIdentifiers = eto.OrderIdentifiers, + CustomId = eto.CustomId, + SubSystemId = eto.SubSystemId, + Extra = eto.Extra + }; + + if (eto.IsAdd) + data.Option = 1; + else + data.Option = 3; + + _rabbitClientBus.Publish(GlobalConst.TrackChangeExchange, $"TrackChange.{subSystemCode}", + Encoding.UTF8.GetBytes(data.ToJson())); + } + + public void TrackChangePublicTopic(TrackChangeEto eto, string subSystemCode) + { + eto.Option = 2; + _rabbitClientBus.Publish(GlobalConst.TrackChangeExchange, $"TrackChange.{subSystemCode}", + Encoding.UTF8.GetBytes(eto.ToJson())); + } + + /// + /// 轨迹推送完成广播 + /// + /// + /// + public void TrackPushCompletedPublicTopic(TrackPushRecordDto log) + { + var data = new TrackPushCompletedEvent + { + RequestId = log.RequestId, + IsSuccess = log.IsSuccess, + Message = log.Message, + OperationMan = log.OperationMan, + PushTime = log.PushTime, + OptionType = log.OptionType, + IsManualPush = log.IsManualPush, //操作人不为系统用户,则认为是仍推送 + PushContent = log.PushContent, + OrderNo = log.OrderNo, + TrackStatus = log.TrackStatus, + TrackContent = log.TrackContent, + TrackTimeZone = log.TrackTimeZone, + TrackTime = log.TrackTime, + TrackPlace = log.TrackPlace, + TrackCode = log.TrackCode, + Extra = log.Extra + }; + + _rabbitClientBus.Publish(GlobalConst.TrackPushExchange, $"TrackPush.{log.SubSystemCode}", + Encoding.UTF8.GetBytes(data.ToJson())); + } + + public void TrackPushFailedPubilcTopic(TrackPushRecordDto log) + { + //暂时使用推送完成模型,后续可能会出现有区分度的模型 + TrackPushCompletedPublicTopic(log); + } +} diff --git a/src/SJZY.Track.Application/Services/DebugApis/NormalService.cs b/src/SJZY.Track.Application/Services/DebugApis/NormalService.cs new file mode 100644 index 00000000..96eaee0f --- /dev/null +++ b/src/SJZY.Track.Application/Services/DebugApis/NormalService.cs @@ -0,0 +1,27 @@ +using Microsoft.AspNetCore.Authorization; +using SJZY.Track.Domain.Aggregates.OrderAggregate; + +namespace SJZY.Track.Application.Services.DebugApis; + +[AllowAnonymous] +[ApiExplorerSettings(GroupName = "调试专用")] +public class NormalService : ApplicationService +{ + private readonly IOrderRepository _orderRepository; + + public NormalService(IOrderRepository orderRepository) + { + _orderRepository = orderRepository; + } + + public async Task Hello(string name) + { + var order = await _orderRepository.GetFirstAsync(x => true); + if (order == null) + { + throw new BusinessException(message: "订单不存在"); + } + + return $"hello {name}"; + } +} diff --git a/src/SJZY.Track.Application/Services/DebugApis/OTelService.cs b/src/SJZY.Track.Application/Services/DebugApis/OTelService.cs new file mode 100644 index 00000000..7770d26f --- /dev/null +++ b/src/SJZY.Track.Application/Services/DebugApis/OTelService.cs @@ -0,0 +1,50 @@ +using Microsoft.AspNetCore.Authorization; +using SJZY.Track.Domain.Aggregates.OrderAggregate; + +namespace SJZY.Track.Application.Services.DebugApis; + +[AllowAnonymous] +[ApiExplorerSettings(GroupName = "调试专用")] +public class OTelService : ApplicationService +{ + private readonly IBasicRepository _orderRepository; + + public OTelService(IBasicRepository orderRepository) + { + _orderRepository = orderRepository; + } + + // [OTel] + public async Task Hello(string name) + { + var order = await _orderRepository.GetFirstAsync(x => true); + if (order == null) + { + throw new BusinessException(message: "订单不存在"); + } + + await DoSomethingAsync(order); + + return $"hello {name}"; + } + + // [OTel] + private async Task DoSomethingAsync(OrderEntity order) + { + var order2 = await _orderRepository.GetFirstAsync(x => true); + + if (order.Id == order2?.Id) + { + await Task.Delay(3000); + } + + + await DoWorkAsync(); + } + + // [OTel] + private async Task DoWorkAsync() + { + await Task.Delay(1000); + } +} diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningCacheService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningCacheService.cs new file mode 100644 index 00000000..88c7582d --- /dev/null +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningCacheService.cs @@ -0,0 +1,222 @@ +using System.Collections.Concurrent; +using SJZY.Expand.ABP.Core; +using SJZY.Expand.ABP.Core.PublicMethords; +using SJZY.Track.Application.Contract.Dtos.Forewarning; +using SJZY.Track.Application.Contract.Events; +using SJZY.Track.Application.Contract.Services; +using SJZY.Track.Domain.Aggregates.KPIAreaAggregate; +using SJZY.Track.Domain.Dtos.Forewarning; +using SJZY.Track.Domain.Queries; +using Volo.Abp.DependencyInjection; + +namespace SJZY.Track.Application.Services.ForewarningServices; + +public class ForewarningCacheService : IForewarningCacheService, ISingletonDependency +{ + private const string GlobalWaningLockKey = "GlobalWaningLockKey_GlobalLock"; + private readonly ConcurrentDictionary> _areas = new(); + readonly IKpiAreaRepository _kpiAreaRepository; + + private readonly ConcurrentDictionary> _rules = new(); + private readonly IWarningQueries _warningQueries; + object _lock = new object(); + + public ForewarningCacheService(IKpiAreaRepository kpiAreaRepository, IWarningQueries warningQueries) + { + _kpiAreaRepository = kpiAreaRepository; + _warningQueries = warningQueries; + } + + public async Task?> GetRulesAsync(int subSystemId, int customerId) + { + var key = WarningKey(subSystemId, customerId); + if (_rules.TryGetValue(key, out var rules)) + { + return rules; + } + + return await GetRules(subSystemId, customerId); + } + + public Task Clear(ClearRulCacheEvent @event) + { + foreach (var item in @event.Items) + { + var redisKey = WarningKey(item.SystemId, item.CustomerId); + _rules.Remove(redisKey, out _); + } + + return Task.CompletedTask; + } + + public async Task ClearRedisBySystemIdAndCustomer(int subSystemId, int customerId) + { + await RedisHelper.Client.DelAsync(WarningKey(subSystemId, customerId)); + var eventModel = new ClearRulCacheEvent + { + Items = new List() + { + new RuleAreaBaseInfo(subSystemId, customerId) + } + }; + + await PublishEvent(eventModel); + } + + public async Task ClearRedisByAreaId(int areaId) + { + var baseInfos = await _warningQueries.GetWarningRuleByAreaId(areaId); + if (!baseInfos.Any()) return; + baseInfos = baseInfos.DistinctBy(val => WarningKey(val.SystemId, val.CustomerId)).ToList(); + + var willDelKeys = baseInfos.Select(val => WarningKey(val.SystemId, val.CustomerId)).ToArray(); + await RedisHelper.Client.DelAsync(willDelKeys); + await RedisHelper.Client.DelAsync(AreaKey(areaId)); + var eventModel = new ClearRulCacheEvent + { + Items = baseInfos.Select(x => new RuleAreaBaseInfo + { + SystemId = x.SystemId, + CustomerId = x.CustomerId + }).ToList() + }; + + await PublishEvent(eventModel); + } + + string WarningKey(int subSystemId, int customerId) => + $"{GlobalConst.TrackWarningKeyPrefix}:{subSystemId}:{customerId}"; + + string AreaKey(int areaId) => $"{GlobalConst.TrackAreaKeyPrefix}:{areaId}"; + + private List WriteRules(List rules) + { + var result = new List(); + foreach (var item in rules) + { + List? areaList = null; + if (item.AreaId.HasValue) + { + areaList = GetAreaInfoByAreaId(item.AreaId!.Value); + } + + var entry = new ForewarningRuleCacheEntry + { + Id = item.Id, + WarningId = item.WarningId, + TotalTimeSpan = item.TotalTimeSpan, + WarnTimeSpan = item.WarnTimeSpan, + WarnCount = item.WarnCount, + StartTrackStatusId = item.StartTrackStatusId, + EndTrackStatusId = item.EndTrackStatusId, + CargoType = item.CargoType, + Months = string.IsNullOrEmpty(item.Months) + ? new List() + : item.Months.Split('/').Select(int.Parse).ToList(), + IsTransit = item.IsTransit, + Areas = areaList, + ProductCode = item.ProductCode, + LeavePort = item.LeavePort + }; + + result.Add(entry); + } + + return result; + } + + private async Task?> GetRules(int systemId, int customerId) + { + var key = WarningKey(systemId, customerId); + var result = RedisHelper.Client.Get>(key); + if (result != null) + { + // 非线程安全,需要加锁 + lock (_lock) + { + if (_rules.TryGetValue(key, out var ruleResult)) + { + return ruleResult; + } + + ruleResult = WriteRules(result); + _rules.TryAdd(key, ruleResult); + return ruleResult; + } + } + + // 非线程安全,需要加锁 + using (RedisHelper.Client.Lock(GlobalWaningLockKey, 20)) + { + if (_rules.TryGetValue(key, out var ruleResult)) return ruleResult; + + var warnings = await _warningQueries.GetWarningRule(systemId, customerId); + if (warnings == null || warnings.Count == 0) + { + await RedisHelper.Client.SetAsync(key, new List(), TimeSpan.FromSeconds(20)); + return new List(); + } + + await RedisHelper.Client.SetAsync(key, warnings, TimeSpan.FromHours(24)); + ruleResult = WriteRules(warnings); + _rules.TryAdd(key, ruleResult); + return ruleResult; + } + } + + private List? GetAreaInfoByAreaId(int areaId) + { + if (_areas.TryGetValue(areaId, out var areaInfos)) return areaInfos; + + var areas = GetAreas(areaId); + if (areas.Count == 0) return null; + + areaInfos = areas.Select(KpiAreaInfoToEntry).ToList(); + _areas.TryAdd(areaId, areaInfos); + return areaInfos; + } + + AreaCacheEntry KpiAreaInfoToEntry(KpiAreaInfo model) + { + return new AreaCacheEntry + { + Country = model.Country, + Province = model.Province, + City = model.City, + LeftPostcode = model.LeftPostcode, + RightPostcode = model.RightPostcode + }; + } + + /// + /// 获取区域 + /// + /// + private List GetAreas(int areaId) + { + var key = AreaKey(areaId); + var result = RedisHelper.Client.Get>(key); + if (result == null) + { + result = RedisHelper.Client.Get>(key); + if (result != null) return new List(); + + var kpiArea = _kpiAreaRepository.GetAreaInfosByAreaId(areaId); + if (kpiArea == null) + { + RedisHelper.Client.Set(key, new List(), TimeSpan.FromSeconds(20)); + return new List(); + } + + RedisHelper.Client.Set(key, kpiArea); + return kpiArea; + } + + return result; + } + + private async Task PublishEvent(ClearRulCacheEvent @event) + { + await RedisHelper.Client.PublishAsync(GlobalConst.PublishNotifyChannelKey, @event.ToJson()); + } +} diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs new file mode 100644 index 00000000..692a5646 --- /dev/null +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningNotifyService.cs @@ -0,0 +1,374 @@ +using System.Text; +using FreeRedis; +using Microsoft.Extensions.Options; +using SJZY.Expand.ABP.Core; +using SJZY.Expand.ABP.Core.Logger; +using SJZY.Expand.ABP.Core.PublicMethords; +using SJZY.Track.Application.Contract.Dtos.Forewarning; +using SJZY.Track.Application.Contract.Services; +using SJZY.Track.Application.Options; +using SJZY.Track.Domain.Aggregates.ForewarningAggregate; +using SJZY.Track.Domain.Dtos.Forewarning; +using SJZY.Track.Domain.Enums; +using SJZY.Track.Domain.Queries; +using SJZY.UserCenter.HttpApi.Services.Message; +using SJZY.UserCenter.SharedModel.Dtos.Message; +using SJZY.UserCenter.SharedModel.Enums; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Http.Client.DynamicProxying; + +namespace SJZY.Track.Application.Services.ForewarningServices; + +/// +/// 用于处理预警通知 +/// +public class ForewarningNotifyService : IForewarningNotifyService, ITransientDependency +{ + private readonly IForewarningCacheService _forewarningCacheService; + private readonly IOptionsSnapshot _options; // not hot path + private readonly IHttpClientProxy _requestSendMessageService; + private readonly IWarningQueries _warningQueries; + private readonly IWarningRecordEsRepository _warningRecordEsRepository; + + public ForewarningNotifyService(IWarningQueries warningQueries, + IWarningRecordEsRepository warningRecordEsRepository, + IHttpClientProxy requestSendMessageService, + IForewarningCacheService forewarningCacheService, IOptionsSnapshot options) + { + _warningQueries = warningQueries; + _warningRecordEsRepository = warningRecordEsRepository; + _requestSendMessageService = requestSendMessageService; + _forewarningCacheService = forewarningCacheService; + _options = options; + } + + + /// + /// 创建预警通知 + /// + /// 创建预警通知需要的订单信息 + public async Task WarningCalculateAsync(WarningDto dto) + { + if (dto.Orders.Count == 0) return; + + var rules = await _forewarningCacheService.GetRulesAsync(dto.SubSystemId, dto.CustomerId); + if (rules == null || rules.Count == 0) return; + + var adds = new List<(int ruleId, int orderId, int counter, long ts)>(); + var dels = new List<(int ruleId, int orderId, int counter)>(); + foreach (var order in dto.Orders) + { + // 加左区间 + MatchRule( + rules.Where(rule => rule.StartTrackStatusId == dto.TrackStatusId).ToList(), + order + ).ForEach(rule => + { + var interval = (rule.TotalTimeSpan - rule.WarnTimeSpan) / rule.WarnCount; + var startTime = order.TrackTime.AddHours(rule.WarnTimeSpan); + + for (var i = 1; i <= rule.WarnCount; i++) + { + var timestamp = GetTimestamp(startTime); + startTime = startTime.AddHours(interval); + + // 计算预警时间戳,作为排序依据 + adds.Add((rule.Id, order.Id, i, timestamp)); + } + }); + + // 删右区间 + MatchRule( + rules.Where(rule => rule.EndTrackStatusId == dto.TrackStatusId).ToList(), + order + ).ForEach(rule => + { + for (var i = 1; i <= rule.WarnCount; i++) + { + dels.Add((rule.Id, order.Id, i)); + } + }); + } + + var redisKey = GetForewarningNotifySetKeyRedisKey(dto.SubSystemId); + long addCounter = 0, delCounter = 0; + + // 左区间加入预警队列,【只有第一次发生的才会被加入】 + var left = adds.Select(x => + { + var entry = new WarningNotifyCacheEntry(x.ruleId, x.orderId, x.counter); + return new ZMember(entry.ToString(), x.ts); + }).ToArray(); + if (!left.IsNullOrEmpty()) + { + addCounter = await RedisHelper.Client.ZAddNxAsync(redisKey, left); + } + + // tips:由于预警队列的设计 是悲观的认为所有预警都会在未来发生,实际上预警占真实业务的发生总比应该在少数,所以这里是有优化空间的 + + // 右区间移出预警队列,【只要发生了就移除】 + var right = dels.Select(x => new WarningNotifyCacheEntry(x.ruleId, x.orderId, x.counter)).ToList(); + if (!right.IsNullOrEmpty()) + { + delCounter = await RedisHelper.Client.ZRemAsync(redisKey, right.Select(x => x.ToString()).ToArray()); + } + + LogHelper.Info($"{nameof(ForewarningNotifyService)} 本次共计产生{addCounter}条预警,移除{delCounter}条预警,触发缘由是{dto}"); + + await _warningRecordEsRepository.BulkUpdateAsync(dels); // 标记处理完成 + } + + public async Task SendNotificationAsync(int subSystemId) + { + var redisKey = GetForewarningNotifySetKeyRedisKey(subSystemId); + var timestamp = GetTimestamp(DateTime.Now); + var set = await RedisHelper.Client.ZRangeByScoreAsync(redisKey, 0, timestamp); + + if (set.IsNullOrEmpty()) + { + LogHelper.Info($"{nameof(ForewarningNotifyService)} 子系统:{subSystemId} 没有运输时效需要预警"); + return 0; + } + + var entries = set.Select(x => new WarningNotifyCacheEntry(x)).ToList(); + var ruleIds = entries.Select(x => x.RuleId).Distinct().ToList(); + var notifyRules = await _warningQueries.GetWarningNotifyRulesAsync(ruleIds); + + // 写入es预警记录 + var warningRecords = await WriteWarningRecordAsync(entries, notifyRules); + + // 移除已处理的预警 + await RedisHelper.Client.ZRemRangeByScoreAsync(redisKey, 0, timestamp); + + // 发通知 + // tips:通知发送失败不应该影响预警记录的写入,可以进入重试队列 + await SendCoreAsync(subSystemId, entries, notifyRules); + + return warningRecords.Count; + } + + private async Task> WriteWarningRecordAsync(List entries, + List notifyRules) + { + var orders = await _warningQueries.GetOrderNoByIdsAsync(entries.Select(x => x.OrderId).ToArray()); + var orderNoDict = orders.ToDictionary(x => x.Id, x => x.Name); + + var warningRecords = new List(); + foreach (var entry in entries) + { + var rule = notifyRules.FirstOrDefault(x => x.RuleId == entry.RuleId); + if (rule == null) continue; + + foreach (var notifyUser in rule.NotifyUsers) + { + warningRecords.Add(new WarningRecordIndex + { + SubSystemId = rule.SubSystemId, + SubSystemName = rule.SubSystemName, + WarningName = rule.WarningName, + CustomId = rule.CustomId, + CustomName = rule.CustomName, + RuleId = entry.RuleId, + Rule = rule.ToString(), + Counter = entry.Counter, + IsLast = rule.WarnCount == entry.Counter, + OrderId = entry.OrderId, + OrderNo = orderNoDict.TryGetValue(entry.OrderId, out var orderNo) ? orderNo : string.Empty, + WarningStatus = WarningStatus.UnProcessed, + NotifyUserId = notifyUser.UserId, + NotifyUserName = notifyUser.UserName, + CreateTime = DateTime.Now, + }); + } + } + + // 批量写入es + await _warningRecordEsRepository.BulkInsertAsync(warningRecords); + return warningRecords; + } + + private async Task SendCoreAsync(int subSystemId, List entries, + List notifyRules) + { + var userRules = new Dictionary>(); + foreach (var rule in notifyRules) + { + foreach (var notifyUser in rule.NotifyUsers) + { + if (!userRules.ContainsKey(notifyUser.UserId)) + { + userRules[notifyUser.UserId] = new List(); + } + + userRules[notifyUser.UserId].Add(rule); + } + } + + // 以人的维度发送通知,异步 + var tasks = new List(); + + foreach (var userRule in userRules) + { + tasks.Add(DoNotifyAsync(subSystemId, userRule.Key, userRule.Value, entries, NotifyMode.SiteInternal)); + tasks.Add(DoNotifyAsync(subSystemId, userRule.Key, userRule.Value, entries, NotifyMode.FeiShu)); + } + + // 等待所有任务完成 + await Task.WhenAll(tasks); + } + + private string GetForewarningNotifySetKeyRedisKey(int subSystemId) => + $"{GlobalConst.ForewarningNotifySetKey}:{subSystemId}"; + + private async Task DoNotifyAsync(int subSystemId, int userId, List rules, + List entries, + NotifyMode mode) + { + /* 以人的维度发送通知 + * + 预警名称:字节全程时效 + 预警规则: + {起飞-落地+普货+12345678+美国 时效9,预警时效7,次数3} 命中订单总数:124,详情点击https://middlebusiness.pet.shijizhongyun.com/trajectoryCenter/trajectoryOrder + {清关-提货+普货+12345678+美国 时效4,预警时效3,次数1} 命中订单总数:3250,详情点击https://middlebusiness.pet.shijizhongyun.com/trajectoryCenter/trajectoryOrder + 预警名称:字节全程时效 + 预警规则: + {起飞-落地+普货+12345678+美国 时效9,预警时效7,次数3} 命中订单总数:124,详情点击https://middlebusiness.pet.shijizhongyun.com/trajectoryCenter/trajectoryOrder + {清关-提货+普货+12345678+美国 时效4,预警时效3,次数1} 命中订单总数:3250,详情点击https://middlebusiness.pet.shijizhongyun.com/trajectoryCenter/trajectoryOrder + */ + var notifyContent = new StringBuilder(); + + foreach (var warningGroup in rules + .Where(x => x.NotifyMode.Split(',').Select(Enum.Parse).Contains(mode)) + .GroupBy(x => x.WarningName)) + { + notifyContent.AppendLine($"预警名称:{warningGroup.Key}"); + notifyContent.AppendLine($"预警规则:"); + + foreach (var rule in warningGroup.ToList()) + { + var cnt = entries.Count(x => x.RuleId == rule.RuleId); + notifyContent.AppendLine( + $"{rule.ToString()} 命中订单总数:{cnt},详情点击{_options.Value.WarningNotifyUrl}?userId={userId}"); + } + } + + var msgContent = notifyContent.ToString(); + + if (string.IsNullOrEmpty(msgContent)) return; + + var res = await _requestSendMessageService.Service.SendMessageByEmptyTemplateAsync( + new SendMessageByEmptyTemplateInput + { + IsNeedToHandle = true, + MsgSource = MsgSourceEnum.系统提醒, + SystemId = subSystemId, + TemplateCode = "trackWarning", + Channels = new List() + { + mode == NotifyMode.FeiShu ? ChannelEnum.飞书 : ChannelEnum.站内信, + }, + MsgTitle = "轨迹运输时效预警", + MsgContent = msgContent, + receivers = new List + { + new() + { + RecipientType = 1, + ReceiverId = userId, + } + }, + }); + + if (res.Code != GlobalConst.SuccessCode) + { + // todo:失败是否上报重试? + LogHelper.Error( + $"{nameof(ForewarningNotifyService)} 发送{mode.ToString()}通知失败,用户:{userId}\n内容:\n{msgContent}\n失败报文:{res.ToJson()}"); + } + } + + private static List MatchRule(List rules, + WarningOrderDto order) + { + var res = new List(); + foreach (var rule in rules) + { + // 规则至少有一个因素,如果订单任一因素不符合则不命中 + if (rule.IsTransit != null) + { + if (order.IsTransit != rule.IsTransit) continue; + } + + if (!rule.CargoType.IsNullOrEmpty()) + { + if (order.CargoType != rule.CargoType) continue; + } + + if (!rule.LeavePort.IsNullOrEmpty()) + { + if (order.LeavePort != rule.LeavePort) continue; + } + + if (!rule.ProductCode.IsNullOrEmpty()) + { + if (order.ProductCode != rule.ProductCode) continue; + } + + if (!rule.Months.IsNullOrEmpty()) + { + if (!order.Month.IsIn(rule.Months)) continue; + } + + if (!rule.Areas.IsNullOrEmpty()) + { + var inArea = false; + var areas = rule.Areas!.Where(area => order.ArrivalCountry == area.Country).ToList(); + foreach (var area in areas) + { + if (!area.LeftPostcode.IsNullOrEmpty() && !area.RightPostcode.IsNullOrEmpty()) + { + // tips: 参考小包的邮编匹配,字典序 + if (string.CompareOrdinal(order.ArrivalPostCode, area.LeftPostcode) < 0 || + string.CompareOrdinal(order.ArrivalPostCode, area.RightPostcode) > 0) continue; + } + + inArea = true; + break; + } + + if (!inArea) + { + foreach (var area in areas) + { + if (!area.City.IsNullOrEmpty() && order.ArrivalCity != area.City) continue; + inArea = true; + break; + } + } + + if (!inArea) + { + foreach (var area in areas) + { + if (!area.Province.IsNullOrEmpty() && order.ArrivalProvince != area.Province) continue; + inArea = true; + break; + } + } + + + if (!inArea) continue; + } + + // 命中规则 + res.Add(rule); + } + + return res; + } + + private static long GetTimestamp(DateTime dateTime) + { + return new DateTimeOffset(dateTime).ToUnixTimeSeconds(); + } +} diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs new file mode 100644 index 00000000..a2430bd8 --- /dev/null +++ b/src/SJZY.Track.Application/Services/ForewarningServices/ForewarningService.cs @@ -0,0 +1,221 @@ +using System.ComponentModel.DataAnnotations; +using SJZY.Expand.ABP.Core.PublicMethords; +using SJZY.Track.Application.Contract.Dtos.Forewarning; +using SJZY.Track.Application.Contract.Services; +using SJZY.Track.Application.Helpers; +using SJZY.Track.Domain.Aggregates.ForewarningAggregate; +using SJZY.Track.Domain.Aggregates.KPIAreaAggregate; +using SJZY.Track.Domain.Aggregates.TrackStatusAggregate; +using SJZY.Track.Domain.Dtos.Common; +using SJZY.Track.Domain.Dtos.Forewarning; +using SJZY.Track.Domain.Queries; + +namespace SJZY.Track.Application.Services.ForewarningServices; + +[ApiExplorerSettings(GroupName = "预警服务")] +[Route("/ForewarningService")] +public class ForewarningService : ApplicationService +{ + private readonly IForewarningCacheService _forewarningCacheService; + private readonly IWarningRepository _warningRepository; + + public ForewarningService(IWarningRepository warningRepository, IForewarningCacheService forewarningCacheService) + { + _warningRepository = warningRepository; + _forewarningCacheService = forewarningCacheService; + } + + /// + /// 获取预警分页列表 + /// + /// + /// + [HttpPost("GetWarningPageList")] + public async Task> GetWarningPageList(GetWarningPageInputVo inputVo) + { + if (!inputVo.KeyWord.IsNullOrEmpty()) inputVo.KeyWord = inputVo.KeyWord!.Trim(); + return await _warningRepository.GetWarningPageListAsync(inputVo); + } + + /// + /// 创建预警 + /// + /// + /// + [HttpPost("CreateWarning")] + public async Task CreateWarning(CreateWarningInput input) + { + var warning = ObjectMapper.Map(input); + + if (await _warningRepository.IsAnyAsync(x => + x.SubSystemId == warning.SubSystemId && x.CustomerId == warning.CustomerId && x.Name == warning.Name)) + { + throw new BusinessException(message: "该子系统下的客户已经存在一个同名预警: " + warning.Name); + } + + warning.WarningRules = ForewarningHelper.CalcRuleList(input.TrackStatusSpans, input.WarningFactors); + warning.FactorTypeSort = input.WarningFactors.Select(x => x.FactorType).JoinAsString(","); + + warning.WarningFactors = ForewarningHelper.MapFactorEntities(input.WarningFactors); + warning.WarningNotifies = ForewarningHelper.MapNotifyEntities(input); + await _warningRepository.CreateForewarningAsync(warning); + return true; + } + + /// + /// 编辑预警 + /// + /// + /// + /// + /// + [HttpGet("EditWarning")] + public async Task EditWarning(int warningId, + [FromServices] IBasicQuery statusQuery, + [FromServices] IKpiAreaRepository kpiAreaRepository) + { + var warning = await _warningRepository.GetByIdAsync(warningId); + + if (warning == null) + { + throw new BusinessException(message: "预警不存在"); + } + + var statusList = await statusQuery.GetListAsync(x => x.SubSystemId == warning.SubSystemId, x => + new IdWithNameDto + { + Id = x.Id, + Name = x.Status + }); + + var areaList = await kpiAreaRepository.GetListAsync(x => x.SubSystemId == warning.SubSystemId, x => + new IdWithNameDto + { + Id = x.Id, + Name = x.Name + }); + + return ForewarningHelper.MapWarningSummary(warning, statusList, areaList); + } + + /// + /// 更新预警 + /// + /// + /// + [HttpPost("UpdateWarning")] + public async Task UpdateWarning(UpdateWarningInput input) + { + var warning = await _warningRepository.GetFirstAsync(x => x.Id == input.Id); + if (warning == null) + { + throw new BusinessException(message: "预警不存在"); + } + + if (await _warningRepository.IsAnyAsync(x => + x.SubSystemId == warning.SubSystemId && x.CustomerId == warning.CustomerId && x.Id != warning.Id && + x.Name == input.Name)) + { + throw new BusinessException(message: "该子系统下的客户已经存在一个同名预警: " + warning.Name); + } + + warning.SetName(input.Name); + + warning.WarningNotifies = input.Notifies.Select(x => new WarningNotifyEntity + { + Id = x.Id, + NotifyMode = x.NotifyModes.JoinAsString(","), + NotifyUser = x.NotifyUsers.ToJson(), + }).ToList(); + + await _warningRepository.UpdateForewarningAsync(warning); + + return true; + } + + /// + /// 启用or禁用预警 + /// + /// 预警id + /// 是否启用 + /// + [HttpPost("TurnWarning")] + public async Task TurnWarning(int warningId, bool isEnable) + { + var warning = await _warningRepository.GetFirstAsync(x => x.Id == warningId); + if (warning == null) + { + throw new BusinessException(message: "预警不存在"); + } + + if (isEnable) + { + if (await _warningRepository.IsAnyAsync(x => + x.SubSystemId == warning.SubSystemId && x.CustomerId == warning.CustomerId && x.IsEnable)) + { + throw new BusinessException(message: "该子系统下的客户已经存在一个启用的预警,请先禁用"); + } + } + + warning.SetEnable(isEnable); + + await _warningRepository.TurnWarningAsync(warning); + + // 清除缓存 + await _forewarningCacheService.ClearRedisBySystemIdAndCustomer(warning.SubSystemId, warning.CustomerId); + + return true; + } + + /// + /// 查询预警规则列表 + /// + /// 预警规则id + /// + /// + [HttpGet("GetWarningRuleList")] + public async Task> GetWarningRuleListAsync([Required] int warningId, + [FromServices] IBasicQuery factorQuery) + { + var factors = await factorQuery.GetListAsync(x => x.WarningId == warningId, x => x.Type); + var rules = await _warningRepository.GetWarningRuleListAsync(warningId); + + var dynamicList = ForewarningHelper.DynamicCalcRuleList(rules, factors); + return dynamicList; + } + + /// + /// 修改预警规则时效 + /// + /// + /// + /// + [HttpPost("ModifyTimeSpans")] + public async Task ModifyTimeSpans(ModifyTimeSpanInput input) + { + if (input.Items.IsNullOrEmpty()) return false; + if (input.Items.Any(x => x.TotalTimeSpan < x.WarnTimeSpan)) + { + throw new BusinessException(message: "预警时效不能小于预警提醒时效"); + } + + if (input.Items.Any(x => x.WarnCount is < 1 or > 10)) + { + throw new BusinessException(message: "预警次数范围为1-10"); + } + + var warning = await _warningRepository.GetFirstAsync(x => x.Id == input.WarningId); + if (warning == null) + { + throw new BusinessException(message: "预警不存在"); + } + + var warningRules = ObjectMapper.Map, List>(input.Items); + + await _warningRepository.ModifyTimeSpansAsync(warningRules); + + // 清除缓存 + await _forewarningCacheService.ClearRedisBySystemIdAndCustomer(warning.SubSystemId, warning.CustomerId); + return true; + } +} diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaCacheService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaCacheService.cs new file mode 100644 index 00000000..2a841b82 --- /dev/null +++ b/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaCacheService.cs @@ -0,0 +1,26 @@ +using SJZY.Track.Application.Contract.Services; +using SJZY.Track.Domain.Aggregates.KPIAreaAggregate; +using Volo.Abp.DependencyInjection; + +namespace SJZY.Track.Application.Services.ForewarningServices; + +public class KpiAreaCacheService : IKpiAreaCacheService, ITransientDependency +{ + const string GlobalKpiAreaLockKey = "KpiAreaCacheService_GlobalLock"; + IKpiAreaRepository _kpiAreaRepository; + + public KpiAreaCacheService(IKpiAreaRepository kpiAreaRepository) + { + _kpiAreaRepository = kpiAreaRepository; + } + + private string GetKey(int systemId, string country) + { + return $"{GlobalConst.KpiAreaKeyPrefix}:{systemId}:{country}"; + } + + public Task GetKpiArea(int systemId, string country) + { + throw new NotImplementedException(); + } +} diff --git a/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaService.cs b/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaService.cs new file mode 100644 index 00000000..f54c3504 --- /dev/null +++ b/src/SJZY.Track.Application/Services/ForewarningServices/KpiAreaService.cs @@ -0,0 +1,145 @@ +using SJZY.Track.Application.Contract.Services; +using SJZY.Track.Domain.Aggregates.KPIAreaAggregate; +using SJZY.Track.Domain.Dtos.Forewarning; + +namespace SJZY.Track.Application.Services.ForewarningServices; + +[ApiExplorerSettings(GroupName = "预警服务")] +[Route("/ForewarningService")] +public class KpiAreaService : ApplicationService +{ + private readonly IForewarningCacheService _forewarningCacheService; + private readonly IKpiAreaRepository _ruleAreaRepository; + + public KpiAreaService(IKpiAreaRepository ruleAreaRepository, IForewarningCacheService forewarningCacheService) + { + _ruleAreaRepository = ruleAreaRepository; + _forewarningCacheService = forewarningCacheService; + } + + /// + /// 创建分区 + /// + /// + /// 分区id + [HttpPost("KpiArea/CreateKpiArea")] + public async ValueTask CreateKpiArea(CreateRuleAreaRequest input) + { + var ruleAreaEntity = ObjectMapper.Map(input); + var hasSameName = + await _ruleAreaRepository.IsAnyAsync(val => val.SubSystemId == input.SystemId && val.Name == input.Name); + if (hasSameName) + { + return new UnifyResultDto(false, "分区名称重复,请重新修改提交"); + } + + var areaId = await _ruleAreaRepository.CreateAreaAsync(ruleAreaEntity); + return new UnifyResultDto(true, areaId, "创建成功"); + } + + /// + /// 添加区域信息 + /// + /// + /// 区域id + [HttpPost("KpiArea/AddAreaInfo")] + public async ValueTask AddAreaInfoAsync(AddRuleAreaInfoRequest input) + { + var ruleAreaEntity = ObjectMapper.Map(input); + var ruleInfoId = await _ruleAreaRepository.AddAreaInfoAsync(ruleAreaEntity); + await _forewarningCacheService.ClearRedisByAreaId(input.AreaId); + return new UnifyResultDto(true, ruleInfoId, "添加成功"); + } + + /// + /// 删除分区 + /// + /// 分区id + /// + [HttpDelete("KpiArea/DeleteKpiArea")] + public async ValueTask DeleteKpiArea(int id) + { + await _ruleAreaRepository.DeleteArea(id); + await _forewarningCacheService.ClearRedisByAreaId(id); + return new UnifyResultDto(true, "删除成功"); + } + + /// + /// 删除分区信息 + /// + /// 分区信息id + /// + [HttpDelete("KpiArea/DeleteKpiAreaInfo")] + public async ValueTask DeleteKpiAreaInfo(int id) + { + var info = await _ruleAreaRepository.GetAreaInfoById(id); + if (info == null) return new UnifyResultDto(false, "未找到该区域信息"); + await _ruleAreaRepository.DeleteAreaInfo(id); + await _forewarningCacheService.ClearRedisByAreaId(info.AreaId); + return new UnifyResultDto(true, "删除成功"); + } + + /// + /// 更新区域信息 + /// + /// + /// + [HttpPost("KpiArea/ModifyKpiArea")] + public async Task ModifyKpiArea(UpdateRuleAreaRequest input) + { + if (input.Id <= 0) + return new UnifyResultDto(false, "id不能为空"); + + var ruleArea = await _ruleAreaRepository.GetFirstAsync(val => val.Id == input.Id); + if (ruleArea == null) + return new UnifyResultDto(false, "未找到该区域"); + + ruleArea.Name = input.Name; + await _ruleAreaRepository.UpdateAsync(ruleArea); + return new UnifyResultDto(true, "更新成功"); + } + + /// + /// 更新区域信息 + /// + /// + /// + [HttpPost("KpiArea/ModifyKpiAreaInfo")] + public async Task ModifyKpiAreaInfo(UpdateRuleAreaInfoRequest input) + { + if (input.Id <= 0) + return new UnifyResultDto(false, "id不能为空"); + + var areaInfo = await _ruleAreaRepository.GetAreaInfoById(input.Id); + if (areaInfo == null) + return new UnifyResultDto(false, "未找到该区域信息"); + + var ruleAreaEntity = ObjectMapper.Map(input, areaInfo); + await _ruleAreaRepository.UpdateAreaInfoAsync(ruleAreaEntity); + + await _forewarningCacheService.ClearRedisByAreaId(areaInfo.AreaId); + return new UnifyResultDto(true, "更新成功"); + } + + /// + /// 查询分区列表 + /// + /// + /// + [HttpPost("KpiArea/GetKpiAreas")] + public async Task> GetKpiAreas(QueryAreaRequest input) + { + return await _ruleAreaRepository.GetAreas(input); + } + + /// + /// 查询分区列表 + /// + /// + /// + [HttpPost("KpiArea/GetKpiAreaInfos")] + public async Task> GetKpiAreaInfos(QueryAreaInfoRequest query) + { + return await _ruleAreaRepository.GetAreaInfos(query); + } +} diff --git a/src/SJZY.Track.Application/Services/ProvideServices/OrderService.Link.cs b/src/SJZY.Track.Application/Services/ProvideServices/OrderService.Link.cs index e9554da2..0d4b4cfe 100644 --- a/src/SJZY.Track.Application/Services/ProvideServices/OrderService.Link.cs +++ b/src/SJZY.Track.Application/Services/ProvideServices/OrderService.Link.cs @@ -1,10 +1,8 @@ -using DotNetCore.CAP; +using DotNetCore.CAP; using SJZY.Track.Application.Contract.Dtos.ProvideServices; using SJZY.Track.Application.Contract.Events; using SJZY.Track.Domain.Aggregates.OrderAggregate; using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; -using SJZY.Track.Domain.Consts; -using SJZY.Track.Domain.Queries; namespace SJZY.Track.Application.Services.ProvideServices; @@ -13,9 +11,8 @@ namespace SJZY.Track.Application.Services.ProvideServices; /// public partial class OrderService { - private readonly IBasicQuery _orderLinkQuery; private readonly ICapPublisher _capPublisher; - private readonly ITrackDetailsRepository _trackDetailsRepository; + private readonly ITrackDetailsEsRepository _trackDetailsEsRepository; /// /// 关联、解除关联订单 @@ -26,18 +23,15 @@ public partial class OrderService [HttpPost("Order/Link")] public async Task LinkOrderAsync(LinkOrderInput input) { - var order = await _orderRepository.GetFirstAsync(x => - x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, x => new - { - x.Id, - x.SubSystemId - }); - if (order == default) + var orderId = await _orderRepository.GetFirstAsync(x => + x.SubSystemId == input.SubSystemId && x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, + x => x.Id); + if (orderId == default) { throw new BusinessException(message: $"订单:{input.OrderNo}不存在"); } - //tips:循环关联问题再消费时解决 + // tips:循环关联问题再消费时解决 if (input.OrderType == input.LinkOrderType) { throw new BusinessException(message: "不能同级关联"); @@ -50,11 +44,16 @@ public partial class OrderService .Where(x => !x.IsNullOrWhiteSpace() && x != input.OrderNo) .Distinct().ToList(); - // 解绑 - if (!input.IsLink) return await UnLinkOrderAsync(input); - - // 关联订单 - await DoLinkOrderAsync(input, order.Id); + if (!input.IsLink) + { + // 解绑 + await UnLinkOrderAsync(input, orderId); + } + else + { + // 关联订单 + await DoLinkOrderAsync(input, orderId); + } return new UnifyResultDto(true, true); } @@ -62,52 +61,67 @@ public partial class OrderService private async Task DoLinkOrderAsync(LinkOrderInput input, int orderId) { // 获取已关联的订单 - var linkOrderNos = await _orderLinkQuery.GetListAsync(x => - x.OrderType == input.OrderType && x.OrderNo == input.OrderNo && x.LinkOrderType == input.LinkOrderType, - x => x.LinkOrderNo); + var linkOrderNos = + await _orderRepository.GetLinkedOrdersAsync(orderId, input.LinkSubSystemId, input.LinkOrderType); // 计算出未关联的订单 - var noLinkOrderNos = input.LinkOrderNos.Except(linkOrderNos); + var noLinkOrderNos = input.LinkOrderNos.Except(linkOrderNos).ToList(); - // 过滤掉不存在的订单 - var canLinkOrders = await _orderRepository.GetListAsync(x => - x.OrderType == input.LinkOrderType && noLinkOrderNos.Contains(x.OrderNo), - x => new { x.Id, x.OrderNo, x.OrderType, x.SubSystemId, x.CustomId }); + // 查询存在的订单 + var existedOrders = await _orderRepository.GetListAsync(x => + x.SubSystemId == input.LinkSubSystemId && x.OrderType == input.LinkOrderType && + noLinkOrderNos.Contains(x.OrderNo), + x => new + { + x.Id, + x.OrderNo, + x.OrderType, + x.SubSystemId, + x.CustomId + }); - if (canLinkOrders.Count == 0) return; + // 如果有不存在的单,需要抛异常 + if (existedOrders.Count != noLinkOrderNos.Count) + { + throw new BusinessException( + message: $"关联单:{noLinkOrderNos.Except(existedOrders.Select(x => x.OrderNo)).JoinAsString(", ")}不存在"); + } - await _orderRepository.LinkOrderAsync(canLinkOrders.Select(x => new OrderLinkEntity + await _orderRepository.LinkOrderAsync(existedOrders.Select(x => new OrderLinkEntity { OrderId = orderId, - OrderNo = input.OrderNo, - OrderType = input.OrderType, LinkOrderId = x.Id, - LinkOrderNo = x.OrderNo, - LinkOrderType = input.LinkOrderType }).ToList()); - var tracks = await _trackDetailsRepository.GetListAsync(orderId); + var tracks = await _trackDetailsEsRepository.GetListAsync(orderId); - // 补轨迹 - foreach (var group in canLinkOrders.GroupBy(x => x.SubSystemId)) + // 补轨迹(按子系统、按客户分,同样是为了方便轨迹upsert和push) + foreach (var group in existedOrders.GroupBy(x => new + { + x.SubSystemId, + x.CustomId + })) { foreach (var track in tracks) { var fillTrackEvent = new TrackUpsertEvent { - SubSystemId = group.Key, - OrderIdentifiers = group.Select(x => new OrderIdentifier - { - OrderId = x.Id, - OrderNo = x.OrderNo, - OrderType = x.OrderType, - CustomId = x.CustomId - }).ToArray(), + SubSystemId = group.Key.SubSystemId, + CustomId = group.Key.CustomId, + OrderIdentifiers = + group.Select(x => + new OrderIdentifier + { + OrderId = x.Id, + OrderNo = x.OrderNo, + OrderType = x.OrderType, + }) + .ToArray(), TrackCode = track.TrackCode, TrackPlace = track.TrackPlace, TrackTime = track.TrackTime, TrackTimeZone = track.TrackTimeZone, - IsAdd = true + IsAdd = true // 存在则不新增 }; await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, fillTrackEvent); @@ -115,16 +129,12 @@ public partial class OrderService } } - private async Task UnLinkOrderAsync(LinkOrderInput input) + private async Task UnLinkOrderAsync(LinkOrderInput input, int orderId) { - var unLinkIds = await _orderLinkQuery.GetListAsync(x => - x.OrderType == input.OrderType && x.OrderNo == input.OrderNo && - x.LinkOrderType == input.LinkOrderType && input.LinkOrderNos.Contains(x.LinkOrderNo), - x => x.Id); + var unLinkIds = await _orderRepository.GetLinkedOrdersAsync(orderId, input.LinkSubSystemId, input.LinkOrderType, + input.LinkOrderNos); // real del await _orderRepository.UnLinkByIdsAsync(unLinkIds); - - return new UnifyResultDto(true, true); } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/Services/ProvideServices/OrderService.PullConfigs.cs b/src/SJZY.Track.Application/Services/ProvideServices/OrderService.PullConfigs.cs new file mode 100644 index 00000000..332d0624 --- /dev/null +++ b/src/SJZY.Track.Application/Services/ProvideServices/OrderService.PullConfigs.cs @@ -0,0 +1,34 @@ +using SJZY.Expand.ABP.Core.Logger; +using SJZY.Expand.ABP.Core.PublicMethords; +using SJZY.Track.Application.Contract.Dtos.ProvideServices; +using SJZY.Track.Domain.Dtos.Order; +using SJZY.UserCenter.HttpApi.Services; + +namespace SJZY.Track.Application.Services.ProvideServices; + +public partial class OrderService +{ + /// + /// 修改订单拉取信息(轻易勿动) + /// + /// + /// + [HttpPost("Order/UpdateOrderPullConfigs")] + public async Task UpdateOrderPullConfigsAsync(UpdateOrderPullConfigsInput input) + { + var orderIds = await _orderRepository.GetArrayAsync( + x => x.SubSystemId == input.SubSystemId && x.OrderType == input.OrderType && + input.OrderNos.Contains(x.OrderNo), + x => x.Id); + var inputVo = ObjectMapper + .Map(input.Config); + inputVo.OrderIds = orderIds; + var cnt = await _orderRepository.UpdateOrderPullConfigForServiceProviderAsync(inputVo); + + LogHelper.Warn( + $"{CurrentUserRequest.CurrentUser.UserId}正在修改服务商拉取信息,本次共计影响了{orderIds.Length}个订单、{cnt}段拉取,请求参数是:{input.ToJson()}", + true); + + return new UnifyResultDto(true); + } +} diff --git a/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs b/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs index 4a72f258..ed613ffb 100644 --- a/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs +++ b/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs @@ -1,9 +1,9 @@ using DotNetCore.CAP; +using SJZY.Expand.ABP.Core.PublicMethords; using SJZY.Track.Application.Contract.Dtos.ProvideServices; -using SJZY.Track.Application.Contract.Services; +using SJZY.Track.Application.Contract.Services.ProvideServices; using SJZY.Track.Domain.Aggregates.OrderAggregate; using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; -using SJZY.Track.Domain.Queries; using SJZY.UserCenter.HttpApi.Services; namespace SJZY.Track.Application.Services.ProvideServices; @@ -15,15 +15,17 @@ namespace SJZY.Track.Application.Services.ProvideServices; [Route("/ProviderService")] public partial class OrderService : ApplicationService, IOrderService { + private readonly IOrderOperationRecordEsRepository _orderOperationRecordEsRepository; private readonly IOrderRepository _orderRepository; - public OrderService(IOrderRepository orderRepository, IBasicQuery orderLinkQuery, - ICapPublisher capPublisher, ITrackDetailsRepository trackDetailsRepository) + public OrderService(IOrderRepository orderRepository, + ICapPublisher capPublisher, ITrackDetailsEsRepository trackDetailsEsRepository, + IOrderOperationRecordEsRepository orderOperationRecordEsRepository) { _orderRepository = orderRepository; - _trackDetailsRepository = trackDetailsRepository; + _orderOperationRecordEsRepository = orderOperationRecordEsRepository; + _trackDetailsEsRepository = trackDetailsEsRepository; _capPublisher = capPublisher; - _orderLinkQuery = orderLinkQuery; } /// @@ -32,26 +34,70 @@ public partial class OrderService : ApplicationService, IOrderService /// /// [HttpPost("Order/Upsert")] - public async Task UpsertAsync(UpsertOrderInput input) + public async Task> UpsertAsync(UpsertOrderInput input) { - if (input.Templates.Count == 0) throw new BusinessException(message: "至少有一个模板"); + // 校验预计到达时间是否不是同时存在或同时不存在 + if ((input.EstimatedDeliveryDate.HasValue && input.DestinationTimeZone.HasValue == false) || + (input.EstimatedDeliveryDate.HasValue == false && input.DestinationTimeZone.HasValue)) + { + throw new BusinessException(message: "【预计签收时间】和【签收地时区】必须同时输入"); + } + + var currentUser = CurrentUserRequest.CurrentUser; + + // 校验订单是否已存在,存在则更新 var order = await _orderRepository.GetFirstAsync(x => - x.OrderType == input.OrderType && x.OrderNo == input.OrderNo); + x.SubSystemId == input.SubSystemId && x.OrderType == input.OrderType && x.OrderNo == input.OrderNo); if (order != default) { // 订单已存在则视为更新 await UpdateOrderAsync(input, order); - return new UnifyResultDto() { Code = "200", Msg = "操作成功", Data = "创建成功" }; + var index = new OrderOperationRecordIndex + { + OrderId = order.Id, + OrderNo = input.OrderNo, + OptionType = OrderOperationType.修改订单.ToString(), + Content = input.ToJson(), + CreateUserId = currentUser.UserId, + CreateUserName = currentUser.Name, + }; + + _ = _orderOperationRecordEsRepository.AddAsync(index); + + return new UnifyResultDto(true, new IdBaseDto + { + Id = order.Id + }); } order = ObjectMapper.Map(input); - order.SubSystemId = CurrentUserRequest.SubSystemId; - order.OrderTemplates = ObjectMapper.Map, List>(input.Templates); + order.SubSystemId = input.SubSystemId; order.OrderFlights = ObjectMapper.Map, List>(input.FlightInfos); + order.OrderPullStatus = BuiltOrderPullStatus(input.PullConfigInfos); + order.OrderPlatformNumbers = BuiltOrderPlatformNumbers(input.PullConfigInfos); + order.TemplateCodes = input.TemplateCodes == null ? null : string.Join(',', input.TemplateCodes); - await _orderRepository.CreateOrderAsync(order); - return new UnifyResultDto() { Code = "200", Msg = "操作成功", Data = "新增成功" }; + var orderId = await _orderRepository.CreateOrderAsync(order); + + // 写入操作日志 + var indexForAdd = new OrderOperationRecordIndex + { + OrderId = orderId, + OrderNo = input.OrderNo, + OptionType = OrderOperationType.创建订单.ToString(), + Content = input.ToJson(), + CreateUserId = currentUser.UserId, + CreateUserName = currentUser.Name, + CreateTime = DateTime.Now + }; + _ = _orderOperationRecordEsRepository.AddAsync(indexForAdd); + + + return new UnifyResultDto(true, new IdBaseDto + { + Id = orderId + }); } /// @@ -61,10 +107,11 @@ public partial class OrderService : ApplicationService, IOrderService /// /// [HttpPost("Order/Delete")] - public async Task DeleteOrderAsync(DeleteOrderInput input) + public async Task> DeleteOrderAsync(DeleteOrderInput input) { var orderId = await _orderRepository.GetFirstAsync(x => - x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, x => x.Id); + x.SubSystemId == input.SubSystemId && x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, + x => x.Id); if (orderId == default) { throw new BusinessException(message: $"订单:{input.OrderNo}不存在"); @@ -72,14 +119,68 @@ public partial class OrderService : ApplicationService, IOrderService await _orderRepository.DeleteOrderAsync(orderId); - return new UnifyResultDto(true, true); + return new UnifyResultDto(true, new IdBaseDto + { + Id = orderId + }); } private async Task UpdateOrderAsync(UpdateOrderInput input, OrderEntity order) { order = ObjectMapper.Map(input, order); - order.OrderTemplates = ObjectMapper.Map, List>(input.Templates); order.OrderFlights = ObjectMapper.Map, List>(input.FlightInfos); + order.OrderPullStatus = BuiltOrderPullStatus(input.PullConfigInfos); + order.OrderPlatformNumbers = BuiltOrderPlatformNumbers(input.PullConfigInfos); + order.TemplateCodes = input.TemplateCodes == null ? null : string.Join(',', input.TemplateCodes); await _orderRepository.UpdateOrderAsync(order); } -} \ No newline at end of file + + + private List BuiltOrderPullStatus(List? pullConfigInfos) + { + if (pullConfigInfos == null) return new List(); + + return pullConfigInfos.Select(x => + { + var status = new OrderPullStatusEntity + { + ServiceProviderCode = x.ServiceCode, + OrderNo = x.OrderNo, + PullStatus = TrackPullStatus.Init, + StartTrackCode = x.StartCode ?? GlobalConst.EmptyString, + EndTrackCode = x.EndCode ?? GlobalConst.EmptyString, + SilenceBeforeStart = x.SilenceTime, + SilenceAfterEnd = x.StopTime, + StartTime = GlobalConst.MaxDateTime, + EndTime = GlobalConst.MaxDateTime, + }; + + // 没有开始轨迹则立即进入拉取前静默期 + if (x.StartCode == null) + { + status.PullStatus = TrackPullStatus.SilenceBeforeStart; // 会被定时任务扫描到并启动 + status.StartTime = DateTime.Now.AddHours(x.SilenceTime); + } + + return status; + }).ToList(); + } + + private List BuiltOrderPlatformNumbers(List? pullConfigInfos) + { + if (pullConfigInfos == null) return new List(); + + return pullConfigInfos.Select(x => + { + var status = new OrderPlatformNumberEntity + { + //三方单号 + OrderNumber = x.OrderNo, + //三方平台名称,目前认为是服务商code + Platform = x.ServiceCode, + }; + + return status; + }).ToList(); + } +} diff --git a/src/SJZY.Track.Application/Services/ProvideServices/TrackPullService.cs b/src/SJZY.Track.Application/Services/ProvideServices/TrackPullService.cs index cb7cd5e1..f82db360 100644 --- a/src/SJZY.Track.Application/Services/ProvideServices/TrackPullService.cs +++ b/src/SJZY.Track.Application/Services/ProvideServices/TrackPullService.cs @@ -1,11 +1,15 @@ -using Microsoft.AspNetCore.Authorization; -using SJZY.Expand.ABP.Core; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Options; +using SJZY.Expand.ABP.Core.Logger; +using SJZY.Expand.ABP.Core.PublicMethords; using SJZY.InterfaceRelay.Application.Contracts; using SJZY.Track.Application.Contract.Dtos.ProvideServices; using SJZY.Track.Application.Contract.Dtos.TrackPull; -using SJZY.Track.Application.Contract.Services; +using SJZY.Track.Application.Contract.Services.ProvideServices; using SJZY.Track.Application.Helpers; -using SJZY.Track.Domain.Consts; +using SJZY.Track.Application.Options; +using SJZY.Track.Application.Rabbit; +using SJZY.Track.Application.Track2InterfaceRelay; using SJZY.Track.Domain.Queries; using Volo.Abp.Http.Client.DynamicProxying; @@ -16,19 +20,19 @@ namespace SJZY.Track.Application.Services.ProvideServices; /// [ApiExplorerSettings(GroupName = "提供接口")] [Route("/ProviderService")] -public class TrackPullService : ApplicationService +public class TrackPullService : ApplicationService, ITrackPullService { - private readonly IProvideQueries _provideQueries; private readonly IHttpClientProxy _httpClientProxy; - private readonly ITrackPullCacheService _trackPullCacheService; + private readonly IOptionsMonitor _options; + private readonly IProvideQueries _provideQueries; public TrackPullService(IProvideQueries provideQueries, IHttpClientProxy httpClientProxy, - ITrackPullCacheService trackPullCacheService) + IOptionsMonitor options) { _provideQueries = provideQueries; _httpClientProxy = httpClientProxy; - _trackPullCacheService = trackPullCacheService; + _options = options; } /// @@ -43,7 +47,7 @@ public class TrackPullService : ApplicationService input.OrderNos = input.OrderNos.Where(x => !x.IsNullOrWhiteSpace()).Distinct().ToList(); // 单号去重、去空 // tips:这里没有区分订单类型,就算的不同类型的单一起刷新了也无所谓 - var orders = await _provideQueries.FindOrderWithServiceProviderAsync(input.OrderNos); + var orders = await _provideQueries.FindOrderWithServiceProviderAsync(input.SubSystemId, input.OrderNos); if (orders.Count == 0) { @@ -51,78 +55,59 @@ public class TrackPullService : ApplicationService throw new BusinessException(message: "一个能更新的都没有"); } - - foreach (var group in orders.GroupBy(x => new - { x.ServiceProviderId, x.ServiceProviderName, x.SubSystemId, x.OrderType })) + foreach (var group in orders.GroupBy(x => + new + { + x.ServiceProviderCode, + x.SubSystemId, + x.SubSystemCode, + x.OrderType + })) { - var data = group.Select(x => new + var data = new List(group.Select(x => new TrackPullPayload { - x.OrderNo - }).ToList(); - + OrderNo = x.OrderNo + })); var serviceProviderCode = group.FirstOrDefault()!.ServiceProviderCode; - var attach = Base64Helper.SerializeObject(group.Key); - // 批量获取轨迹 - var _ = await _httpClientProxy.Service.BatchForwardThenPushToQueueAsync( - InterfaceRelayConst.GetTrackInterfaceCode, serviceProviderCode, data, GlobalConst.TrackRefreshSubscribe, - attach); + var attach = Base64Helper.SerializeObject(new TrackRefreshAttach(group.Key.ServiceProviderCode, + group.Key.SubSystemId, group.Key.OrderType)); + + using (Track2InterfaceRelaySubSystemContext.Use( + new Track2InterfaceRelaySubSystemContext(group.Key.SubSystemCode))) + { + // 批量获取轨迹 + var res = await _httpClientProxy.Service.BatchForwardThenPushToQueueAsync( + _options.CurrentValue.GetTrackInterfaceCode, serviceProviderCode, data, + GlobalConst.TrackRefreshSubscribe, + attach); + + if (res.Code != GlobalConst.SuccessCode) + { + LogHelper.Error($"刷新轨迹失败:{res.ToJson()}"); + } + } } return true; } + /// - /// 定时任务刷新轨迹 + /// 轨迹刷新测试 /// + /// + /// /// + [HttpPost("Track/TrackRefreshEventTest")] +#if DEBUG [AllowAnonymous] - [HttpPost("Track/RefreshForTask")] - public bool RefreshForTaskAsync() +#endif + public async Task TrackRefreshEventTest([FromServices] TrackRefreshEventHandler trackRefreshEventHandler, + InterfaceRelayForwardReplayEvent input) { - Task.Run(async () => - { - var configs = await _trackPullCacheService.GetAllPullConfigsAsync(); - - foreach (var config in configs) - { - var redisKey = _trackPullCacheService.TrackPullKey(config.SubSystemId, config.ServiceProviderId); - if (await RedisHelper.Client.ExistsAsync(redisKey)) - { - continue; - } - - var page = 1; - var orders = await _provideQueries.FindOrderWithServiceProviderAsync(config.ServiceProviderId, page); - while (orders.Any()) - { - var serviceProviderCode = orders.FirstOrDefault()?.ServiceProviderCode; - var serviceProviderName = orders.FirstOrDefault()?.ServiceProviderName; - - foreach (var group in orders.GroupBy(x => - new { x.SubSystemId, x.OrderType })) - { - var data = group.Select(x => new - { - x.OrderNo - }).ToList(); - - var attach = Base64Helper.SerializeObject(new TrackRefreshAttach(config.ServiceProviderId, - serviceProviderName!, - group.Key.SubSystemId, group.Key.OrderType)); - // 批量获取轨迹 - await _httpClientProxy.Service.BatchForwardThenPushToQueueAsync( - InterfaceRelayConst.GetTrackInterfaceCode, serviceProviderCode, data, - GlobalConst.TrackRefreshSubscribe, attach); - } - - orders = await _provideQueries.FindOrderWithServiceProviderAsync(config.ServiceProviderId, ++page); - } - - await RedisHelper.Client.SetExAsync(redisKey, config.PullInterval * 60, orders.Count); - } - }); + await trackRefreshEventHandler.ConsumerAsync(input); return true; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/Services/ProvideServices/TrackPushConfigService.cs b/src/SJZY.Track.Application/Services/ProvideServices/TrackPushConfigService.cs index 04a8ea53..af0a2f16 100644 --- a/src/SJZY.Track.Application/Services/ProvideServices/TrackPushConfigService.cs +++ b/src/SJZY.Track.Application/Services/ProvideServices/TrackPushConfigService.cs @@ -1,45 +1,39 @@ -using SJZY.Track.Application.Contract.Dtos.ProvideServices; +using SJZY.Track.Application.Contract.Dtos.ProvideServices; using SJZY.Track.Application.Contract.Services; using SJZY.Track.Domain.Aggregates.TrackPushAggregate; using SJZY.Track.Domain.Dtos.TrackPush; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Volo.Abp.ObjectMapping; -namespace SJZY.Track.Application.Services.ProvideServices +namespace SJZY.Track.Application.Services.ProvideServices; + +/// +/// 轨迹推送配置服务 +/// +[ApiExplorerSettings(GroupName = "提供接口")] +[Route("/ProviderService")] +public class TrackPushConfigService : ApplicationService, ITrackPushConfigService { - /// - /// 轨迹推送配置服务 - /// - [ApiExplorerSettings(GroupName = "提供接口")] - [Route("/ProviderService")] - public class TrackPushConfigService : ApplicationService, ITrackPushConfigService + private readonly ITrackPushConfigRepository _trackPushConfigRepository; + + public TrackPushConfigService( + ITrackPushConfigRepository trackPushConfigRepository + ) { - private readonly ITrackPushConfigRepository _trackPushConfigRepository; + _trackPushConfigRepository = trackPushConfigRepository; + } - public TrackPushConfigService( - ITrackPushConfigRepository trackPushConfigRepository - ) - { - _trackPushConfigRepository = trackPushConfigRepository; - } + /// + /// 查询轨迹推送配置关系 + /// + /// + /// + [HttpPost("Track/QueryTrackPullMappings")] + public async Task>> QueryTrackPullMappingsAsync( + QueryTrackPullMappingsInput input) + { + var vo = ObjectMapper.Map(input); + var result = await _trackPushConfigRepository.QueryTrackPullMappingsAsync(vo); + var output = ObjectMapper.Map, List>(result); - /// - /// 查询轨迹推送配置关系 - /// - /// - /// - [HttpPost("Track/QueryTrackPullMappings")] - public async Task QueryTrackPullMappingsAsync(QueryTrackPullMappingsInput input) - { - var vo = ObjectMapper.Map(input); - var result = await _trackPushConfigRepository.QueryTrackPullMappingsAsync(vo); - var output = ObjectMapper.Map, List>(result); - - return new UnifyResultDto(true, output, "操作成功"); - } + return new UnifyResultDto>(true, output, "操作成功"); } } diff --git a/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs b/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs index 41a91a72..ec3289a3 100644 --- a/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs +++ b/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs @@ -1,11 +1,17 @@ -using DotNetCore.CAP; -using Microsoft.AspNetCore.Authorization; +using DotNetCore.CAP; +using SJZY.Expand.ABP.Core.Common; using SJZY.Track.Application.Contract.Dtos.ProvideServices; +using SJZY.Track.Application.Contract.Dtos.TrackOrder; +using SJZY.Track.Application.Contract.Dtos.TrackPush; using SJZY.Track.Application.Contract.Events; +using SJZY.Track.Application.Contract.Services.ProvideServices; +using SJZY.Track.Application.Helpers; using SJZY.Track.Domain.Aggregates.OrderAggregate; +using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; using SJZY.Track.Domain.Aggregates.TrackPushAggregate; -using SJZY.Track.Domain.Consts; -using SJZY.UserCenter.HttpApi.Services; +using SJZY.Track.Domain.Dtos.TrackPush; +using SJZY.Track.Domain.Queries; +using SJZY.UserCenter.HttpApi.Services.User; using Volo.Abp.Http.Client.DynamicProxying; namespace SJZY.Track.Application.Services.ProvideServices; @@ -15,22 +21,30 @@ namespace SJZY.Track.Application.Services.ProvideServices; /// [ApiExplorerSettings(GroupName = "提供接口")] [Route("/ProviderService")] -public class TrackPushService : ApplicationService +public class TrackPushService : ApplicationService, ITrackPushService { - private readonly IOrderRepository _orderRepository; private readonly ICapPublisher _capPublisher; - private readonly ITrackPushRecordsRepository _trackPushRecordsRepository; - private readonly IHttpClientProxy _requestCurrentUserService; + private readonly IOrderRepository _orderRepository; + private readonly IProvideQueries _provideQueries; + private readonly IHttpClientProxy _requestCurrentUserService; + private readonly ITrackPushConfigRepository _trackPushConfigRepository; + private readonly ITrackPushRecordEsRepository _trackPushRecordEsRepository; + private readonly ITrackDetailsEsRepository _trackDetailsEsRepository; public TrackPushService(IOrderRepository orderRepository , ICapPublisher capPublisher - , ITrackPushRecordsRepository trackPushRecordsRepository, - IHttpClientProxy requestCurrentUserService) + , ITrackPushRecordEsRepository trackPushRecordEsRepository + , IHttpClientProxy requestCurrentUserService + , ITrackPushConfigRepository trackPushConfigRepository, IProvideQueries provideQueries, + ITrackDetailsEsRepository trackDetailsEsRepository) { _orderRepository = orderRepository; _capPublisher = capPublisher; - _trackPushRecordsRepository = trackPushRecordsRepository; + _trackPushRecordEsRepository = trackPushRecordEsRepository; _requestCurrentUserService = requestCurrentUserService; + _trackPushConfigRepository = trackPushConfigRepository; + _provideQueries = provideQueries; + _trackDetailsEsRepository = trackDetailsEsRepository; } /// @@ -39,15 +53,20 @@ public class TrackPushService : ApplicationService /// /// [HttpPost("Track/Push")] - public async Task PushTrackAsync(PushTrackInput input) + [CustomerResult] + public async Task PushTrackAsync(PushTrackInput input) { input.OrderNos = input.OrderNos.Where(x => !x.IsNullOrWhiteSpace()).Distinct().ToList(); // 单号去重、去空 + var subSystemCode = await _provideQueries.SubSystemId2CodeAsync(input.SubSystemId); var orders = await _orderRepository.GetArrayAsync(x => - x.OrderType == input.OrderType && input.OrderNos.Contains(x.OrderNo), x => new - { - x.Id, x.SubSystemId, x.CustomId - }); + x.SubSystemId == input.SubSystemId && x.OrderType == input.OrderType && + input.OrderNos.Contains(x.OrderNo), + x => new + { + x.Id, + x.CustomId + }); if (!orders.Any()) { @@ -55,44 +74,117 @@ public class TrackPushService : ApplicationService } var userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync(); - if (userInfo.Code != "200" || userInfo.Data is null) + if (userInfo.Code != GlobalConst.SuccessCode || userInfo.Data is null) { - //TODO: log || ex - throw new BusinessException(message: $"调用用户中心,获取用户信息失败:{userInfo?.Msg}"); + throw new BusinessException(message: $"调用用户中心,获取用户信息失败:{userInfo.Msg}"); } var name = userInfo.Data.UserName; - foreach (var group in orders.GroupBy(x => new { x.SubSystemId, x.CustomId })) + //查出需要推送的轨迹 + var tracks = await _trackDetailsEsRepository + .GetListAsync(input.SubSystemId, input.OrderType, input.OrderNos, + new List + { + input.TrackCode + }); + if (tracks.Count == 0) { + throw new BusinessException(message: "没有需要推送的轨迹"); + } + + //存在比较字段,需要做过滤处理 + if (!string.IsNullOrWhiteSpace(input.CompareFields)) + { + //根据输入值来进行过滤,比如选取code1,批次1的轨迹,可能会有多条,下面使用创建时间最新的一条 + tracks = tracks.Where(x => + { + if (string.IsNullOrWhiteSpace(x.Extra)) + { + throw new BusinessException(message: $"当前轨迹不存在扩展信息,无法利用扩展字段:{input.CompareFields}"); + } + + var extraDict = GetExtraDictForTextJson(x.Extra); + if (extraDict == null || !extraDict.TryGetValue(input.CompareFields, out var compareValue)) + { + throw new BusinessException(message: $"请检查拓展字段,为什么找不到比较字段:{input.CompareFields}"); + } + + //补充轨迹内容 + return TextJsonHelper.EqJsonElementAndObject(compareValue, input.CompareValue); + }).ToList(); + } + + //不同单可能会有不同的轨迹内容,先推送只推送最新的一条 + foreach (var order in orders) + { + //找出每个单的某个code的最新轨迹内容 + var track = tracks.Where(x => x.OrderId == order.Id) + .OrderByDescending(x => x.CreateTime) + .FirstOrDefault(); + if (track == null) continue; + var trackPushEvent = new TrackPushEvent { OptionType = OptionType.新增, - SubSystemId = group.Key.SubSystemId, - CustomId = group.Key.CustomId, - OrderIds = group.Select(x => x.Id).ToArray(), + SubSystemId = input.SubSystemId, + SubSystemCode = subSystemCode, + CustomId = order.CustomId, + OrderIds = new[] { order.Id }, TrackCode = input.TrackCode, OperationMan = name, + SystemPushInfo = new SystemPushStruct() + { + TrackStatus = track.TrackStatus, + TrackContent = track.TrackContent, + TrackPlace = track.TrackPlace, + TrackTime = track.TrackTime, + TrackTimeZone = track.TrackTimeZone, + CompareFields = input.CompareFields, + Extra = track.Extra + } }; await _capPublisher.PublishAsync(GlobalConst.TrackManualPushSubscribe, trackPushEvent); } - return $"即将推送轨迹代码{input.TrackCode}给{orders.Length}个订单"; + + // foreach (var group in orders.GroupBy(x => x.CustomId)) + // { + // var trackPushEvent = new TrackPushEvent + // { + // OptionType = OptionType.新增, + // SubSystemId = input.SubSystemId, + // SubSystemCode = subSystemCode, + // CustomId = group.Key, + // OrderIds = group.Select(x => x.Id).ToArray(), + // TrackCode = input.TrackCode, + // OperationMan = name, + // SystemPushInfo = new SystemPushStruct() + // }; + // + // await _capPublisher.PublishAsync(GlobalConst.TrackManualPushSubscribe, trackPushEvent); + // } + + return new UnifyResultDto(true, $"即将推送轨迹代码{input.TrackCode}给{orders.Length}个订单"); } /// - /// 定时任务推送预警(》12小时没有推送的) + /// 获取轨迹推送内容 /// + /// + /// /// - [AllowAnonymous] - [HttpPost("Track/PushWarnForTask")] - public async Task PushWarnForTaskAsync() + [HttpGet("Track/GetTrackPushContentList")] + [CustomerResult] + public async Task>> GetTrackPushContentListAsync(int subSystemId, int customerId) { - // todo:订单数据上来后一次性update是否会引发长时间X独占? - var count = await _orderRepository.PushWarnOrdersAsync(); - return $"本次预警扫描了:{count}个订单"; + var list = await _trackPushConfigRepository.GetTrackPushContentListAsync(subSystemId, customerId); + + var result = ObjectMapper.Map, List>(list); + + return new UnifyResultDto>(true, result, "操作成功"); } /// @@ -101,15 +193,27 @@ public class TrackPushService : ApplicationService /// /// [HttpGet("Track/GetTrackPushRecords")] - public async Task> GetTrackPushRecordsAsync(OrderNoInfo input) + [CustomerResult] + public async Task>> GetTrackPushRecordsAsync([FromQuery] OrderNoInfo input) { var orderId = await _orderRepository.GetFirstAsync(x => - x.OrderType == input.OrderType && input.OrderNo == x.OrderNo, x => x.Id); + x.SubSystemId == input.SubSystemId && x.OrderType == input.OrderType && input.OrderNo == x.OrderNo, + x => x.Id); if (orderId == default) { throw new BusinessException(message: "订单不存在"); } - return await _trackPushRecordsRepository.GetTrackPushRecordsAsync(orderId); + var records = await _trackPushRecordEsRepository.GetTrackPushRecordsAsync(orderId); + + var res = ObjectMapper.Map, List>(records); + return new UnifyResultDto>(true, res, "操作成功"); } -} \ No newline at end of file + + private Dictionary? GetExtraDictForTextJson(string? extraStr) + { + return string.IsNullOrWhiteSpace(extraStr) + ? null + : System.Text.Json.JsonSerializer.Deserialize>(extraStr); + } +} diff --git a/src/SJZY.Track.Application/Services/ProvideServices/TrackService.Query.cs b/src/SJZY.Track.Application/Services/ProvideServices/TrackService.Query.cs index 74f4e52f..e5b184cb 100644 --- a/src/SJZY.Track.Application/Services/ProvideServices/TrackService.Query.cs +++ b/src/SJZY.Track.Application/Services/ProvideServices/TrackService.Query.cs @@ -1,5 +1,10 @@ +using Microsoft.AspNetCore.Http; +using SJZY.Expand.AliyunOSS; using SJZY.Track.Application.Contract.Dtos.ProvideServices; using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; +using SJZY.Track.Domain.Aggregates.TrackTemplateAggregate; +using SJZY.Track.Domain.Dtos.TrackTemplate; +using SJZY.Track.Domain.Queries; namespace SJZY.Track.Application.Services.ProvideServices; @@ -8,101 +13,385 @@ namespace SJZY.Track.Application.Services.ProvideServices; /// public partial class TrackService { - private readonly ITrackDetailsRepository _trackDetailsRepository; + private readonly ITrackDetailsEsRepository _trackDetailsEsRepository; + private readonly ITrackTemplateRepository _trackTemplateRepository; + private readonly IHttpContextAccessor _contextAccessor; + private readonly IVSystemQueries _vSystemQueries; /// - /// 查询轨迹 + /// 查询轨迹(时区补正) /// /// /// /// [HttpPost("Track/Query")] - public async Task QueryAsync(GetTrackInput input) + public async Task>> QueryAsync(GetTrackInput input) { - if (input.OrderNos.Count > 500) - { - throw new BusinessException(message: "最多只能查询500单"); - } - var res = new List(); input.OrderNos = input.OrderNos.Where(x => !x.IsNullOrWhiteSpace()).Distinct().ToList(); // 单号去重、去空 - var details = await _trackDetailsRepository.GetListAsync(input.OrderType, input.OrderNos); + + var details = await _trackDetailsEsRepository.GetListAsync(input.SubSystemId, input.OrderType, input.OrderNos); + + //内部子系统不过滤外部轨迹 + var isFilterExternal = await HasFilterExternalTrack(); + + var ossKeys = details + .Where(x => x.Files != null && x.Files.Count > 0) + .SelectMany(x => x.Files!.Select(y => y.OssKey)) + .ToArray(); + //根据osskey获取下载地址 + var ossKeyUrlDict = OSSHelper.GetUrlByKeys(ossKeys); foreach (var group in details.GroupBy(x => x.OrderId)) { var item = new GetTrackOutput(); - var trackDetails = group.ToList(); + var trackDetails = group + .WhereIf(isFilterExternal, x => x.IsExternal) + .ToList(); + if (trackDetails.Count == 0) + continue; item.OrderNo = trackDetails.First().OrderNo; item.TrackDetails = trackDetails.Select(x => new TrackDetail { + EsId = x.Id, Code = x.TrackCode, Status = x.TrackStatus, Content = x.TrackContent, + EnContent = x.TrackEnContent, OriginContent = x.OriginTrackContent, Location = x.TrackPlace, - Time = x.TrackTime.AddHours(input.TimeZone ?? 8 - x.TrackTimeZone), - TimeZone = input.TimeZone ?? 8 + Time = Math.Abs(x.TrackTimeZone - GlobalConst.NoneTrackTimeZone) < 1 + ? x.TrackTime + : x.ZeroTrackTime.AddHours(input.TimeZone ?? 8), + TimeZone = Math.Abs(x.TrackTimeZone - GlobalConst.NoneTrackTimeZone) < 1 + ? null + : input.TimeZone ?? 8, + IsDisplay = x.IsExternal, + IsVisibility = x.IsVisibility, + IsExternal = x.IsExternal, + Source = x.Source, + Remarks = x.Remarks, + Files = x.Files?.Select(y => new FileItemDto + { + FileName = y.FileName, + OssKey = y.OssKey, + DownloadUrl = ossKeyUrlDict.TryGetValue(y.OssKey, out var url) ? url : null + }).ToList(), + TrackPlaceCity = x.TrackPlaceCity, + TrackPlaceCityId = x.TrackPlaceCityId, + TrackPlaceProvince = x.TrackPlaceProvince, + TrackPlaceProvinceId = x.TrackPlaceProvinceId, + TrackPlaceNation = x.TrackPlaceNation, + TrackPlaceNationId = x.TrackPlaceNationId, + TrackPlacePostcode = x.TrackPlacePostcode, + DestinationTimeZone = x.DestinationTimeZone, + EstimatedDeliveryDate = x.EstimatedDeliveryDate, + Extra = x.Extra }).ToList(); res.Add(item); } - await TrackDetailSort(res, input); - return new UnifyResultDto(true, res, "操作成功"); + // 排序 + var sortedList = await TracksOrdered(res, input, input.SortMethod); + + return new UnifyResultDto>(true, sortedList, "操作成功"); } - private async Task TrackDetailSort(List list, GetTrackInput input) + + /// + /// 查询轨迹(原样返回) + /// + /// + /// + [HttpPost("Track/QueryV2")] + public async Task>> QueryV2Async(GetTrackInputV2 input) { - var orderTemplates = await _provideQueries - .GetOrderTemplateLinksAsync(input.OrderType, input.OrderNos); - var distinctTemplateIds = orderTemplates.Select(x => x.TemplateId).Distinct().ToList(); - var templateContent = await _provideQueries.GetOrderedTrackCodesAsync(distinctTemplateIds); + var res = new List(); + input.OrderNos = input.OrderNos.Where(x => !x.IsNullOrWhiteSpace()).Distinct().ToList(); // 单号去重、去空 - list.ForEach(item => + var details = await _trackDetailsEsRepository.GetListAsync(input.SubSystemId, input.OrderType, input.OrderNos); + + //内部子系统不过滤外部轨迹 + var isFilterExternal = await HasFilterExternalTrack(); + + var ossKeys = details + .Where(x => x.Files != null && x.Files.Count > 0) + .SelectMany(x => x.Files!.Select(y => y.OssKey)) + .ToArray(); + //根据osskey获取下载地址 + var ossKeyUrlDict = OSSHelper.GetUrlByKeys(ossKeys); + + foreach (var group in details.GroupBy(x => x.OrderId)) { - var codes = new List(); - // 多模板拼接显示 - foreach (var orderTemplate in orderTemplates.Where(x => x.OrderNo == item.OrderNo)) - { - codes.AddRange(templateContent - .Where(t => t.TemplateId == orderTemplate.TemplateId) // 按模板 - .Where(t => t.IsExternal) // 过滤不对外的 - .Select(t => t.Code)); - } - - item.TrackDetails = item.TrackDetails - .Where(x => codes.Contains(x.Code)) // 剔除不在模板内容中的元素 - .OrderBy(x => codes.IndexOf(x.Code)) // 按照在模板内容的位置排序 + var item = new GetTrackOutput(); + var trackDetails = group + .WhereIf(isFilterExternal, x => x.IsExternal) .ToList(); - }); + if (trackDetails.Count == 0) + continue; + item.OrderNo = trackDetails.First().OrderNo; - switch (input.SortMethod) + item.TrackDetails = trackDetails.Select(x => new TrackDetail + { + EsId = x.Id, + Code = x.TrackCode, + Status = x.TrackStatus, + Content = x.TrackContent, + EnContent = x.TrackEnContent, + OriginContent = x.OriginTrackContent, + Location = x.TrackPlace, + Time = x.TrackTime, + TimeZone = x.TrackTimeZone, + IsDisplay = x.IsExternal, + IsVisibility = x.IsVisibility, + IsExternal = x.IsExternal, + Source = x.Source, + Remarks = x.Remarks, + Files = x.Files?.Select(y => new FileItemDto + { + FileName = y.FileName, + OssKey = y.OssKey, + DownloadUrl = ossKeyUrlDict.TryGetValue(y.OssKey, out var url) ? url : null + }).ToList(), + TrackPlaceCity = x.TrackPlaceCity, + TrackPlaceCityId = x.TrackPlaceCityId, + TrackPlaceProvince = x.TrackPlaceProvince, + TrackPlaceProvinceId = x.TrackPlaceProvinceId, + TrackPlaceNation = x.TrackPlaceNation, + TrackPlaceNationId = x.TrackPlaceNationId, + TrackPlacePostcode = x.TrackPlacePostcode, + DestinationTimeZone = x.DestinationTimeZone, + EstimatedDeliveryDate = x.EstimatedDeliveryDate, + Extra = x.Extra + }).ToList(); + + res.Add(item); + } + + // 排序 + var sortedList = await TracksOrdered(res, input, input.SortMethod); + + return new UnifyResultDto>(true, sortedList, "操作成功"); + } + + //内部系统展示所有轨迹,外部系统则要求过滤外部轨迹 + private async Task HasFilterExternalTrack() + { + var isFilter = true; + if (_contextAccessor.HttpContext!.Request.Headers.TryGetValue(GlobalConst.HTTP_HEADER_SUBSYSTEMID, out var subsystemIdStr)) + { + if (int.TryParse(subsystemIdStr, out var subsystemId)) + { + var systemEntity = await _vSystemQueries.GetFirstAsync(x => x.Id == subsystemId); + isFilter = systemEntity?.SystemProperty != 1; + } + } + + return isFilter; + } + + + private async Task> TracksOrdered(List list, OrderNosInfo orderNosInfo, SortMethod? sortMethod) + { + switch (sortMethod) { case SortMethod.ByTrackTime: + case SortMethod.ByTemplateAndTrackTime: // tips:quick-sort 直接修改原list list.ForEach(item => item.TrackDetails.Sort((a, b) => a.Time.CompareTo(b.Time))); break; + case null: case SortMethod.ByTrackTimeDesc: + case SortMethod.ByTemplateAndTrackTimeDesc: list.ForEach(item => item.TrackDetails.Sort((a, b) => b.Time.CompareTo(a.Time))); break; - case SortMethod.ByTemplate: - break; default: - throw new ArgumentOutOfRangeException(nameof(input.SortMethod), input.SortMethod, "不支持的排序方式"); + throw new ArgumentOutOfRangeException(nameof(sortMethod), sortMethod, "不支持的排序方式"); } - // 显示原轨迹 - list.ForEach(item => + if (sortMethod != SortMethod.ByTemplateAndTrackTime + && sortMethod != SortMethod.ByTemplateAndTrackTimeDesc) { - item.TrackDetails.ForEach(track => - { - if (templateContent.First(x => x.Code == track.Code).ShowOrigin) - { - track.Content = track.OriginContent; - } - }); + return list; + } + + //查出订单模板 + var templates = await _trackTemplateRepository.GetTrackTemplateListAsync(new GetTrackTemplateListInputVo + { + SubSystemId = orderNosInfo.SubSystemId }); + + if (templates.Count == 0) + { + return list; + } + + //查出订单和模板的关系,构建订单号和模板code的关系 + var orderNoTemplateDict = (await _orderRepository + .GetOrderTemplateAsync(orderNosInfo.SubSystemId, orderNosInfo.OrderType, orderNosInfo.OrderNos)) + .ToDictionary(x => x.OrderNo, x => x.TemplateCodes?.Split(",").ToHashSet()); + + //查询出订单和模板的关联关系,保证该订单使用自己的模板排序 + foreach (var getTrackOutput in list) + { + //查看该订单具有的模板 + var curOrderNoTemplateCodes = orderNoTemplateDict[getTrackOutput.OrderNo]; + if (curOrderNoTemplateCodes == null || curOrderNoTemplateCodes.Count == 0) continue; + + //选出这个订单号所具有的模板 + var tipTemplates = templates.Where(x => curOrderNoTemplateCodes.Contains(x.TemplateCode)).ToList(); + if (tipTemplates.Count == 0) continue; + + getTrackOutput.TrackDetails = SortByTemplatesAsync(getTrackOutput.TrackDetails, tipTemplates, sortMethod == SortMethod.ByTemplateAndTrackTime); + } + + return list; } -} \ No newline at end of file + + + /// + /// 轨迹发生时间(统一utc)排序,相同时间按模板排序,考虑多个模板的情况 + /// + /// + private static List SortByTemplatesAsync(List seq, List templates, bool isAsc = true) + { + //转化为统一时间 + var trackWraps = seq.Select(x => new TrackWrap(x)); + var sortedTracks = (isAsc + ? trackWraps.OrderBy(x => x.Time) + : trackWraps.OrderByDescending(x => x.Time)).ToList(); + + + //用于统计时间相同的轨迹 + var timeEqTrackDict = new Dictionary>(); + for (var i = 0; i < sortedTracks.Count; i++) + { + var trackWrap = sortedTracks[i]; + if (timeEqTrackDict.TryGetValue(trackWrap.Time, out var list)) + list.Add(new TrackIdxWarp(trackWrap.Track, i)); + else + timeEqTrackDict.Add(trackWrap.Time, new List + { + new TrackIdxWarp(trackWrap.Track, i) + }); + } + + + //选出需要按模板重排序的轨迹 + var timeEqTracks = timeEqTrackDict + .Where(kv => kv.Value.Count > 1) + .ToDictionary(kv => kv.Key, kv => kv.Value); + + //初始化为最后一个模板排序 + var preSortDict = templates[templates.Count - 1] + .TemplateContents + .OrderBy(x => x.Sort) + .ToDictionary(x => x.Code, x => x.Sort); + + for (var i = templates.Count - 2; i >= 0; i--) + { + var curCodeSortDict = templates[i] + .TemplateContents + .ToDictionary(x => x.Code, y => y.Sort); + + //没在之前模板出现的code + var noTipPreCodeSortDict = curCodeSortDict + .Where(x => !preSortDict.ContainsKey(x.Key)) + .ToDictionary(x => x.Key, y => y.Value); + + //插入未命中的模板code + foreach (var (noTipCode, curNoTipCodeSort) in noTipPreCodeSortDict) + { + //初始化插入位置 + var insertPos = -1; + foreach (var (preCode, _) in preSortDict) + { + if (curCodeSortDict.TryGetValue(preCode, out var preCodeSort)) + { + //未命中的相对于之前模板的偏后,设置插入位置在 + if (preCodeSort < curNoTipCodeSort) + { + insertPos = preSortDict[preCode] + 1; + } + } + } + + //结束了还没选好位置,未命中的code相对于之前的模板code在当前模板最前面 + if (insertPos == -1) + { + foreach (var (c, s) in preSortDict) + preSortDict[c] = s + 1; + preSortDict[noTipCode] = 0; + } + else + { + foreach (var (c, s) in preSortDict.Where(x => x.Value >= insertPos)) + preSortDict[c] = s + 1; + preSortDict[noTipCode] = insertPos; + } + } + } + + + foreach (var trackIdxWarps in timeEqTracks.Values) + { + var curIndex = trackIdxWarps.Min(x => x.Index); + //按模板从小到大排序 + var sortByTemplate = (isAsc + ? trackIdxWarps + .OrderBy(x => preSortDict.GetValueOrDefault(x.Track.Code, int.MaxValue)) + : trackIdxWarps + .OrderByDescending(x => preSortDict.GetValueOrDefault(x.Track.Code, int.MaxValue)) + ).ToList(); + for (var j = 0; j < sortByTemplate.Count; j++) + { + var track = sortByTemplate[j]; + //当前索引不对应 + if (track.Index != curIndex + j) + { + var temp1 = sortedTracks[track.Index].Track; + var temp2 = sortedTracks[curIndex + j].Track; + sortedTracks[track.Index].Track = temp2; + sortedTracks[curIndex + j].Track = temp1; + trackIdxWarps.First(x => x.Index == curIndex + j).Index = track.Index; + track.Index = curIndex + j; + } + } + } + + return sortedTracks.Select(x => x.Track).ToList(); + } + + + private class TrackIdxWarp + { + public TrackDetail Track { get; set; } + public int Index { get; set; } + + public TrackIdxWarp(TrackDetail track, int index) + { + Track = track; + Index = index; + } + } + + + private class TrackWrap + { + public TrackDetail Track { get; set; } + + public DateTime Time { get; set; } + + public TrackWrap(TrackDetail track) + { + Track = track; + var timeZone = track.TimeZone ?? GlobalConst.NoneTrackTimeZone; + Time = Math.Abs(timeZone - GlobalConst.NoneTrackTimeZone) < 1 + ? track.Time + : track.Time.Subtract(TimeSpan.FromHours(timeZone)); + } + } +} diff --git a/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs b/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs index f3d63ca2..b7b9e305 100644 --- a/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs +++ b/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs @@ -1,12 +1,17 @@ -using DotNetCore.CAP; +using DotNetCore.CAP; +using Microsoft.AspNetCore.Http; using SJZY.Track.Application.Contract.Dtos.ProvideServices; using SJZY.Track.Application.Contract.Events; -using SJZY.Track.Application.Contract.Services; +using SJZY.Track.Application.Contract.Services.ProvideServices; +using SJZY.Track.Application.Helpers; using SJZY.Track.Domain.Aggregates.OrderAggregate; +using SJZY.Track.Domain.Aggregates.TrackContentAggregate; using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; -using SJZY.Track.Domain.Consts; +using SJZY.Track.Domain.Aggregates.TrackTemplateAggregate; +using SJZY.Track.Domain.Enums; using SJZY.Track.Domain.Queries; using SJZY.UserCenter.HttpApi.Services; +using SJZY.UserCenter.HttpApi.Services.User; using Volo.Abp.Http.Client.DynamicProxying; namespace SJZY.Track.Application.Services.ProvideServices; @@ -18,21 +23,234 @@ namespace SJZY.Track.Application.Services.ProvideServices; [Route("/ProviderService")] public partial class TrackService : ApplicationService, ITrackService { - private readonly IOrderRepository _orderRepository; - private readonly IProvideQueries _provideQueries; private readonly ICapPublisher _capPublisher; - private readonly IHttpClientProxy _requestCurrentUserService; + private readonly IOrderRepository _orderRepository; + private readonly IHttpClientProxy _requestCurrentUserService; + private readonly ITrackContentRepository _trackContentRepository; - public TrackService(IOrderRepository orderRepository, IProvideQueries provideQueries, ICapPublisher capPublisher, - ITrackDetailsRepository trackDetailsRepository, - IHttpClientProxy requestCurrentUserService) + public TrackService(IOrderRepository orderRepository, + ICapPublisher capPublisher, + ITrackDetailsEsRepository trackDetailsEsRepository, + ITrackContentRepository trackContentRepository, + IHttpClientProxy requestCurrentUserService, + ITrackTemplateRepository trackTemplateRepository, + IHttpContextAccessor contextAccessor, + IVSystemQueries vSystemQueries) { _orderRepository = orderRepository; - _provideQueries = provideQueries; - _provideQueries = provideQueries; _capPublisher = capPublisher; + _trackContentRepository = trackContentRepository; _requestCurrentUserService = requestCurrentUserService; - _trackDetailsRepository = trackDetailsRepository; + _vSystemQueries = vSystemQueries; + _contextAccessor = contextAccessor; + _trackTemplateRepository = trackTemplateRepository; + _trackDetailsEsRepository = trackDetailsEsRepository; + } + + /// + /// 删除轨迹 + /// + /// + /// + /// + [HttpPost("Track/Delete")] + public async Task DeleteTrackAsync(DeleteTrackInput input) + { + var orderId = await _orderRepository.GetFirstAsync( + x => x.SubSystemId == input.SubSystemId && x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, + x => x.Id); + if (orderId == default) + { + throw new BusinessException(message: $"订单:{input.OrderNo}不存在"); + } + + var userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync(); + if (userInfo.Code != GlobalConst.SuccessCode || userInfo.Data is null) + { + //TODO: log || ex + throw new BusinessException(message: $"调用用户中心,获取用户信息失败:{userInfo.Msg}"); + } + + var name = userInfo.Data.UserName; + + var tracks = new List(); + var existsExternal = false; + var esIds = input.EsIds?.Distinct().ToArray(); + //优先使用esId + if (esIds != null && esIds.Length > 0) + { + tracks = await _trackDetailsEsRepository.GetDataByIds(esIds); + existsExternal = tracks.Any(x => x.Source == (int) TrackSourceEnum.ExternalServiceProvide); + } + else + { + var trackCodes = input.TrackIdentifiers?.Select(x => x.TrackCode).ToList(); + var trackIds = input.TrackIdentifiers?.Select(y => $"{y.TrackCode}{y.TrackTime}").ToHashSet(); + //没有任何需要操作的轨迹 + if (trackIds == null || trackIds.Count == 0) + { + throw new BusinessException(message: "没有任何轨迹要删除,请检查输入参数"); + } + + //删除轨迹约束,只要其中有一条来源是外部的就立即返回错误 + tracks = await _trackDetailsEsRepository.GetListAsync(new[] { orderId }, trackCodes); + //检查删除的轨迹中是否包含外部轨迹 + existsExternal = tracks + .Where(x => x.Source == (int) TrackSourceEnum.ExternalServiceProvide) + .WhereIf(!input.CompareFields.IsNullOrWhiteSpace(), y => + { + if (string.IsNullOrWhiteSpace(y.Extra)) + { + throw new BusinessException(message: "轨迹extra为空无法使用比较字段比较,请检查轨迹"); + } + + var extraDict = System.Text.Json.JsonSerializer.Deserialize>(y.Extra); + if (extraDict!.TryGetValue(input.CompareFields!, out var compareValueJsonElement)) + return TextJsonHelper.EqJsonElementAndObject(compareValueJsonElement, input.CompareValue); + + return false; + }) + .Select(x => $"{x.TrackCode}{x.TrackTime}") + .Any(x => trackIds.Contains(x)); + } + + if (existsExternal) + { + throw new BusinessException(message: "存在来源于外部服务商的轨迹,不允许删除"); + } + + if (tracks.Count == 0) + { + throw new BusinessException(message: "没有任何轨迹要删除,请检查输入参数"); + } + + // 删除轨迹 + await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe, + new TrackDeleteEvent + { + EsIds = input.EsIds?.ToArray(), + OrderIds = new[] { orderId }, + CompareFields = input.CompareFields, + CompareValue = input.CompareValue, + TrackIdentifiers = input.TrackIdentifiers, + SubSystemId = input.SubSystemId, + OperationMan = name + }); + + return new UnifyResultDto(true, true); + } + + /// + /// 根据esid删除轨迹内容 + /// + /// + /// + [HttpPost("Track/BatchDeleteByEsId")] + public async Task BatchDeleteTrackByEsIdAsync(BatchDeleteTrackByEsIdInput input) + { + var tracks = await _trackDetailsEsRepository.GetDataByIds(input.TrackContentEsIds.ToArray()); + if (tracks == null || tracks.Count == 0) + return new UnifyResultDto(false, "未找到指定id下的轨迹内容"); + + if (tracks.Any(m => m.Source == TrackSourceEnum.ExternalServiceProvide.GetHashCode())) + return new UnifyResultDto(false, "存在来源于外部服务商的轨迹,不允许删除"); + + if (tracks.GroupBy(m => m.SubSystemId).Count() > 1) + return new UnifyResultDto(false, "暂不支持跨子系统批量删除"); + + // 获取用户name + var userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync(); + if (userInfo.Code != GlobalConst.SuccessCode || userInfo.Data is null) + { + throw new BusinessException(message: $"调用用户中心,获取用户信息失败:{userInfo.Msg}"); + } + + // 删除轨迹 + var currentUser = CurrentUserRequest.CurrentUser; + var userName = userInfo.Data.UserName; + if (string.IsNullOrEmpty(userName)) + userName = (await _orderRepository.GetUserById(currentUser.UserId))?.Name; + + var @event = new TrackDeleteEvent + { + EsIds = input.TrackContentEsIds.ToArray(), + SubSystemId = tracks.First().SubSystemId, + OperationMan = userName, + OperationManId = currentUser.UserId + }; + await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe, @event); + + return new UnifyResultDto(true); + } + + /// + /// 批量删除轨迹 + /// + /// + /// + /// + [HttpPost("Track/BatchDelete")] + public async Task BatchDeleteTrackAsync(BatchDeleteTrackInput input) + { + input.OrderNos = input.OrderNos.Where(x => !x.IsNullOrWhiteSpace()).Distinct().ToList(); // 单号去重、去空 + var orderIds = await _orderRepository.GetListAsync(x => + x.SubSystemId == input.SubSystemId && x.OrderType == input.OrderType && + input.OrderNos.Contains(x.OrderNo) + , x => x.Id); + + if (orderIds.Count == 0) + { + throw new BusinessException(message: "订单一个都不存在"); + } + + // 获取用户name + var userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync(); + if (userInfo.Code != GlobalConst.SuccessCode || userInfo.Data is null) + { + throw new BusinessException(message: $"调用用户中心,获取用户信息失败:{userInfo.Msg}"); + } + + //删除轨迹约束,只要其中有一条来源是外部的就立即返回错误 + var tracks = await _trackDetailsEsRepository + .GetListAsync(orderIds.ToArray(), + input.TrackIdentifiers.Select(x => x.TrackCode).ToList(), + TrackSourceEnum.ExternalServiceProvide); + + //当要删除的轨迹标识出现交叉则不允许删除 + var intersect = tracks + .WhereIf(!input.CompareFields.IsNullOrWhiteSpace(), y => + { + if (string.IsNullOrWhiteSpace(y.Extra)) + { + throw new BusinessException(message: "轨迹extra为空无法使用比较字段比较,请检查轨迹"); + } + + var extraDict = TextJsonHelper.DeserializeToDictionary(y.Extra); + if (extraDict!.TryGetValue(input.CompareFields!, out var compareValueJsonElement)) + return TextJsonHelper.EqJsonElementAndObject(compareValueJsonElement, input.CompareValue); + + return false; + }) + .Select(x => $"{x.TrackCode}{x.TrackTime}") + .Intersect(input.TrackIdentifiers.Select(y => $"{y.TrackCode}{y.TrackTime}")).ToList(); + if (intersect.Count > 0) + { + throw new BusinessException(message: "存在来源于外部服务商的轨迹,不允许删除"); + } + + // 删除轨迹 + var @event = new TrackDeleteEvent + { + OrderIds = orderIds.ToArray(), + TrackIdentifiers = input.TrackIdentifiers, + CompareFields = input.CompareFields, + CompareValue = input.CompareValue, + SubSystemId = input.SubSystemId, + OperationMan = userInfo.Data.UserName, + }; + await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe, @event); + + return new UnifyResultDto(true, true); } /// @@ -45,35 +263,59 @@ public partial class TrackService : ApplicationService, ITrackService public async Task UpsertTrackAsync(UpsertTrackInput input) { var order = await _orderRepository.GetFirstAsync(x => - x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, x => new - { - x.Id, x.SubSystemId, x.OrderNo, x.OrderType, x.CustomId - }); + x.SubSystemId == input.SubSystemId + && x.OrderType == input.OrderType + && x.OrderNo == input.OrderNo, + x => new + { + x.Id, + x.OrderNo, + x.CustomId + }); if (order == default) { throw new BusinessException(message: $"订单:{input.OrderNo}不存在"); } + // 输入参数的静态规则检查 + // 轨迹内容上的约束检查 + // 更新轨迹时是否可以匹配到轨迹的检查 + await TrackUpsertValidation(input.IsAdd, + input.SubSystemId, + order.Id, + order.OrderNo, + input.TrackCode, + input.Source, + input.TrackTime, + input.NewTrackTime, + input.EstimatedDeliveryDate, + input.DestinationTimeZone, + input.Extra, + input.CompareFields); + var userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync(); - if (userInfo.Code != "200" || userInfo.Data is null) + if (userInfo.Code != GlobalConst.SuccessCode || userInfo.Data is null) { - //TODO: log || ex - throw new BusinessException(message: $"调用用户中心,获取用户信息失败:{userInfo?.Msg}"); + //todo:保留之前的方式(FBA在用) 后续可能去除 + userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync(input.OptionUserId); + + if (userInfo.Code != GlobalConst.SuccessCode || userInfo.Data is null) + throw new BusinessException(message: $"调用用户中心,获取用户信息失败:{userInfo.Msg}"); } var name = userInfo.Data.UserName; // 新增/更新轨迹 var @event = ObjectMapper.Map(input); - @event.SubSystemId = order.SubSystemId; + @event.SubSystemId = input.SubSystemId; + @event.CustomId = order.CustomId; @event.OrderIdentifiers = new[] { new OrderIdentifier { OrderId = order.Id, - OrderNo = order.OrderNo, - OrderType = order.OrderType, - CustomId = order.CustomId + OrderNo = input.OrderNo, + OrderType = input.OrderType, } }; @event.OperationMan = name; @@ -91,150 +333,249 @@ public partial class TrackService : ApplicationService, ITrackService public async Task BatchUpsertTrackAsync(BatchUpsertTrackInput input) { input.OrderNos = input.OrderNos.Where(x => !x.IsNullOrWhiteSpace()).Distinct().ToList(); // 单号去重、去空 - if (input.OrderNos.Count == 0) + var orders = await _orderRepository.GetListAsync(x => + x.SubSystemId == input.SubSystemId + && x.OrderType == input.OrderType + && input.OrderNos.Contains(x.OrderNo), + x => new + { + x.Id, + x.OrderNo, + x.CustomId + }); + + if (orders.Count == 0) { throw new BusinessException(message: "订单一个都不存在"); } - var orders = await _orderRepository.GetListAsync(x => - x.OrderType == input.OrderType && input.OrderNos.Contains(x.OrderNo), x => new - { - x.Id, x.OrderNo, x.SubSystemId, x.CustomId - }); + // 校验主体:批量新增只选取第一条订单进行校验 + //【新增】存在指定轨迹的内容,进行更新覆盖(只处理一条的情况,并且决定权交给用户),不存在直接插入即可 + //【更新】存在指定轨迹的内容(匹配到多条则不处理) + var order = orders.First(); + // 输入参数的静态规则检查 + // 轨迹内容上的约束检查 + // 更新轨迹时是否可以匹配到轨迹的检查 + await TrackUpsertValidation(input.IsAdd, + input.SubSystemId, + order.Id, + order.OrderNo, + input.TrackCode, + input.Source, + input.TrackTime, + input.NewTrackTime, + input.EstimatedDeliveryDate, + input.DestinationTimeZone, + input.Extra, + input.CompareFields); + + // 获取用户name var userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync(); - if (userInfo.Code != "200" || userInfo.Data is null) + if (userInfo.Code != GlobalConst.SuccessCode || userInfo.Data is null) { - //TODO: log || ex - throw new BusinessException(message: $"调用用户中心,获取用户信息失败:{userInfo?.Msg}"); + throw new BusinessException(message: $"调用用户中心,获取用户信息失败:{userInfo.Msg}"); } - var name = userInfo.Data.UserName; - - foreach (var group in orders.GroupBy(x => x.SubSystemId)) + // 按客户新增/更新轨迹(为了推送轨迹时方便) + foreach (var group in orders.GroupBy(x => x.CustomId)) { - // 新增/更新轨迹 var @event = new TrackUpsertEvent { - SubSystemId = group.Key, - OrderIdentifiers = group.Select(order => new OrderIdentifier + SubSystemId = input.SubSystemId, + CustomId = group.Key, + OrderIdentifiers = group.Select(o => new OrderIdentifier { - OrderId = order.Id, - OrderNo = order.OrderNo, + OrderId = o.Id, + OrderNo = o.OrderNo, OrderType = input.OrderType, - CustomId = order.CustomId }).ToArray(), IsAdd = input.IsAdd, TrackCode = input.TrackCode, TrackPlace = input.TrackPlace, - TrackTime = input.TrackTime!.Value, - TrackTimeZone = input.TrackTimeZone!.Value, - OperationMan = name + TrackTime = input.TrackTime, + NewTrackTime = input.NewTrackTime, + TrackTimeZone = input.TrackTimeZone, + OperationMan = userInfo.Data.UserName, + OperationManId = userInfo.Data.UserId, + IsVisibility = input.IsVisibility, + IsExternal = input.IsExternal, + Source = input.Source, + Remarks = input.Remarks, + Files = input.Files, + Content = input.Content, + EnStatus = input.EnStatus, + TrackPlaceCity = input.TrackPlaceCity, + TrackPlaceCityId = input.TrackPlaceCityId, + TrackPlaceProvince = input.TrackPlaceProvince, + TrackPlaceProvinceId = input.TrackPlaceProvinceId, + TrackPlaceNation = input.TrackPlaceNation, + TrackPlaceNationId = input.TrackPlaceNationId, + TrackPlacePostcode = input.TrackPlacePostcode, + EstimatedDeliveryDate = input.EstimatedDeliveryDate, + DestinationTimeZone = input.DestinationTimeZone, + CompareFields = input.CompareFields, + Extra = input.Extra, + ForcedPush = input.ForcedPush, + IsToMq = input.IsToMq, }; await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, @event); } - return new UnifyResultDto(true, true); } - /// - /// 删除轨迹 - /// - /// - /// - /// - [HttpPost("Track/Delete")] - public async Task DeleteTrackAsync(DeleteTrackInput input) + //在轨迹更新主流程之前的前置检查 + private async Task TrackUpsertValidation( + bool isAdd, + int subSystemId, + int orderId, + string orderNo, + string trackCode, + int source, + DateTime trackTime, + DateTime? newTrackTime, + DateTime? estimatedDeliveryDate, + float? destinationTimeZone, + string? extra, + string? compareFields + ) { - var order = await _orderRepository.GetFirstAsync(x => - x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, x => new + #region 静态规则检查 + + // 约束轨迹来源只能选取 1-外部 2-内部 3-手动 + if (!GlobalConst.SupportTrackSources.Contains(source)) { - x.Id, - x.SubSystemId - }); - if (order == default) - { - throw new BusinessException(message: $"订单:{input.OrderNo}不存在"); + throw new BusinessException(message: "轨迹来源是必须的,1:外部服务商 2:内部系统 3:人工操作"); } - var codes = await _provideQueries.GetCanDeleteTrackCodesAsync(new List { order.Id }, input.TrackCodes); - - if (codes.Count == 0) + //当修改时,如果为来源为外部提供商则不允许修改 + if (!isAdd && source == (int) TrackSourceEnum.ExternalServiceProvide) { - throw new BusinessException(message: "没有一个轨迹代码是可删的"); + throw new BusinessException(message: "来源为外部服务商轨迹不允许修改"); } - var userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync(); - if (userInfo.Code != "200" || userInfo.Data is null) + //要求时间在当前时间的前后100年之间内 + bool ValidateTrackTime(DateTime? d) => (d != null && d < DateTime.Now.AddYears(-100) || d > DateTime.Now.AddYears(100)); + if (ValidateTrackTime(trackTime) || ValidateTrackTime(newTrackTime) || ValidateTrackTime(estimatedDeliveryDate)) { - //TODO: log || ex - throw new BusinessException(message: $"调用用户中心,获取用户信息失败:{userInfo?.Msg}"); + throw new BusinessException(message: "轨迹时间不合法"); } - var name = userInfo.Data.UserName; - - // 删除轨迹 - var @event = new TrackDeleteEvent + if ((estimatedDeliveryDate.HasValue == false && destinationTimeZone.HasValue) || + (estimatedDeliveryDate.HasValue && destinationTimeZone.HasValue == false)) { - OrderIds = new[] { order.Id }, - TrackCodes = codes.Select(x => x.TrackCode).ToList(), - SubSystemId = order.SubSystemId, - OperationMan = name - }; - await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe, @event); + throw new BusinessException(message: "【预计签收时间】和【签收地时区】必须同时输入"); + } - return new UnifyResultDto(true, true); + if (!string.IsNullOrWhiteSpace(compareFields) && string.IsNullOrWhiteSpace(extra)) + { + throw new BusinessException(message: "当输入了【轨迹对比字段】则轨迹扩展是必须的的"); + } + + #endregion + + #region 轨迹内容中的配置规则检查 + + var trackContent = await _trackContentRepository.GetByCodeAsync(subSystemId, trackCode); + if (trackContent == default) + { + throw new BusinessException(message: $"轨迹代码:{trackCode}轨迹内容不存在"); + } + + //指示是否为手动操作 + var manualOperation = source == (int) TrackSourceEnum.Artificial; + + //不允许手动创建 + if (manualOperation && isAdd && !trackContent.IsAllowManuallyCreate) + { + throw new BusinessException(message: $"轨迹代码:{trackCode}不允许手动创建"); + } + + //不允许手动更新 + if (manualOperation && !isAdd && !trackContent.IsAllowManuallyUpdate) + { + throw new BusinessException(message: $"轨迹代码:{trackCode}不允许手动更新"); + } + + #endregion + + //轨迹新增,不允许重复的轨迹提前拦截 + if (isAdd) + { + //允许重复,跳过检查 + if (trackContent.IsRepeatable) return; + //找到这个订单的这个轨迹code的所有轨迹 + var tracks = await QueryAndFilterAsync(orderId, trackCode, trackTime, extra, compareFields); + if (tracks.Count > 0) + throw new BusinessException(message: $"订单:[{orderNo}],轨迹代码:{trackCode}不允许重复创建轨迹"); + } + //针对于轨迹更新检查 + else + { + //找到这个订单的这个轨迹code的所有轨迹, + var tracks = await RetryQueryTrackAsync(orderId, trackCode, trackTime, extra, compareFields); + //不存在需要更新的轨迹 + if (tracks.Count == 0) + throw new BusinessException(message: $"订单:[{orderNo}],轨迹代码:{trackCode}没有要更新的记录"); + + //更新轨迹,同一时间存在多条轨迹记录,理由:不清晰到底要修改哪一条或是全部修改 + if (tracks.Count > 1) + throw new BusinessException(message: $"订单:{orderNo},轨迹代码:{trackCode}存在多条记录,不允许修改"); + } } - /// - /// 批量删除轨迹 - /// - /// - /// - /// - [HttpPost("Track/BatchDelete")] - public async Task BatchDeleteTrackAsync(BatchDeleteTrackInput input) + // 重试查询轨迹,直到存在符合要求的轨迹,或者超过最大重试次数 + private async Task> RetryQueryTrackAsync(int orderId, string trackCode, DateTime trackTime, string? extra, string? compareFields) { - var orders = await _orderRepository.GetListAsync(x => - x.OrderType == input.OrderType && input.OrderNos.Contains(x.OrderNo) - , x => new + var tracks = await QueryAndFilterAsync(orderId, trackCode, trackTime, extra, compareFields); + if (tracks.Count > 0) + return tracks; + + //重试阶段 + var curRetryCount = 0; + while (curRetryCount < GlobalConst.MaxUpdateTrackRetryCount) //tips:后续将最大重试次数提出到配置中 + { + try { - x.Id, - x.SubSystemId - }); - - var codes = await _provideQueries.GetCanDeleteTrackCodesAsync( - orders.Select(x => x.Id).ToList(), input.TrackCodes - ); - - if (codes.Count == 0) - { - throw new BusinessException(message: "没有一个轨迹代码是可删的"); - } - - var userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync(); - if (userInfo.Code != "200" || userInfo.Data is null) - { - //TODO: log || ex - throw new BusinessException(message: $"调用用户中心,获取用户信息失败:{userInfo?.Msg}"); - } - - var name = userInfo.Data.UserName; - - // 删除轨迹 - foreach (var group in codes.GroupBy(x => x.OrderId)) - { - var @event = new TrackDeleteEvent + tracks = await QueryAndFilterAsync(orderId, trackCode, trackTime, extra, compareFields); + if (tracks.Count > 0) + return tracks; + //指数退避等待 + var delay = TimeSpan.FromMilliseconds(Math.Pow(2, curRetryCount) * 150); // 150ms, 300ms, 600ms, ... + await Task.Delay(delay); + } + finally { - OrderIds = group.Select(x => x.OrderId).ToArray(), - TrackCodes = input.TrackCodes, - SubSystemId = orders.First(x => x.Id == group.Key).SubSystemId, - OperationMan = name - }; - await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe, @event); + curRetryCount++; + } } - return new UnifyResultDto(true, true); + //超过最大重试次数还没找到 + return tracks; } -} \ No newline at end of file + + //查询并按比较字段过滤轨迹,当比较字段为空时则使用轨迹发生时间过滤 + //tips:后续进行投影缩参优化 + private async Task> QueryAndFilterAsync(int orderId1, string trackCode1, DateTime trackTime1, string? extra1, string? compareFields1) + { + var tracks1 = await _trackDetailsEsRepository.GetListAsync(new[] { orderId1 }, trackCode1, true); + //无比较字段时使用轨迹时间参与过滤(兼容老版本) + if (string.IsNullOrWhiteSpace(compareFields1)) + { + return tracks1.Where(x => x.TrackTime == trackTime1).ToList(); + } + + return tracks1.Where(x => + { + if (string.IsNullOrWhiteSpace(x.Extra)) + throw new BusinessException(message: "轨迹extra为空无法使用比较字段比较,请检查轨迹"); + + var extraJsonElement = TextJsonHelper.DeserializeToJsonElement(x.Extra); + var inputExtraJsonElement = TextJsonHelper.DeserializeToJsonElement(extra1); + + return TextJsonHelper.EqByJsonElementField(extraJsonElement, inputExtraJsonElement, compareFields1); + }) + .ToList(); + } +} diff --git a/src/SJZY.Track.Application/Services/ProvideServices/TrackTemplateService.cs b/src/SJZY.Track.Application/Services/ProvideServices/TrackTemplateService.cs new file mode 100644 index 00000000..ae02e06e --- /dev/null +++ b/src/SJZY.Track.Application/Services/ProvideServices/TrackTemplateService.cs @@ -0,0 +1,50 @@ +using SJZY.Track.Application.Contract.Dtos.ProvideServices; +using SJZY.Track.Application.Contract.Services.ProvideServices; +using SJZY.Track.Domain.Aggregates.TrackTemplateAggregate; +using SJZY.Track.Domain.Dtos.TrackTemplate; + +namespace SJZY.Track.Application.Services.ProvideServices; + +/// +/// 轨迹模版服务 +/// +[ApiExplorerSettings(GroupName = "提供接口")] +[Route("/ProviderService")] +public class TrackTemplateService : ApplicationService, ITrackTemplateService +{ + private readonly ITrackTemplateRepository _trackTemplateRepository; + + public TrackTemplateService(ITrackTemplateRepository trackTemplateRepository) + { + _trackTemplateRepository = trackTemplateRepository; + } + + /// + /// 获取轨迹模版列表 + /// + /// + /// + /// + [HttpPost("Template/GetTrackTemplateList")] + public async Task> GetTrackTemplateListAsync(GetTrackTemplateListInput input) + { + var inputVo = ObjectMapper.Map(input); + var templates = await _trackTemplateRepository.GetTrackTemplateListAsync(inputVo); + var res = ObjectMapper.Map, List>(templates); + return res; + } + + /// + /// 分页获取轨迹模版列表 + /// + /// + /// + [HttpPost("Template/GetTrackTemplateListByPage")] + public async Task> GetTrackTemplateListByPageAsync(GetPageTrackTemplateListInput input) + { + var inputVo = ObjectMapper.Map(input); + var templates = await _trackTemplateRepository.GetPageTrackTemplateListAsync(inputVo); + var res = ObjectMapper.Map, UnifyPageResultDto>(templates); + return res; + } +} diff --git a/src/SJZY.Track.Application/Services/TimerTaskss/OrderPullStatusScanTask.cs b/src/SJZY.Track.Application/Services/TimerTaskss/OrderPullStatusScanTask.cs new file mode 100644 index 00000000..8d3bdfd1 --- /dev/null +++ b/src/SJZY.Track.Application/Services/TimerTaskss/OrderPullStatusScanTask.cs @@ -0,0 +1,66 @@ +using System.Diagnostics; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Options; +using SJZY.Expand.ABP.Core; +using SJZY.Expand.ABP.Core.Logger; +using SJZY.Track.Application.Options; +using SJZY.Track.Domain.Aggregates.OrderAggregate; + +namespace SJZY.Track.Application.Services.TimerTaskss; + +/// +/// 订单拉取状态扫描定时任务 +/// +[ApiExplorerSettings(GroupName = "定时任务")] +public class OrderPullStatusScanTask : ApplicationService +{ + private readonly IOptionsSnapshot _options; + private readonly IOrderRepository _orderRepository; + + public OrderPullStatusScanTask(IOrderRepository orderRepository, IOptionsSnapshot options) + { + _orderRepository = orderRepository; + _options = options; + } + + /// + /// 定时任务对订单拉取状态进行扫描,计算更新拉取状态 + /// + /// + [AllowAnonymous] + [HttpPost("/TimerTask/OrderPullStatusScan")] + public async Task OrderPullStatusScanAsync() + { + var redisKey = GlobalConst.OrderPullStatusScanCheckKey; + if (await RedisHelper.Client.ExistsAsync(redisKey)) + { + return "冷却中"; + } + + await RedisHelper.Client.SetAsync(redisKey, 1, + TimeSpan.FromSeconds(_options.Value.OrderPullStatusScanInterval)); + + var res = string.Empty; + try + { + var stopwatch = new Stopwatch(); + + stopwatch.Restart(); + var count1 = await _orderRepository.UpdatePullStatusBySilenceAsync(); + // real del + var count2 = await _orderRepository.ClearPullStatusAsync(); + stopwatch.Stop(); + + res = + $"{nameof(OrderPullStatusScanTask)}本次扫描更新了{count1}条,删除了{count2}条订单拉取状态,耗时{stopwatch.ElapsedMilliseconds}ms"; + } + catch (Exception e) + { + await RedisHelper.Client.DelAsync(redisKey); + LogHelper.Error(e.ToString()); + } + + + return res; + } +} diff --git a/src/SJZY.Track.Application/Services/TimerTaskss/TrackButtomUpScanTask.cs b/src/SJZY.Track.Application/Services/TimerTaskss/TrackButtomUpScanTask.cs new file mode 100644 index 00000000..bd1826d2 --- /dev/null +++ b/src/SJZY.Track.Application/Services/TimerTaskss/TrackButtomUpScanTask.cs @@ -0,0 +1,189 @@ +using System.Linq.Expressions; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Options; +using Newtonsoft.Json.Linq; +using SJZY.Expand.ABP.Core; +using SJZY.Expand.ABP.Core.Logger; +using SJZY.Track.Application.Contract.Dtos.TrackPull; +using SJZY.Track.Application.Helpers; +using SJZY.Track.Application.Options; +using SJZY.Track.Domain.Aggregates.OrderAggregate; +using SJZY.Track.Domain.Enums; +using SJZY.Track.Domain.Queries; + +namespace SJZY.Track.Application.Services.TimerTaskss; + +/// +/// 轨迹兜底扫描定时任务 +/// +[ApiExplorerSettings(GroupName = "定时任务")] +public class TrackButtomUpScanTask : ApplicationService +{ + private readonly IOptionsSnapshot _options; + private readonly IOrderRepository _orderRepository; + private readonly ITimezoneQueries _timezoneQueries; + + public TrackButtomUpScanTask(IOptionsSnapshot options, IOrderRepository orderRepository, + ITimezoneQueries timezoneQueries) + { + _options = options; + _orderRepository = orderRepository; + _timezoneQueries = timezoneQueries; + } + + /// + /// 定时任务对轨迹进行兜底扫描,尝试弥补轨迹中的缺失信息 + /// + /// + [AllowAnonymous] + [HttpPost("/TimerTask/TrackButtomUpScan")] + public async Task TrackButtomUpScanAsync() + { + var redisKey = GlobalConst.OrderPullStatusScanCheckKey; + if (await RedisHelper.Client.ExistsAsync(redisKey)) + { + return "冷却中"; + } + + await RedisHelper.Client.SetAsync(redisKey, 1, + TimeSpan.FromSeconds(_options.Value.OrderPullStatusScanInterval)); + + try + { + // do st + } + catch (Exception e) + { + await RedisHelper.Client.DelAsync(redisKey); + LogHelper.Error(e.ToString()); + } + + return "ok"; + } + + + /// + /// 获取轨迹时区 + /// + /// 配置信息 + /// 订单id + /// 时区,是否执行了兜底轨迹时区 + private async Task<(float? trackTimeZone, bool hasTimezoneBottomLine)> GetTimezone( + TrackPullContentConfigDto? matchedContentConfig, + TrackRefreshContext context) + { + float? trackTimeZone = null; + var hasTimezoneBottomLine = false; // 执行了兜底但是没有兜底住,需要记录 + if (matchedContentConfig?.TrackZonePlaceValue is not null) + { + //兜底没配置的就不需要兜底,拉取的发生地没就没 + var timezone = await GetTimezone(matchedContentConfig, context.OrderId); + + trackTimeZone = timezone; + hasTimezoneBottomLine = !timezone.HasValue; + } + + return (trackTimeZone, hasTimezoneBottomLine); + } + + /// + /// 获得轨迹地址 + /// + /// 配置信息 + /// 订单id + /// 时区,是否执行了兜底轨迹时区 + private async Task<(string? trackPlace, bool hasPlaceBottomLine)> GetTrackPlace( + TrackPullContentConfigDto? matchedContentConfig, TrackRefreshContext context) + { + string? trackPlace = null; + var hasPlaceBottomLine = false; //执行了兜底但是没有兜底住,需要记录 + if (matchedContentConfig?.TrackPlaceValue is not null) + { + //兜底没配置的就不需要兜底,拉取的发生地没就没 + trackPlace = await GetPlaceByOrder(matchedContentConfig!.TrackPlaceValue.Value, context.OrderId); + hasPlaceBottomLine = string.IsNullOrWhiteSpace(trackPlace); + } + + return (trackPlace, hasPlaceBottomLine); + } + + /// + /// 根据订单id获取兜底位置 + /// + /// + /// + /// + private Task GetPlaceByOrder(int trackValue, int orderId) + { + Expression> resultExpression = + (TrackLocationValue) trackValue switch + { + TrackLocationValue.ArrivalPort => x => x.ArrivalPort, + TrackLocationValue.ArriveCity => x => x.ArrivalCity, + TrackLocationValue.ArrivalCountry => x => x.ArrivalCountry, + TrackLocationValue.LeavePort => x => x.LeavePort, + TrackLocationValue.LeaveCity => x => x.LeaveCity, + TrackLocationValue.LeaveCountry => x => x.LeaveCountry, + _ => x => x.LeaveCountry + }; + return _orderRepository.GetFirstAsync(x => x.Id == orderId, resultExpression); + } + + /// + /// 获取时区 + /// + /// + /// + /// + private async Task GetTimezone(TrackPullContentConfigDto matchedContentConfig, int orderId) + { + var placeOrCode = await GetPlaceByOrder(matchedContentConfig!.TrackZonePlaceValue.Value, orderId); + string timezone = null; + if (!string.IsNullOrEmpty(placeOrCode)) + { + if (matchedContentConfig!.TrackZonePlaceValue.Value == (int) TrackLocationValue.ArrivalPort + || matchedContentConfig!.TrackZonePlaceValue.Value == (int) TrackLocationValue.LeavePort) + { + timezone = await _timezoneQueries.GetPortTimezone(placeOrCode); + return DateTimeHelper.ConvertTimeZoneToFloat(timezone); + } + + timezone = await _timezoneQueries.GetCityTimezone(placeOrCode); + return DateTimeHelper.ConvertTimeZoneToFloat(timezone); + } + + return null; + } + + + /// + /// 触发了兜底,但是没有兜底住,对订单进行标记 + /// 1表示时区,2表示发生地,3表示两种 + /// + /// + /// + /// + /// + /// + private int CalcDeficiencyTagValue(bool hasPlaceBottomLine, bool hasTimezoneBottomLine, JToken trackToken, + TrackRefreshContext context) + { + var deficiencyTagValue = 0; + + if (hasTimezoneBottomLine) + { + // _logger.LogWarning("订单号:{@OrderNo}, 轨迹发生时区无法解析,触发了兜底,但是没有兜底住:{@Data}", context.OrderNo, + // trackToken.ToString()); + deficiencyTagValue += 1; + } + + if (hasPlaceBottomLine) + { + // _logger.LogWarning("订单号:{@OrderNo}, 轨迹发生地无法解析,触发了兜底,但是没有兜底住:{@Data}", context.OrderNo, + // trackToken.ToString()); + deficiencyTagValue += 2; + } + + return deficiencyTagValue; + } +} diff --git a/src/SJZY.Track.Application/Services/TimerTaskss/TrackPullTask.cs b/src/SJZY.Track.Application/Services/TimerTaskss/TrackPullTask.cs new file mode 100644 index 00000000..6bd0edb1 --- /dev/null +++ b/src/SJZY.Track.Application/Services/TimerTaskss/TrackPullTask.cs @@ -0,0 +1,122 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Options; +using SJZY.Expand.ABP.Core; +using SJZY.Expand.ABP.Core.Logger; +using SJZY.Expand.ABP.Core.PublicMethords; +using SJZY.InterfaceRelay.Application.Contracts; +using SJZY.Track.Application.Contract.Dtos.TrackPull; +using SJZY.Track.Application.Contract.Services; +using SJZY.Track.Application.Helpers; +using SJZY.Track.Application.Options; +using SJZY.Track.Application.Track2InterfaceRelay; +using SJZY.Track.Domain.Dtos.TrackPull; +using SJZY.Track.Domain.Queries; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Http.Client.DynamicProxying; + +namespace SJZY.Track.Application.Services.TimerTaskss; + +/// +/// 轨迹拉取定时任务 +/// +[ApiExplorerSettings(GroupName = "定时任务")] +public class TrackPullTask : ApplicationService, ISingletonDependency +{ + private readonly IServiceScopeFactory _serviceScopeFactory; + + public TrackPullTask(IServiceScopeFactory serviceScopeFactory) + { + _serviceScopeFactory = serviceScopeFactory; + } + + /// + /// 定时任务刷新轨迹 + /// + /// + [AllowAnonymous] + [HttpPost("/TimerTask/Refresh")] + public async Task RefreshForTaskAsync() + { + using var serviceScope = _serviceScopeFactory.CreateScope(); + + var provideQueries = serviceScope.ServiceProvider.GetRequiredService(); + var configs = await provideQueries.GetAllPullConfigsAsync(); + + foreach (var config in configs) + { + await RefreshForConfigAsync(serviceScope, config); + } + + await Task.Delay(1000); // life-time possible dispose + + return true; + } + + private async Task RefreshForConfigAsync(IServiceScope serviceScope, TrackPullConfigVo config) + { + var trackPullCacheService = LazyServiceProvider.LazyGetRequiredService(); + var redisKey = trackPullCacheService.TrackPullKey(config.SubSystemId, config.ServiceProviderCode); + if (await RedisHelper.Client.ExistsAsync(redisKey)) + { + return; + } + + await RedisHelper.Client.SetExAsync(redisKey, config.PullInterval * 60, 1); + + _ = Task.Run(async () => + { + try + { + var provideQueries = serviceScope.ServiceProvider.GetRequiredService(); + var httpClientProxy = serviceScope.ServiceProvider + .GetRequiredService>(); + var interfaceOptions = serviceScope.ServiceProvider + .GetRequiredService>(); + await DoRefreshAsync(config, provideQueries, httpClientProxy, interfaceOptions.Value); + } + catch (Exception e) + { + await RedisHelper.Client.DelAsync(redisKey); + LogHelper.Error(e.ToString()); + } + }); + } + + private static async Task DoRefreshAsync(TrackPullConfigVo config, IProvideQueries provideQueries, + IHttpClientProxy httpClientProxy, + InterfaceRelayParamsConfigOptions interfaceOptionsValue) + { + using (Track2InterfaceRelaySubSystemContext.Use( + new Track2InterfaceRelaySubSystemContext(config.SubSystemCode))) + { + var page = 1; + var orders = + await provideQueries.FindOrderWithServiceProviderAsync(config.ServiceProviderCode, page); + while (orders.Any()) + { + var serviceProviderCode = orders.FirstOrDefault()?.ServiceProviderCode; + + foreach (var group in orders.GroupBy(x => x.OrderType)) + { + var data = new List(group.Select(x => new TrackPullPayload + { + OrderNo = x.OrderNo + })); + var attach = Base64Helper.SerializeObject(new TrackRefreshAttach(config.ServiceProviderCode, + config.SubSystemId, group.Key)); + var res = await httpClientProxy.Service.BatchForwardThenPushToQueueAsync( + interfaceOptionsValue.GetTrackInterfaceCode, serviceProviderCode, data, + GlobalConst.TrackRefreshSubscribe, attach); + + if (res.Code != GlobalConst.SuccessCode) + { + LogHelper.Error($"刷新轨迹失败:{res.ToJson()}"); + } + } + + orders = await provideQueries.FindOrderWithServiceProviderAsync(config.ServiceProviderCode, + ++page); + } + } + } +} diff --git a/src/SJZY.Track.Application/Services/TimerTaskss/TrackPushTask.cs b/src/SJZY.Track.Application/Services/TimerTaskss/TrackPushTask.cs new file mode 100644 index 00000000..47f150de --- /dev/null +++ b/src/SJZY.Track.Application/Services/TimerTaskss/TrackPushTask.cs @@ -0,0 +1,93 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Options; +using SJZY.Expand.ABP.Core; +using SJZY.Expand.ABP.Core.Logger; +using SJZY.Track.Application.Track2InterfaceRelay; +using SJZY.Track.Domain.Aggregates.OrderAggregate; + +namespace SJZY.Track.Application.Services.TimerTaskss; + +/// +/// 轨迹推送定时任务 +/// +[ApiExplorerSettings(GroupName = "定时任务")] +public class TrackPushTask : ApplicationService +{ + private readonly IServiceScopeFactory _serviceScopeFactory; + + public TrackPushTask(IServiceScopeFactory serviceScopeFactory) + { + _serviceScopeFactory = serviceScopeFactory; + } + + /// + /// 定时任务推送预警(》12小时没有推送的) + /// + /// + [AllowAnonymous] + [HttpPost("/TimerTask/PushWarn")] + public async Task PushWarnForTaskAsync() + { + using var serviceScope = _serviceScopeFactory.CreateScope(); + + var configs = serviceScope.ServiceProvider.GetRequiredService>() + .Value; + if (configs == null || configs.Keys.Count == 0) + { + throw new BusinessException("未配置子系统"); + } + + var orderRepository = serviceScope.ServiceProvider.GetRequiredService(); + var subSystemIds = await orderRepository.GetSubSystemListByCodesAsync(configs.Keys.ToList()); + foreach (var item in subSystemIds) + { + await PushWarningBySubSystemAsync(serviceScope, item.id); + } + + await Task.Delay(1000); // life-time possible dispose + + return "预警中"; + } + + private async Task PushWarningBySubSystemAsync(IServiceScope serviceScope, int subSystemId) + { + var redisKey = $"{GlobalConst.TrackPushWaringKeyPrefix}:{subSystemId}"; + if (await RedisHelper.Client.ExistsAsync(redisKey)) + { + return; + } + + await RedisHelper.Client.SetAsync(redisKey, 1, TimeSpan.FromHours(1)); + + _ = Task.Run(async () => + { + try + { + var orderRepository = serviceScope.ServiceProvider.GetRequiredService(); + await DoPushWarningAsync(orderRepository, subSystemId); + } + catch (Exception e) + { + await RedisHelper.Client.DelAsync(redisKey); + LogHelper.Error(e.ToString()); + } + }); + } + + private async Task DoPushWarningAsync(IOrderRepository orderRepository, int subSystemId) + { + int total = 0, pageSize = 1000, waitTime = 1000; + int rows; + var pageindex = 0; + + do + { + rows = await orderRepository.PushWarnOrdersAsync(subSystemId, pageSize, pageindex); + pageindex++; + total += rows; + await Task.Delay(waitTime); + } while (rows == pageSize); + + LogHelper.Info($"本次预警扫描了:{total}个订单"); + } +} diff --git a/src/SJZY.Track.Application/Services/TimerTaskss/TrackWarningTask.cs b/src/SJZY.Track.Application/Services/TimerTaskss/TrackWarningTask.cs new file mode 100644 index 00000000..3b9a93d3 --- /dev/null +++ b/src/SJZY.Track.Application/Services/TimerTaskss/TrackWarningTask.cs @@ -0,0 +1,84 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Options; +using SJZY.Expand.ABP.Core; +using SJZY.Expand.ABP.Core.Logger; +using SJZY.Track.Application.Contract.Services; +using SJZY.Track.Application.Track2InterfaceRelay; +using SJZY.Track.Domain.Aggregates.OrderAggregate; +using Volo.Abp.DependencyInjection; + +namespace SJZY.Track.Application.Services.TimerTaskss; + +/// +/// 轨迹运输时效预警定时任务 +/// +[ApiExplorerSettings(GroupName = "定时任务")] +public class TrackWarningTask : ApplicationService, ISingletonDependency +{ + private readonly IOptionsSnapshot _options; + private readonly IOrderRepository _orderRepository; + private readonly IServiceScopeFactory _serviceScopeFactory; + + public TrackWarningTask(IOrderRepository orderRepository, IOptionsSnapshot options, + IServiceScopeFactory serviceScopeFactory) + { + _orderRepository = orderRepository; + _options = options; + _serviceScopeFactory = serviceScopeFactory; + } + + /// + /// 轨迹运输时效预警通知 + /// + /// + [AllowAnonymous] + [HttpPost("/TimerTask/SendWarning")] + public async Task SendWarningForTaskAsync() + { + var configs = _options.Value; + if (configs == null || configs.Keys.Count == 0) + { + throw new BusinessException("未配置子系统"); + } + + var subSystemIds = await _orderRepository.GetSubSystemListByCodesAsync(configs.Keys.ToList()); + foreach (var item in subSystemIds) + { + var ttl = configs[item.code].WarningNotifyInterval * 60; + await TrackWarningBySubSystemAsync(item.id, ttl); + } + + return true; + } + + private async Task TrackWarningBySubSystemAsync(int subSystemId, int ttl) + { + // 如果已经发送过通知,不再发送 + var redisKey = $"{GlobalConst.ForewarningNotifyCheckKey}:{subSystemId}"; + if (await RedisHelper.Client.ExistsAsync(redisKey)) + { + return; + } + + await RedisHelper.Client.SetExAsync(redisKey, ttl, 1); + + // todo:改mq分流? + _ = Task.Run(async () => + { + try + { + using var serviceScope = _serviceScopeFactory.CreateScope(); + + var forewarningNotifyService = + serviceScope.ServiceProvider.GetRequiredService(); + var cnt = await forewarningNotifyService.SendNotificationAsync(subSystemId); + LogHelper.Info($"预警通知发送成功,新增预警记录{cnt}条"); + } + catch (Exception e) + { + await RedisHelper.Client.DelAsync(redisKey); + LogHelper.Error(e.ToString()); + } + }); + } +} diff --git a/src/SJZY.Track.Application/Services/TrackContents/TrackContentService.cs b/src/SJZY.Track.Application/Services/TrackContents/TrackContentService.cs index 9ed8374e..4113d9ff 100644 --- a/src/SJZY.Track.Application/Services/TrackContents/TrackContentService.cs +++ b/src/SJZY.Track.Application/Services/TrackContents/TrackContentService.cs @@ -1,11 +1,21 @@ -using System.Linq.Expressions; +using System.Linq.Expressions; using Microsoft.Extensions.Localization; using SJZY.Expand.ABP.Core.Localization; using SJZY.Expand.ABP.Core.PublicMethords; +using SJZY.Expand.AliyunOSS; +using SJZY.Track.Application.Contract.Dtos.ProvideServices; using SJZY.Track.Application.Contract.Dtos.TrackContents; +using SJZY.Track.Application.Contract.Services; using SJZY.Track.Application.Localization; +using SJZY.Track.Domain.Aggregates.OrderAggregate; using SJZY.Track.Domain.Aggregates.TrackContentAggregate; +using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; +using SJZY.Track.Domain.Aggregates.TrackFlagAggregate; +using SJZY.Track.Domain.Aggregates.TrackStatusAggregate; +using SJZY.Track.Domain.Aggregates.TrackTemplateAggregate; using SJZY.Track.Domain.Dtos.TrackContents; +using SJZY.Track.Domain.Enums; +using SJZY.Track.Domain.Queries; namespace SJZY.Track.Application.Services.TrackContents; @@ -18,14 +28,30 @@ public class TrackContentService : ApplicationService { private readonly IStringLocalizer _stringLocalizer; private readonly ITrackContentRepository _trackContentRepository; + private readonly ITrackTemplateRepository _trackTemplateRepository; + private readonly IBasicQuery _trackFlagBasicQuery; + private readonly IBasicQuery _trackStatusBasicQuery; + private readonly IOrderRepository _orderRepository; + private readonly ITrackDetailsEsRepository _trackDetailsEsRepository; + private readonly ITrackPushCacheService _trackPushCacheService; public TrackContentService( IStringLocalizer stringLocalizer, - ITrackContentRepository trackContentRepository - ) + ITrackContentRepository trackContentRepository, + IBasicQuery trackStatusBasicQuery, + IBasicQuery trackFlagBasicQuery, + IOrderRepository orderRepository, + ITrackDetailsEsRepository trackDetailsEsRepository, + ITrackTemplateRepository trackTemplateRepository, ITrackPushCacheService trackPushCacheService) { _stringLocalizer = stringLocalizer; _trackContentRepository = trackContentRepository; + _trackStatusBasicQuery = trackStatusBasicQuery; + _trackFlagBasicQuery = trackFlagBasicQuery; + _orderRepository = orderRepository; + _trackDetailsEsRepository = trackDetailsEsRepository; + _trackTemplateRepository = trackTemplateRepository; + _trackPushCacheService = trackPushCacheService; } /// @@ -35,6 +61,25 @@ public class TrackContentService : ApplicationService [HttpPost("Edit")] public async Task EditAsync(EditTrackContentInput input) { + if (input.TrackStatusId != null) + { + if (!await _trackStatusBasicQuery.IsAnyAsync(x => + x.SubSystemId == input.SubSystemId && x.Id == input.TrackStatusId)) + { + throw new BusinessException(message: "轨迹状态不存在"); + } + } + + if (!input.TrackFlagIds.IsNullOrEmpty()) + { + var counter = await _trackFlagBasicQuery.CountAsync(x => + x.SubSystemId == input.SubSystemId && input.TrackFlagIds!.Contains(x.Id)); + if (counter != input.TrackFlagIds!.Length) + { + throw new BusinessException(message: "存在非法轨迹标记"); + } + } + return input.Options switch { OptionType.新增 => await AddAsync(input), @@ -60,8 +105,7 @@ public class TrackContentService : ApplicationService var dto = ObjectMapper.Map(detailInfo); - if (dto.TrackFlagId == 0) dto.TrackFlagId = null; - return new UnifyResultDto("200", "", dto); + return new UnifyResultDto(GlobalConst.SuccessCode, "", dto); } /// @@ -70,8 +114,7 @@ public class TrackContentService : ApplicationService /// /// [HttpPost("GetList")] - public async Task> GetPageTrackContent( - GetPageTrackContentInput input) + public async Task> GetPageTrackContent(GetPageTrackContentInput input) { var vo = ObjectMapper.Map(input); var resultDto = await _trackContentRepository.GetPageTrackContent(vo); @@ -82,143 +125,6 @@ public class TrackContentService : ApplicationService return pageResultDto; } - #region 私有方法 - - private async Task AddAsync(EditTrackContentInput input) - { - #region 业务逻辑校验 - - var trackContentEntitys = await _trackContentRepository.GetListAsync(a => - a.SubSystemId == input.SubSystemId && (a.Code == input.Code || - a.Content == input.Content || a.EnContent == input.EnContent)); - if (trackContentEntitys.Any()) - { - //throw new BusinessException(message: _stringLocalizer["TrackContentExist"]); - var codes = trackContentEntitys.FirstOrDefault(a => a.Code == input.Code); - if (codes != null) - { - throw new BusinessException(message: "该子系统下轨迹代码已存在"); - } - - var contents = trackContentEntitys.FirstOrDefault(a => a.Content == input.Content); - if (contents != null) - { - throw new BusinessException(message: "该子系统下轨迹内容已存在"); - } - - var contentEns = trackContentEntitys.FirstOrDefault(a => a.EnContent == input.EnContent); - if (contentEns != null) - { - throw new BusinessException(message: "该子系统下轨迹内容英文已存在"); - } - //throw new BusinessException(message: "当前子系统下,轨迹代码或轨迹内容或轨迹内容英文存在"); - } - - #endregion 业务逻辑校验 - - var entity = ObjectMapper.Map(input); - var isTrue = await _trackContentRepository.InsertAsync(entity); - - return new UnifyResultDto("200", "新增成功", isTrue); - } - - private async Task UpdateAsync(EditTrackContentInput input) - { - #region 业务逻辑校验 - - var trackContentEntitys = await _trackContentRepository.GetListAsync(a => a.Id != input.Id && - a.SubSystemId == input.SubSystemId && (a.Code == input.Code || - a.Content == input.Content || a.EnContent == input.EnContent)); - if (trackContentEntitys.Any()) - { - //throw new BusinessException(message: _stringLocalizer["TrackContentExist"]); - //throw new BusinessException(message: "当前子系统下,轨迹代码或轨迹内容或轨迹内容英文存在"); - var codes = trackContentEntitys.FirstOrDefault(a => a.Code == input.Code); - if (codes != null) - { - throw new BusinessException(message: "该子系统下轨迹代码已存在"); - } - - var contents = trackContentEntitys.FirstOrDefault(a => a.Content == input.Content); - if (contents != null) - { - throw new BusinessException(message: "该子系统下轨迹内容已存在"); - } - - var contentEns = trackContentEntitys.FirstOrDefault(a => a.EnContent == input.EnContent); - if (contentEns != null) - { - throw new BusinessException(message: "该子系统下轨迹内容英文已存在"); - } - } - - #endregion 业务逻辑校验 - - //更新的时候需要覆盖内容映射轨迹代码 - var templateEntity = await _trackContentRepository.GetFirstAsync(a => a.Id == input.Id); - - bool isTrue; - - using (var ts = TransactionScopeHelper.Create()) - { - // 如果轨迹内容的子系统和code发生变化,同步到轨迹映射表 - if (templateEntity.SubSystemId != input.SubSystemId || templateEntity.Code != input.Code) - { - await _trackContentRepository.UpdateMapAsync(x => new TrackContentMapEntity - { - SubSystemId = input.SubSystemId, - TrackContentCode = input.Code - }, x => x.TrackContentId == input.Id); - - await _trackContentRepository.UpdateMapAsync(x => new TrackContentMapEntity - { - MapSubSystemId = input.SubSystemId, - MapTrackContentCode = input.Code - }, x => x.MapTrackContentId == input.Id); - } - - ObjectMapper.Map(input, templateEntity); - - isTrue = await _trackContentRepository.UpdateAsync(templateEntity); - - ts.Complete(); - } - - return new UnifyResultDto("200", "修改成功", isTrue); - } - - private async Task DeleteAsync(EditTrackContentInput input) - { - #region 业务校验 - - //查询是否关联了轨迹模版内容 - var isExistTemplate = await _trackContentRepository.GetTemplateIsExist(input.Id); - if (isExistTemplate) - { - throw new BusinessException(message: "该轨迹内容关联轨迹模板,禁止删除"); - } - //var trackTemplateContents = await _trackTemplateContentBasicQuery.GetListAsync(a => a.TrackContentId == input.Id); - //if (trackTemplateContents.Any()) - //{ - // throw new BusinessException(message: "该轨迹内容关联轨迹模板,禁止删除"); - //} - - //需要加个判断,存在内容映射,则出提示 - //var trackContentMapEntities = await _trackContentMapBasicQuery.GetListAsync(a => a.TrackContentId == input.Id || a.MapTrackContentId == input.Id); - //if (trackContentMapEntities.Any()) - //{ - // throw new BusinessException(message: "无法删除该内容,该轨迹内容已在轨迹内容映射中使用了,请检查"); - //} - - #endregion 业务校验 - - var isTrue = await _trackContentRepository.SoftDeleteAsync(x => x.Id == input.Id); - - return new UnifyResultDto("200", "删除成功", isTrue); - } - - #endregion 私有方法 - /// /// 轨迹内容映射列表 /// @@ -266,22 +172,18 @@ public class TrackContentService : ApplicationService switch (input.Options) { case OptionTypeNoNull.新增: - { var trackContentMapEntity = ObjectMapper.Map(input); await _trackContentRepository.InsertMapAsync(trackContentMapEntity); - } break; case OptionTypeNoNull.修改: - { var oldTrackContentMapEntity = await _trackContentRepository.GetMapByIdAsync(input.Id!.Value) ?? throw new BusinessException(message: _stringLocalizer["NotFindData"]); ObjectMapper.Map(input, oldTrackContentMapEntity); await _trackContentRepository.UpdateMapAsync(oldTrackContentMapEntity); - } break; case OptionTypeNoNull.删除: @@ -295,4 +197,371 @@ public class TrackContentService : ApplicationService return true; } -} \ No newline at end of file + + /// + /// 根据轨迹内容code获取轨迹内容 + /// + /// + /// + [HttpPost("GetTrackContentByCode")] + public async Task> GetTrackContentByCodeAsync([FromBody] GetTrackContentByCodeInput input) + { + if (input.SystemId <= 0) + return new UnifyResultDto(false, "子系统Id必须大于等于0"); + + if (string.IsNullOrEmpty(input.Code)) + return new UnifyResultDto(false, "轨迹内容code不能为空"); + + var content = await _trackContentRepository.GetByCodeAsync(input.SystemId, input.Code); + if (content == null) + return new UnifyResultDto(false, "在当前子系统中未找到指定code的轨迹内容"); + + var res = new UnifyResultDto(true) + { + Data = new GetTrackContentByCodeOutput + { + Content = content.Content, + EnContent = content.EnContent, + IsExternal = content.IsExternal + } + }; + + return res; + } + + /// + /// 根据子系统id、单号、订单类型、轨迹发生时间、轨迹code获取轨迹内容 + /// + /// + /// + [HttpPost("GetContentDetail")] + public async Task> GetContentDetail([FromBody] GetContentDetailInput input) + { + if (input.SystemId <= 0) + return new UnifyResultDto(false, "子系统Id必须大于等于0"); + + if (string.IsNullOrEmpty(input.TrackCode)) + return new UnifyResultDto(false, "轨迹内容code不能为空"); + + if (string.IsNullOrEmpty(input.OrderNumber)) + return new UnifyResultDto(false, "订单code不能为空"); + + if (input.OrderType <= 0) + return new UnifyResultDto(false, "订单类型不能为空"); + + if (input.TrackTime == default) + return new UnifyResultDto(false, "轨迹发生时间不能为空"); + + var content = await _trackDetailsEsRepository.GetDetailAsync(input.OrderNumber, input.TrackCode, input.OrderType, input.SystemId, input.TrackTime); + if (content == default) + return new UnifyResultDto(false, "在当前子系统中未找到指定code的轨迹内容"); + + var res = new UnifyResultDto(true) + { + Data = ObjectMapper.Map(content) + }; + + + if (res.Data != default && res.Data.Files.Any()) + { + foreach (var item in res.Data.Files) + { + item.Url = OSSHelper.GetUrlByKey(item.OssKey); + } + } + + return res; + } + + /// + /// 创建轨迹时获取可用的轨迹内容 + /// + /// + /// + [HttpPost("GetAvailableContent")] + public async Task>> GetAvailableContent(GetAvailableContentInput input) + { + if (input.SystemId <= 0) + return new UnifyResultDto>(false, "系统id需大于0!"); + + if (string.IsNullOrEmpty(input.OrderNo)) + return new UnifyResultDto>(false, "单号不能为空!"); + + //获取当前订单下已有的轨迹内容 + var order = await _orderRepository.GetFirstAsync(x => x.OrderNo == input.OrderNo && x.SubSystemId == input.SystemId); + if (order == default) + throw new BusinessException(message: "订单不存在!"); + + var res = new UnifyResultDto>(true) + { + Data = new List() + }; + + //获取轨迹详情 + var trackDetails = await _trackDetailsEsRepository.GetListAsync(order.Id); + + // 删除时去除掉外部服务商轨迹 + if (input.TrackOptionType == TrackOptionType.删除) + { + trackDetails = trackDetails.Where(m => m.Source != (int) TrackSourceEnum.ExternalServiceProvide).ToList(); + } + //进行推送时,匹配订单类型一致的轨迹 + if (input.TrackOptionType == TrackOptionType.推送) + { + var pushConfigs = await _trackPushCacheService.GetPushContentConfigsAsync(order.SubSystemId, order.CustomId); + //没有推送配置也不会展示任何下拉 + if (pushConfigs == null || pushConfigs.Count == 0) return res; + //选订单类型和配置订单类型一致的配置的轨迹代码 + var trackCodes = pushConfigs.Where(m => m.OrderType == order.OrderType) + .Select(x=>x.TrackCode) + .Distinct() + .ToHashSet(); + //根据配置过滤轨迹 + trackDetails = trackDetails.Where(m => trackCodes.Contains(m.TrackCode)).ToList(); + } + + //进行删除和推送行为无任何轨迹内容,直接返回为空即可 + if (input.TrackOptionType is TrackOptionType.删除 or TrackOptionType.推送 && trackDetails.Count == 0) + { + return res; + } + + //获取当前子系统下所有的轨迹内容 + var contentList = await _trackContentRepository.GetListBySystemIdAsync(input.SystemId); + if (contentList == null) + throw new BusinessException(message: "当前子系统下未找到任何可用的轨迹内容!"); + + //如果订单给了获取模板code,则进一步根据模板code进行过滤 + if (!string.IsNullOrEmpty(order.TemplateCodes)) + { + var currentCodes = order.TemplateCodes.Split(","); + var template = await _trackTemplateRepository.GetContentByTemplateCodes(currentCodes, input.SystemId); + contentList = contentList.Where(m => template.Contains(m.Code)).ToList(); + } + + foreach (var item in contentList) + { + //新增时跳过已存在轨迹内容 + if (input.TrackOptionType == TrackOptionType.创建 && !item.IsRepeatable && trackDetails?.Any(m => m.TrackCode == item.Code) == true) + continue; + + // 修改时跳过不存在轨迹内容 + if (input.TrackOptionType == TrackOptionType.修改 && trackDetails != null && trackDetails.All(m => m.TrackCode != item.Code)) + continue; + + if (!item.IsAllowManuallyCreate && input.TrackOptionType == TrackOptionType.创建) //跳过不允许手动创建的轨迹内容 + continue; + + if (!item.IsAllowManuallyUpdate && input.TrackOptionType == TrackOptionType.修改) //跳过不允许手动修改的轨迹内容 + continue; + + res.Data.Add(new GetAvailableContentOutput() + { + IsExternal = item.IsExternal, + EnContent = item.EnContent, + Content = item.Content, + Code = item.Code, + Id = item.Id + }); + } + + if (input.TrackOptionType == TrackOptionType.创建 + || trackDetails == null + || trackDetails.Count == 0) + { + return res; + } + + + //修改/删除/推送 操作,查轨迹内容列表反映明细表数据,重新构造响应数据 + var matchContent = new List(); + var contents = res.Data.Select(x => new + { + x.Id, + x.IsExternal, + x.Code + }); + + foreach (var content in contents) + { + var match = trackDetails + .Where(x => x.TrackCode == content.Code) + .Select(matchItem => new GetAvailableContentOutput + { + IsExternal = content.IsExternal, + Id = content.Id, + EnContent = matchItem.TrackEnContent, + Content = matchItem.TrackContent, + Code = matchItem.TrackCode, + TrackPlace = matchItem.TrackPlace, + TrackTime = matchItem.TrackTime, + TrackTimeZone = matchItem.TrackTimeZone, + Source = matchItem.Source, + + DestinationTimeZone = matchItem.DestinationTimeZone, + EstimatedDeliveryDate = matchItem.EstimatedDeliveryDate, + TrackPlacePostcode = matchItem.TrackPlacePostcode, + TrackPlaceNation = matchItem.TrackPlaceNation, + TrackPlaceNationId = matchItem.TrackPlaceNationId, + TrackPlaceProvince = matchItem.TrackPlaceProvince, + TrackPlaceProvinceId = matchItem.TrackPlaceProvinceId, + TrackPlaceCity = matchItem.TrackPlaceCity, + TrackPlaceCityId = matchItem.TrackPlaceCityId, + Remarks = matchItem.Remarks, + TrackTimeZoneValue = matchItem.DestinationTimeZone, + IsVisibility = matchItem.IsVisibility, + FileItems = matchItem.Files?.Select(x => new FileItemDto + { + FileName = x.FileName, + OssKey = x.OssKey + }).ToList() + }); + matchContent.AddRange(match); + } + + res.Data = matchContent; + return res; + } + + #region 私有方法 + + private async Task AddAsync(EditTrackContentInput input) + { + #region 业务逻辑校验 + + var trackContentEntitys = await _trackContentRepository.GetListAsync(a => + a.SubSystemId == input.SubSystemId && (a.Code == input.Code || + a.Content == input.Content || a.EnContent == input.EnContent)); + if (trackContentEntitys.Any()) + { + var codes = trackContentEntitys.FirstOrDefault(a => a.Code == input.Code); + if (codes != null) + { + throw new BusinessException(message: "该子系统下轨迹代码已存在"); + } + + var contents = trackContentEntitys.FirstOrDefault(a => a.Content == input.Content); + if (contents != null) + { + throw new BusinessException(message: "该子系统下轨迹内容已存在"); + } + + var contentEns = trackContentEntitys.FirstOrDefault(a => a.EnContent == input.EnContent); + if (contentEns != null) + { + throw new BusinessException(message: "该子系统下轨迹内容英文已存在"); + } + } + + #endregion 业务逻辑校验 + + var entity = ObjectMapper.Map(input); + entity.TrackFlagId = input.TrackFlagIds?.JoinAsString(","); + var isTrue = await _trackContentRepository.InsertAsync(entity); + + return new UnifyResultDto(GlobalConst.SuccessCode, "新增成功", isTrue); + } + + private async Task UpdateAsync(EditTrackContentInput input) + { + #region 业务逻辑校验 + + var trackContentEntities = await _trackContentRepository.GetListAsync( + a => a.Id != input.Id && a.SubSystemId == input.SubSystemId && + (a.Code == input.Code || a.Content == input.Content || a.EnContent == input.EnContent)); + if (trackContentEntities.Any()) + { + var codes = trackContentEntities.FirstOrDefault(a => a.Code == input.Code); + if (codes != null) + { + throw new BusinessException(message: "该子系统下轨迹代码已存在"); + } + + var contents = trackContentEntities.FirstOrDefault(a => a.Content == input.Content); + if (contents != null) + { + throw new BusinessException(message: "该子系统下轨迹内容已存在"); + } + + var contentEns = trackContentEntities.FirstOrDefault(a => a.EnContent == input.EnContent); + if (contentEns != null) + { + throw new BusinessException(message: "该子系统下轨迹内容英文已存在"); + } + } + + #endregion 业务逻辑校验 + + //更新的时候需要覆盖内容映射轨迹代码 + var trackContent = await _trackContentRepository.GetFirstAsync(a => a.Id == input.Id); + + if (trackContent == null) + { + throw new BusinessException(message: "轨迹内容不存在"); + } + + bool isTrue; + + using (var ts = TransactionScopeHelper.Create()) + { + // 如果轨迹内容的子系统和code发生变化,同步到轨迹映射表 + if (trackContent.SubSystemId != input.SubSystemId || trackContent.Code != input.Code) + { + await _trackContentRepository.UpdateMapAsync( + x => new TrackContentMapEntity + { + SubSystemId = input.SubSystemId, + TrackContentCode = input.Code + }, + x => x.TrackContentId == input.Id); + + await _trackContentRepository.UpdateMapAsync( + x => new TrackContentMapEntity + { + MapSubSystemId = input.SubSystemId, + MapTrackContentCode = input.Code + }, x => x.MapTrackContentId == input.Id); + } + + ObjectMapper.Map(input, trackContent); + trackContent.TrackFlagId = input.TrackFlagIds?.JoinAsString(","); + isTrue = await _trackContentRepository.UpdateAsync(trackContent); + + ts.Complete(); + } + + return new UnifyResultDto(GlobalConst.SuccessCode, "修改成功", isTrue); + } + + private async Task DeleteAsync(EditTrackContentInput input) + { + #region 业务校验 + + //查询是否关联了轨迹模版内容 + var isExistTemplate = await _trackContentRepository.GetTemplateIsExist(input.Id); + if (isExistTemplate) + { + throw new BusinessException(message: "该轨迹内容关联轨迹模板,禁止删除"); + } + //var trackTemplateContents = await _trackTemplateContentBasicQuery.GetListAsync(a => a.TrackContentId == input.Id); + //if (trackTemplateContents.Any()) + //{ + // throw new BusinessException(message: "该轨迹内容关联轨迹模板,禁止删除"); + //} + + //需要加个判断,存在内容映射,则出提示 + //var trackContentMapEntities = await _trackContentMapBasicQuery.GetListAsync(a => a.TrackContentId == input.Id || a.MapTrackContentId == input.Id); + //if (trackContentMapEntities.Any()) + //{ + // throw new BusinessException(message: "无法删除该内容,该轨迹内容已在轨迹内容映射中使用了,请检查"); + //} + + #endregion 业务校验 + + var isTrue = await _trackContentRepository.SoftDeleteAsync(x => x.Id == input.Id); + + return new UnifyResultDto(GlobalConst.SuccessCode, "删除成功", isTrue); + } + + #endregion 私有方法 +} diff --git a/src/SJZY.Track.Application/Services/TrackFlags/TrackFlagService.cs b/src/SJZY.Track.Application/Services/TrackFlags/TrackFlagService.cs index 9e7d4056..b42afce5 100644 --- a/src/SJZY.Track.Application/Services/TrackFlags/TrackFlagService.cs +++ b/src/SJZY.Track.Application/Services/TrackFlags/TrackFlagService.cs @@ -4,160 +4,169 @@ using SJZY.Track.Application.Localization; using SJZY.Track.Domain.Aggregates.TrackContentAggregate; using SJZY.Track.Domain.Aggregates.TrackFlagAggregate; using SJZY.Track.Domain.Dtos.TrackFlags; +using SqlSugar; using Volo.Abp.DependencyInjection; -namespace SJZY.Track.Application.Services.TrackFlags +namespace SJZY.Track.Application.Services.TrackFlags; + +/// +/// 轨迹标记服务 +/// +[ApiExplorerSettings(GroupName = "轨迹标记")] +[Route("/Track/Flag")] +public class TrackFlagService : ApplicationService, ITransientDependency { - /// - /// 轨迹标记服务 - /// - [ApiExplorerSettings(GroupName = "轨迹标记")] - [Route("/Track/Flag")] - public class TrackFlagService : ApplicationService, ITransientDependency + private readonly IStringLocalizer _stringLocalizer; + private readonly ITrackContentRepository _trackContentRepository; + private readonly ITrackFlagRepository _trackFlagRepository; + + public TrackFlagService( + IStringLocalizer stringLocalizer, + ITrackFlagRepository trackFlagRepository, + ITrackContentRepository trackContentRepository + ) { - private readonly IStringLocalizer _stringLocalizer; - private readonly ITrackFlagRepository _trackFlagRepository; - private readonly ITrackContentRepository _trackContentRepository; + this._stringLocalizer = stringLocalizer; + this._trackFlagRepository = trackFlagRepository; + this._trackContentRepository = trackContentRepository; + } - public TrackFlagService( - IStringLocalizer stringLocalizer, - ITrackFlagRepository trackFlagRepository, - ITrackContentRepository trackContentRepository - ) + /// + /// 轨迹标记编辑 + /// + /// + [HttpPost("Edit")] + public async Task EditAsync(EditTrackFlagInput input) + { + return input.Options switch { - this._stringLocalizer = stringLocalizer; - this._trackFlagRepository = trackFlagRepository; - this._trackContentRepository=trackContentRepository; + OptionType.新增 => await AddAsync(input), + OptionType.修改 => await UpdateAsync(input), + OptionType.删除 => await DeleteAsync(input), + _ => throw new BusinessException(message: "当前操作动作不合法") + }; + } + + /// + /// 根据标记id获取轨迹标记 + /// + /// + /// + [HttpGet("GetDetail")] + public async Task> GetDetailAsync(int id) + { + var detailInfo = await _trackFlagRepository.GetDetailAsync(id); + if (detailInfo == null) + { + return new UnifyResultDto(false, null, "未查询到轨迹状态"); } - /// - /// 轨迹标记编辑 - /// - /// - [HttpPost("Edit")] - public async Task EditAsync(EditTrackFlagInput input) - { - return input.Options switch - { - OptionType.新增 => await AddAsync(input), - OptionType.修改 => await UpdateAsync(input), - OptionType.删除 => await DeleteAsync(input), - _ => throw new BusinessException(message: "当前操作动作不合法") - }; - } + var dto = ObjectMapper.Map(detailInfo); + return new UnifyResultDto(GlobalConst.SuccessCode, "", dto); + } - /// - /// 根据标记id获取轨迹标记 - /// - /// - /// - [HttpGet("GetDetail")] - public async Task> GetDetailAsync(int id) + /// + /// 获取分页轨迹标记 + /// + /// + /// + [HttpPost("GetList")] + public async Task> GetPageTrackFlag(GetPageTrackFlagInput input) + { + var vo = ObjectMapper.Map(input); + var resultDto = await _trackFlagRepository.GetPageTrackFlag(vo); + var pageResultDto = + ObjectMapper.Map, UnifyPageResultDto>( + resultDto); + + return pageResultDto; + } + + #region 私有方法 + + private async Task AddAsync(EditTrackFlagInput input) + { + #region 业务校验 + + var trackFlagsEntitys = await _trackFlagRepository.GetListAsync(a => + a.SubSystemId == input.SubSystemId && (a.Code == input.Code || a.Name == input.Flag)); + if (trackFlagsEntitys.Any()) { - var detailInfo = await _trackFlagRepository.GetDetailAsync(id); - if (detailInfo == null) + var trackFlagCode = trackFlagsEntitys.FirstOrDefault(a => a.Code == input.Code); + if (trackFlagCode != null) { - return new UnifyResultDto(false, null, "未查询到轨迹状态"); + throw new BusinessException(message: "该子系统下代码已存在"); } - var dto = ObjectMapper.Map(detailInfo); - return new UnifyResultDto("200", "", dto); - } - - /// - /// 获取分页轨迹标记 - /// - /// - /// - [HttpPost("GetList")] - public async Task> GetPageTrackFlag(GetPageTrackFlagInput input) - { - var vo = ObjectMapper.Map(input); - var resultDto = await _trackFlagRepository.GetPageTrackFlag(vo); - var pageResultDto = - ObjectMapper.Map, UnifyPageResultDto>( - resultDto); - - return pageResultDto; - } - - #region 私有方法 - - private async Task AddAsync(EditTrackFlagInput input) - { - #region 业务校验 - var trackFlagsEntitys = await _trackFlagRepository.GetListAsync(a => - a.SubSystemId == input.SubSystemId && (a.Code == input.Code || a.Name == input.Flag)); - if (trackFlagsEntitys.Any()) + var trackFlagName = trackFlagsEntitys.FirstOrDefault(a => a.Name == input.Flag); + if (trackFlagName != null) { - //throw new BusinessException(message: _stringLocalizer["TrackFlagExist"]); - //throw new BusinessException(message: "当前子系统下已存在轨迹标记代码"); - var trackFlagCode = trackFlagsEntitys.FirstOrDefault(a => a.Code==input.Code); - if (trackFlagCode!=null) - { - throw new BusinessException(message: "该子系统下代码已存在"); - } - var trackFlagName = trackFlagsEntitys.FirstOrDefault(a => a.Name==input.Flag); - if (trackFlagName!=null) - { - throw new BusinessException(message: "该子系统下标记已存在"); - } + throw new BusinessException(message: "该子系统下标记已存在"); } - #endregion - - var entity = ObjectMapper.Map(input); - var isTrue = await _trackFlagRepository.InsertAsync(entity); - - return new UnifyResultDto("200", "新增成功", isTrue); - } - - private async Task UpdateAsync(EditTrackFlagInput input) - { - #region 业务校验 - - var trackFlagsEntitys = await _trackFlagRepository.GetListAsync(a => a.Id != input.Id && - a.SubSystemId == input.SubSystemId && (a.Code == input.Code || - a.Name == input.Flag)); - if (trackFlagsEntitys.Any()) - { - //throw new BusinessException(message: _stringLocalizer["TrackFlagExist"]); - //throw new BusinessException(message: "当前子系统下已存在轨迹标记代码"); - var trackFlagCode = trackFlagsEntitys.FirstOrDefault(a => a.Code==input.Code); - if (trackFlagCode!=null) - { - throw new BusinessException(message: "该子系统下代码已存在"); - } - var trackFlagName = trackFlagsEntitys.FirstOrDefault(a => a.Name==input.Flag); - if (trackFlagName!=null) - { - throw new BusinessException(message: "该子系统下标记已存在"); - } - } - - #endregion - - var templateEntity = await _trackFlagRepository.GetFirstAsync(a => a.Id == input.Id); - ObjectMapper.Map(input, templateEntity); - var isTrue = await _trackFlagRepository.UpdateAsync(templateEntity); - - return new UnifyResultDto("200", "修改成功", isTrue); - } - - private async Task DeleteAsync(EditTrackFlagInput input) - { - #region 业务校验 - var isExistContent = await _trackContentRepository.GetFirstAsync(a => a.TrackFlagId==input.Id); - if (isExistContent!=null) - { - //throw new BusinessException(message: _stringLocalizer["IsExistTrackFlag"]); - throw new BusinessException(message: "该标记关联轨迹内容,禁止删除"); - } - #endregion - var isTrue = await _trackFlagRepository.SoftDeleteAsync(x => x.Id == input.Id); - - return new UnifyResultDto("200", "删除成功", isTrue); } #endregion + + var entity = ObjectMapper.Map(input); + var isTrue = await _trackFlagRepository.InsertAsync(entity); + + return new UnifyResultDto(GlobalConst.SuccessCode, "新增成功", isTrue); } -} \ No newline at end of file + + private async Task UpdateAsync(EditTrackFlagInput input) + { + #region 业务校验 + + var trackFlagsEntitys = await _trackFlagRepository.GetListAsync(a => a.Id != input.Id && + a.SubSystemId == input.SubSystemId && + (a.Code == input.Code || + a.Name == input.Flag)); + if (trackFlagsEntitys.Any()) + { + var trackFlagCode = trackFlagsEntitys.FirstOrDefault(a => a.Code == input.Code); + if (trackFlagCode != null) + { + throw new BusinessException(message: "该子系统下代码已存在"); + } + + var trackFlagName = trackFlagsEntitys.FirstOrDefault(a => a.Name == input.Flag); + if (trackFlagName != null) + { + throw new BusinessException(message: "该子系统下标记已存在"); + } + } + + #endregion + + var trackFlag = await _trackFlagRepository.GetFirstAsync(a => a.Id == input.Id); + if (trackFlag == null) + { + throw new BusinessException(message: "轨迹标记不存在"); + } + + ObjectMapper.Map(input, trackFlag); + var isTrue = await _trackFlagRepository.UpdateAsync(trackFlag); + + return new UnifyResultDto(GlobalConst.SuccessCode, "修改成功", isTrue); + } + + private async Task DeleteAsync(EditTrackFlagInput input) + { + #region 业务校验 + + var isExistContent = + await _trackContentRepository.GetFirstAsync(a => SqlFunc.SplitIn(a.TrackFlagId, input.Id.ToString())); + if (isExistContent != null) + { + throw new BusinessException(message: "该标记关联轨迹内容,禁止删除"); + } + + #endregion + + var isTrue = await _trackFlagRepository.SoftDeleteAsync(x => x.Id == input.Id); + + return new UnifyResultDto(GlobalConst.SuccessCode, "删除成功", isTrue); + } + + #endregion +} diff --git a/src/SJZY.Track.Application/Services/TrackNode/TrackNodeService.cs b/src/SJZY.Track.Application/Services/TrackNode/TrackNodeService.cs new file mode 100644 index 00000000..d24eeaef --- /dev/null +++ b/src/SJZY.Track.Application/Services/TrackNode/TrackNodeService.cs @@ -0,0 +1,169 @@ +using SJZY.Track.Application.Contract.Dtos.TrackNode; +using SJZY.Track.Application.Contract.Dtos.TrackStatus; +using SJZY.Track.Application.Helpers; +using SJZY.Track.Domain.Aggregates.TrackNodeAggregate; +using SJZY.Track.Domain.Aggregates.TrackStatusAggregate; +using SJZY.Track.Domain.Dtos.TrackNode; +using Volo.Abp.DependencyInjection; + +namespace SJZY.Track.Application.Services.TrackNode; + +/// +/// 轨迹节点服务 +/// +[ApiExplorerSettings(GroupName = "轨迹节点")] +[Route("/Track/Node")] +public class TrackNodeService : ApplicationService, ITransientDependency +{ + private readonly ITrackNodeRepository _trackNodeRepository; + private readonly ITrackStatusRepository _trackStatusRepository; + + public TrackNodeService( + ITrackNodeRepository trackNodeRepository, ITrackStatusRepository trackStatusRepository) + { + this._trackNodeRepository = trackNodeRepository; + _trackStatusRepository = trackStatusRepository; + } + + /// + /// 轨迹节点编辑 + /// + /// + [HttpPost("Edit")] + public async Task EditAsync(EditTrackNodeInput input) + { + return input.Options switch + { + OptionType.新增 => await AddAsync(input), + OptionType.修改 => await UpdateAsync(input), + OptionType.删除 => await DeleteAsync(input), + _ => throw new BusinessException(message: "当前操作动作不合法") + }; + } + + /// + /// 获取分页轨迹节点 + /// + /// + /// + [HttpPost("GetList")] + public async Task> GetPageTrackNode(QueryTrackNodeRequest input) + { + var queryParam = ObjectMapper.Map(input); + var resultDto = await _trackNodeRepository.GetPageList(queryParam); + return resultDto; + } + + /// + /// 获取详情 + /// + /// 节点id + /// + [HttpPost("GetDetail")] + public async Task GetDetail(int nodeid) + { + var resultDto = await _trackNodeRepository.GetDetail(nodeid); + return new UnifyResultDto(true, resultDto); + } + + /// + /// 获取分页轨迹字典,下拉框用的 + /// + /// + /// + [HttpPost("GetTrackNodeOption")] + public async Task> GetTrackNodeOption(QueryTrackNodeRequest input) + { + var queryParam = ObjectMapper.Map(input); + var resultDto = await _trackNodeRepository.GetPageDicList(queryParam); + return resultDto; + } + + #region 私有方法 + + private async Task AddAsync(EditTrackNodeInput input) + { + #region 业务校验 + + if (string.IsNullOrEmpty(input.NodeName) || string.IsNullOrEmpty(input.NodeEnName) || + !input.SubSystemId.HasValue) + { + return new UnifyResultDto(GlobalConst.SuccessCode, "NodeName,NodeEnName,SubSystemId 必填", false); + } + + var trackNodesEntitys = await _trackNodeRepository.GetListAsync(a => + a.SubSystemId == input.SubSystemId && + (a.NodeName == input.NodeName || a.NodeEnName == input.NodeEnName)); + if (trackNodesEntitys.Any()) + { + var trackNodeName = trackNodesEntitys.FirstOrDefault(a => a.NodeName == input.NodeName); + if (trackNodeName != null) + { + throw new BusinessException(message: "该子系统下节点名称已存在"); + } + + var trackNodeEnName = trackNodesEntitys.FirstOrDefault(a => a.NodeEnName == input.NodeEnName); + if (trackNodeEnName != null) + { + throw new BusinessException(message: "该子系统下节点英文名称已存在"); + } + } + + #endregion + + if (!StringHelper.IsValidEnglishString(input.NodeEnName)) + { + return new UnifyResultDto(GlobalConst.SuccessCode, "节点英文名称必须是英文和常用英文符号", false); + } + + var entity = ObjectMapper.Map(input); + var isTrue = await _trackNodeRepository.InsertAsync(entity); + + return new UnifyResultDto(GlobalConst.SuccessCode, "新增成功", isTrue); + } + + private async Task UpdateAsync(EditTrackNodeInput input) + { + #region 业务校验 + + if (string.IsNullOrEmpty(input.NodeName) || string.IsNullOrEmpty(input.NodeEnName)) + { + return new UnifyResultDto(GlobalConst.SuccessCode, "NodeName,NodeEnName 必填", false); + } + + var trackNodesEntitys = await _trackNodeRepository.GetFirstAsync(a => a.Id == input.Id); + if (trackNodesEntitys == null) + { + return new UnifyResultDto(GlobalConst.SuccessCode, "没有找到数据,更新失败", false); + } + + #endregion + + trackNodesEntitys.NodeEnName = input.NodeEnName; + trackNodesEntitys.NodeName = input.NodeName; + var isTrue = await _trackNodeRepository.UpdateAsync(trackNodesEntitys); + + return new UnifyResultDto(GlobalConst.SuccessCode, "修改成功", isTrue); + } + + private async Task DeleteAsync(EditTrackNodeInput input) + { + if (input.Id <= 0 || !input.SubSystemId.HasValue) + { + return new UnifyResultDto(GlobalConst.SuccessCode, "SubSystemId 必填", false); + } + + var trackStatus = + await _trackStatusRepository.GetFirstAsync(val => + val.Node == input.Id && val.SubSystemId == input.SubSystemId); + if (trackStatus != null) + { + return new UnifyResultDto(GlobalConst.SuccessCode, "删除失败,该节点已被使用", false); + } + + var rows = await _trackNodeRepository.DeleteById(input.Id); + return new UnifyResultDto(GlobalConst.SuccessCode, "删除成功", rows > 0); + } + + #endregion +} diff --git a/src/SJZY.Track.Application/Services/TrackOrders/OrderWarningService.cs b/src/SJZY.Track.Application/Services/TrackOrders/OrderWarningService.cs new file mode 100644 index 00000000..92219f8b --- /dev/null +++ b/src/SJZY.Track.Application/Services/TrackOrders/OrderWarningService.cs @@ -0,0 +1,77 @@ +using SJZY.Track.Domain.Aggregates.ForewarningAggregate; +using SJZY.Track.Domain.Aggregates.OrderAggregate; +using SJZY.Track.Domain.Dtos.Forewarning; + +namespace SJZY.Track.Application.Services.TrackOrders; + +/// +/// 订单预警服务 +/// +[ApiExplorerSettings(GroupName = "轨迹订单")] +[Route("/Track/Order")] +public class OrderWarningService : ApplicationService +{ + private readonly IOrderRepository _orderRepository; + private readonly IWarningRecordEsRepository _warningRecordEsRepository; + + public OrderWarningService(IWarningRecordEsRepository warningRecordEsRepository, IOrderRepository orderRepository) + { + _warningRecordEsRepository = warningRecordEsRepository; + _orderRepository = orderRepository; + } + + /// + /// 获取订单运输时效预警分页列表 + /// + /// + /// + /// + [HttpGet("GetOrderWarningPageList/{userId:int?}")] + [HttpPost("GetOrderWarningPageList")] + public async Task> GetOrderWarningPageListAsync( + [FromBody] GetOrderWarningPageListVo inputVo, [FromQuery] int? userId) + { + if (userId != null) inputVo.NotifyUserId = userId; + var result = await _warningRecordEsRepository.GetOrderWarningPageListAsync(inputVo); + var orderIds = result.list.Select(x => x.OrderId).ToList(); + var orders = await _orderRepository.GetListAsync(x => orderIds.Contains(x.Id), x => new + { + x.Id, + x.LatestTrackContent, + x.LatestTrackTime, + x.LatestTrackPlace, + x.OrderType + }); + + var list = new List(); + + result.list.ForEach(x => + { + var item = new GetOrderWarningPageOutput + { + SubSystemId = x.SubSystemId, + SubSystemName = x.SubSystemName, + OrderNo = x.OrderNo, + Rule = x.Rule, + Counter = x.Counter, + IsLast = x.IsLast, + WarningName = x.WarningName, + WarningStatus = x.WarningStatus, + CreateTime = x.CreateTime, + NotifyUser = x.NotifyUserName, + CustomName = x.CustomName, + }; + var order = orders.FirstOrDefault(o => o.Id == x.OrderId); + if (order == default) return; + item.LatestTrackTime = order.LatestTrackTime; + item.LatestTrackPlace = order.LatestTrackPlace; + item.LatestTrackContent = order.LatestTrackContent; + item.OrderType = order.OrderType; + + list.Add(item); + }); + + return new UnifyPageResultDto(list, inputVo.PageIndex, inputVo.PageSize, + (int) result.total); + } +} diff --git a/src/SJZY.Track.Application/Services/TrackOrders/TrackOrderService.cs b/src/SJZY.Track.Application/Services/TrackOrders/TrackOrderService.cs index 477456cb..71487d75 100644 --- a/src/SJZY.Track.Application/Services/TrackOrders/TrackOrderService.cs +++ b/src/SJZY.Track.Application/Services/TrackOrders/TrackOrderService.cs @@ -1,111 +1,46 @@ -using System.Diagnostics; +using System.Linq.Expressions; +using SJZY.Expand.AliyunOSS; using SJZY.Track.Application.Contract.Dtos.ProvideServices; using SJZY.Track.Application.Contract.Dtos.TrackOrder; using SJZY.Track.Domain.Aggregates.OrderAggregate; using SJZY.Track.Domain.Aggregates.TrackContentAggregate; using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; using SJZY.Track.Domain.Aggregates.TrackPushAggregate; +using SJZY.Track.Domain.Aggregates.TrackStatusAggregate; using SJZY.Track.Domain.Dtos.Order; -using SJZY.Track.Domain.Dtos.TrackTemplate; -using SJZY.Track.Domain.Enums; -using SJZY.Track.Domain.Queries; namespace SJZY.Track.Application.Services.TrackOrders; +/// +/// 轨迹订单服务 +/// [ApiExplorerSettings(GroupName = "轨迹订单")] [Route("/Track/Order")] public class TrackOrderService : ApplicationService { + private readonly IOrderOperationRecordEsRepository _orderOperationRecordEsRepository; private readonly IOrderRepository _orderRepository; - private readonly ITrackOrderQueries _trackOrderQueries; - private readonly ITrackDetailsRepository _trackDetailsRepository; private readonly ITrackContentRepository _trackContentRepository; - private readonly ITrackPushRecordsRepository _trackPushRecordsRepository; + private readonly ITrackStatusRepository _trackStatusRepository; + private readonly ITrackDetailsEsRepository _trackDetailsEsRepository; + private readonly ITrackPushRecordEsRepository _trackPushRecordEsRepository; public TrackOrderService( IOrderRepository orderRepository, - ITrackOrderQueries trackOrderQueries, - ITrackDetailsRepository trackDetailsRepository, + ITrackDetailsEsRepository trackDetailsEsRepository, ITrackContentRepository trackContentRepository, - ITrackPushRecordsRepository trackPushRecordsRepository - ) + ITrackPushRecordEsRepository trackPushRecordEsRepository, + IOrderOperationRecordEsRepository orderOperationRecordEsRepository, + ITrackStatusRepository trackStatusRepository) { _orderRepository = orderRepository; - _trackOrderQueries = trackOrderQueries; - _trackDetailsRepository = trackDetailsRepository; + _trackDetailsEsRepository = trackDetailsEsRepository; _trackContentRepository = trackContentRepository; - _trackPushRecordsRepository = trackPushRecordsRepository; + _trackPushRecordEsRepository = trackPushRecordEsRepository; + _orderOperationRecordEsRepository = orderOperationRecordEsRepository; + _trackStatusRepository = trackStatusRepository; } - #region 轨迹订单明细 - - /// - /// 根据轨迹订单id获取轨迹订单明细列表 - /// - /// - /// - [HttpPost("GetDetails")] - public async Task> GetOrderDetails(GetOrderDetailsInput input) - { - var trackDetails = await _trackDetailsRepository.GetListAsync(input.OrderId); - if (!trackDetails.IsNullOrEmpty()) - { - var list = ObjectMapper.Map, List>(trackDetails); - var trackCodes = list.Where(a => !a.Code.IsNullOrWhiteSpace()).Select(a => a.Code).Distinct().ToList(); - - var trackContents = await _trackContentRepository.GetTrackContentAttributeValue( - new GetTemplateContentAttributeValueInputVO - { - SubSystemId = input.SubSystemId, - TrackTemplateIds = input.TrackTemplateIds, - TrackCodes = trackCodes - }); - Debug.Assert(input.TrackTemplateIds != null, "input.TrackTemplateIds != null"); - input.TrackTemplateIds = input.TrackTemplateIds.Where(a => a > 0).ToList(); - list.ForEach(a => - { - var trackContentsOfTemplates = trackContents.Where(b => - b.SubSystemId == input.SubSystemId && b.TrackCode == a.Code && - input.TrackTemplateIds.Contains(b.TrackTemplateId)) - .ToList(); - GetTemplateContentAttributeValueVO? trackContent = null; - var insertData = input.TrackTemplateIds - .Intersect(trackContentsOfTemplates.Select(aa => aa.TrackTemplateId)).ToList(); - if (!insertData.IsNullOrEmpty()) - { - trackContent = - trackContentsOfTemplates.FirstOrDefault(it => - it.TrackTemplateId == insertData.FirstOrDefault()); - } - - if (trackContent != null) - { - a.IsExternal = trackContent.IsExternal; - } - - if (a.TrackTimeZoneValue == 0f) - { - a.TrackTimeZone = "GTM +00:00"; - } - else - { - // 将小数形式的小时转换为时区偏移量 - int hours = (int)a.TrackTimeZoneValue; // 提取整数部分作为小时 - int minutes = (int)((a.TrackTimeZoneValue - hours) * 60); // 将小数部分乘以 60 转换为分钟 - TimeSpan offset = new TimeSpan(hours, minutes, 0); - string timeZoneStr = offset.ToString(); - string flag = a.TrackTimeZoneValue > 0f ? "+" : ""; - a.TrackTimeZone = $"GTM {flag}{timeZoneStr.RemovePostFix(":00")}"; - } - }); - return list; - } - - return new List(); - } - - #endregion - #region 轨迹订单列表 /// @@ -114,10 +49,10 @@ public class TrackOrderService : ApplicationService /// /// [HttpPost("GetTrackOrderList")] - public async Task> GetPageTrackOrder(GetPageTrackOrderInput input) + public async Task> GetTrackOrderPagedList(GetPageTrackOrderInput input) { var vo = ObjectMapper.Map(input); - var pageList = await _trackOrderQueries.GetPageTrackOrder(vo); + var pageList = await _orderRepository.GetTrackOrderPagedList(vo); var pageResultDto = ObjectMapper.Map, UnifyPageResultDto>(pageList); return pageResultDto; @@ -125,6 +60,13 @@ public class TrackOrderService : ApplicationService #endregion + + /// + /// 更新订单状态 + /// + /// + /// + /// [HttpPost("UpdateOrderStatus")] public async Task UpdateOrderStatus(UpdateOrderStatusInput input) { @@ -134,24 +76,10 @@ public class TrackOrderService : ApplicationService order.IsCompleted = input.IsCompleted; - return await _orderRepository.UpdateColumnAsync(order, x => new { x.IsCompleted }); - } - - /// - /// 获取轨迹计数器 - /// - /// - [HttpGet("GetTrackCounter")] - public async Task GetTrackCounterAsync() - { - var counts = await _trackOrderQueries.GetTrackProblemCountsAsync(); - - return new GetTrackCounterOutput + return await _orderRepository.UpdateColumnAsync(order, x => new { - TotalCount = counts.Sum(x => x.Count), - ErrorCount = counts.FirstOrDefault(x => x.ProblemType == (int)TrackProblemType.Error)?.Count ?? 0, - WarnCount = counts.FirstOrDefault(x => x.ProblemType == (int)TrackProblemType.Warn)?.Count ?? 0, - }; + x.IsCompleted + }); } /// @@ -162,18 +90,220 @@ public class TrackOrderService : ApplicationService [HttpGet("GetTrackPushRecords")] public async Task> GetTrackPushRecordsAsync(int orderId) { - var records = await _trackPushRecordsRepository.GetTrackPushRecordsAsync(orderId); + var records = await _trackPushRecordEsRepository.GetTrackPushRecordsAsync(orderId); var res = ObjectMapper.Map, List>(records); res.ForEach(x => { - int hours = (int)x.TrackTimeZone; // 提取整数部分作为小时 - int minutes = (int)((x.TrackTimeZone - hours) * 60); // 将小数部分乘以 60 转换为分钟 + int hours = (int) x.TrackTimeZone; // 提取整数部分作为小时 + int minutes = (int) ((x.TrackTimeZone - hours) * 60); // 将小数部分乘以 60 转换为分钟 x.TrackGTMTimeZone = - $"GTM {(x.TrackTimeZone >= 0 ? "+" : "-")}{new TimeSpan(hours, minutes, 0).ToString().RemovePostFix(":00")}"; + $"GMT {(x.TrackTimeZone >= 0 ? "+" : "-")}{new TimeSpan(hours, minutes, 0).ToString().RemovePostFix(":00")}"; }); return res; } -} \ No newline at end of file + + /// + /// 根据订单id获取轨迹明细列表 + /// + /// + /// + /// + /// + [HttpPost("GetDetails")] + public async Task> GetTracksAsync(int? orderId, string? orderNo, int? systemId) + { + Expression>? whereExpression = null; + //根据订单id查询 + if (orderId != null && orderId > 0) + whereExpression = m => m.Id == orderId; + + //根据订单号+系统id查询 + if (!string.IsNullOrEmpty(orderNo) && systemId != null && systemId > 0) + whereExpression = m => m.OrderNo == orderNo && m.SubSystemId == systemId; + + if (whereExpression == default) + throw new BusinessException(message: "请求参数异常"); + + var order = await _orderRepository.GetFirstAsync(whereExpression); + if (order == default) + { + throw new BusinessException(message: "订单不存在"); + } + + var trackDetails = await _trackDetailsEsRepository.GetListAsync(order.Id); + if (trackDetails.IsNullOrEmpty()) + { + return new List(); + } + + var list = ObjectMapper.Map, List>(trackDetails); + + // 计算时区 + list.ForEach(a => + { + if (a.TrackTimeZoneValue == 0f) + { + a.TrackTimeZone = "GMT +00:00"; + } + else if (Math.Abs(a.TrackTimeZoneValue - GlobalConst.NoneTrackTimeZone) < 1) + { + a.TrackTimeZone = "--"; + } + else + { + // 将小数形式的小时转换为时区偏移量 + var hours = (int) a.TrackTimeZoneValue; // 提取整数部分作为小时 + var minutes = (int) ((a.TrackTimeZoneValue - hours) * 60); // 将小数部分乘以 60 转换为分钟 + var offset = new TimeSpan(hours, minutes, 0); + var timeZoneStr = offset.ToString(); + var flag = a.TrackTimeZoneValue > 0f ? "+" : ""; + a.TrackTimeZone = $"GMT {flag}{timeZoneStr.RemovePostFix(":00")}"; + } + }); + return list; + } + + + /// + /// 按时间轴获取轨迹内容 + /// + /// + /// + [HttpPost("GetDetailTimeline")] + public async Task>> GetDetailTimeline(GetDetailTimelineInput input) + { + var res = new UnifyResultDto>(true); + + var order = await _orderRepository.GetFirstAsync(m => m.OrderNo == input.OrderNumber); + if (order == null) + return new UnifyResultDto>(false, "订单不存在"); + + if (input.SystemId <= 0) + return new UnifyResultDto>(false, "子系统id不合法"); + + if (input.CurrenUserSystemId <= 0) + return new UnifyResultDto>(false, "当前登陆用户子系统id不合法"); + + var system = await _orderRepository.GetSystemInfoById(input.CurrenUserSystemId); + if (system == null) + return new UnifyResultDto>(false, "未找到指定id的子系统"); + + var trackDetails = await _trackDetailsEsRepository.GetListAsync(order.Id); + //时间轴不显示轨迹内容为空的轨迹,进行过滤 + trackDetails = trackDetails.Where(x => !x.TrackContent.IsNullOrWhiteSpace() && x.TrackContent != GlobalConst.EmptyString).ToList(); + res.Data = new List(); + + foreach (var item in trackDetails) + { + //如果是外部系统,且轨迹内容不对外则跳过这条轨迹内容 + if (system.SystemProperty == 2 && !item.IsExternal) + continue; + + //时间和时区任意一个为空则使用创建时间做为排序参照值 + var timeTick = ToUnixTimestamp((item.TrackTime == null + || Math.Abs(item.TrackTimeZone - GlobalConst.NoneTrackTimeZone) < 1) + ? item.CreateTime + : item.TrackTime); + res.Data.Add(new GetDetailTimelineOutput() + { + IsHighlight = true, + IsShowHover = true, + Remark = item.Remarks == null || item.Remarks == "--" ? "" : item.Remarks, + TrackTimeZone = $"GMT{(item.TrackTimeZone >= 0 ? "+" : "-")}{GetTimeZoneStr(item.TrackTimeZone)}", + TrackTime = timeTick, + TrackPlace = item.TrackPlace, + EnContent = item.TrackEnContent, + Files = item.Files == null + ? new List() + : item.Files!.Select(m => new TrackFileItem() + { + OssKey = m.OssKey, + FileName = m.FileName, + Url = m.OssKey.GetUrlByKey(), + }).ToList(), + Content = item.TrackContent, + TrackCode = item.TrackCode, + TrackPlaceNation = item.TrackPlaceNation, + TrackPlaceProvince = item.TrackPlaceProvince, + TrackPlaceCity = item.TrackPlaceCity, + }); + } + + // 按轨迹发生时间正序排序 + res.Data = res.Data.OrderBy(m => m.TrackTime).ToList(); + + if (!order.IsCompleted) //如果没完结则显示签收节点 + { + var eddUnixTimestamp = order.EstimatedDeliveryDate.HasValue ? ToUnixTimestamp(DateTime.Parse(order.EstimatedDeliveryDate.ToString()!)) : 0; + var isShowTime = eddUnixTimestamp > 0 && res.Data.All(m => m.TrackTime < eddUnixTimestamp); + + //当存在需要显示的轨迹才需要补充签收节点 + if (res.Data.Count != 0) + { + res.Data.Add(new GetDetailTimelineOutput() + { + Content = "签收", + IsHighlight = false, + TrackTimeZone = isShowTime ? $"GMT{(order.DestinationTimeZone >= 0 ? "+" : "-")}{order.DestinationTimeZone}" : "", + TrackTime = isShowTime ? eddUnixTimestamp : 0, + TrackTimePrefix = isShowTime ? "预计签收时间:" : "", + }); + } + } + + return res; + } + + public static long ToUnixTimestamp(DateTime time) + { + var sTime = TimeZoneInfo.ConvertTime(new DateTime(1970, 1, 1), TimeZoneInfo.Utc, TimeZoneInfo.Local); + return (long) (time - sTime).TotalMilliseconds; + } + + private string GetTimeZoneStr(float timeZone) + { + var time = timeZone.ToString().Split('.'); + if (time.Length > 1 && time[1] != "0") //如果时区有小数点 + { + return time[0] + ":30"; + } + else + { + return time[0] + ":00"; + } + } + + /// + /// 根据轨迹id删除单条轨迹 + /// + /// 轨迹id + /// + [HttpPost("DeleteTrackById")] + public async Task DeleteTrackByIdAsync(string trackId) + { + var track = await _trackDetailsEsRepository.GetByIdAsync(trackId); + + // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + if (track == null) + { + throw new BusinessException(message: "轨迹不存在!"); + } + + await _trackDetailsEsRepository.DeleteTrackByIdAsync(trackId, track.IndexName); + return true; + } + + /// + /// 根据订单id查询订单操作记录 + /// + /// 订单id + /// + [HttpGet("GetOrderOperationsById")] + public async Task> GetOrderOperationsByIdAsync(int orderId) + { + return await _orderOperationRecordEsRepository.GetOrderOperationsByIdAsync(orderId); + } +} diff --git a/src/SJZY.Track.Application/Services/TrackPull/TrackPullCacheService.cs b/src/SJZY.Track.Application/Services/TrackPull/TrackPullCacheService.cs index 76ae531c..e7d2a2e1 100644 --- a/src/SJZY.Track.Application/Services/TrackPull/TrackPullCacheService.cs +++ b/src/SJZY.Track.Application/Services/TrackPull/TrackPullCacheService.cs @@ -1,79 +1,67 @@ -using System.Linq.Expressions; using SJZY.Expand.ABP.Core; using SJZY.Track.Application.Contract.Dtos.TrackPull; using SJZY.Track.Application.Contract.Services; using SJZY.Track.Domain.Aggregates.TrackPullAggregate; -using SJZY.Track.Domain.Consts; using SJZY.Track.Domain.Dtos.TrackPull; +using Volo.Abp.DependencyInjection; +using Volo.Abp.ObjectMapping; namespace SJZY.Track.Application.Services.TrackPull; -public class TrackPullCacheService : ApplicationService, ITrackPullCacheService +public class TrackPullCacheService : ITransientDependency, ITrackPullCacheService { + private readonly IObjectMapper _objectMapper; private readonly ITrackPullConfigRepository _trackPullConfigRepository; - public string TrackPullKey(int subSystemId, int serviceProviderId) => - $"{GlobalConst.TrackPullKeyPrefix}:{subSystemId}:{serviceProviderId}"; - - public string TrackPullContentKey(int subSystemId, int serviceProviderId) => - $"{GlobalConst.TrackPullContentKeyPrefix}:{subSystemId}:{serviceProviderId}"; - - public TrackPullCacheService(ITrackPullConfigRepository trackPullConfigRepository) + public TrackPullCacheService(ITrackPullConfigRepository trackPullConfigRepository, IObjectMapper objectMapper) { _trackPullConfigRepository = trackPullConfigRepository; + _objectMapper = objectMapper; } - [NonAction] - public async Task> GetAllPullConfigsAsync() + public string TrackPullKey(int subSystemId, string serviceProviderCode) => + $"{GlobalConst.TrackPullKeyPrefix}:{subSystemId}:{serviceProviderCode}"; + + public async Task GetPullParamsWithContentAsync(int subSystemId, + string serviceProviderCode) { - return await _trackPullConfigRepository.GetListAsync(x => true, x => new TrackPullConfigDto + var data = await RedisHelper.Client.GetAsync(TrackPullContentKey( + subSystemId, serviceProviderCode)); + + var pullId = await _trackPullConfigRepository.FindIdAsync(subSystemId, serviceProviderCode); + data ??= await SetPullConfigAsync(pullId); + + return data; + } + + public async Task SetPullConfigAsync(int id) + { + var trackPullConfigDetail = await _trackPullConfigRepository.GetDetailAsync(id); + if (trackPullConfigDetail == null) { - SubSystemId = x.SubSystemId, - ServiceProviderId = x.ServiceProviderId, - PullInterval = x.PullInterval - }); - } + return null; + } - [NonAction] - public async Task GetPullParamWithContentConfigAsync(int subSystemId, - int serviceProviderId) - { - var data = await RedisHelper.Client.GetAsync(TrackPullContentKey( - subSystemId, - serviceProviderId)); + var trackPullContentList = await _trackPullConfigRepository.GetContentListCacheAsync(id); + if (trackPullContentList.Count == 0) + { + return null; + } - data ??= await SetPullConfigAsync(subSystemId: subSystemId, serviceProviderId: serviceProviderId); + var data = new TrackPullParamsWithContentDto + { + ParamConfig = + _objectMapper.Map(trackPullConfigDetail), + ContentConfigs = _objectMapper.Map, List>( + trackPullContentList) + }; + + var key = TrackPullContentKey(trackPullConfigDetail.SubSystemId, trackPullConfigDetail.ServiceProviderCode); + await RedisHelper.Client.SetAsync(key, data, TimeSpan.FromHours(24)); return data; } - [NonAction] - public async Task SetPullConfigAsync(int? id = null, int? subSystemId = null, - int? serviceProviderId = null) - { - Expression> exp = x => true; - if (id.HasValue) exp = x => x.Id == id; - else if (subSystemId.HasValue && serviceProviderId.HasValue) - exp = x => x.SubSystemId == subSystemId && x.ServiceProviderId == serviceProviderId; - - var trackPullConfigEntity = await _trackPullConfigRepository.GetFirstAsync(exp); - if (trackPullConfigEntity == null) return null; - - var trackPullConfigDetail = await _trackPullConfigRepository.GetDetailAsync(trackPullConfigEntity.Id); - var trackPullContentList = await _trackPullConfigRepository.GetContentListCacheAsync(trackPullConfigEntity.Id); - if (trackPullContentList.Count == 0) return null; - - var data = new TrackPullParamWithContentConfigDto(); - - data.ParamConfig = - ObjectMapper.Map(trackPullConfigDetail); - data.ContentConfigs = - ObjectMapper.Map, List>( - trackPullContentList); - - await RedisHelper.Client.SetAsync( - TrackPullContentKey(trackPullConfigEntity.SubSystemId, trackPullConfigEntity.ServiceProviderId), data); - - return data; - } -} \ No newline at end of file + public string TrackPullContentKey(int subSystemId, string serviceProviderCode) => + $"{GlobalConst.TrackPullContentKeyPrefix}:{subSystemId}:{serviceProviderCode}"; +} diff --git a/src/SJZY.Track.Application/Services/TrackPull/TrackPullService.cs b/src/SJZY.Track.Application/Services/TrackPull/TrackPullService.cs index cd027698..a72916e9 100644 --- a/src/SJZY.Track.Application/Services/TrackPull/TrackPullService.cs +++ b/src/SJZY.Track.Application/Services/TrackPull/TrackPullService.cs @@ -1,10 +1,12 @@ -using System.Linq.Expressions; +using System.Linq.Expressions; using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Options; using SJZY.Expand.ABP.Core.Localization; using SJZY.Expand.ABP.Core.PublicMethords; using SJZY.Track.Application.Contract.Dtos.TrackPull; using SJZY.Track.Application.Contract.Services; using SJZY.Track.Application.Localization; +using SJZY.Track.Application.Options; using SJZY.Track.Domain.Aggregates.TrackPullAggregate; using SJZY.Track.Domain.Dtos.Common; using SJZY.Track.Domain.Dtos.TrackPull; @@ -19,18 +21,20 @@ namespace SJZY.Track.Application.Services.TrackPull; [Route("/Track/PullConfig")] public class TrackPullService : ApplicationService { + private readonly IOptionsMonitor _options; private readonly IStringLocalizer _stringLocalizer; - private readonly ITrackPullConfigRepository _trackPullConfigRepository; private readonly ITrackPullCacheService _trackPullCacheService; + private readonly ITrackPullConfigRepository _trackPullConfigRepository; public TrackPullService( IStringLocalizer stringLocalizer, ITrackPullConfigRepository trackPullConfigRepository, - ITrackPullCacheService trackPullCacheService) + ITrackPullCacheService trackPullCacheService, IOptionsMonitor options) { _stringLocalizer = stringLocalizer; _trackPullConfigRepository = trackPullConfigRepository; _trackPullCacheService = trackPullCacheService; + _options = options; } /// @@ -64,7 +68,14 @@ public class TrackPullService : ApplicationService [HttpGet("GetDetail")] public async Task GetDetailAsync(int id) { - return await _trackPullConfigRepository.GetDetailAsync(id); + var res = await _trackPullConfigRepository.GetDetailAsync(id); + + if (res == null) + { + throw new BusinessException(message: "轨迹拉取配置不存在"); + } + + return res; } /// @@ -101,60 +112,73 @@ public class TrackPullService : ApplicationService switch (input.Options) { case OptionTypeNoNull.新增: - { - var trackPullEntity = ObjectMapper.Map(input); - var trackPullParamsEntity = - ObjectMapper.Map(input); - - int id; - - using (var ts = TransactionScopeHelper.Create()) { - id = await _trackPullConfigRepository.InsertReturnIdentityAsync(trackPullEntity); + var trackPullEntity = ObjectMapper.Map(input); - trackPullParamsEntity.PullOrPushConfigId = id; - await _trackPullConfigRepository.InsertParamsAsync(trackPullParamsEntity); + if (input.ParseMethod == (int) ParseMethod.InterfaceRelay) + { + var paramsConfig = _options.CurrentValue; + if (paramsConfig == null) + { + throw new BusinessException(message: "未找到接口通参数配置,联系管理员添加"); + } - ts.Complete(); + trackPullEntity.OrderPath = paramsConfig.OrderPath; + trackPullEntity.OrderNoName = paramsConfig.OrderNoName; + trackPullEntity.TrackDetailsPath = paramsConfig.TrackDetailsPath; + trackPullEntity.TrackContentCodeName = paramsConfig.TrackContentCodeName; + trackPullEntity.TrackStatusName = paramsConfig.TrackStatusName; + trackPullEntity.TrackContentName = paramsConfig.TrackContentName; + trackPullEntity.TrackPlaceName = paramsConfig.TrackPlaceName; + trackPullEntity.TrackTimeName = paramsConfig.TrackTimeName; + trackPullEntity.TrackTimeZoneName = paramsConfig.TrackTimeZoneName; + } + + var id = await _trackPullConfigRepository.InsertReturnIdentityAsync(trackPullEntity); + + await _trackPullCacheService.SetPullConfigAsync(id); } - - await _trackPullCacheService.SetPullConfigAsync(id); - } break; case OptionTypeNoNull.修改: - { - var oldTrackPullEntity = await _trackPullConfigRepository.GetFirstAsync(x => x.Id == input.Id) ?? - throw new BusinessException(message: _stringLocalizer["NotFindData"]); - - var oldTrackPullParamsEntity = - await _trackPullConfigRepository.GetParamsSingleAsync(x => - x.PullOrPushConfigId == input.Id && !x.IsPush); - - ObjectMapper.Map(input, oldTrackPullEntity); - ObjectMapper.Map(input, oldTrackPullParamsEntity); - - using (var ts = TransactionScopeHelper.Create()) { + var oldTrackPullEntity = await _trackPullConfigRepository.GetFirstAsync(x => x.Id == input.Id) ?? + throw new BusinessException(message: _stringLocalizer["NotFindData"]); + + ObjectMapper.Map(input, oldTrackPullEntity); + if (input.ParseMethod == (int) ParseMethod.InterfaceRelay) + { + var paramsConfig = _options.CurrentValue; + if (paramsConfig == null) + { + throw new BusinessException(message: "未找到接口通参数配置,联系管理员添加"); + } + + oldTrackPullEntity.OrderPath = paramsConfig.OrderPath; + oldTrackPullEntity.OrderNoName = paramsConfig.OrderNoName; + oldTrackPullEntity.TrackDetailsPath = paramsConfig.TrackDetailsPath; + oldTrackPullEntity.TrackContentCodeName = paramsConfig.TrackContentCodeName; + oldTrackPullEntity.TrackStatusName = paramsConfig.TrackStatusName; + oldTrackPullEntity.TrackContentName = paramsConfig.TrackContentName; + oldTrackPullEntity.TrackPlaceName = paramsConfig.TrackPlaceName; + oldTrackPullEntity.TrackTimeName = paramsConfig.TrackTimeName; + oldTrackPullEntity.TrackTimeZoneName = paramsConfig.TrackTimeZoneName; + } + await _trackPullConfigRepository.UpdateAsync(oldTrackPullEntity); - await _trackPullConfigRepository.UpdateParamsAsync(oldTrackPullParamsEntity); - ts.Complete(); + await _trackPullCacheService.SetPullConfigAsync(input.Id!.Value); } - - await _trackPullCacheService.SetPullConfigAsync(input.Id); - } break; case OptionTypeNoNull.删除: using (var ts = TransactionScopeHelper.Create()) { await _trackPullConfigRepository.SoftDeleteAsync(x => x.Id == input.Id); - await _trackPullConfigRepository.SoftDeleteParamsAsync(x => - x.PullOrPushConfigId == input.Id && !x.IsPush); + await _trackPullConfigRepository.SoftDeleteContentAsync(x => x.TrackPullConfigId == input.Id); - await _trackPullCacheService.SetPullConfigAsync(input.Id); + await _trackPullCacheService.SetPullConfigAsync(input.Id!.Value); ts.Complete(); } @@ -180,23 +204,28 @@ public class TrackPullService : ApplicationService { Expression> isContentAnyExp = x => x.TrackPullConfigId == input.TrackPullConfigId; - if (input.Options == OptionTypeNoNull.修改) isContentAnyExp = isContentAnyExp.And(x => x.Id != input.Id); + + if (input.Options == OptionTypeNoNull.修改) + { + isContentAnyExp = isContentAnyExp.And(x => x.Id != input.Id); + } if (await _trackPullConfigRepository.IsContentAnyAsync(isContentAnyExp.And(x => x.TrackContentId == input.TrackContentId))) throw new BusinessException(message: _stringLocalizer["IsTrackPullContentAny"]); - if (!input.TrackContentCodeValue.IsNullOrWhiteSpace() && - await _trackPullConfigRepository.IsContentAnyAsync(isContentAnyExp.And(x => - x.TrackContentCodeValue == input.TrackContentCodeValue))) - throw new BusinessException(message: _stringLocalizer["IsTrackPullContentCodeValueAny"]); - if (!input.TrackStatusValue.IsNullOrWhiteSpace() && - await _trackPullConfigRepository.IsContentAnyAsync(isContentAnyExp.And(x => - x.TrackStatusValue == input.TrackStatusValue))) - throw new BusinessException(message: _stringLocalizer["IsTrackPullContentStatusValueAny"]); - if (!input.TrackContentValue.IsNullOrWhiteSpace() && - await _trackPullConfigRepository.IsContentAnyAsync(isContentAnyExp.And(x => - x.TrackContentValue == input.TrackContentValue))) - throw new BusinessException(message: _stringLocalizer["IsTrackPullContentValueAny"]); + + if (!input.TrackStatusValues.IsNullOrEmpty()) + { + Expression> trackStatusValuesExp = _ => false; + input.TrackStatusValues!.ForEach(item => + { + trackStatusValuesExp = trackStatusValuesExp.Or(x => SqlFunc.SplitIn(x.TrackStatusValue, item)); + }); + + if (await _trackPullConfigRepository.IsContentAnyAsync(isContentAnyExp.And(trackStatusValuesExp))) + throw new BusinessException(message: _stringLocalizer["IsTrackPullContentStatusValueAny"]); + } + if (!input.TrackKeywords.IsNullOrEmpty()) { Expression> trackKeywordExp = _ => false; @@ -213,38 +242,40 @@ public class TrackPullService : ApplicationService switch (input.Options) { case OptionTypeNoNull.新增: - { - var entity = ObjectMapper.Map(input); + { + var entity = ObjectMapper.Map(input); - await _trackPullConfigRepository.InsertContentAsync(entity); - await _trackPullCacheService.SetPullConfigAsync(input.TrackPullConfigId); + await _trackPullConfigRepository.InsertContentAsync(entity); + await _trackPullCacheService.SetPullConfigAsync(input.TrackPullConfigId!.Value); - break; - } + break; + } case OptionTypeNoNull.修改: - { - var oldTrackPullContentEntity = await _trackPullConfigRepository.GetContentByIdAsync(input.Id!.Value) ?? - throw new BusinessException(message: _stringLocalizer["NotFindData"]); + { + var oldTrackPullContentEntity = + await _trackPullConfigRepository.GetContentByIdAsync(input.Id!.Value) ?? + throw new BusinessException(message: _stringLocalizer["NotFindData"]); - ObjectMapper.Map(input, oldTrackPullContentEntity); + ObjectMapper.Map(input, oldTrackPullContentEntity); - await _trackPullConfigRepository.UpdateContentAsync(oldTrackPullContentEntity); - await _trackPullCacheService.SetPullConfigAsync(oldTrackPullContentEntity.TrackPullConfigId); + await _trackPullConfigRepository.UpdateContentAsync(oldTrackPullContentEntity); + await _trackPullCacheService.SetPullConfigAsync(oldTrackPullContentEntity.TrackPullConfigId); - break; - } + break; + } case OptionTypeNoNull.删除: - { - var oldTrackPullContentEntity = await _trackPullConfigRepository.GetContentByIdAsync(input.Id!.Value) ?? - throw new BusinessException(message: _stringLocalizer["NotFindData"]); + { + var oldTrackPullContentEntity = + await _trackPullConfigRepository.GetContentByIdAsync(input.Id!.Value) ?? + throw new BusinessException(message: _stringLocalizer["NotFindData"]); - await _trackPullConfigRepository.SoftDeleteContentAsync(x => x.Id == input.Id); - await _trackPullCacheService.SetPullConfigAsync(oldTrackPullContentEntity.TrackPullConfigId); + await _trackPullConfigRepository.SoftDeleteContentAsync(x => x.Id == input.Id); + await _trackPullCacheService.SetPullConfigAsync(oldTrackPullContentEntity.TrackPullConfigId); - break; - } + break; + } default: throw new BusinessException(message: _stringLocalizer[SjzyBasicLocalization.Validation_IsInEnum, @@ -253,4 +284,4 @@ public class TrackPullService : ApplicationService return true; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/Services/TrackPush/TrackPushCacheService.cs b/src/SJZY.Track.Application/Services/TrackPush/TrackPushCacheService.cs index dfda8279..5b64b496 100644 --- a/src/SJZY.Track.Application/Services/TrackPush/TrackPushCacheService.cs +++ b/src/SJZY.Track.Application/Services/TrackPush/TrackPushCacheService.cs @@ -1,8 +1,7 @@ -using SJZY.Expand.ABP.Core; +using SJZY.Expand.ABP.Core; using SJZY.Track.Application.Contract.Dtos.TrackPush; using SJZY.Track.Application.Contract.Services; using SJZY.Track.Domain.Aggregates.TrackPushAggregate; -using SJZY.Track.Domain.Consts; using Volo.Abp.DependencyInjection; namespace SJZY.Track.Application.Services.TrackPush; @@ -11,9 +10,6 @@ public class TrackPushCacheService : ITrackPushCacheService, ITransientDependenc { private readonly ITrackPushConfigRepository _trackPushConfigRepository; - private string TrackPushContentKey(int subSystemId, int customId) => - $"{GlobalConst.TrackPushKeyPrefix}:{subSystemId}:{customId}"; - public TrackPushCacheService(ITrackPushConfigRepository trackPushConfigRepository) { _trackPushConfigRepository = trackPushConfigRepository; @@ -43,12 +39,26 @@ public class TrackPushCacheService : ITrackPushCacheService, ITransientDependenc return data; } + private string TrackPushContentKey(int subSystemId, int customId) => + $"{GlobalConst.TrackPushContentKeyPrefix}:{subSystemId}:{customId}"; + private async Task?> DoGetPushContentConfigsAsync(int subSystemId, int customId) { var trackPushConfig = await _trackPushConfigRepository.GetFirstAsync( - x => x.SubSystemId == subSystemId && x.CustomId == customId, x => new + x => x.SubSystemId == subSystemId && x.CustomId == customId, + x => new { - x.Id, x.IsAutoPush, x.IsAllPush, x.IsCanDelete, x.IsCanUpdate, x.SubSystemId, x.CustomId + x.Id, + x.IsAutoPush, + x.IsAllPush, + x.IsAllPushWithLatest, + x.IsCanDelete, + x.IsCanUpdate, + x.SubSystemId, + x.CustomId, + x.DateTimeFormatType, + x.DateTimeFormat, + x.TimezoneFormat }); if (trackPushConfig == null) { @@ -67,7 +77,11 @@ public class TrackPushCacheService : ITrackPushCacheService, ITransientDependenc IsAutoPush = trackPushConfig.IsAutoPush, IsCanUpdate = trackPushConfig.IsCanUpdate, IsAllPush = trackPushConfig.IsAllPush, + IsAllPushWithLatest = trackPushConfig.IsAllPushWithLatest, IsCanDelete = trackPushConfig.IsCanDelete, + DateTimeFormatType = (int) trackPushConfig.DateTimeFormatType, + DateTimeFormat = trackPushConfig.DateTimeFormat, + TimezoneFormat = trackPushConfig.TimezoneFormat, ServiceProviderCode = item.ServiceProviderCode, OrderType = item.OrderType, TrackCode = item.TrackCode, @@ -77,9 +91,10 @@ public class TrackPushCacheService : ITrackPushCacheService, ITransientDependenc TrackContentValue = item.TrackContentValue, TrackEnContentValue = item.TrackEnContentValue, TrackTimeZone = item.TrackTimeZone, + // todo:废弃字段如果没有外部子系统依赖,可以逐步删除 ExpandFieldsValue = item.ExpandFieldsValue, }).ToList(); return res; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/Services/TrackPush/TrackPushService.cs b/src/SJZY.Track.Application/Services/TrackPush/TrackPushService.cs index f7d69e1d..66e95cf2 100644 --- a/src/SJZY.Track.Application/Services/TrackPush/TrackPushService.cs +++ b/src/SJZY.Track.Application/Services/TrackPush/TrackPushService.cs @@ -1,4 +1,4 @@ -using System.Linq.Expressions; +using System.Linq.Expressions; using Microsoft.Extensions.Localization; using SJZY.Expand.ABP.Core.Localization; using SJZY.Expand.ABP.Core.PublicMethords; @@ -8,6 +8,7 @@ using SJZY.Track.Application.Localization; using SJZY.Track.Domain.Aggregates.TrackPushAggregate; using SJZY.Track.Domain.Dtos.Common; using SJZY.Track.Domain.Dtos.TrackPush; +using Volo.Abp.DependencyInjection; namespace SJZY.Track.Application.Services.TrackPush; @@ -16,11 +17,11 @@ namespace SJZY.Track.Application.Services.TrackPush; /// [ApiExplorerSettings(GroupName = "轨迹推送")] [Route("/Track/PushConfig")] -public class TrackPushService : ApplicationService +public class TrackPushService : ApplicationService, ISingletonDependency { private readonly IStringLocalizer _stringLocalizer; - private readonly ITrackPushConfigRepository _trackPushConfigRepository; private readonly ITrackPushCacheService _trackPushCacheService; + private readonly ITrackPushConfigRepository _trackPushConfigRepository; public TrackPushService( IStringLocalizer stringLocalizer, @@ -100,17 +101,14 @@ public class TrackPushService : ApplicationService switch (input.Options) { case OptionTypeNoNull.新增: - { var trackPushEntity = ObjectMapper.Map(input); await _trackPushConfigRepository.InsertReturnIdentityAsync(trackPushEntity); await _trackPushCacheService.SetPushContentConfigsAsync(trackPushEntity.SubSystemId, trackPushEntity.CustomId); - } break; case OptionTypeNoNull.修改: - { var oldTrackPushEntity = await _trackPushConfigRepository.GetFirstAsync(x => x.Id == input.Id) ?? throw new BusinessException(message: _stringLocalizer["NotFindData"]); @@ -118,18 +116,15 @@ public class TrackPushService : ApplicationService await _trackPushConfigRepository.UpdateAsync(oldTrackPushEntity); await _trackPushCacheService.SetPushContentConfigsAsync(oldTrackPushEntity.SubSystemId, oldTrackPushEntity.CustomId); - } break; case OptionTypeNoNull.删除: - { var entity = await _trackPushConfigRepository.GetFirstAsync(x => x.Id == input.Id) ?? throw new BusinessException(message: _stringLocalizer["NotFindData"]); await _trackPushConfigRepository.SoftDeleteAsync(x => x.Id == input.Id); await _trackPushConfigRepository.SoftDeleteContentAsync(x => x.TrackPushConfigId == input.Id); await _trackPushCacheService.SetPushContentConfigsAsync(entity.SubSystemId, entity.CustomId); - } break; default: @@ -141,6 +136,18 @@ public class TrackPushService : ApplicationService return true; } + + /// + /// 获取服务商code根据客户id + /// + /// + /// + [HttpGet("GetServiceCodeByCustomerId")] + public async Task GetServiceCodeByCustomerId(int customerId) + { + return await _trackPushConfigRepository.GetServiceCodeByCustomerIdAsync(customerId); + } + /// /// 轨迹推送配置内容编辑 /// @@ -183,36 +190,36 @@ public class TrackPushService : ApplicationService switch (input.Options) { case OptionTypeNoNull.新增: - { - int maxSort = await _trackPushConfigRepository.ContentMaxAsync(x => x.Sort, - x => x.TrackPushConfigId == input.TrackPushConfigId); + { + int maxSort = await _trackPushConfigRepository.ContentMaxAsync(x => x.Sort, + x => x.TrackPushConfigId == input.TrackPushConfigId); - var entity = ObjectMapper.Map(input); - entity.Sort = maxSort + 1; - await _trackPushConfigRepository.InsertContentAsync(entity); - break; - } + var entity = ObjectMapper.Map(input); + entity.Sort = maxSort + 1; + await _trackPushConfigRepository.InsertContentAsync(entity); + break; + } case OptionTypeNoNull.修改: - { - var entity = await _trackPushConfigRepository.GetContentByIdAsync(input.Id!.Value) ?? - throw new BusinessException(message: _stringLocalizer["NotFindData"]); + { + var entity = await _trackPushConfigRepository.GetContentByIdAsync(input.Id!.Value) ?? + throw new BusinessException(message: _stringLocalizer["NotFindData"]); - ObjectMapper.Map(input, entity); - await _trackPushConfigRepository.UpdateContentAsync(entity); - break; - } + ObjectMapper.Map(input, entity); + await _trackPushConfigRepository.UpdateContentAsync(entity); + break; + } case OptionTypeNoNull.删除: - { - var entity = await _trackPushConfigRepository.GetContentByIdAsync(input.Id!.Value) ?? - throw new BusinessException(message: _stringLocalizer["NotFindData"]); - trackPushConfigId = entity.TrackPushConfigId; - await _trackPushConfigRepository.SoftDeleteContentAsync(x => x.Id == input.Id); - await _trackPushConfigRepository.UpdateContentAsync(x => x.Sort == x.Sort - 1, - x => x.TrackPushConfigId == entity.TrackPushConfigId && x.Sort > entity.Sort); - break; - } + { + var entity = await _trackPushConfigRepository.GetContentByIdAsync(input.Id!.Value) ?? + throw new BusinessException(message: _stringLocalizer["NotFindData"]); + trackPushConfigId = entity.TrackPushConfigId; + await _trackPushConfigRepository.SoftDeleteContentAsync(x => x.Id == input.Id); + await _trackPushConfigRepository.UpdateContentAsync(x => x.Sort == x.Sort - 1, + x => x.TrackPushConfigId == entity.TrackPushConfigId && x.Sort > entity.Sort); + break; + } default: throw new BusinessException(message: _stringLocalizer[SjzyBasicLocalization.Validation_IsInEnum, @@ -266,4 +273,4 @@ public class TrackPushService : ApplicationService return true; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/Services/TrackStatus/TrackStatusService.cs b/src/SJZY.Track.Application/Services/TrackStatus/TrackStatusService.cs index 979d412d..0061c2c4 100644 --- a/src/SJZY.Track.Application/Services/TrackStatus/TrackStatusService.cs +++ b/src/SJZY.Track.Application/Services/TrackStatus/TrackStatusService.cs @@ -1,10 +1,7 @@ -using Microsoft.Extensions.Localization; using SJZY.Track.Application.Contract.Dtos.TrackStatus; -using SJZY.Track.Application.Localization; using SJZY.Track.Domain.Aggregates.TrackContentAggregate; using SJZY.Track.Domain.Aggregates.TrackStatusAggregate; using SJZY.Track.Domain.Dtos.TrackStatus; -using Volo.Abp.DependencyInjection; namespace SJZY.Track.Application.Services.TrackStatus; @@ -13,21 +10,18 @@ namespace SJZY.Track.Application.Services.TrackStatus; /// [ApiExplorerSettings(GroupName = "轨迹状态")] [Route("/Track/Status")] -public class TrackStatusService : ApplicationService, ITransientDependency +public class TrackStatusService : ApplicationService { - private readonly IStringLocalizer _stringLocalizer; - private readonly ITrackStatusRepository _trackStatusRepository; private readonly ITrackContentRepository _trackContentRepository; + private readonly ITrackStatusRepository _trackStatusRepository; public TrackStatusService( - IStringLocalizer stringLocalizer, ITrackStatusRepository trackStatusRepository, ITrackContentRepository trackContentRepository ) { - this._stringLocalizer = stringLocalizer; - this._trackStatusRepository = trackStatusRepository; - this._trackContentRepository=trackContentRepository; + _trackStatusRepository = trackStatusRepository; + _trackContentRepository = trackContentRepository; } /// @@ -61,7 +55,7 @@ public class TrackStatusService : ApplicationService, ITransientDependency } var dto = ObjectMapper.Map(detailInfo); - return new UnifyResultDto("200", "", dto); + return new UnifyResultDto(GlobalConst.SuccessCode, "", dto); } /// @@ -70,9 +64,9 @@ public class TrackStatusService : ApplicationService, ITransientDependency /// /// [HttpPost("GetList")] - public async Task> GetPageTrackStatus(GetPageTrackStatusInput input) + public async Task> GetPagedTrackStatus(GetPagedTrackStatusInput input) { - var vo = ObjectMapper.Map(input); + var vo = ObjectMapper.Map(input); var resultDto = await _trackStatusRepository.GetPageTrackStatus(vo); var pageResultDto = ObjectMapper.Map, UnifyPageResultDto>( @@ -89,23 +83,23 @@ public class TrackStatusService : ApplicationService, ITransientDependency var trackStatusEntitys = await _trackStatusRepository.GetListAsync(a => a.SubSystemId == input.SubSystemId && (a.Code == input.Code || - a.Status == input.TrackStatus || a.EnStatus == input.EntrackStatus)); + a.Status == input.TrackStatus || a.EnStatus == input.EnTrackStatus)); if (trackStatusEntitys.Any()) { - //throw new BusinessException(message: _stringLocalizer["TrackStatusExist"]); - //throw new BusinessException(message: "当前子系统下,轨迹状态代码或轨迹状态或轨迹状态英文存在"); - var trackStatusCode = trackStatusEntitys.FirstOrDefault(t => t.Code==input.Code); - if (trackStatusCode!=null) + var trackStatusCode = trackStatusEntitys.FirstOrDefault(t => t.Code == input.Code); + if (trackStatusCode != null) { throw new BusinessException(message: "该子系统下轨迹状态代码已存在"); } - var trackStatusName = trackStatusEntitys.FirstOrDefault(t => t.Status==input.TrackStatus); - if (trackStatusName!=null) + + var trackStatusName = trackStatusEntitys.FirstOrDefault(t => t.Status == input.TrackStatus); + if (trackStatusName != null) { throw new BusinessException(message: "该子系统下轨迹状态已存在"); } - var trackStatusEnName = trackStatusEntitys.FirstOrDefault(t => t.EnStatus==input.EntrackStatus); - if (trackStatusEnName!=null) + + var trackStatusEnName = trackStatusEntitys.FirstOrDefault(t => t.EnStatus == input.EnTrackStatus); + if (trackStatusEnName != null) { throw new BusinessException(message: "该子系统下轨迹状态英文已存在"); } @@ -116,7 +110,7 @@ public class TrackStatusService : ApplicationService, ITransientDependency var entity = ObjectMapper.Map(input); var isTrue = await _trackStatusRepository.InsertAsync(entity); - return new UnifyResultDto("200", "新增成功", isTrue); + return new UnifyResultDto(GlobalConst.SuccessCode, "新增成功", isTrue); } private async Task UpdateAsync(EditTrackStatusInput input) @@ -125,23 +119,23 @@ public class TrackStatusService : ApplicationService, ITransientDependency var trackStatusEntitys = await _trackStatusRepository.GetListAsync(a => a.Id != input.Id && a.SubSystemId == input.SubSystemId && (a.Code == input.Code || - a.Status == input.TrackStatus || a.EnStatus == input.EntrackStatus)); + a.Status == input.TrackStatus || a.EnStatus == input.EnTrackStatus)); if (trackStatusEntitys.Any()) { - //throw new BusinessException(message: _stringLocalizer["TrackStatusExist"]); - //throw new BusinessException(message: "当前子系统下,轨迹状态代码或轨迹状态或轨迹状态英文存在"); - var trackStatusCode = trackStatusEntitys.FirstOrDefault(t => t.Code==input.Code); - if (trackStatusCode!=null) + var trackStatusCode = trackStatusEntitys.FirstOrDefault(t => t.Code == input.Code); + if (trackStatusCode != null) { throw new BusinessException(message: "该子系统下轨迹状态代码已存在"); } - var trackStatusName = trackStatusEntitys.FirstOrDefault(t => t.Status==input.TrackStatus); - if (trackStatusName!=null) + + var trackStatusName = trackStatusEntitys.FirstOrDefault(t => t.Status == input.TrackStatus); + if (trackStatusName != null) { throw new BusinessException(message: "该子系统下轨迹状态已存在"); } - var trackStatusEnName = trackStatusEntitys.FirstOrDefault(t => t.EnStatus==input.EntrackStatus); - if (trackStatusEnName!=null) + + var trackStatusEnName = trackStatusEntitys.FirstOrDefault(t => t.EnStatus == input.EnTrackStatus); + if (trackStatusEnName != null) { throw new BusinessException(message: "该子系统下轨迹状态英文已存在"); } @@ -149,27 +143,35 @@ public class TrackStatusService : ApplicationService, ITransientDependency #endregion - var templateEntity = await _trackStatusRepository.GetFirstAsync(a => a.Id == input.Id); - ObjectMapper.Map(input, templateEntity); - var isTrue = await _trackStatusRepository.UpdateAsync(templateEntity); + var trackStatus = await _trackStatusRepository.GetFirstAsync(a => a.Id == input.Id); + if (trackStatus == null) + { + throw new BusinessException(message: "轨迹状态不存在"); + } - return new UnifyResultDto("200", "修改成功", isTrue); + ObjectMapper.Map(input, trackStatus); + var isTrue = await _trackStatusRepository.UpdateAsync(trackStatus); + + return new UnifyResultDto(GlobalConst.SuccessCode, "修改成功", isTrue); } private async Task DeleteAsync(EditTrackStatusInput input) { #region 业务校验 - var isExistStatus = await _trackContentRepository.GetFirstAsync(a => a.TrackStatusId==input.Id); - if (isExistStatus!=null) + + var isExistStatus = await _trackContentRepository.GetFirstAsync(a => a.TrackStatusId == input.Id); + if (isExistStatus != null) { //throw new BusinessException(message: _stringLocalizer["IsExistTrackStatus"]); throw new BusinessException(message: "该状态关联轨迹内容,禁止删除"); } + #endregion + var isTrue = await _trackStatusRepository.SoftDeleteAsync(x => x.Id == input.Id); - return new UnifyResultDto("200", "删除成功", isTrue); + return new UnifyResultDto(GlobalConst.SuccessCode, "删除成功", isTrue); } #endregion -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/Services/TrackTemplates/TrackTemplateService.cs b/src/SJZY.Track.Application/Services/TrackTemplates/TrackTemplateService.cs index 6f1ce384..9dfc58bd 100644 --- a/src/SJZY.Track.Application/Services/TrackTemplates/TrackTemplateService.cs +++ b/src/SJZY.Track.Application/Services/TrackTemplates/TrackTemplateService.cs @@ -1,4 +1,4 @@ -using System.Linq.Expressions; +using System.Linq.Expressions; using Microsoft.Extensions.Localization; using SJZY.Expand.ABP.Core.Localization; using SJZY.Expand.ABP.Core.PublicMethords; @@ -51,16 +51,9 @@ public class TrackTemplateService : ApplicationService /// /// [HttpGet("GetDetail")] - public async Task> GetDetailAsync(int id) + public async Task GetDetailAsync(int id) { - var detailInfo = await _trackTemplateRepository.GetDetailAsync(id); - if (detailInfo == null) - { - return new UnifyResultDto(false, null, "未查询到轨迹模版"); - } - - var dto = ObjectMapper.Map(detailInfo); - return new UnifyResultDto("200", "", dto); + return await _trackTemplateRepository.GetDetailAsync(id); } /// @@ -80,83 +73,6 @@ public class TrackTemplateService : ApplicationService return pageResultDto; } - #region 私有方法 - - private async Task AddAsync(EditTrackTemplateInput input) - { - #region 业务校验 - - //校验模版代码唯一性 - //var templateEntity = - // await _trackTemplateRepository.GetFirstAsync( - // a => a.SubSystemId == input.SubSystemId && a.Code == input.Code); - var templateEntitys = await _trackTemplateRepository.GetListAsync(a => - a.SubSystemId == input.SubSystemId && (a.Code == input.Code || a.Name == input.Name)); - if (templateEntitys.Any()) - { - //throw new BusinessException(message: _stringLocalizer["TemplateExist"]); - //throw new BusinessException(message: "模板代码已存在于当前选择的子系统下"); - var trackTemplateCode = templateEntitys.FirstOrDefault(t => t.Code == input.Code); - if (trackTemplateCode != null) - { - throw new BusinessException(message: "该子系统下模板代码已存在"); - } - - var trackTemplateName = templateEntitys.FirstOrDefault(t => t.Name == input.Name); - if (trackTemplateName != null) - { - throw new BusinessException(message: "该子系统下模板名称已存在"); - } - } - - #endregion 业务校验 - - var entity = ObjectMapper.Map(input); - var isTrue = await _trackTemplateRepository.InsertAsync(entity); - - return new UnifyResultDto("200", "新增成功", isTrue); - } - - private async Task UpdateAsync(EditTrackTemplateInput input) - { - #region 业务校验 - - var templateEntitys = await _trackTemplateRepository.GetListAsync(a => - a.Id != input.Id && a.SubSystemId == input.SubSystemId && (a.Code == input.Code || a.Name == input.Name)); - if (templateEntitys.Any()) - { - //throw new BusinessException(message: "模板代码已存在于当前选择的子系统下"); - var trackTemplateCode = templateEntitys.FirstOrDefault(t => t.Code == input.Code); - if (trackTemplateCode != null) - { - throw new BusinessException(message: "该子系统下模板代码已存在"); - } - - var trackTemplateName = templateEntitys.FirstOrDefault(t => t.Name == input.Name); - if (trackTemplateName != null) - { - throw new BusinessException(message: "该子系统下模板名称已存在"); - } - } - - #endregion 业务校验 - - var templateEntity = await _trackTemplateRepository.GetFirstAsync(a => a.Id == input.Id); - ObjectMapper.Map(input, templateEntity); - var isTrue = await _trackTemplateRepository.UpdateAsync(templateEntity); - - return new UnifyResultDto("200", "修改成功", isTrue); - } - - private async Task DeleteAsync(EditTrackTemplateInput input) - { - var isTrue = await _trackTemplateRepository.SoftDeleteAsync(x => x.Id == input.Id); - - return new UnifyResultDto("200", "删除成功", isTrue); - } - - #endregion 私有方法 - /// /// 轨迹模板内容列表 /// @@ -175,7 +91,7 @@ public class TrackTemplateService : ApplicationService /// /// [HttpGet("GetContentDetail")] - public async Task GetContentDetailAsync(int id) + public async Task GetContentDetailAsync(int id) { return await _trackTemplateRepository.GetContentDetailAsync(id); } @@ -201,47 +117,45 @@ public class TrackTemplateService : ApplicationService switch (input.Options) { case OptionTypeNoNull.新增: - { - int maxSort = await _trackTemplateRepository.ContentMaxAsync(x => x.Sort, - x => x.TrackTemplateId == input.TrackTemplateId); + { + int maxSort = await _trackTemplateRepository.ContentMaxAsync(x => x.Sort, + x => x.TrackTemplateId == input.TrackTemplateId); - var entity = ObjectMapper.Map(input); - entity.Sort = maxSort + 1; + var entity = ObjectMapper.Map(input); + entity.Sort = maxSort + 1; - await _trackTemplateRepository.InsertContentAsync(entity); + await _trackTemplateRepository.InsertContentAsync(entity); - break; - } + break; + } case OptionTypeNoNull.修改: - { - var entity = await _trackTemplateRepository.GetContentByIdAsync(input.Id!.Value) ?? - throw new BusinessException(message: _stringLocalizer["NotFindData"]); + { + var entity = await _trackTemplateRepository.GetContentByIdAsync(input.Id!.Value) ?? + throw new BusinessException(message: _stringLocalizer["NotFindData"]); - ObjectMapper.Map(input, entity); + ObjectMapper.Map(input, entity); - await _trackTemplateRepository.UpdateContentAsync(entity); + await _trackTemplateRepository.UpdateContentAsync(entity); - break; - } + break; + } case OptionTypeNoNull.删除: - { - var entity = await _trackTemplateRepository.GetContentByIdAsync(input.Id!.Value) ?? - throw new BusinessException(message: _stringLocalizer["NotFindData"]); - - using (var ts = TransactionScopeHelper.Create()) { + var entity = await _trackTemplateRepository.GetContentByIdAsync(input.Id!.Value) ?? + throw new BusinessException(message: _stringLocalizer["NotFindData"]); + + using var ts = TransactionScopeHelper.Create(); await _trackTemplateRepository.SoftDeleteContentAsync(input.Id!.Value); await _trackTemplateRepository.UpdateContentAsync(x => x.Sort == x.Sort - 1, x => x.TrackTemplateId == entity.TrackTemplateId && x.Sort > entity.Sort); ts.Complete(); - } - break; - } + break; + } default: throw new BusinessException(message: _stringLocalizer[SjzyBasicLocalization.Validation_IsInEnum, @@ -272,4 +186,96 @@ public class TrackTemplateService : ApplicationService return true; } -} \ No newline at end of file + + #region 私有方法 + + private async Task AddAsync(EditTrackTemplateInput input) + { + #region 业务校验 + + if (await _trackTemplateRepository.IsAnyAsync(a => + a.SubSystemId == input.SubSystemId && a.Code == input.Code && a.Name == input.Name && + a.CategoryId == input.CategoryId && a.CustomerId == input.CustomerId)) + { + throw new BusinessException(message: "该子系统下该分类的客户模版已存在"); + } + + //校验模版代码唯一性 + var templateEntitys = await _trackTemplateRepository.GetListAsync(a => + a.SubSystemId == input.SubSystemId && (a.Code == input.Code || a.Name == input.Name)); + if (templateEntitys.Any()) + { + var trackTemplateCode = templateEntitys.FirstOrDefault(t => t.Code == input.Code); + if (trackTemplateCode != null) + { + throw new BusinessException(message: "该子系统下模板代码已存在"); + } + + var trackTemplateName = templateEntitys.FirstOrDefault(t => t.Name == input.Name); + if (trackTemplateName != null) + { + throw new BusinessException(message: "该子系统下模板名称已存在"); + } + } + + #endregion 业务校验 + + var entity = ObjectMapper.Map(input); + var isTrue = await _trackTemplateRepository.InsertAsync(entity); + + return new UnifyResultDto(GlobalConst.SuccessCode, "新增成功", isTrue); + } + + private async Task UpdateAsync(EditTrackTemplateInput input) + { + #region 业务校验 + + if (await _trackTemplateRepository.IsAnyAsync(a => + a.Id != input.Id && + a.SubSystemId == input.SubSystemId && a.Code == input.Code && a.Name == input.Name && + a.CategoryId == input.CategoryId && a.CustomerId == input.CustomerId)) + { + throw new BusinessException(message: "该子系统下该分类的客户模版已存在"); + } + + var templateEntitys = await _trackTemplateRepository.GetListAsync(a => + a.Id != input.Id && a.SubSystemId == input.SubSystemId && (a.Code == input.Code || a.Name == input.Name)); + if (templateEntitys.Any()) + { + //throw new BusinessException(message: "模板代码已存在于当前选择的子系统下"); + var trackTemplateCode = templateEntitys.FirstOrDefault(t => t.Code == input.Code); + if (trackTemplateCode != null) + { + throw new BusinessException(message: "该子系统下模板代码已存在"); + } + + var trackTemplateName = templateEntitys.FirstOrDefault(t => t.Name == input.Name); + if (trackTemplateName != null) + { + throw new BusinessException(message: "该子系统下模板名称已存在"); + } + } + + #endregion 业务校验 + + var templateEntity = await _trackTemplateRepository.GetFirstAsync(a => a.Id == input.Id); + if (templateEntity == null) + { + throw new BusinessException(message: "模版不存在"); + } + + ObjectMapper.Map(input, templateEntity); + var isTrue = await _trackTemplateRepository.UpdateAsync(templateEntity); + + return new UnifyResultDto(GlobalConst.SuccessCode, "修改成功", isTrue); + } + + private async Task DeleteAsync(EditTrackTemplateInput input) + { + var isTrue = await _trackTemplateRepository.SoftDeleteAsync(x => x.Id == input.Id); + + return new UnifyResultDto(GlobalConst.SuccessCode, "删除成功", isTrue); + } + + #endregion 私有方法 +} diff --git a/src/SJZY.Track.Application/SjzyTrackApplicationModule.cs b/src/SJZY.Track.Application/SjzyTrackApplicationModule.cs index 10394daa..a26eb785 100644 --- a/src/SJZY.Track.Application/SjzyTrackApplicationModule.cs +++ b/src/SJZY.Track.Application/SjzyTrackApplicationModule.cs @@ -1,14 +1,19 @@ -using DotNetCore.CAP; +using BSI.Stack.Rabbit; +using DotNetCore.CAP; using DotNetCore.CAP.Internal; using Microsoft.Extensions.Configuration; +using RabbitMQ.Client; using Savorboard.CAP.InMemoryMessageQueue; using SJZY.Expand.ABP.Core.Localization; using SJZY.Expand.ABP.Core.Logger; using SJZY.Expand.ABP.Core.PublicMethords; +using SJZY.Expand.AliyunOSS; using SJZY.InterfaceRelay.Application.Contracts; using SJZY.Track.Application.CAP; using SJZY.Track.Application.Contract; using SJZY.Track.Application.Localization; +using SJZY.Track.Application.Options; +using SJZY.Track.Application.Track2InterfaceRelay; using SJZY.UserCenter.Contracts; using SJZY.UserCenter.SharedModel; using SJZY.UserCenter.SharedModel.Pub; @@ -20,69 +25,65 @@ using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.VirtualFileSystem; -namespace SJZY.Track.Application +namespace SJZY.Track.Application; + +[DependsOn( + typeof(AbpAutoMapperModule), + typeof(AbpFluentValidationModule), + typeof(AbpLocalizationModule), + typeof(AbpVirtualFileSystemModule), + typeof(AbpHttpClientModule), + typeof(SjzyUserCenterHttpApiModule), + typeof(SJZYInterfaceRelayApplicationContractsModule), + typeof(SjzyTrackDomainModule), + typeof(SjzyTrackApplicationContractModule) +)] +public class SjzyTrackApplicationModule : AbpModule { - [DependsOn( - typeof(AbpAutoMapperModule), - typeof(AbpFluentValidationModule), - typeof(AbpLocalizationModule), - typeof(AbpVirtualFileSystemModule), - typeof(AbpHttpClientModule), - typeof(SjzyUserCenterHttpApiModule), - typeof(SJZYInterfaceRelayApplicationContractsModule), - typeof(SjzyTrackDomainModule), - typeof(SjzyTrackApplicationContractModule) - )] - public class SjzyTrackApplicationModule : AbpModule + public override void ConfigureServices(ServiceConfigurationContext context) { - public override void ConfigureServices(ServiceConfigurationContext context) + var configuration = context.Services.GetConfiguration(); + Configure(options => { options.AddMaps(true); }); + + Configure(options => { - var configuration = context.Services.GetConfiguration(); - Configure(options => { options.AddMaps(true); }); + options.ConventionalControllers.Create(typeof(SjzyTrackApplicationModule).Assembly); //创建动态api + }); - Configure(options => - { - options.ConventionalControllers.Create(typeof(SjzyTrackApplicationModule).Assembly); //创建动态api - }); + //添加虚拟文件系统 + Configure(options => { options.FileSets.AddEmbedded("SJZY.Track.Application"); }); - //添加虚拟文件系统 - Configure(options => - { - options.FileSets.AddEmbedded("SJZY.Track.Application"); - }); + //添加多语言 + var languageConfig = configuration.GetSection("Language"); + Configure(options => + { + options.Resources + .Add("zh") + .AddBaseTypes(typeof(SjzyBasicLocalization)) + .AddRedisResource(languageConfig) + .AddVirtualJson("/Localization/Resources"); + }); + //授权拦截提示 + context.Services.Configure(options => { options.Filters.Add(new ApiAsyncAuthorizationFilter()); }); - //添加多语言 - var languageConfig = configuration.GetSection("Language"); - Configure(options => - { - options.Resources - .Add("zh") - .AddBaseTypes(typeof(SjzyBasicLocalization)) - .AddRedisResource(languageConfig) - .AddVirtualJson("/Localization/Resources"); - }); - //授权拦截提示 - context.Services.Configure(options => - { - options.Filters.Add(new ApiAsyncAuthorizationFilter()); - }); + //用户中心 + context.Services.AddHttpClientProxies(typeof(SjzyUserCenterHttpApiModule).Assembly, "UserCenter", false); - //用户中心 - context.Services.AddHttpClientProxies(typeof(SjzyUserCenterHttpApiModule).Assembly, "UserCenter", false); - context.Services.AddHttpClient("InterfaceForward").AddHttpMessageHandler(); - context.Services.AddHttpClientProxies(typeof(SJZYInterfaceRelayApplicationContractsModule).Assembly, - "InterfaceForward", false - ); + // 接口通 + context.Services.Configure(configuration.GetSection("Track2InterfaceRelay")); + context.Services.AddHttpClient("InterfaceForward") + .AddHttpMessageHandler(); + context.Services.AddHttpClientProxies(typeof(SJZYInterfaceRelayApplicationContractsModule).Assembly, + "InterfaceForward", false + ); - //CAP - context.Services.AddSingleton(); - context.Services.AddCapTableNameService(); + //CAP + context.Services.AddSingleton(); + context.Services.AddCapTableNameService(); + if (!System.Diagnostics.Debugger.IsAttached) + { context.Services.AddCap(options => { -#if DEBUG - options.UseInMemoryStorage(); - options.UseInMemoryMessageQueue(); -#else options.UseMySql(configuration["ConnectionStrings:DefaultConnection"]!); options.UseRabbitMQ(configure => { @@ -93,13 +94,11 @@ namespace SJZY.Track.Application configure.BasicQosOptions = new RabbitMQOptions.BasicQos(configuration.GetValue("CAP:PrefetchCount")); }); -#endif options.FailedRetryInterval = configuration.GetValue("CAP:FailedRetryInterval"); options.FailedRetryCount = configuration.GetValue("CAP:FailedRetryCount"); options.SucceedMessageExpiredAfter = configuration.GetValue("CAP:SucceedMessageExpiredAfter"); options.FallbackWindowLookbackSeconds = configuration.GetValue("CAP:FallbackWindowLookbackSeconds"); - options.EnableSubscriberParallelExecute = true; options.UseDashboard(dashboardOptions => { @@ -123,18 +122,85 @@ namespace SJZY.Track.Application }; }).AddSubscribeFilter(); } - - public override void PreConfigureServices(ServiceConfigurationContext context) + else { - PreConfigure(options => + //是本地调试环境,用内存存储和内存队列 + context.Services.AddCap(capOptions => { - options.ProxyClientActions.Add((_, _, httpClient) => - { - //如果设置Token,前端需要传入Token 否则引发异常 - httpClient.SetTokenHeader(); - httpClient.Timeout = TimeSpan.FromMinutes(3); - }); - }); + capOptions.UseInMemoryStorage(); + capOptions.UseInMemoryMessageQueue(); + capOptions.UseDashboard(); + }).AddSubscribeFilter(); + Console.WriteLine("-- 当前为VS本地环境,用内存存储和内存队列"); } + + + context.Services.AddRabbitBoot(options => + { + options.ConnectionString = + $"amqp://{configuration["RabbitMQ:UserName"]}:{configuration["RabbitMQ:Password"]}@{configuration["RabbitMQ:HostName"]}:{configuration["RabbitMQ:Port"]}"; + options.PoolSize = configuration.GetValue("RabbitMQ:PoolSize"); + options.Declarations = new List>() + { + o => o.ExchangeDeclare(GlobalConst.TrackChangeExchange, ExchangeType.Topic, true), + o => o.ExchangeDeclare(GlobalConst.TrackPushExchange, ExchangeType.Topic, true) + }; + options.Consumes = new List + { + new() + { + Queue = GlobalConst.TrackRefreshSubscribe, + FetchCount = configuration.GetValue("TrackApp:TrackRefreshFetchCount"), + FailedRequeue = false, + Declaration = o => + { + o.ExchangeDeclare(GlobalConst.InterfaceRelayExchange, ExchangeType.Direct, true); + o.QueueDeclare(GlobalConst.TrackRefreshSubscribe, true); + o.QueueBind(GlobalConst.TrackRefreshSubscribe, GlobalConst.InterfaceRelayExchange, + GlobalConst.TrackRefreshSubscribe); + } + }, + new() + { + Queue = GlobalConst.TrackPushCompletedSubscribe, + FetchCount = configuration.GetValue("TrackApp:TrackRefreshFetchCount"), + FailedRequeue = false, + Declaration = o => + { + o.ExchangeDeclare(GlobalConst.InterfaceRelayExchange, ExchangeType.Direct, true); + o.QueueDeclare(GlobalConst.TrackPushCompletedSubscribe, true); + o.QueueBind(GlobalConst.TrackPushCompletedSubscribe, GlobalConst.InterfaceRelayExchange, + GlobalConst.TrackPushCompletedSubscribe); + } + } + }; + }, typeof(SjzyTrackApplicationModule).Assembly); + + context.Services.Configure(configuration.GetSection("TrackApp")); + context.Services.Configure( + configuration.GetSection("InterfaceRelayParamsConfig")); + + //注册阿里云OSS服务 + context.Services.AddAliOSS(option => + { + option.AccessKeyId = configuration["OSS:AccessKeyId"]; + option.AccessKeySecret = configuration["OSS:AccessKeySecret"]; + option.Endpoint = configuration["OSS:Endpoint"]; + option.BucketName = configuration["OSS:BucketName"]; + option.ReturnHttpsUrl = true; + }); } -} \ No newline at end of file + + public override void PreConfigureServices(ServiceConfigurationContext context) + { + PreConfigure(options => + { + options.ProxyClientActions.Add((_, _, httpClient) => + { + //如果设置Token,前端需要传入Token 否则引发异常 + httpClient.SetTokenHeader(); + httpClient.Timeout = TimeSpan.FromMinutes(3); + }); + }); + } +} diff --git a/src/SJZY.Track.Application/Track2InterfaceRelay/Track2InterfaceRelayHttpMessageHandler.cs b/src/SJZY.Track.Application/Track2InterfaceRelay/Track2InterfaceRelayHttpMessageHandler.cs new file mode 100644 index 00000000..0320ac1a --- /dev/null +++ b/src/SJZY.Track.Application/Track2InterfaceRelay/Track2InterfaceRelayHttpMessageHandler.cs @@ -0,0 +1,36 @@ +using Microsoft.Extensions.Options; +using SJZY.InterfaceRelay.Application.Contracts; +using Volo.Abp.DependencyInjection; + +namespace SJZY.Track.Application.Track2InterfaceRelay; + +public class Track2InterfaceRelayHttpMessageHandler : DelegatingHandler, ITransientDependency +{ + private readonly Track2InterfaceRelayOptions _options; + + public Track2InterfaceRelayHttpMessageHandler(IOptionsMonitor options) + { + _options = options.CurrentValue; + } + + protected override async Task SendAsync(HttpRequestMessage request, + CancellationToken cancellationToken) + { + if (Track2InterfaceRelaySubSystemContext.Current == null) + { + throw new BusinessException(message: $"请在{nameof(Track2InterfaceRelaySubSystemContext)}中调用接口通"); + } + + var subSystemCode = Track2InterfaceRelaySubSystemContext.Current.SubSystemCode; + var config = _options.GetOrDefault(subSystemCode); + if (config == null) + { + throw new BusinessException(message: $"子系统{subSystemCode}未在轨迹中台配置,请联系管理员"); + } + + request.Headers.TryAddWithoutValidation(nameof(InterfaceForwardOptions.AppKey), config.AppKey); + request.Headers.TryAddWithoutValidation(nameof(InterfaceForwardOptions.AppSecret), config.AppSecret); + + return await base.SendAsync(request, cancellationToken); + } +} diff --git a/src/SJZY.Track.Application/Track2InterfaceRelay/Track2InterfaceRelayOptions.cs b/src/SJZY.Track.Application/Track2InterfaceRelay/Track2InterfaceRelayOptions.cs new file mode 100644 index 00000000..093501ad --- /dev/null +++ b/src/SJZY.Track.Application/Track2InterfaceRelay/Track2InterfaceRelayOptions.cs @@ -0,0 +1,23 @@ +namespace SJZY.Track.Application.Track2InterfaceRelay; + +public class Track2InterfaceRelayOptions : Dictionary +{ +} + +public class SubSystemConfig +{ + /// + /// 接口通appKey + /// + public string AppKey { get; set; } + + /// + /// 接口通app秘钥 + /// + public string AppSecret { get; set; } + + /// + /// 预警通知间隔(分钟) + /// + public int WarningNotifyInterval { get; set; } = 30; +} diff --git a/src/SJZY.Track.Application/Track2InterfaceRelay/Track2InterfaceRelaySubSystemContext.cs b/src/SJZY.Track.Application/Track2InterfaceRelay/Track2InterfaceRelaySubSystemContext.cs new file mode 100644 index 00000000..9f271000 --- /dev/null +++ b/src/SJZY.Track.Application/Track2InterfaceRelay/Track2InterfaceRelaySubSystemContext.cs @@ -0,0 +1,26 @@ +namespace SJZY.Track.Application.Track2InterfaceRelay; + +public class Track2InterfaceRelaySubSystemContext +{ + private static readonly AsyncLocal LocalContext = new(); + + public Track2InterfaceRelaySubSystemContext(string subSystemCode) + { + if (subSystemCode.IsNullOrWhiteSpace()) + { + throw new BusinessException(message: "请求接口通需要子系统上下文,子系统代码不能为空,请检查是否配置"); + } + + SubSystemCode = subSystemCode; + } + + public string SubSystemCode { get; set; } + public static Track2InterfaceRelaySubSystemContext? Current => LocalContext.Value; + + public static IDisposable Use(Track2InterfaceRelaySubSystemContext context) + { + var previousValue = Current; + LocalContext.Value = context; + return new DisposeAction(() => LocalContext.Value = previousValue); + } +} diff --git a/src/SJZY.Track.Application/Validations/Forewarning/CreateRuleFactorValidation.cs b/src/SJZY.Track.Application/Validations/Forewarning/CreateRuleFactorValidation.cs new file mode 100644 index 00000000..b79a7bbd --- /dev/null +++ b/src/SJZY.Track.Application/Validations/Forewarning/CreateRuleFactorValidation.cs @@ -0,0 +1,15 @@ +using FluentValidation; +using SJZY.Track.Application.Contract.Dtos.Forewarning; + +namespace SJZY.Track.Application.Validations.Forewarning; + +public class CreateRuleFactorValidation : AbstractValidator +{ + public CreateRuleFactorValidation() + { + RuleFor(x => x.WarningFactors).NotNull().WithMessage("因素列表不能为空"); + RuleFor(x => x.TrackStatusSpans).NotNull().WithMessage("轨迹状态列表不能为空"); + + // todo: more validation + } +} diff --git a/src/SJZY.Track.Application/Validations/Forewarning/FactorItemDtoValidator.cs b/src/SJZY.Track.Application/Validations/Forewarning/FactorItemDtoValidator.cs new file mode 100644 index 00000000..368e5d63 --- /dev/null +++ b/src/SJZY.Track.Application/Validations/Forewarning/FactorItemDtoValidator.cs @@ -0,0 +1,6 @@ +namespace SJZY.Track.Application.Validations.Forewarning; + +public class FactorItemDtoValidator +{ + +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/Validations/Forewarning/RuleTrackStateDtoValidator.cs b/src/SJZY.Track.Application/Validations/Forewarning/RuleTrackStateDtoValidator.cs new file mode 100644 index 00000000..cde7aee8 --- /dev/null +++ b/src/SJZY.Track.Application/Validations/Forewarning/RuleTrackStateDtoValidator.cs @@ -0,0 +1,15 @@ +using FluentValidation; +using SJZY.Track.Application.Contract.Dtos.Forewarning; + +namespace SJZY.Track.Application.Validations.Forewarning; + +public class RuleTrackStateDtoValidator : AbstractValidator +{ + public RuleTrackStateDtoValidator() + { + RuleFor(x => x.StartTrackStatusId).GreaterThan(0).WithMessage("起始轨迹状态id必须大于0"); + RuleFor(x => x.EndTrackStatusId).GreaterThan(0).WithMessage("终止轨迹状态id必须大于0"); + RuleFor(x => x.NotifyModes).NotEmpty().WithMessage("通知方式不能为空"); + RuleFor(x => x.NotifyUsers).NotEmpty().WithMessage("通知对象不能为空"); + } +} diff --git a/src/SJZY.Track.Application/Validations/TrackContents/EditTrackContentInputValidation.cs b/src/SJZY.Track.Application/Validations/TrackContents/EditTrackContentInputValidation.cs index af97fc37..600dec8c 100644 --- a/src/SJZY.Track.Application/Validations/TrackContents/EditTrackContentInputValidation.cs +++ b/src/SJZY.Track.Application/Validations/TrackContents/EditTrackContentInputValidation.cs @@ -1,26 +1,25 @@ -using FluentValidation; +using FluentValidation; using SJZY.Track.Application.Contract.Dtos.TrackContents; -namespace SJZY.Track.Application.Validations.TrackContents +namespace SJZY.Track.Application.Validations.TrackContents; + +public class EditTrackContentInputValidation : AbstractValidator, IValidationEnabled { - public class EditTrackContentInputValidation : AbstractValidator, IValidationEnabled + public EditTrackContentInputValidation() { - public EditTrackContentInputValidation() + //条件分支 + When(x => x.Options == OptionType.修改 || x.Options == OptionType.删除, + () => { RuleFor(x => x.Id).GreaterThan(0).WithMessage("修改或删除时Id必须大于0!"); }); + + When(x => x.Options == OptionType.新增, () => { RuleFor(x => x.Id).Equal(0).WithMessage("新增时Id必须等于0!"); }); + + When(x => x.Options == OptionType.修改 || x.Options == OptionType.新增, () => { - //条件分支 - When(x => x.Options == OptionType.修改 || x.Options == OptionType.删除, - () => { RuleFor(x => x.Id).GreaterThan(0).WithMessage("修改或删除时Id必须大于0!"); }); - - When(x => x.Options == OptionType.新增, () => { RuleFor(x => x.Id).Equal(0).WithMessage("新增时Id必须等于0!"); }); - - When(x => x.Options == OptionType.修改 || x.Options == OptionType.新增, () => - { - RuleFor(x => x.SubSystemId).GreaterThan(0).WithMessage("子系统的id必须大于0!"); - RuleFor(x => x.TrackStatusId).GreaterThan(0).WithMessage("所属状态的id必须大于0!"); - RuleFor(x => x.Code).NotNull().WithMessage("轨迹内容代码必填!").NotEmpty().WithMessage("轨迹内容代码不能为空!"); - RuleFor(x => x.Content).NotNull().WithMessage("轨迹内容必填!").NotEmpty().WithMessage("轨迹内容不能为空!"); - RuleFor(x => x.EnContent).NotNull().WithMessage("轨迹内容英文必填!").NotEmpty().WithMessage("轨迹内容英文不能为空!"); - }); - } + RuleFor(x => x.SubSystemId).GreaterThan(0).WithMessage("子系统的id必须大于0!"); + RuleFor(x => x.TrackStatusId).GreaterThan(0).WithMessage("所属状态的id必须大于0!"); + RuleFor(x => x.Code).NotNull().WithMessage("轨迹内容代码必填!").NotEmpty().WithMessage("轨迹内容代码不能为空!"); + RuleFor(x => x.Content).NotNull().WithMessage("轨迹内容必填!").NotEmpty().WithMessage("轨迹内容不能为空!"); + RuleFor(x => x.EnContent).NotNull().WithMessage("轨迹内容英文必填!").NotEmpty().WithMessage("轨迹内容英文不能为空!"); + }); } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/Validations/TrackContents/EditTrackContentMapInputValidation.cs b/src/SJZY.Track.Application/Validations/TrackContents/EditTrackContentMapInputValidation.cs index b4cf3ed8..33341e79 100644 --- a/src/SJZY.Track.Application/Validations/TrackContents/EditTrackContentMapInputValidation.cs +++ b/src/SJZY.Track.Application/Validations/TrackContents/EditTrackContentMapInputValidation.cs @@ -1,4 +1,4 @@ -using FluentValidation; +using FluentValidation; using Microsoft.Extensions.Localization; using SJZY.Expand.ABP.Core.Localization; using SJZY.Track.Application.Contract.Dtos.TrackContents; @@ -10,36 +10,50 @@ public class EditTrackContentMapInputValidation : AbstractValidator stringLocalizer) { - RuleFor(x => x.Options).IsInEnum().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_IsInEnum, nameof(EditTrackContentMapInput.Options)]); + RuleFor(x => x.Options).IsInEnum().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_IsInEnum, + nameof(EditTrackContentMapInput.Options)]); - RuleFor(x => x.Id).GreaterThan(0).WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_GreaterThan, nameof(EditTrackContentMapInput.Id), 0]); + RuleFor(x => x.Id).GreaterThan(0).WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_GreaterThan, + nameof(EditTrackContentMapInput.Id), 0]); - RuleFor(x => x.MapSubSystemId).GreaterThan(0).WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_GreaterThan, nameof(EditTrackContentMapInput.MapSubSystemId), 0]); + RuleFor(x => x.MapSubSystemId).GreaterThan(0).WithMessage(stringLocalizer[ + SjzyBasicLocalization.Validation_GreaterThan, nameof(EditTrackContentMapInput.MapSubSystemId), 0]); - RuleFor(x => x.MapTrackContentId).GreaterThan(0).WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_GreaterThan, nameof(EditTrackContentMapInput.MapTrackContentId), 0]); + RuleFor(x => x.MapTrackContentId).GreaterThan(0).WithMessage(stringLocalizer[ + SjzyBasicLocalization.Validation_GreaterThan, nameof(EditTrackContentMapInput.MapTrackContentId), 0]); - RuleFor(x => x.SubSystemId).GreaterThan(0).WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_GreaterThan, nameof(EditTrackContentMapInput.SubSystemId), 0]); + RuleFor(x => x.SubSystemId).GreaterThan(0).WithMessage(stringLocalizer[ + SjzyBasicLocalization.Validation_GreaterThan, nameof(EditTrackContentMapInput.SubSystemId), 0]); - RuleFor(x => x.TrackContentId).GreaterThan(0).WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_GreaterThan, nameof(EditTrackContentMapInput.TrackContentId), 0]); + RuleFor(x => x.TrackContentId).GreaterThan(0).WithMessage(stringLocalizer[ + SjzyBasicLocalization.Validation_GreaterThan, nameof(EditTrackContentMapInput.TrackContentId), 0]); - When(x => x.Options != OptionTypeNoNull.新增, () => - { - RuleFor(x => x.Id).NotNull().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotNull, nameof(EditTrackContentMapInput.Id)]); - }); + When(x => x.Options != OptionTypeNoNull.新增, + () => + { + RuleFor(x => x.Id).NotNull().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotNull, + nameof(EditTrackContentMapInput.Id)]); + }); When(x => x.Options != OptionTypeNoNull.删除, () => { - RuleFor(x => x.MapSubSystemId).NotNull().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotNull, nameof(EditTrackContentMapInput.MapSubSystemId)]); + RuleFor(x => x.MapSubSystemId).NotNull().WithMessage(stringLocalizer[ + SjzyBasicLocalization.Validation_NotNull, nameof(EditTrackContentMapInput.MapSubSystemId)]); - RuleFor(x => x.MapTrackContentCode).NotEmpty().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotEmpty, nameof(EditTrackContentMapInput.MapTrackContentCode)]); + RuleFor(x => x.MapTrackContentCode).NotEmpty().WithMessage(stringLocalizer[ + SjzyBasicLocalization.Validation_NotEmpty, nameof(EditTrackContentMapInput.MapTrackContentCode)]); - RuleFor(x => x.MapTrackContentId).NotNull().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotNull, nameof(EditTrackContentMapInput.MapTrackContentId)]); + RuleFor(x => x.MapTrackContentId).NotNull().WithMessage(stringLocalizer[ + SjzyBasicLocalization.Validation_NotNull, nameof(EditTrackContentMapInput.MapTrackContentId)]); - RuleFor(x => x.SubSystemId).NotNull().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotNull, nameof(EditTrackContentMapInput.SubSystemId)]); + RuleFor(x => x.SubSystemId).NotNull().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotNull, + nameof(EditTrackContentMapInput.SubSystemId)]); - RuleFor(x => x.TrackContentCode).NotEmpty().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotEmpty, nameof(EditTrackContentMapInput.TrackContentCode)]); + RuleFor(x => x.TrackContentCode).NotEmpty().WithMessage(stringLocalizer[ + SjzyBasicLocalization.Validation_NotEmpty, nameof(EditTrackContentMapInput.TrackContentCode)]); - RuleFor(x => x.TrackContentId).NotNull().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotNull, nameof(EditTrackContentMapInput.TrackContentId)]); + RuleFor(x => x.TrackContentId).NotNull().WithMessage(stringLocalizer[ + SjzyBasicLocalization.Validation_NotNull, nameof(EditTrackContentMapInput.TrackContentId)]); }); } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/Validations/TrackFlags/EditTrackFlagInputValidation.cs b/src/SJZY.Track.Application/Validations/TrackFlags/EditTrackFlagInputValidation.cs index 6a06da65..1a596799 100644 --- a/src/SJZY.Track.Application/Validations/TrackFlags/EditTrackFlagInputValidation.cs +++ b/src/SJZY.Track.Application/Validations/TrackFlags/EditTrackFlagInputValidation.cs @@ -1,24 +1,23 @@ -using FluentValidation; +using FluentValidation; using SJZY.Track.Application.Contract.Dtos.TrackFlags; -namespace SJZY.Track.Application.Validations.TrackFlags +namespace SJZY.Track.Application.Validations.TrackFlags; + +public class EditTrackFlagInputValidation : AbstractValidator, IValidationEnabled { - public class EditTrackFlagInputValidation : AbstractValidator, IValidationEnabled + public EditTrackFlagInputValidation() { - public EditTrackFlagInputValidation() + //条件分支 + When(x => x.Options == OptionType.修改 || x.Options == OptionType.删除, + () => { RuleFor(x => x.Id).GreaterThan(0).WithMessage("修改或删除时Id必须大于0!"); }); + + When(x => x.Options == OptionType.新增, () => { RuleFor(x => x.Id).Equal(0).WithMessage("新增时Id必须等于0!"); }); + + When(x => x.Options == OptionType.修改 || x.Options == OptionType.新增, () => { - //条件分支 - When(x => x.Options == OptionType.修改 || x.Options == OptionType.删除, - () => { RuleFor(x => x.Id).GreaterThan(0).WithMessage("修改或删除时Id必须大于0!"); }); - - When(x => x.Options == OptionType.新增, () => { RuleFor(x => x.Id).Equal(0).WithMessage("新增时Id必须等于0!"); }); - - When(x => x.Options == OptionType.修改 || x.Options == OptionType.新增, () => - { - RuleFor(x => x.SubSystemId).GreaterThan(0).WithMessage("子系统的id必须大于0!"); - RuleFor(x => x.Code).NotNull().WithMessage("轨迹标记代码必填!").NotEmpty().WithMessage("轨迹标记代码不能为空!"); - RuleFor(x => x.Flag).NotNull().WithMessage("轨迹标记必填!").NotEmpty().WithMessage("轨迹标记不能为空!"); - }); - } + RuleFor(x => x.SubSystemId).GreaterThan(0).WithMessage("子系统的id必须大于0!"); + RuleFor(x => x.Code).NotNull().WithMessage("轨迹标记代码必填!").NotEmpty().WithMessage("轨迹标记代码不能为空!"); + RuleFor(x => x.Flag).NotNull().WithMessage("轨迹标记必填!").NotEmpty().WithMessage("轨迹标记不能为空!"); + }); } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/Validations/TrackPull/EditTrackPullConfigInputValidation.cs b/src/SJZY.Track.Application/Validations/TrackPull/EditTrackPullConfigInputValidation.cs index 50beea14..84ae5166 100644 --- a/src/SJZY.Track.Application/Validations/TrackPull/EditTrackPullConfigInputValidation.cs +++ b/src/SJZY.Track.Application/Validations/TrackPull/EditTrackPullConfigInputValidation.cs @@ -10,56 +10,44 @@ public class EditTrackPullConfigInputValidation : AbstractValidator stringLocalizer) { - RuleFor(x => x.Options).IsInEnum().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_IsInEnum, nameof(EditTrackPullConfigInput.Options)]); + RuleFor(x => x.Options).IsInEnum().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_IsInEnum, + nameof(EditTrackPullConfigInput.Options)]); - RuleFor(x => x.Id).GreaterThan(0).WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_GreaterThan, nameof(EditTrackPullConfigInput.Id), 0]); - - RuleFor(x => x.ParseMethod).GreaterThan(0).WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_GreaterThan, nameof(EditTrackPullConfigInput.ParseMethod), 0]); - - RuleFor(x => x.PullInterval) - .GreaterThanOrEqualTo(30).WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_GreaterThanOrEqualTo, nameof(EditTrackPullConfigInput.PullInterval), 30]); - - RuleFor(x => x.SubSystemId).GreaterThan(0).WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_GreaterThan, nameof(EditTrackPullConfigInput.SubSystemId), 0]); - - RuleFor(x => x.ServiceProviderId).GreaterThan(0).WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_GreaterThan, nameof(EditTrackPullConfigInput.ServiceProviderId), 0]); - - RuleFor(x => x.SubSystemId).GreaterThan(0).WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_GreaterThan, nameof(EditTrackPullConfigInput.SubSystemId), 0]); - - When(x => x.Options != OptionTypeNoNull.新增, () => - { - RuleFor(x => x.Id).NotNull().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotNull, nameof(EditTrackPullConfigInput.Id)]); - }); + When(x => x.Options != OptionTypeNoNull.新增, + () => + { + RuleFor(x => x.Id).GreaterThan(0).WithMessage(stringLocalizer[ + SjzyBasicLocalization.Validation_GreaterThan, + nameof(EditTrackPullConfigInput.Id), 0]); + }); When(x => x.Options != OptionTypeNoNull.删除, () => { - RuleFor(x => x.SubSystemId).NotNull().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotNull, nameof(EditTrackPullConfigInput.SubSystemId)]); + RuleFor(x => x.SubSystemId).NotNull().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotNull, + nameof(EditTrackPullConfigInput.SubSystemId)]); - RuleFor(x => x.ServiceProviderId).NotNull().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotNull, nameof(EditTrackPullConfigInput.ServiceProviderId)]); + RuleFor(x => x.ServiceProviderId).NotNull().WithMessage(stringLocalizer[ + SjzyBasicLocalization.Validation_NotNull, nameof(EditTrackPullConfigInput.ServiceProviderId)]); - RuleFor(x => x.PullInterval).NotNull().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotNull, nameof(EditTrackPullConfigInput.PullInterval)]); + RuleFor(x => x.PullInterval).NotNull().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotNull, + nameof(EditTrackPullConfigInput.PullInterval)]); - RuleFor(x => x.ParseMethod).NotNull().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotNull, nameof(EditTrackPullConfigInput.ParseMethod)]); + RuleFor(x => x.ParseMethod).NotNull().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotNull, + nameof(EditTrackPullConfigInput.ParseMethod)]); - RuleFor(x => x.OrderNoName).NotEmpty().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotEmpty, nameof(EditTrackPullConfigInput.OrderNoName)]); - - RuleFor(x => x.OrderPath).NotEmpty().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotEmpty, nameof(EditTrackPullConfigInput.OrderPath)]); - - RuleFor(x => x.TrackDetailsPath).NotEmpty().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotEmpty, nameof(EditTrackPullConfigInput.TrackDetailsPath)]); - - When(x => x.ParseMethod == 1, () => + When(x => x.ParseMethod == 2, () => { - RuleFor(x => x.TrackTimeZoneName).NotEmpty().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotEmpty, nameof(EditTrackPullConfigInput.TrackTimeZoneName)]); + RuleFor(x => x.OrderNoName).NotEmpty().WithMessage( + stringLocalizer[SjzyBasicLocalization.Validation_NotEmpty, + nameof(EditTrackPullConfigInput.OrderNoName)]); - RuleFor(x => x.TrackContentCodeName).NotEmpty().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotEmpty, nameof(EditTrackPullConfigInput.TrackContentCodeName)]); + RuleFor(x => x.OrderPath).NotEmpty().WithMessage(stringLocalizer[ + SjzyBasicLocalization.Validation_NotEmpty, + nameof(EditTrackPullConfigInput.OrderPath)]); - RuleFor(x => x.TrackContentName).NotEmpty().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotEmpty, nameof(EditTrackPullConfigInput.TrackContentName)]); - - RuleFor(x => x.TrackPlaceName).NotEmpty().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotEmpty, nameof(EditTrackPullConfigInput.TrackPlaceName)]); - - RuleFor(x => x.TrackStatusName).NotEmpty().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotEmpty, nameof(EditTrackPullConfigInput.TrackStatusName)]); - - RuleFor(x => x.TrackTimeName).NotEmpty().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotEmpty, nameof(EditTrackPullConfigInput.TrackTimeName)]); + RuleFor(x => x.TrackDetailsPath).NotEmpty().WithMessage(stringLocalizer[ + SjzyBasicLocalization.Validation_NotEmpty, nameof(EditTrackPullConfigInput.TrackDetailsPath)]); }); }); } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/Validations/TrackPull/EditTrackPullContentInputValidation.cs b/src/SJZY.Track.Application/Validations/TrackPull/EditTrackPullContentInputValidation.cs index dcf6ff1c..51ae24a7 100644 --- a/src/SJZY.Track.Application/Validations/TrackPull/EditTrackPullContentInputValidation.cs +++ b/src/SJZY.Track.Application/Validations/TrackPull/EditTrackPullContentInputValidation.cs @@ -1,4 +1,4 @@ -using FluentValidation; +using FluentValidation; using Microsoft.Extensions.Localization; using SJZY.Expand.ABP.Core.Localization; using SJZY.Track.Application.Contract.Dtos.TrackPull; @@ -10,24 +10,32 @@ public class EditTrackPullContentInputValidation : AbstractValidator stringLocalizer) { - RuleFor(x => x.Options).IsInEnum().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_IsInEnum, nameof(EditTrackPullContentInput.Options)]); + RuleFor(x => x.Options).IsInEnum().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_IsInEnum, + nameof(EditTrackPullContentInput.Options)]); - RuleFor(x => x.Id).GreaterThan(0).WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_GreaterThan, nameof(EditTrackPullContentInput.Id), 0]); + RuleFor(x => x.Id).GreaterThan(0).WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_GreaterThan, + nameof(EditTrackPullContentInput.Id), 0]); - RuleFor(x => x.TrackContentId).GreaterThan(0).WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_GreaterThan, nameof(EditTrackPullContentInput.TrackContentId), 0]); + RuleFor(x => x.TrackContentId).GreaterThan(0).WithMessage(stringLocalizer[ + SjzyBasicLocalization.Validation_GreaterThan, nameof(EditTrackPullContentInput.TrackContentId), 0]); - RuleFor(x => x.TrackPullConfigId).GreaterThan(0).WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_GreaterThan, nameof(EditTrackPullContentInput.TrackPullConfigId), 0]); + RuleFor(x => x.TrackPullConfigId).GreaterThan(0).WithMessage(stringLocalizer[ + SjzyBasicLocalization.Validation_GreaterThan, nameof(EditTrackPullContentInput.TrackPullConfigId), 0]); - When(x => x.Options != OptionTypeNoNull.新增, () => - { - RuleFor(x => x.Id).NotNull().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotNull, nameof(EditTrackPullContentInput.Id)]); - }); + When(x => x.Options != OptionTypeNoNull.新增, + () => + { + RuleFor(x => x.Id).NotNull().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotNull, + nameof(EditTrackPullContentInput.Id)]); + }); When(x => x.Options != OptionTypeNoNull.删除, () => { - RuleFor(x => x.TrackContentId).NotNull().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotNull, nameof(EditTrackPullContentInput.TrackContentId)]); + RuleFor(x => x.TrackContentId).NotNull().WithMessage(stringLocalizer[ + SjzyBasicLocalization.Validation_NotNull, nameof(EditTrackPullContentInput.TrackContentId)]); - RuleFor(x => x.TrackPullConfigId).NotNull().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotNull, nameof(EditTrackPullContentInput.TrackPullConfigId)]); + RuleFor(x => x.TrackPullConfigId).NotNull().WithMessage(stringLocalizer[ + SjzyBasicLocalization.Validation_NotNull, nameof(EditTrackPullContentInput.TrackPullConfigId)]); }); } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/Validations/TrackStatus/EditTrackStatusInputValidation.cs b/src/SJZY.Track.Application/Validations/TrackStatus/EditTrackStatusInputValidation.cs index e492a542..96a00eff 100644 --- a/src/SJZY.Track.Application/Validations/TrackStatus/EditTrackStatusInputValidation.cs +++ b/src/SJZY.Track.Application/Validations/TrackStatus/EditTrackStatusInputValidation.cs @@ -1,26 +1,25 @@ -using FluentValidation; +using FluentValidation; using SJZY.Track.Application.Contract.Dtos.TrackStatus; -namespace SJZY.Track.Application.Validations.TrackStatus +namespace SJZY.Track.Application.Validations.TrackStatus; + +public class EditTrackStatusInputValidation : AbstractValidator, IValidationEnabled { - public class EditTrackStatusInputValidation : AbstractValidator, IValidationEnabled + public EditTrackStatusInputValidation() { - public EditTrackStatusInputValidation() + //条件分支 + When(x => x.Options == OptionType.修改 || x.Options == OptionType.删除, + () => { RuleFor(x => x.Id).GreaterThan(0).WithMessage("修改或删除时Id必须大于0!"); }); + + When(x => x.Options == OptionType.新增, () => { RuleFor(x => x.Id).Equal(0).WithMessage("新增时Id必须等于0!"); }); + + When(x => x.Options == OptionType.修改 || x.Options == OptionType.新增, () => { - //条件分支 - When(x => x.Options == OptionType.修改 || x.Options == OptionType.删除, - () => { RuleFor(x => x.Id).GreaterThan(0).WithMessage("修改或删除时Id必须大于0!"); }); - - When(x => x.Options == OptionType.新增, () => { RuleFor(x => x.Id).Equal(0).WithMessage("新增时Id必须等于0!"); }); - - When(x => x.Options == OptionType.修改 || x.Options == OptionType.新增, () => - { - RuleFor(x => x.SubSystemId).GreaterThan(0).WithMessage("子系统的id必须大于0!"); - RuleFor(x => x.NodeId).GreaterThan(0).WithMessage("所属节点的id必须大于0!"); - RuleFor(x => x.Code).NotNull().WithMessage("轨迹状态代码必填!").NotEmpty().WithMessage("轨迹状态代码不能为空!"); - RuleFor(x => x.TrackStatus).NotNull().WithMessage("轨迹状态必填!").NotEmpty().WithMessage("轨迹状态不能为空!"); - RuleFor(x => x.EntrackStatus).NotNull().WithMessage("轨迹状态英文必填!").NotEmpty().WithMessage("轨迹状态英文不能为空!"); - }); - } + RuleFor(x => x.SubSystemId).GreaterThan(0).WithMessage("子系统的id必须大于0!"); + RuleFor(x => x.NodeId).GreaterThan(0).WithMessage("所属节点的id必须大于0!"); + RuleFor(x => x.Code).NotNull().WithMessage("轨迹状态代码必填!").NotEmpty().WithMessage("轨迹状态代码不能为空!"); + RuleFor(x => x.TrackStatus).NotNull().WithMessage("轨迹状态必填!").NotEmpty().WithMessage("轨迹状态不能为空!"); + RuleFor(x => x.EnTrackStatus).NotNull().WithMessage("轨迹状态英文必填!").NotEmpty().WithMessage("轨迹状态英文不能为空!"); + }); } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/Validations/TrackTemplates/EditTrackTemplateContentInputValidation.cs b/src/SJZY.Track.Application/Validations/TrackTemplates/EditTrackTemplateContentInputValidation.cs index c23984d4..5fdf076c 100644 --- a/src/SJZY.Track.Application/Validations/TrackTemplates/EditTrackTemplateContentInputValidation.cs +++ b/src/SJZY.Track.Application/Validations/TrackTemplates/EditTrackTemplateContentInputValidation.cs @@ -1,4 +1,4 @@ -using FluentValidation; +using FluentValidation; using Microsoft.Extensions.Localization; using SJZY.Expand.ABP.Core.Localization; using SJZY.Track.Application.Contract.Dtos.TrackTemplates; @@ -6,32 +6,37 @@ using SJZY.Track.Application.Localization; namespace SJZY.Track.Application.Validations.TrackTemplates; -public class EditTrackTemplateContentInputValidation : AbstractValidator, IValidationEnabled +public class EditTrackTemplateContentInputValidation : AbstractValidator, + IValidationEnabled { public EditTrackTemplateContentInputValidation(IStringLocalizer stringLocalizer) { - RuleFor(x => x.Options).IsInEnum().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_IsInEnum, nameof(EditTrackTemplateContentInput.Options)]); + RuleFor(x => x.Options).IsInEnum().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_IsInEnum, + nameof(EditTrackTemplateContentInput.Options)]); - RuleFor(x => x.Id).GreaterThan(0).WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_GreaterThan, nameof(EditTrackTemplateContentInput.Id), 0]); + RuleFor(x => x.Id).GreaterThan(0).WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_GreaterThan, + nameof(EditTrackTemplateContentInput.Id), 0]); - RuleFor(x => x.TrackContentId).GreaterThan(0).WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_GreaterThan, nameof(EditTrackTemplateContentInput.TrackContentId), 0]); + RuleFor(x => x.TrackContentId).GreaterThan(0).WithMessage(stringLocalizer[ + SjzyBasicLocalization.Validation_GreaterThan, nameof(EditTrackTemplateContentInput.TrackContentId), 0]); - RuleFor(x => x.TrackTemplateId).GreaterThan(0).WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_GreaterThan, nameof(EditTrackTemplateContentInput.TrackTemplateId), 0]); + RuleFor(x => x.TrackTemplateId).GreaterThan(0).WithMessage(stringLocalizer[ + SjzyBasicLocalization.Validation_GreaterThan, nameof(EditTrackTemplateContentInput.TrackTemplateId), 0]); - When(x => x.Options != OptionTypeNoNull.新增, () => - { - RuleFor(x => x.Id).NotNull().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotNull, nameof(EditTrackTemplateContentInput.Id)]); - }); + When(x => x.Options != OptionTypeNoNull.新增, + () => + { + RuleFor(x => x.Id).NotNull().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotNull, + nameof(EditTrackTemplateContentInput.Id)]); + }); When(x => x.Options != OptionTypeNoNull.删除, () => { - RuleFor(x => x.IsCanDelete).NotNull().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotNull, nameof(EditTrackTemplateContentInput.IsCanDelete)]); + RuleFor(x => x.TrackContentId).NotNull().WithMessage(stringLocalizer[ + SjzyBasicLocalization.Validation_NotNull, nameof(EditTrackTemplateContentInput.TrackContentId)]); - RuleFor(x => x.IsExternal).NotNull().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotNull, nameof(EditTrackTemplateContentInput.IsExternal)]); - - RuleFor(x => x.TrackContentId).NotNull().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotNull, nameof(EditTrackTemplateContentInput.TrackContentId)]); - - RuleFor(x => x.TrackTemplateId).NotNull().WithMessage(stringLocalizer[SjzyBasicLocalization.Validation_NotNull, nameof(EditTrackTemplateContentInput.TrackTemplateId)]); + RuleFor(x => x.TrackTemplateId).NotNull().WithMessage(stringLocalizer[ + SjzyBasicLocalization.Validation_NotNull, nameof(EditTrackTemplateContentInput.TrackTemplateId)]); }); } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application/Validations/TrackTemplates/EditTrackTemplateInputValidation.cs b/src/SJZY.Track.Application/Validations/TrackTemplates/EditTrackTemplateInputValidation.cs index aa4bdad8..afa52d4d 100644 --- a/src/SJZY.Track.Application/Validations/TrackTemplates/EditTrackTemplateInputValidation.cs +++ b/src/SJZY.Track.Application/Validations/TrackTemplates/EditTrackTemplateInputValidation.cs @@ -1,27 +1,26 @@ -using FluentValidation; +using FluentValidation; using SJZY.Track.Application.Contract.Dtos.TrackTemplates; -namespace SJZY.Track.Application.Validations.TrackTemplates +namespace SJZY.Track.Application.Validations.TrackTemplates; + +/// +/// 轨迹模版编辑校验 +/// +public class EditTrackTemplateInputValidation : AbstractValidator, IValidationEnabled { - /// - /// 轨迹模版编辑校验 - /// - public class EditTrackTemplateInputValidation : AbstractValidator, IValidationEnabled + public EditTrackTemplateInputValidation() { - public EditTrackTemplateInputValidation() + //条件分支 + When(x => x.Options == OptionType.修改 || x.Options == OptionType.删除, + () => { RuleFor(x => x.Id).GreaterThan(0).WithMessage("修改或删除时Id必须大于0!"); }); + + When(x => x.Options == OptionType.新增, () => { RuleFor(x => x.Id).Equal(0).WithMessage("新增时Id必须等于0!"); }); + + When(x => x.Options == OptionType.修改 || x.Options == OptionType.新增, () => { - //条件分支 - When(x => x.Options == OptionType.修改 || x.Options == OptionType.删除, - () => { RuleFor(x => x.Id).GreaterThan(0).WithMessage("修改或删除时Id必须大于0!"); }); - - When(x => x.Options == OptionType.新增, () => { RuleFor(x => x.Id).Equal(0).WithMessage("新增时Id必须等于0!"); }); - - When(x => x.Options == OptionType.修改 || x.Options == OptionType.新增, () => - { - RuleFor(x => x.SubSystemId).GreaterThan(0).WithMessage("子系统的id必须大于0!"); - RuleFor(x => x.Name).NotNull().WithMessage("模版名称必填!").NotEmpty().WithMessage("模版名称不能为空!"); - RuleFor(x => x.Code).NotNull().WithMessage("模版代码必填!").NotEmpty().WithMessage("模版代码不能为空!"); - }); - } + RuleFor(x => x.SubSystemId).GreaterThan(0).WithMessage("子系统的id必须大于0!"); + RuleFor(x => x.Name).NotNull().WithMessage("模版名称必填!").NotEmpty().WithMessage("模版名称不能为空!"); + RuleFor(x => x.Code).NotNull().WithMessage("模版代码必填!").NotEmpty().WithMessage("模版代码不能为空!"); + }); } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Aggregates/DemoAggregate/DemoDetailEntity.cs b/src/SJZY.Track.Domain/Aggregates/DemoAggregate/DemoDetailEntity.cs deleted file mode 100644 index 65734437..00000000 --- a/src/SJZY.Track.Domain/Aggregates/DemoAggregate/DemoDetailEntity.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace SJZY.Track.Domain.Aggregates.DemoAggregate; - -[SugarTable("t_demo_detail")] -public class DemoDetailEntity : IEntity -{ - /// - /// Id - /// - [SugarColumn(ColumnName = "id", IsPrimaryKey = true)] - public long Id { get; set; } - - /// - /// t_demo.id - /// - [SugarColumn(ColumnName = "DemoId")] - public long DemoId { get; set; } - - /// - /// 一些说明.. - /// - [SugarColumn(ColumnName = "OtherInfo")] - public string OtherInfo { get; set; } -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/DemoAggregate/DemoEntity.cs b/src/SJZY.Track.Domain/Aggregates/DemoAggregate/DemoEntity.cs deleted file mode 100644 index 44d7d6eb..00000000 --- a/src/SJZY.Track.Domain/Aggregates/DemoAggregate/DemoEntity.cs +++ /dev/null @@ -1,36 +0,0 @@ -namespace SJZY.Track.Domain.Aggregates.DemoAggregate; - -/// -/// 测试表 -/// -[SugarTable("t_demo")] -public class DemoEntity : IFullAuditedBasicEntitys, IAggregateRoot -{ - /// - /// Id - /// - [SugarColumn(ColumnName = "id", IsPrimaryKey = true, IsIdentity = true)] - public long Id { get; set; } - - /// - /// 姓名 - /// - [SugarColumn(ColumnName = "Name")] - public string Name { get; set; } - - /// - /// 年龄 - /// - [SugarColumn(ColumnName = "Age")] - public int Age { get; set; } - - /// - /// 描述 - /// - [SugarColumn(ColumnName = "Description")] - public string Description { get; set; } - - - [Navigate(NavigateType.OneToMany, nameof(DemoDetailEntity.DemoId))] - public List DemoDetailList { get; set; } -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/DemoAggregate/IDemoRepository.cs b/src/SJZY.Track.Domain/Aggregates/DemoAggregate/IDemoRepository.cs deleted file mode 100644 index 207cc3b3..00000000 --- a/src/SJZY.Track.Domain/Aggregates/DemoAggregate/IDemoRepository.cs +++ /dev/null @@ -1,23 +0,0 @@ -using SJZY.Track.Domain.Dtos.Demo; - -namespace SJZY.Track.Domain.Aggregates.DemoAggregate -{ - public interface IDemoRepository - { - Task EntityRelationSave(DemoEntity entity); - Task InsertReturnIdentityAsync(DemoEntity entity); - Task UpdateAsync(DemoEntity entity); - Task DeleteAsync(DemoEntity entity); - Task GetById1(int id); - Task> GetListByPage(int pageSize, int pageindex, string name); - Task> OriginalSql(DemoValueObject obj); - Task> InputToValueObject(DemoValueObject obj); - Task Transaction(); - Task MultipleMethodTrans1(); - Task MultipleMethodTrans2(); - Task InternalTrans(); - Task UpdatePartColumns(DemoEntity entity); - - Task GetDataCache(int Id); - } -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IWarningRecordEsRepository.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IWarningRecordEsRepository.cs new file mode 100644 index 00000000..5f7d1ad3 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IWarningRecordEsRepository.cs @@ -0,0 +1,34 @@ +using SJZY.Track.Domain.Dtos.Forewarning; + +namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +public interface IWarningRecordEsRepository +{ + /// + /// 添加预警记录 + /// + /// + /// + Task AddAsync(WarningRecordIndex index); + + /// + /// 批量添加预警记录 + /// + /// + /// + Task BulkInsertAsync(List warningRecords); + + /// + /// 批量更新预警记录 + /// + /// + /// + Task BulkUpdateAsync(List<(int ruleId, int orderId, int counter)> warningRecords); + + /// + /// 获取订单运输时效预警分页列表 + /// + /// + /// + Task<(List list, long total)> GetOrderWarningPageListAsync(GetOrderWarningPageListVo inputVo); +} diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IWarningRepository.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IWarningRepository.cs new file mode 100644 index 00000000..bf638ac2 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/IWarningRepository.cs @@ -0,0 +1,62 @@ +using SJZY.Track.Domain.Dtos.Forewarning; + +namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +public interface IWarningRepository : IBasicRepository +{ + /// + /// 创建预警,include factors, notifies, rules + /// + /// + /// + Task CreateForewarningAsync(WarningEntity warning); + + /// + /// 复制预警 + /// + /// + /// + Task CopyForewarning(int warningId); + + /// + /// 获取预警分页列表 + /// + /// + /// + Task> GetWarningPageListAsync(GetWarningPageInputVo input); + + /// + /// 获取预警规则列表 + /// + /// 预警id + /// + Task> GetWarningRuleListAsync(int warningId); + + /// + /// 修改预警 + /// + /// + /// + Task UpdateForewarningAsync(WarningEntity warning); + + /// + /// 修改预警时效 + /// + /// + /// + Task ModifyTimeSpansAsync(List inputItems); + + /// + /// 启用预警 + /// + /// + /// + Task TurnWarningAsync(WarningEntity warning); + + /// + /// 获取预警,include factors, notifies + /// + /// + /// + Task GetByIdAsync(int warningId); +} diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningEntity.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningEntity.cs new file mode 100644 index 00000000..7f407fa2 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningEntity.cs @@ -0,0 +1,76 @@ +using Volo.Abp; + +namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +[SugarTable("t_warning")] +public class WarningEntity : IFullAuditedBasicEntitys, IAggregateRoot +{ + /// + /// 自增主键 + /// + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 子系统id + /// + [SugarColumn(ColumnName = "SubSystemId")] + public int SubSystemId { get; set; } + + /// + /// 客户id + /// + [SugarColumn(ColumnName = "CustomerId")] + public int CustomerId { get; set; } + + /// + /// 规则模板名称,KPI名称 + /// + [SugarColumn(ColumnName = "Name")] + public string Name { get; set; } = null!; + + /// + /// 因素类型排序 + /// + [SugarColumn(ColumnName = "FactorTypeSort")] + public string FactorTypeSort { get; set; } = null!; + + /// + /// 是否启用,默认否 + /// + [SugarColumn(ColumnName = "IsEnable")] + public bool IsEnable { get; set; } + + /// + /// 预警规则 + /// + [SugarColumn(IsIgnore = true)] + public List WarningRules { get; set; } = new(); + + /// + /// 预警因素 + /// + [SugarColumn(IsIgnore = true)] + public List WarningFactors { get; set; } = new(); + + /// + /// 预警通知 + /// + [SugarColumn(IsIgnore = true)] + public List WarningNotifies { get; set; } = new(); + + public void SetName(string name) + { + Name = name; + } + + public void SetEnable(bool isEnable) + { + if (IsEnable == isEnable) + { + throw new BusinessException(message: $"预警已经是{(isEnable ? "启用" : "禁用")}状态"); + } + + IsEnable = isEnable; + } +} diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningFactorEntity.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningFactorEntity.cs new file mode 100644 index 00000000..c54ac6fa --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningFactorEntity.cs @@ -0,0 +1,31 @@ +using SJZY.Track.Domain.Enums; + +namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +[SugarTable("t_warning_factor")] +public class WarningFactorEntity : IFullAuditedBasicEntitys, IEntity +{ + /// + /// 自增主键 + /// + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 预警id + /// + [SugarColumn(ColumnName = "WarningId")] + public int WarningId { get; set; } + + /// + /// 因素类型(1货物类型,2月份,3分区,4是否中转,5起运港口,6销售产品) + /// + [SugarColumn(ColumnName = "Type")] + public RuleFactorType Type { get; set; } + + /// + /// 预警因素值(json数组字符串) + /// + [SugarColumn(ColumnName = "Value")] + public string Value { get; set; } = null!; +} diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningNotifyEntity.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningNotifyEntity.cs new file mode 100644 index 00000000..d0de3ab7 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningNotifyEntity.cs @@ -0,0 +1,41 @@ +namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +[SugarTable("t_warning_notify")] +public class WarningNotifyEntity : IFullAuditedBasicEntitys, IEntity +{ + /// + /// 自增主键 + /// + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 预警id + /// + [SugarColumn(ColumnName = "WarningId")] + public int WarningId { get; set; } + + /// + /// 起始轨迹状态id + /// + [SugarColumn(ColumnName = "StartTrackStatusId", IsNullable = false)] + public int StartTrackStatusId { get; set; } + + /// + /// 终止轨迹状态id + /// + [SugarColumn(ColumnName = "EndTrackStatusId", IsNullable = false)] + public int EndTrackStatusId { get; set; } + + /// + /// 通知方式,多个逗号分隔 + /// + [SugarColumn(ColumnName = "NotifyMode")] + public string NotifyMode { get; set; } + + /// + /// 通知人,json格式 多个 + /// + [SugarColumn(ColumnName = "NotifyUser")] + public string NotifyUser { get; set; } +} diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningRecordIndex.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningRecordIndex.cs new file mode 100644 index 00000000..4b700010 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningRecordIndex.cs @@ -0,0 +1,89 @@ +using Nest; +using SJZY.Expand.ElasticSearch; +using SJZY.Track.Domain.Consts; + +namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +[ElasticsearchType(RelationName = GlobalConst.TrackWarningRecordIndex)] +public class WarningRecordIndex : IdBaseIndex +{ + /// + /// 子系统id + /// + public int SubSystemId { get; set; } + + /// + /// 子系统name + /// + public string SubSystemName { get; set; } + + /// + /// 索引名称 + /// + public string IndexName { get; set; } = null!; + + /// + /// 预警名称 + /// + public string WarningName { get; set; } = null!; + + /// + /// 客户id + /// + public int CustomId { get; set; } + + /// + /// 客户简称 + /// + public string CustomName { get; set; } + + /// + /// 预警规则id + /// + public int RuleId { get; set; } + + /// + /// 订单Id + /// + public int OrderId { get; set; } + + /// + /// 订单号 + /// + public string OrderNo { get; set; } = null!; + + /// + /// 预警规则 + /// + public string Rule { get; set; } = null!; + + /// + /// 预警次数 + /// + public int Counter { get; set; } + + /// + /// 是否最后一次 + /// + public bool IsLast { get; set; } + + /// + /// 预警状态 + /// + public WarningStatus WarningStatus { get; set; } + + /// + /// 通知用户name + /// + public string NotifyUserName { get; set; } + + /// + /// 通知用户id + /// + public int NotifyUserId { get; set; } + + /// + /// 创建时间 + /// + public DateTime CreateTime { get; set; } +} diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningRuleEntity.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningRuleEntity.cs new file mode 100644 index 00000000..d2f6bd0a --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningRuleEntity.cs @@ -0,0 +1,95 @@ +namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +[SugarTable("t_warning_rule")] +public class WarningRuleEntity : IFullAuditedBasicEntitys, IEntity +{ + /// + /// 自增主键 + /// + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 预警id + /// + [SugarColumn(ColumnName = "WarningId")] + public int WarningId { get; set; } + + /// + /// 时效(小时) + /// + [SugarColumn(ColumnName = "TotalTimeSpan")] + public float TotalTimeSpan { get; set; } + + /// + /// 提醒的时间(小时) + /// + [SugarColumn(ColumnName = "WarnTimeSpan")] + public float WarnTimeSpan { get; set; } + + /// + /// 提醒次数 + /// + [SugarColumn(ColumnName = "WarnCount")] + public int WarnCount { get; set; } + + /// + /// 起始轨迹状态id + /// + [SugarColumn(ColumnName = "StartTrackStatusId")] + public int StartTrackStatusId { get; set; } + + /// + /// 起始轨迹状态(冗余) + /// + [SugarColumn(ColumnName = "StartTrackStatus")] + public string StartTrackStatus { get; set; } = null!; + + /// + /// 终止轨迹状态id + /// + [SugarColumn(ColumnName = "EndTrackStatusId")] + public int EndTrackStatusId { get; set; } + + /// + /// 终止轨迹状态(冗余) + /// + [SugarColumn(ColumnName = "EndTrackStatus")] + public string EndTrackStatus { get; set; } = null!; + + /// + /// 货物类型 + /// + [SugarColumn(ColumnName = "CargoType", Length = 64)] + public string? CargoType { get; set; } + + /// + /// 月份 + /// + [SugarColumn(ColumnName = "Months", Length = 25)] + public string? Months { get; set; } + + /// + /// 区域 + /// + [SugarColumn(ColumnName = "AreaId")] + public int? AreaId { get; set; } + + /// + /// 是否中转 + /// + [SugarColumn(ColumnName = "IsTransit")] + public bool? IsTransit { get; set; } + + /// + /// 起运港口 + /// + [SugarColumn(ColumnName = "LeavePort")] + public string? LeavePort { get; set; } + + /// + /// 产品编码 + /// + [SugarColumn(ColumnName = "ProductCode")] + public string? ProductCode { get; set; } +} diff --git a/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningStatus.cs b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningStatus.cs new file mode 100644 index 00000000..f5a76c9e --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/ForewarningAggregate/WarningStatus.cs @@ -0,0 +1,14 @@ +namespace SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +public enum WarningStatus +{ + /// + /// 待处理 + /// + UnProcessed = 1, + + /// + /// 已处理 + /// + Processed = 2, +} diff --git a/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/IKpiAreaRepository.cs b/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/IKpiAreaRepository.cs new file mode 100644 index 00000000..e84baad6 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/IKpiAreaRepository.cs @@ -0,0 +1,68 @@ +using SJZY.Track.Domain.Dtos.Forewarning; + +namespace SJZY.Track.Domain.Aggregates.KPIAreaAggregate; + +public interface IKpiAreaRepository : IBasicRepository +{ + /// + /// 创建分区 + /// + /// + /// + ValueTask CreateAreaAsync(RuleAreaEntity entity); + + /// + /// 添加分区信息 + /// + /// + /// + ValueTask AddAreaInfoAsync(RuleAreaInfoEntity entity); + + /// + /// 删除分区信息 + /// + /// 分区信息id + /// + Task DeleteAreaInfo(int areaInfoId); + + /// + /// 删除分区 + /// + /// 分区id + /// + ValueTask DeleteArea(int areaId); + + /// + /// 更新区域信息 + /// + /// + /// + Task UpdateAreaInfoAsync(RuleAreaInfoEntity entity); + + /// + /// 获得分区 + /// + /// + /// + Task> GetAreas(QueryAreaRequest query); + + /// + /// 获取分区信息 + /// + /// + /// + Task> GetAreaInfos(QueryAreaInfoRequest query); + + /// + /// 获取分区信息通过id + /// + /// + /// + Task GetAreaInfoById(int id); + + /// + /// 获取所有区域信息 + /// + /// + List? GetAreaInfosByAreaId(int areaId); +} diff --git a/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/RuleAreaEntity.cs b/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/RuleAreaEntity.cs new file mode 100644 index 00000000..192119f6 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/RuleAreaEntity.cs @@ -0,0 +1,49 @@ +namespace SJZY.Track.Domain.Aggregates.KPIAreaAggregate; + +[SugarTable("t_area", TableDescription = "KPI分区主表")] +public class RuleAreaEntity : IAggregateRoot +{ + /// + /// 自增主键 + /// + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true, ColumnDescription = "自增主键")] + public int Id { get; set; } + + /// + /// 子系统id + /// + [SugarColumn(ColumnName = "SubSystemId", ColumnDescription = "子系统id")] + public int SubSystemId { get; set; } + + /// + /// 分区名称KPI名称 + /// + [SugarColumn(ColumnName = "Name", Length = 64, ColumnDescription = "分区名称KPI名称")] + public string Name { get; set; } + + /// + /// 创建人 + /// + [SugarColumn(ColumnName = "CreateUserId", ColumnDescription = "创建人")] + public int CreateUserId { get; set; } + + /// + /// 创建时间 + /// + [SugarColumn(ColumnName = "CreateTime", ColumnDescription = "创建时间")] + public DateTime CreateTime { get; set; } + + /// + /// 更新人 + /// + [SugarColumn(ColumnName = "UpdateUserId", ColumnDescription = "更新人")] + public int UpdateUserId { get; set; } + + /// + /// 更新时间 + /// + [SugarColumn(ColumnName = "UpdateTime", ColumnDescription = "更新时间")] + public DateTime UpdateTime { get; set; } + + [SugarColumn(IsIgnore = true)] public List AreaInfos { get; set; } +} diff --git a/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/RuleAreaInfoEntity.cs b/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/RuleAreaInfoEntity.cs new file mode 100644 index 00000000..b2f14b30 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/KPIAreaAggregate/RuleAreaInfoEntity.cs @@ -0,0 +1,77 @@ +namespace SJZY.Track.Domain.Aggregates.KPIAreaAggregate; + +[SugarTable("t_area_details", TableDescription = "kpi 区域子表")] +public class RuleAreaInfoEntity : IEntity +{ + /// + /// 自增主键 + /// + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true, ColumnDescription = "自增主键")] + public int Id { get; set; } + + /// + /// t_rule_area 表id + /// + [SugarColumn(ColumnName = "AreaId", ColumnDescription = "t_rule_area 表id")] + public int AreaId { get; set; } + + /// + /// 国家或地区二字码 + /// + [SugarColumn(ColumnName = "CountryCode", Length = 128, ColumnDescription = "国家或地区二字码")] + public string CountryCode { get; set; } + + /// + /// 国家或地区名称 + /// + [SugarColumn(ColumnName = "CountryName", Length = 128, ColumnDescription = "国家或地区名称")] + public string CountryName { get; set; } + + /// + /// 州或者省份 + /// + [SugarColumn(ColumnName = "Province", Length = 128, IsNullable = true, ColumnDescription = "州或者省份")] + public string Province { get; set; } + + /// + /// 城市 + /// + [SugarColumn(ColumnName = "City", Length = 128, IsNullable = true, ColumnDescription = "城市")] + public string City { get; set; } + + /// + /// 起始邮编 + /// + [SugarColumn(ColumnName = "LeftPostcode", Length = 10, IsNullable = true, ColumnDescription = "起始邮编")] + public string LeftPostcode { get; set; } + + /// + /// 截止邮编 + /// + [SugarColumn(ColumnName = "RightPostcode", Length = 10, IsNullable = true, ColumnDescription = "截止邮编")] + public string RightPostcode { get; set; } + + /// + /// 创建人 + /// + [SugarColumn(ColumnName = "CreateUserId", ColumnDescription = "创建人")] + public int CreateUserId { get; set; } + + /// + /// 创建时间 + /// + [SugarColumn(ColumnName = "CreateTime", ColumnDescription = "创建时间")] + public DateTime CreateTime { get; set; } + + /// + /// 更新人 + /// + [SugarColumn(ColumnName = "UpdateUserId", IsNullable = false, ColumnDescription = "更新人")] + public int UpdateUserId { get; set; } + + /// + /// 更新时间 + /// + [SugarColumn(ColumnName = "UpdateTime", IsNullable = false, ColumnDescription = "更新时间")] + public DateTime UpdateTime { get; set; } +} diff --git a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderOperationRecordEsRepository.cs b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderOperationRecordEsRepository.cs new file mode 100644 index 00000000..18485b5a --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderOperationRecordEsRepository.cs @@ -0,0 +1,33 @@ +namespace SJZY.Track.Domain.Aggregates.OrderAggregate; + +public interface IOrderOperationRecordEsRepository +{ + /// + /// 添加订单操作记录 + /// + /// + /// + Task AddAsync(OrderOperationRecordIndex index); + + /// + /// 添加订单操作记录(批量) + /// + /// + /// + Task AddManyAsync(List indexes); + + /// + /// 根据id删除订单操作记录 + /// + /// + /// + /// + Task DeleteOperationRecordByIdAsync(string id, string indexName); + + /// + /// 获取订单操作记录 + /// + /// + /// + Task> GetOrderOperationsByIdAsync(int orderId); +} diff --git a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderRepository.cs b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderRepository.cs index 78cdd5df..183b02dd 100644 --- a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderRepository.cs +++ b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderRepository.cs @@ -1,15 +1,31 @@ -using SJZY.Track.Domain.Dtos.Order; +using SJZY.Track.Domain.Dtos.Order; +using SJZY.Track.Domain.VEntities; namespace SJZY.Track.Domain.Aggregates.OrderAggregate; public interface IOrderRepository : IBasicRepository { + /// + /// 获取分页的轨迹订单 + /// + /// + /// + Task> GetTrackOrderPagedList(GetPageTrackOrderInputVO input); + + /// + /// 通过三方平台和三方单号查询订单 + /// + /// 三方平台 + /// 三方平台单号 + /// (主单号id,客户id) + Task<(int MainOrderId, int CustomId)> GetTrackOrderByProviderAndOrderNo(string serviceProviderCode, string orderNo); + /// /// 创建订单 /// /// /// - Task CreateOrderAsync(OrderEntity order); + Task CreateOrderAsync(OrderEntity order); /// /// 更新订单 @@ -29,7 +45,43 @@ public interface IOrderRepository : IBasicRepository /// 更新推送预警单 /// /// - Task PushWarnOrdersAsync(); + Task PushWarnOrdersAsync(int subSystemId, int pageSize, int pageindex); + + /// + /// 更新缺失标记,时区缺失和发生地缺失标记,1表示时区,2表示发生地,3表示两种 + /// + /// 订单id + /// 值 + /// + Task UpdateBatchIdsAsync(List ids, int newValue); + + /// + /// 根据子系统code获取子系统id + /// + /// + /// + Task> GetSubSystemListByCodesAsync(List codes); + + #region 订单模板 + + /// + /// 根据订单id,获取订单所属的模板 + /// + /// + /// + Task> GetOrderTemplateAsync(int[] orderId); + + /// + /// 根据子系统+订单号+类型,获取订单所属的模板 + /// + /// + /// + /// + /// + Task> GetOrderTemplateAsync(int subSystemId,int orderType,List orderNos); + + #endregion + #region 订单关联 @@ -40,6 +92,27 @@ public interface IOrderRepository : IBasicRepository /// Task> GetLinkedOrdersAsync(int[] orderId); + /// + /// 根据订单id,获取指定子系统下指定订单类型的关联订单集合 + /// + /// + /// + /// + /// + Task> GetLinkedOrdersAsync(int orderId, int linkSubSystemId, int linkOrderType); + + + /// + /// 找已经存在的关联订单 + /// + /// + /// + /// + /// + /// + Task> GetLinkedOrdersAsync(int orderId, int linkSubSystemId, int linkOrderType, + List linkOrderNos); + /// /// 关联订单 /// @@ -55,4 +128,51 @@ public interface IOrderRepository : IBasicRepository Task UnLinkByIdsAsync(List linkIds); #endregion -} \ No newline at end of file + + + #region 订单拉取状态 + + /// + /// 更新订单拉取状态为静默,Init->SilenceBeforeStart,Pulling->SilenceAfterEnd + /// + /// + /// + /// + Task UpdatePullStatusToSilenceAsync(List orderIds, string trackCode); + + + /// + /// 更新订单拉取状态根据静默,SilenceBeforeStart->Pulling,SilenceAfterEnd->Completed + /// + /// + Task UpdatePullStatusBySilenceAsync(); + + /// + /// 清理拉取状态 + /// + /// + Task ClearPullStatusAsync(); + + /// + /// 更新订单拉取配置,根据服务商 + /// + /// + /// + Task UpdateOrderPullConfigForServiceProviderAsync(UpdateOrderPullConfigsInputVo inputVo); + + #endregion + + /// + /// 根据id获取子系统信息 + /// + /// + /// + Task GetSystemInfoById(int id); + + /// + /// 根据id获取员工姓名 + /// + /// + /// + Task GetUserById(int id); +} diff --git a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs index e0f19389..d6248fbe 100644 --- a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Aggregates.OrderAggregate; +namespace SJZY.Track.Domain.Aggregates.OrderAggregate; /// /// 轨迹订单主表 @@ -132,8 +132,69 @@ public class OrderEntity : IFullAuditedBasicEntitys, IAggregateRoot [SugarColumn(ColumnName = "LeavePort")] public string? LeavePort { get; set; } - [SugarColumn(IsIgnore = true)] public List OrderFlights { get; set; } - [SugarColumn(IsIgnore = true)] public List OrderTemplates { get; set; } + /// + /// 货物类型 + /// + [SugarColumn(ColumnName = "CargoType")] + public string? CargoType { get; set; } + + /// + /// 是否中转 + /// + [SugarColumn(ColumnName = "IsTransit")] + public bool? IsTransit { get; set; } + + /// + /// 产品编码 + /// + [SugarColumn(ColumnName = "ProductCode")] + public string? ProductCode { get; set; } + + /// + /// 时区缺失和发生地缺失标记,1表示时区,2表示发生地,3表示两种 + /// + [SugarColumn(ColumnName = "DeficiencyTag")] + public int? DeficiencyTag { get; set; } + + /// + /// 到达邮编 + /// + [SugarColumn(ColumnName = "ArrivalPostCode")] + public string? ArrivalPostCode { get; set; } + + /// + /// 到达州省 + /// + [SugarColumn(ColumnName = "ArrivalProvince")] + public string? ArrivalProvince { get; set; } + + /// + /// 预计到达时间 + /// + [SugarColumn(ColumnName = "EstimatedDeliveryDate")] + public DateTime? EstimatedDeliveryDate { get; set; } + + /// + /// 目的地时区 + /// + [SugarColumn(ColumnName = "DestinationTimeZone")] + public float? DestinationTimeZone { get; set; } + + /// + /// 模板code + /// + [SugarColumn(ColumnName = "TemplateCodes")] + public string? TemplateCodes { get; set; } + + [SugarColumn(IsIgnore = true)] + public List OrderFlights { get; set; } + + [SugarColumn(IsIgnore = true)] + public List OrderPullStatus { get; set; } + + [Navigate(NavigateType.OneToMany, nameof(OrderPlatformNumberEntity.OrderId))] + [SugarColumn(IsIgnore = true)] + public List OrderPlatformNumbers { get; set; } public void ResetTrackInfo() { @@ -143,5 +204,7 @@ public class OrderEntity : IFullAuditedBasicEntitys, IAggregateRoot LatestTrackTime = null; LatestTrackPlace = null; LatestTrackTimeZone = null; + EstimatedDeliveryDate = null; + DestinationTimeZone = null; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderFlightEntity.cs b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderFlightEntity.cs index 1ba0393a..766c0d27 100644 --- a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderFlightEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderFlightEntity.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Aggregates.OrderAggregate; +namespace SJZY.Track.Domain.Aggregates.OrderAggregate; /// /// 订单航班表(1:N) @@ -47,4 +47,4 @@ public class OrderFlightEntity : ICreateBaicEntity, ISoftDeleteBasicEntity, IEnt /// [SugarColumn(ColumnName = "IsDeleted")] public bool IsDeleted { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderLinkEntity.cs b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderLinkEntity.cs index 612cdae2..65b43567 100644 --- a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderLinkEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderLinkEntity.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Aggregates.OrderAggregate; +namespace SJZY.Track.Domain.Aggregates.OrderAggregate; /// /// 轨迹订单关联表(1:N) @@ -24,31 +24,6 @@ public class OrderLinkEntity : ICreateBaicEntity, ISoftDeleteBasicEntity, IEntit [SugarColumn(ColumnName = "LinkOrderId")] public int LinkOrderId { get; set; } - /// - /// 订单类型 - /// - [SugarColumn(ColumnName = "OrderType")] - public int OrderType { get; set; } - - /// - /// 订单号 - /// - [SugarColumn(ColumnName = "OrderNo")] - public string OrderNo { get; set; } = null!; - - - /// - /// 关联的订单类型 - /// - [SugarColumn(ColumnName = "LinkOrderType")] - public int LinkOrderType { get; set; } - - /// - /// 关联的订单号 - /// - [SugarColumn(ColumnName = "LinkOrderNo")] - public string LinkOrderNo { get; set; } = null!; - /// /// 创建人 /// @@ -66,4 +41,4 @@ public class OrderLinkEntity : ICreateBaicEntity, ISoftDeleteBasicEntity, IEntit /// [SugarColumn(ColumnName = "IsDeleted")] public bool IsDeleted { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderOperationRecordIndex.cs b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderOperationRecordIndex.cs new file mode 100644 index 00000000..c53ed8c5 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderOperationRecordIndex.cs @@ -0,0 +1,61 @@ +using Nest; +using SJZY.Expand.ElasticSearch; +using SJZY.Track.Domain.Consts; + +namespace SJZY.Track.Domain.Aggregates.OrderAggregate; + +/// +/// 订单操作记录 +/// +[ElasticsearchType(RelationName = GlobalConst.OrderOperationRecordIndex)] +public class OrderOperationRecordIndex : IdBaseIndex +{ + /// + /// 索引名称 + /// + public string IndexName { get; set; } = null!; + + /// + /// 订单Id + /// + public int OrderId { get; set; } + + /// + /// 订单号 + /// + public string OrderNo { get; set; } = null!; + + /// + /// 操作类型 + /// + public string OptionType { get; set; } = null!; + + /// + /// 前期报文(json) + /// + public string Content { get; set; } = null!; + + /// + /// 创建人 + /// + public int CreateUserId { get; set; } + + /// + /// 创建人姓名 + /// + public string CreateUserName { get; set; } + + /// + /// 创建时间 + /// + public DateTime CreateTime { get; set; } +} + +public enum OrderOperationType +{ + 创建订单 = 1, + 修改订单 = 2, + 创建轨迹 = 3, + 修改轨迹 = 4, + 删除轨迹 = 5 +} diff --git a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderPlatformNumberEntity.cs b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderPlatformNumberEntity.cs new file mode 100644 index 00000000..b4ae68bf --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderPlatformNumberEntity.cs @@ -0,0 +1,32 @@ +namespace SJZY.Track.Domain.Aggregates.OrderAggregate; + +/// +/// 外部单号关联表 +/// +[SugarTable("t_order_platform_number")] +public class OrderPlatformNumberEntity : IFullAuditedBasicEntitys, IEntity +{ + /// + /// 自增主键 + /// + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 订单id + /// + [SugarColumn(ColumnName = "OrderId")] + public int OrderId { get; set; } + + /// + /// 外部单号 + /// + [SugarColumn(ColumnName = "OrderNumber")] + public string? OrderNumber { get; set; } + + /// + /// 平台名称 + /// + [SugarColumn(ColumnName = "Platform")] + public string? Platform { get; set; } +} diff --git a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderTemplateEntity.cs b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderTemplateEntity.cs deleted file mode 100644 index 7dee5516..00000000 --- a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderTemplateEntity.cs +++ /dev/null @@ -1,50 +0,0 @@ -namespace SJZY.Track.Domain.Aggregates.OrderAggregate; - -/// -/// 轨迹订单模板表(1:N) -/// -[SugarTable("t_order_template")] -public class OrderTemplateEntity : ICreateBaicEntity, ISoftDeleteBasicEntity, IEntity -{ - /// - /// 自增主键 - /// - [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] - public int Id { get; set; } - - /// - /// 订单id - /// - [SugarColumn(ColumnName = "OrderId")] - public int OrderId { get; set; } - - /// - /// 服务商id - /// - [SugarColumn(ColumnName = "ServiceProviderId")] - public int ServiceProviderId { get; set; } - - /// - /// 模板id - /// - [SugarColumn(ColumnName = "TrackTemplateId")] - public int TrackTemplateId { get; set; } - - /// - /// 创建人 - /// - [SugarColumn(ColumnName = "CreateUserId")] - public int CreateUserId { get; set; } - - /// - /// 创建时间 - /// - [SugarColumn(ColumnName = "CreateTime")] - public DateTime CreateTime { get; set; } - - /// - /// 是否删除 - /// - [SugarColumn(ColumnName = "IsDeleted")] - public bool IsDeleted { get; set; } -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderTrackPullStatusEntity.cs b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderTrackPullStatusEntity.cs new file mode 100644 index 00000000..b4db417c --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderTrackPullStatusEntity.cs @@ -0,0 +1,92 @@ +namespace SJZY.Track.Domain.Aggregates.OrderAggregate; + +/// +/// 订单轨迹拉取状态表(1:N) +/// +[SugarTable("t_order_pull_status")] +public class OrderPullStatusEntity : ICreateBaicEntity, IUpdateBasicEntity, IEntity +{ + /// + /// 自增主键 + /// + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 订单id + /// + [SugarColumn(ColumnName = "OrderId")] + public int OrderId { get; set; } + + /// + /// api服务商订单号(第三方单号) + /// + [SugarColumn(ColumnName = "OrderNo")] + public string? OrderNo { get; set; } + + /// + /// 服务商code + /// + [SugarColumn(ColumnName = "ServiceProviderCode")] + public string ServiceProviderCode { get; set; } + + /// + /// 拉取状态 + /// + [SugarColumn(ColumnName = "PullStatus")] + public TrackPullStatus PullStatus { get; set; } + + /// + /// 开始轨迹code + /// + [SugarColumn(ColumnName = "StartTrackCode")] + public string StartTrackCode { get; set; } + + /// + /// 结束轨迹code + /// + [SugarColumn(ColumnName = "EndTrackCode")] + public string EndTrackCode { get; set; } + + /// + /// 开始前的静默(小时) + /// + [SugarColumn(ColumnName = "SilenceBeforeStart")] + public int SilenceBeforeStart { get; set; } + + /// + /// 结束后的静默(小时) + /// + [SugarColumn(ColumnName = "SilenceAfterEnd")] + public int SilenceAfterEnd { get; set; } + + /// + /// 定时任务开始时间(计算量) + /// + [SugarColumn(ColumnName = "StartTime")] + public DateTime StartTime { get; set; } + + /// + /// 定时任务结束时间(计算量) + /// + [SugarColumn(ColumnName = "EndTime")] + public DateTime EndTime { get; set; } + + /// + /// 创建人 + /// + [SugarColumn(ColumnName = "CreateUserId")] + public int CreateUserId { get; set; } + + /// + /// 创建时间 + /// + [SugarColumn(ColumnName = "CreateTime")] + public DateTime CreateTime { get; set; } + + [SugarColumn(ColumnName = "UpdateTime")] + public DateTime? UpdateTime { get; set; } + + [SugarColumn(ColumnName = "UpdateUserId")] + public int? UpdateUserId { get; set; } +} diff --git a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/TrackPullStatus.cs b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/TrackPullStatus.cs new file mode 100644 index 00000000..6c1ef506 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/TrackPullStatus.cs @@ -0,0 +1,37 @@ +namespace SJZY.Track.Domain.Aggregates.OrderAggregate; + +/* + * 订单轨迹拉取状态: + * 【0初始态,表示订单数据刚刚录入】【1开始前的静默】【2拉取中】【3结束后的静默】【4拉取完成】 + 1.轨迹发生时,将init状态改为silenceBeforeStart,将pulling改为silenceAfterEnd(状态计算及时计算) + 2.定时任务扫描,将符合开始结束的范围订单筛选出来,去拉取轨迹(轨迹拉取最小延迟30min) + 3.定时任务扫描,将silenceBeforeStart改为pulling,将silenceAfterEnd改为completed(状态计算最小延迟1min) + 4.定时任务扫描,将已经拉取完成的订单拉取删除,将开启了30天的订单拉取删除(清理最小延迟1min) + */ +public enum TrackPullStatus +{ + /// + /// 初始态 + /// + Init = 0, + + /// + /// 开始前的静默 + /// + SilenceBeforeStart, + + /// + /// 拉取中 + /// + Pulling, + + /// + /// 结束后的静默 + /// + SilenceAfterEnd, + + /// + /// 拉取完成 + /// + Completed +} diff --git a/src/SJZY.Track.Domain/Aggregates/TrackContentAggregate/ITrackContentRepository.cs b/src/SJZY.Track.Domain/Aggregates/TrackContentAggregate/ITrackContentRepository.cs index 400b7363..fe3a81d7 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackContentAggregate/ITrackContentRepository.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackContentAggregate/ITrackContentRepository.cs @@ -1,5 +1,4 @@ -using SJZY.Track.Domain.Dtos.TrackContents; -using SJZY.Track.Domain.Dtos.TrackTemplate; +using SJZY.Track.Domain.Dtos.TrackContents; namespace SJZY.Track.Domain.Aggregates.TrackContentAggregate; @@ -23,7 +22,11 @@ public interface ITrackContentRepository : IBasicRepository Task SoftDeleteMapAsync(Expression> whereExpression); - Task UpdateMapAsync(Expression> columns, Expression> whereExpression); + Task UpdateMapAsync(Expression> columns, + Expression> whereExpression); + Task GetTemplateIsExist(int trackContentId); - Task> GetTrackContentAttributeValue(GetTemplateContentAttributeValueInputVO input); -} \ No newline at end of file + Task GetByCodeAsync(int systemId, string code); + Task> GetListBySystemIdAsync(int systemId); + Task> GetTrackContentBySyetemIdAsync(int subSystemId); +} diff --git a/src/SJZY.Track.Domain/Aggregates/TrackContentAggregate/TrackContentEntity.cs b/src/SJZY.Track.Domain/Aggregates/TrackContentAggregate/TrackContentEntity.cs index 02fac985..b6809891 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackContentAggregate/TrackContentEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackContentAggregate/TrackContentEntity.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Aggregates.TrackContentAggregate; +namespace SJZY.Track.Domain.Aggregates.TrackContentAggregate; /// /// 轨迹内容 @@ -37,14 +37,44 @@ public class TrackContentEntity : IFullAuditedBasicEntitys, IAggregateRoot public int SubSystemId { get; set; } /// - /// 轨迹标记id + /// 子系统名称 + /// + [SugarColumn(IsIgnore = true)] + public string SubSystem { get; set; } + + /// + /// 轨迹标记id,多个逗号分隔 /// [SugarColumn(ColumnName = "TrackFlagId")] - public int TrackFlagId { get; set; } + public string? TrackFlagId { get; set; } /// /// 所属轨迹状态id /// [SugarColumn(ColumnName = "TrackStatusId")] public int TrackStatusId { get; set; } -} \ No newline at end of file + + /// + /// 是否对外 + /// + [SugarColumn(ColumnName = "IsExternal")] + public bool IsExternal { get; set; } + + /// + /// 是否可重复 + /// + [SugarColumn(ColumnName = "IsRepeatable")] + public bool IsRepeatable { get; set; } + + /// + /// 是否允许手动修改 + /// + [SugarColumn(ColumnName = "IsAllowManuallyUpdate")] + public bool IsAllowManuallyUpdate { get; set; } + + /// + /// 是否允许手动创建 + /// + [SugarColumn(ColumnName = "IsAllowManuallyCreate")] + public bool IsAllowManuallyCreate { get; set; } +} diff --git a/src/SJZY.Track.Domain/Aggregates/TrackContentAggregate/TrackContentMapEntity.cs b/src/SJZY.Track.Domain/Aggregates/TrackContentAggregate/TrackContentMapEntity.cs index 1c20048f..7bf52c06 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackContentAggregate/TrackContentMapEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackContentAggregate/TrackContentMapEntity.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Aggregates.TrackContentAggregate; +namespace SJZY.Track.Domain.Aggregates.TrackContentAggregate; /// /// 轨迹内容映射表 @@ -47,4 +47,4 @@ public class TrackContentMapEntity : IFullAuditedBasicEntitys, IEntity /// [SugarColumn(ColumnName = "MapTrackContentCode")] public string MapTrackContentCode { get; set; } = null!; -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/FileItem.cs b/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/FileItem.cs new file mode 100644 index 00000000..2d2dc4a3 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/FileItem.cs @@ -0,0 +1,14 @@ +namespace SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; + +public class FileItem +{ + /// + /// 文件osskey + /// + public string OssKey { get; set; } + + /// + /// 文件名称 + /// + public string FileName { get; set; } +} diff --git a/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/ITrackDetailsEsRepository.cs b/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/ITrackDetailsEsRepository.cs new file mode 100644 index 00000000..48eac8cb --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/ITrackDetailsEsRepository.cs @@ -0,0 +1,40 @@ +using SJZY.Expand.ElasticSearch.Services; +using SJZY.Track.Domain.Dtos.TrackContents; +using SJZY.Track.Domain.Enums; + +namespace SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; + +public interface ITrackDetailsEsRepository : IElasticsearchClientService +{ + Task> GetListAsync(int[] orderIds, string trackCode, bool forUpsert = false); + + Task> GetLatestListAsync(int[] eventOrderIds, List trackCodes); + + Task> GetListAsync(int subSystemId, int orderType, List orderNos, List? trackCodes = null); + + Task AnyAsync(int orderId, string originTrackDataHash); + + Task UpdateAsync(TrackDetailsIndex index); + + Task UpdateManyAsync(List indexes, int maxRetries = 3); + + Task BulkUpdateAsync(List indexes, int maxRetries = 3); + + Task AddManyAsync(List index); + + Task AddAsync(TrackDetailsIndex track); + + Task> GetListAsync(int orderId); + + Task> GetListAsync(int[] orderIds, List? trackCodes = null, TrackSourceEnum? source = null); + + Task> DeleteTrackAsync(int[] orderIds, List trackCodes); + + Task DeleteTrackByIdAsync(string id, string indexName); + + Task> GetDataByIds(string[] ids); + + Task GetDetailAsync(string orderNo, string trackCode, int orderType, int subSystemId, DateTime trackTime); + + Task MigrateAsync(); +} diff --git a/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/ITrackDetailsRepository.cs b/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/ITrackDetailsRepository.cs deleted file mode 100644 index 4e4a0b9c..00000000 --- a/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/ITrackDetailsRepository.cs +++ /dev/null @@ -1,29 +0,0 @@ -using SJZY.Track.Domain.Dtos.TrackDetails; - -namespace SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; - -public interface ITrackDetailsRepository -{ - Task> GetListAsync(int[] orderIds, string trackCode, bool forUpsert = false); - - Task> GetLatestListAsync(int[] eventOrderIds, List trackCodes); - - Task AnyAsync(int orderId, DateTime trackTime); - - Task AnyAsync(int orderId, string originTrackData); - - Task AnyByCodeAsync(int orderId, string trackCode); - - Task UpdateAsync(TrackDetailsIndex index); - - Task AddManyAsync(List index); - - Task AddAsync(TrackDetailsIndex track); - - Task> GetListAsync(int orderType, List orderNos); - - Task<(List list, long total)> GetListAsync(TrackDetailsQueryInput input); - Task> GetListAsync(int orderId); - - Task DeleteTrackAsync(int[] orderIds, List trackCodes); -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/TrackDetailsIndex.cs b/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/TrackDetailsIndex.cs index 7cb77e84..9cb1adec 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/TrackDetailsIndex.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/TrackDetailsIndex.cs @@ -4,9 +4,14 @@ using SJZY.Track.Domain.Consts; namespace SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; -[ElasticsearchType(RelationName = GlobalConst.TrackIndex)] +[ElasticsearchType(RelationName = GlobalConst.TrackDetailsIndex)] public class TrackDetailsIndex : IdBaseIndex { + /// + /// 子系统 + /// + public int SubSystemId { get; set; } + /// /// 订单Id /// @@ -27,45 +32,60 @@ public class TrackDetailsIndex : IdBaseIndex /// public int OrderType { get; set; } + /// + /// 轨迹状态Id + /// + public int TrackStatusId { get; set; } = GlobalConst.NotExistId; + /// /// 轨迹状态 /// - public string TrackStatus { get; set; } = null!; + public string TrackStatus { get; set; } = GlobalConst.EmptyString; + + /// + /// 轨迹状态code + /// + public string TrackStatusCode { get; set; } = GlobalConst.EmptyString; + + /// + /// 轨迹内容Id + /// + public int TrackContentId { get; set; } = GlobalConst.NotExistId; /// /// 轨迹内容代码 /// - public string TrackCode { get; set; } = null!; + public string TrackCode { get; set; } = GlobalConst.EmptyString; /// /// 轨迹内容 /// - public string TrackContent { get; set; } = null!; - - /// - /// 服务商 - /// - public string? ServiceProviderName { get; set; } - - /// - /// 原轨迹内容 - /// - public string? OriginTrackContent { get; set; } - - /// - /// 原轨迹报文 - /// - public string? OriginTrackData { get; set; } + public string TrackContent { get; set; } = GlobalConst.EmptyString; /// /// 轨迹内容英文 /// - public string TrackEnContent { get; set; } = null!; + public string TrackEnContent { get; set; } = GlobalConst.EmptyString; + + /// + /// 服务商code + /// + public string ServiceProviderCode { get; set; } = GlobalConst.EmptyString; + + /// + /// 原轨迹内容 + /// + public string? OriginTrackContent { get; set; } = GlobalConst.EmptyString; + + /// + /// 原轨迹报文hash(刷新轨迹重复性校验使用) + /// + public string OriginTrackDataHash { get; set; } = null!; /// /// 轨迹发生地 /// - public string TrackPlace { get; set; } = null!; + public string TrackPlace { get; set; } = GlobalConst.EmptyString; /// /// 轨迹发生时间 @@ -82,18 +102,99 @@ public class TrackDetailsIndex : IdBaseIndex /// public DateTime ZeroTrackTime { get; set; } - /// 是否可删 - public bool IsCanDelete { get; set; } + /// + /// 创建人 + /// + public string CreateUser { get; set; } = GlobalConst.EmptyString; - /// 创建人 - public string? CreateUser { get; set; } - - /// 创建时间 + /// + /// 创建时间 + /// public DateTime CreateTime { get; set; } - /// 修改人 - public string? UpdateUser { get; set; } + /// + /// 修改人 + /// + public string UpdateUser { get; set; } = GlobalConst.EmptyString; - /// 修改时间 + /// + /// 修改时间 + /// public DateTime? UpdateTime { get; set; } -} \ No newline at end of file + + /// + /// 客户是否可见 + /// + [Obsolete("废弃的,请使用IsExternal")] + public bool IsVisibility { get; set; } + + /// + /// 是否对外 + /// + public bool IsExternal { get; set; } + + /// + /// 数据来源:1外部服务商创建,2内部系统创建,3人工创建 + /// + public int Source { get; set; } + + /// + /// 备注 + /// + public string? Remarks { get; set; } = GlobalConst.EmptyString; + + /// + /// 附件集合 + /// + public List? Files { get; set; } + + /// + /// 轨迹发生地(城市) + /// + public string? TrackPlaceCity { get; set; } = GlobalConst.EmptyString; + + /// + /// 轨迹发生地(城市)Id + /// + public int? TrackPlaceCityId { get; set; } = GlobalConst.NotExistId; + + /// + /// 轨迹发生地(省/州) + /// + public string? TrackPlaceProvince { get; set; } = GlobalConst.EmptyString; + + /// + ///轨迹发生地(省/州)Id + /// + public int? TrackPlaceProvinceId { get; set; } = GlobalConst.NotExistId; + + /// + /// 轨迹发生地(国家/地区) + /// + public string? TrackPlaceNation { get; set; } = GlobalConst.EmptyString; + + /// + /// 轨迹发生地(国家/地区)Id + /// + public int? TrackPlaceNationId { get; set; } = GlobalConst.NotExistId; + + /// + /// 轨迹发生地邮编 + /// + public string? TrackPlacePostcode { get; set; } = GlobalConst.EmptyString; + + /// + /// 预计签收时间 + /// + public DateTime? EstimatedDeliveryDate { get; set; } + + /// + /// 签收地时区 + /// + public float? DestinationTimeZone { get; set; } + + /// + /// 扩展信息字段,用与轨迹推送的附加字段 + /// + public string? Extra { get; set; } +} diff --git a/src/SJZY.Track.Domain/Aggregates/TrackFlagAggregate/ITrackFlagRepository.cs b/src/SJZY.Track.Domain/Aggregates/TrackFlagAggregate/ITrackFlagRepository.cs index 12ba3bc6..3868a195 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackFlagAggregate/ITrackFlagRepository.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackFlagAggregate/ITrackFlagRepository.cs @@ -1,4 +1,4 @@ -using SJZY.Track.Domain.Dtos.TrackFlags; +using SJZY.Track.Domain.Dtos.TrackFlags; namespace SJZY.Track.Domain.Aggregates.TrackFlagAggregate; @@ -6,4 +6,4 @@ public interface ITrackFlagRepository : IBasicRepository { Task GetDetailAsync(int id); Task> GetPageTrackFlag(GetPageTrackFlagVO input); -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Aggregates/TrackFlagAggregate/TrackFlagEntity.cs b/src/SJZY.Track.Domain/Aggregates/TrackFlagAggregate/TrackFlagEntity.cs index 225c8f85..bd43d84f 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackFlagAggregate/TrackFlagEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackFlagAggregate/TrackFlagEntity.cs @@ -30,9 +30,9 @@ public class TrackFlagEntity : IFullAuditedBasicEntitys, IAggregateRoot [SugarColumn(ColumnName = "SubSystemId")] public int SubSystemId { get; set; } - ///// - ///// 是否完结 - ///// - //[SugarColumn(ColumnName = "IsCompleted")] - //public bool IsCompleted { get; set; } -} \ No newline at end of file + /// + /// 是否广播 + /// + [SugarColumn(ColumnName = "IsToMq")] + public bool IsToMq { get; set; } +} diff --git a/src/SJZY.Track.Domain/Aggregates/TrackNodeAggregate/ITrackNodeRepository.cs b/src/SJZY.Track.Domain/Aggregates/TrackNodeAggregate/ITrackNodeRepository.cs new file mode 100644 index 00000000..80c29962 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/TrackNodeAggregate/ITrackNodeRepository.cs @@ -0,0 +1,34 @@ +using SJZY.Track.Domain.Dtos.TrackNode; + +namespace SJZY.Track.Domain.Aggregates.TrackNodeAggregate; + +public interface ITrackNodeRepository : IBasicRepository +{ + /// + /// 分页查询 + /// + /// + /// + Task> GetPageList(TrackNodePageDto queryParam); + + /// + /// 分页查询字典 + /// + /// + /// + Task> GetPageDicList(TrackNodePageDto queryParam); + + /// + /// 删除 + /// + /// + /// + Task DeleteById(long inputId); + + /// + /// 获取详情 + /// + /// + /// + Task GetDetail(long id); +} diff --git a/src/SJZY.Track.Domain/Aggregates/TrackNodeAggregate/TrackNodeEntity.cs b/src/SJZY.Track.Domain/Aggregates/TrackNodeAggregate/TrackNodeEntity.cs new file mode 100644 index 00000000..2e9432f8 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/TrackNodeAggregate/TrackNodeEntity.cs @@ -0,0 +1,32 @@ +namespace SJZY.Track.Domain.Aggregates.TrackNodeAggregate; + +/// +/// 轨迹节点主表 +/// +[SugarTable("t_track_node", TableDescription = "轨迹节点主表")] +public class TrackNodeEntity : IFullAuditedBasicEntitys, IAggregateRoot +{ + /// + /// 自增主键 + /// + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true, ColumnDescription = "自增主键")] + public long Id { get; set; } + + /// + /// 子系统id + /// + [SugarColumn(ColumnName = "SubSystemId", ColumnDescription = "子系统id")] + public int SubSystemId { get; set; } + + /// + /// 节点名称 + /// + [SugarColumn(ColumnName = "NodeName", Length = 32, ColumnDescription = "节点名称")] + public string NodeName { get; set; } + + /// + /// 节点英文名称 + /// + [SugarColumn(ColumnName = "NodeEnName", Length = 32, ColumnDescription = "节点英文名称")] + public string NodeEnName { get; set; } +} diff --git a/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/ITrackPullConfigRepository.cs b/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/ITrackPullConfigRepository.cs index c21eef77..28534b3f 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/ITrackPullConfigRepository.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/ITrackPullConfigRepository.cs @@ -1,4 +1,4 @@ -using SJZY.Track.Domain.Dtos.Common; +using SJZY.Track.Domain.Dtos.Common; using SJZY.Track.Domain.Dtos.TrackPull; namespace SJZY.Track.Domain.Aggregates.TrackPullAggregate; @@ -31,7 +31,7 @@ public interface ITrackPullConfigRepository : IBasicRepository /// /// - Task GetDetailAsync(int id); + Task GetDetailAsync(int id); /// /// 轨迹拉取配置内容详情 @@ -40,21 +40,14 @@ public interface ITrackPullConfigRepository : IBasicRepository Task GetContentDetailAsync(int id); - Task InsertParamsAsync(TrackPushPullParamsConfigEntity insertObj); - Task InsertContentAsync(TrackPullContentConfigEntity insertObj); - Task GetParamsSingleAsync(Expression> whereExpression); - - Task UpdateParamsAsync(TrackPushPullParamsConfigEntity updateObj); - Task SoftDeleteContentAsync(Expression> whereExpression); - Task SoftDeleteParamsAsync(Expression> whereExpression); - Task GetContentByIdAsync(int id); Task UpdateContentAsync(TrackPullContentConfigEntity updateObj); Task IsContentAnyAsync(Expression> whereExpression); -} \ No newline at end of file + Task FindIdAsync(int subSystemId, string serviceProviderCode); +} diff --git a/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/ParseMethod.cs b/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/ParseMethod.cs new file mode 100644 index 00000000..96df3144 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/ParseMethod.cs @@ -0,0 +1,17 @@ +namespace SJZY.Track.Domain.Aggregates.TrackPullAggregate; + +/// +/// 解析方式 +/// +public enum ParseMethod +{ + /// + /// 接口通映射后 + /// + InterfaceRelay = 1, + + /// + /// 服务商原返回 + /// + ServiceProviderOriginal = 2 +} diff --git a/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/TrackPullConfigEntity.cs b/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/TrackPullConfigEntity.cs index 4c6d7ed7..5862d0f7 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/TrackPullConfigEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/TrackPullConfigEntity.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Aggregates.TrackPullAggregate; +namespace SJZY.Track.Domain.Aggregates.TrackPullAggregate; /// /// 轨迹拉取配置表 @@ -13,16 +13,10 @@ public class TrackPullConfigEntity : IFullAuditedBasicEntitys, IAggregateRoot public int Id { get; set; } /// - /// 解析方式,1取接口通返参映射后的,2取服务商原返参 + /// 子系统id /// - [SugarColumn(ColumnName = "ParseMethod")] - public int ParseMethod { get; set; } - - /// - /// 服务商拉取频率(分钟) - /// - [SugarColumn(ColumnName = "PullInterval")] - public int PullInterval { get; set; } + [SugarColumn(ColumnName = "SubSystemId")] + public int SubSystemId { get; set; } /// /// 服务商id @@ -31,8 +25,68 @@ public class TrackPullConfigEntity : IFullAuditedBasicEntitys, IAggregateRoot public int ServiceProviderId { get; set; } /// - /// 子系统id + /// 服务商拉取频率(分钟) /// - [SugarColumn(ColumnName = "SubSystemId")] - public int SubSystemId { get; set; } -} \ No newline at end of file + [SugarColumn(ColumnName = "PullInterval")] + public int PullInterval { get; set; } + + /// + /// 解析方式,1取接口通返参映射后的,2取服务商原返参 + /// + [SugarColumn(ColumnName = "ParseMethod")] + public ParseMethod ParseMethod { get; set; } + + /// + /// 订单路径 + /// + [SugarColumn(ColumnName = "OrderPath")] + public string OrderPath { get; set; } = null!; + + /// + /// 单号参数名 + /// + [SugarColumn(ColumnName = "OrderNoName")] + public string OrderNoName { get; set; } = null!; + + /// + /// 轨迹明细路径 + /// + [SugarColumn(ColumnName = "TrackDetailsPath")] + public string TrackDetailsPath { get; set; } = null!; + + /// + /// 轨迹状态参数名 + /// + [SugarColumn(ColumnName = "TrackStatusName")] + public string? TrackStatusName { get; set; } + + /// + /// 轨迹代码参数名 + /// + [SugarColumn(ColumnName = "TrackContentCodeName")] + public string? TrackContentCodeName { get; set; } + + /// + /// 轨迹内容参数名 + /// + [SugarColumn(ColumnName = "TrackContentName")] + public string? TrackContentName { get; set; } + + /// + /// 轨迹发生地参数名 + /// + [SugarColumn(ColumnName = "TrackPlaceName")] + public string? TrackPlaceName { get; set; } + + /// + /// 轨迹发生时间参数名 + /// + [SugarColumn(ColumnName = "TrackTimeName")] + public string? TrackTimeName { get; set; } + + /// + /// 轨迹时区参数名 + /// + [SugarColumn(ColumnName = "TrackTimeZoneName")] + public string? TrackTimeZoneName { get; set; } +} diff --git a/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/TrackPullContentConfigEntity.cs b/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/TrackPullContentConfigEntity.cs index 5afef0fb..43a55bc7 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/TrackPullContentConfigEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/TrackPullContentConfigEntity.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Aggregates.TrackPullAggregate; +namespace SJZY.Track.Domain.Aggregates.TrackPullAggregate; /// /// 轨迹拉取内容配置表 @@ -13,10 +13,10 @@ public class TrackPullContentConfigEntity : IFullAuditedBasicEntitys, IEntity public int Id { get; set; } /// - /// 服务商轨迹代码参数值 + /// 轨迹拉取配置id /// - [SugarColumn(ColumnName = "TrackContentCodeValue")] - public string? TrackContentCodeValue { get; set; } + [SugarColumn(ColumnName = "TrackPullConfigId")] + public int TrackPullConfigId { get; set; } /// /// 轨迹内容id @@ -25,10 +25,10 @@ public class TrackPullContentConfigEntity : IFullAuditedBasicEntitys, IEntity public int TrackContentId { get; set; } /// - /// 服务商轨迹内容参数值 + /// 服务商轨迹状态参数值,多个逗分隔 /// - [SugarColumn(ColumnName = "TrackContentValue")] - public string? TrackContentValue { get; set; } + [SugarColumn(ColumnName = "TrackStatusValue")] + public string? TrackStatusValue { get; set; } /// /// 轨迹关键词(正向),多个逗分隔 @@ -43,32 +43,14 @@ public class TrackPullContentConfigEntity : IFullAuditedBasicEntitys, IEntity public string? TrackKeywordReverse { get; set; } /// - /// 轨迹发生地参数值(主数据枚举) + /// 兜底轨迹发生地参数值 /// [SugarColumn(ColumnName = "TrackPlaceValue")] public int? TrackPlaceValue { get; set; } /// - /// 轨迹拉取配置id + /// 兜底轨迹时区所属发生地参数值 /// - [SugarColumn(ColumnName = "TrackPullConfigId")] - public int TrackPullConfigId { get; set; } - - /// - /// 服务商轨迹状态参数值 - /// - [SugarColumn(ColumnName = "TrackStatusValue")] - public string? TrackStatusValue { get; set; } - - /// - /// 轨迹时区GMT - /// - [SugarColumn(ColumnName = "TrackTimeZone")] - public float? TrackTimeZone { get; set; } - - /// - /// 是否完结 - /// - [SugarColumn(ColumnName = "IsCompleted")] - public bool IsCompleted { get; set; } -} \ No newline at end of file + [SugarColumn(ColumnName = "TrackZonePlaceValue")] + public int? TrackZonePlaceValue { get; set; } +} diff --git a/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/TrackPushPullParamsConfigEntity.cs b/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/TrackPushPullParamsConfigEntity.cs deleted file mode 100644 index 59ea07e1..00000000 --- a/src/SJZY.Track.Domain/Aggregates/TrackPullAggregate/TrackPushPullParamsConfigEntity.cs +++ /dev/null @@ -1,92 +0,0 @@ -namespace SJZY.Track.Domain.Aggregates.TrackPullAggregate; - -/// -/// 轨迹拉取/推送参数配置 -/// -[SugarTable("t_track_push_pull_params_config")] -public class TrackPushPullParamsConfigEntity : IFullAuditedBasicEntitys, IEntity -{ - /// - /// 自增主键 - /// - [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] - public int Id { get; set; } - - /// - /// 推拉模式,0拉取,1推送 - /// - [SugarColumn(ColumnName = "IsPush")] - public bool IsPush { get; set; } - - /// - /// 单号参数名 - /// - [SugarColumn(ColumnName = "OrderNoName")] - public string OrderNoName { get; set; } = null!; - - /// - /// 推拉配置id - /// - [SugarColumn(ColumnName = "PullOrPushConfigId")] - public int PullOrPushConfigId { get; set; } - - /// - /// 轨迹时区参数名 - /// - [SugarColumn(ColumnName = "TrackTimeZoneName")] - public string? TrackTimeZoneName { get; set; } - - /// - /// 轨迹代码参数名 - /// - [SugarColumn(ColumnName = "TrackContentCodeName")] - public string? TrackContentCodeName { get; set; } - - /// - /// 轨迹内容参数名 - /// - [SugarColumn(ColumnName = "TrackContentName")] - public string? TrackContentName { get; set; } - - /// - /// 轨迹内容英文参数名 - /// - [SugarColumn(ColumnName = "TrackEnContentName")] - public string? TrackEnContentName { get; set; } - - /// - /// 轨迹发生地参数名 - /// - [SugarColumn(ColumnName = "TrackPlaceName")] - public string? TrackPlaceName { get; set; } - - /// - /// 轨迹状态参数名 - /// - [SugarColumn(ColumnName = "TrackStatusName")] - public string? TrackStatusName { get; set; } - - /// - /// 轨迹发生时间参数名 - /// - [SugarColumn(ColumnName = "TrackTimeName")] - public string? TrackTimeName { get; set; } - - /// - /// 订单路径 - /// - [SugarColumn(ColumnName = "OrderPath")] - public string? OrderPath { get; set; } - - /// - /// 轨迹明细路径 - /// - [SugarColumn(ColumnName = "TrackDetailsPath")] - public string? TrackDetailsPath { get; set; } - - /// - /// 扩展字段参数名 - /// - [SugarColumn(ColumnName = "ExpandFieldsName")] - public string? ExpandFieldsName { get; set; } -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/TrackPushAggregate/ITrackPushConfigRepository.cs b/src/SJZY.Track.Domain/Aggregates/TrackPushAggregate/ITrackPushConfigRepository.cs index 3983cd7c..7784d57f 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackPushAggregate/ITrackPushConfigRepository.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackPushAggregate/ITrackPushConfigRepository.cs @@ -1,4 +1,4 @@ -using SJZY.Track.Domain.Dtos.Common; +using SJZY.Track.Domain.Dtos.Common; using SJZY.Track.Domain.Dtos.TrackPush; namespace SJZY.Track.Domain.Aggregates.TrackPushAggregate; @@ -35,5 +35,8 @@ public interface ITrackPushConfigRepository : IBasicRepository UpdateContentAsync(Expression> columns, Expression> whereExpression); + Task> QueryTrackPullMappingsAsync(QueryTrackPullMappingsInputVO input); -} \ No newline at end of file + Task> GetTrackPushContentListAsync(int subSystemId, int customerId); + Task GetServiceCodeByCustomerIdAsync(int customerId); +} diff --git a/src/SJZY.Track.Domain/Aggregates/TrackPushAggregate/ITrackPushRecordEsRepository.cs b/src/SJZY.Track.Domain/Aggregates/TrackPushAggregate/ITrackPushRecordEsRepository.cs new file mode 100644 index 00000000..de1f0fa3 --- /dev/null +++ b/src/SJZY.Track.Domain/Aggregates/TrackPushAggregate/ITrackPushRecordEsRepository.cs @@ -0,0 +1,43 @@ +namespace SJZY.Track.Domain.Aggregates.TrackPushAggregate; + +public interface ITrackPushRecordEsRepository +{ + /// + /// 添加推送记录 + /// + /// + /// + Task AddAsync(TrackPushRecordIndex index); + + Task AddManyAsync(List index); + + /// + /// 根据id删除轨迹推送记录 + /// + /// + /// + /// + Task DeletePushRecordByIdAsync(string id, string indexName); + + /// + /// 获取轨迹推送记录 + /// + /// + /// + Task> GetTrackPushRecordsAsync(int orderId); + + /// + /// 获取最新轨迹推送记录 + /// + /// + /// 只选择成功的记录 + /// + Task GetLatestTrackPushRecordAsync(int orderId, bool isSuccess = false); + + /// + /// 获取历史中推送成功的记录 + /// + /// + /// + Task> GetHistorySuccessTrackPushRecordAsync(int orderId); +} diff --git a/src/SJZY.Track.Domain/Aggregates/TrackPushAggregate/ITrackPushRecordsRepository.cs b/src/SJZY.Track.Domain/Aggregates/TrackPushAggregate/ITrackPushRecordsRepository.cs deleted file mode 100644 index 99276b4b..00000000 --- a/src/SJZY.Track.Domain/Aggregates/TrackPushAggregate/ITrackPushRecordsRepository.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace SJZY.Track.Domain.Aggregates.TrackPushAggregate; - -public interface ITrackPushRecordsRepository -{ - /// - /// 添加推送记录 - /// - /// - /// - Task AddAsync(TrackPushRecordIndex index); - - Task AddManyAsync(List index); - - /// - /// 获取轨迹推送记录 - /// - /// - /// - Task> GetTrackPushRecordsAsync(int orderId); - - /// - /// 获取最新轨迹推送记录 - /// - /// - /// - Task GetLatestTrackPushRecordAsync(int orderId); -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Aggregates/TrackPushAggregate/TrackPushConfigEntity.cs b/src/SJZY.Track.Domain/Aggregates/TrackPushAggregate/TrackPushConfigEntity.cs index 659e3281..8dc04097 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackPushAggregate/TrackPushConfigEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackPushAggregate/TrackPushConfigEntity.cs @@ -1,4 +1,6 @@ -namespace SJZY.Track.Domain.Aggregates.TrackPushAggregate; +using SJZY.Track.Domain.Enums; + +namespace SJZY.Track.Domain.Aggregates.TrackPushAggregate; /// /// 轨迹推送配置表 @@ -27,8 +29,8 @@ public class TrackPushConfigEntity : IFullAuditedBasicEntitys, IAggregateRoot /// /// 服务商id(客户:服务商 1:1) /// - [SugarColumn(ColumnName = "ServiceProviderId")] - public int ServiceProviderId { get; set; } + [SugarColumn(ColumnName = "ServiceProviderCode")] + public string ServiceProviderCode { get; set; } /// /// 子系统id @@ -53,4 +55,28 @@ public class TrackPushConfigEntity : IFullAuditedBasicEntitys, IAggregateRoot /// [SugarColumn(ColumnName = "IsAllPush")] public bool IsAllPush { get; set; } -} \ No newline at end of file + + /// + /// 是否全量推送(最新轨迹) + /// + [SugarColumn(ColumnName = "IsAllPushWithLatest")] + public bool IsAllPushWithLatest { get; set; } + + /// + /// 日期时间格式类型 + /// + [SugarColumn(ColumnName = "DateTimeFormatType")] + public DateTimeFormatEnum DateTimeFormatType { get; set; } + + /// + /// 日期时间格式模板 + /// + [SugarColumn(ColumnName = "DateTimeFormat")] + public string? DateTimeFormat { get; set; } + + /// + /// 时区格式格式模板 + /// + [SugarColumn(ColumnName = "TimezoneFormat")] + public string? TimezoneFormat { get; set; } +} diff --git a/src/SJZY.Track.Domain/Aggregates/TrackPushAggregate/TrackPushContentConfigEntity.cs b/src/SJZY.Track.Domain/Aggregates/TrackPushAggregate/TrackPushContentConfigEntity.cs index 163b5b34..5d9b9c02 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackPushAggregate/TrackPushContentConfigEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackPushAggregate/TrackPushContentConfigEntity.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Aggregates.TrackPushAggregate; +namespace SJZY.Track.Domain.Aggregates.TrackPushAggregate; /// /// 轨迹推送内容配置表 @@ -77,4 +77,4 @@ public class TrackPushContentConfigEntity : IFullAuditedBasicEntitys, IEntity /// [SugarColumn(ColumnName = "ExpandFieldsValue")] public string ExpandFieldsValue { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Aggregates/TrackPushAggregate/TrackPushRecordIndex.cs b/src/SJZY.Track.Domain/Aggregates/TrackPushAggregate/TrackPushRecordIndex.cs index 956e241d..d127b5c4 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackPushAggregate/TrackPushRecordIndex.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackPushAggregate/TrackPushRecordIndex.cs @@ -1,10 +1,10 @@ -using Nest; +using Nest; using SJZY.Expand.ElasticSearch; using SJZY.Track.Domain.Consts; namespace SJZY.Track.Domain.Aggregates.TrackPushAggregate; -[ElasticsearchType(RelationName = GlobalConst.TrackPushRecordsIndex)] +[ElasticsearchType(RelationName = GlobalConst.TrackPushRecordIndex)] public class TrackPushRecordIndex : IdBaseIndex { /// @@ -82,4 +82,19 @@ public class TrackPushRecordIndex : IdBaseIndex /// 创建时间 public DateTime CreateTime { get; set; } -} \ No newline at end of file + + /// + /// 子系统代码 + /// + public string SubSystemCode { get; set; } + + /// + /// 是否广播 + /// + public bool IsToMq { get; set; } + + /// + /// 轨迹额外信息 + /// + public string? Extra { get; set; } +} diff --git a/src/SJZY.Track.Domain/Aggregates/TrackStatusAggregate/ITrackStatusRepository.cs b/src/SJZY.Track.Domain/Aggregates/TrackStatusAggregate/ITrackStatusRepository.cs index 5123bd2b..809ceea2 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackStatusAggregate/ITrackStatusRepository.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackStatusAggregate/ITrackStatusRepository.cs @@ -5,5 +5,5 @@ namespace SJZY.Track.Domain.Aggregates.TrackStatusAggregate; public interface ITrackStatusRepository : IBasicRepository { Task GetDetailAsync(int id); - Task> GetPageTrackStatus(GetPageTrackStatusVO input); -} \ No newline at end of file + Task> GetPageTrackStatus(GetPagedTrackStatusVO input); +} diff --git a/src/SJZY.Track.Domain/Aggregates/TrackStatusAggregate/TrackStatusEntity.cs b/src/SJZY.Track.Domain/Aggregates/TrackStatusAggregate/TrackStatusEntity.cs index dd98a21d..b0fa80b7 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackStatusAggregate/TrackStatusEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackStatusAggregate/TrackStatusEntity.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Aggregates.TrackStatusAggregate; +namespace SJZY.Track.Domain.Aggregates.TrackStatusAggregate; /// /// 轨迹状态表 @@ -12,24 +12,24 @@ public class TrackStatusEntity : IFullAuditedBasicEntitys, IAggregateRoot [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] public int Id { get; set; } + /// + /// 子系统id + /// + [SugarColumn(ColumnName = "SubSystemId")] + public int SubSystemId { get; set; } + + /// + /// 所属节点(来自表 t_track_node) 之前是枚举,后续调整为表 + /// + [SugarColumn(ColumnName = "Node")] + public int Node { get; set; } + /// /// 轨迹状态代码 /// [SugarColumn(ColumnName = "Code")] public string Code { get; set; } = null!; - /// - /// 轨迹状态英文 - /// - [SugarColumn(ColumnName = "EnStatus")] - public string EnStatus { get; set; } = null!; - - /// - /// 所属节点(主数据枚举ServiceNode) - /// - [SugarColumn(ColumnName = "Node")] - public int Node { get; set; } - /// /// 轨迹状态 /// @@ -37,8 +37,20 @@ public class TrackStatusEntity : IFullAuditedBasicEntitys, IAggregateRoot public string Status { get; set; } = null!; /// - /// 子系统id + /// 轨迹状态英文 /// - [SugarColumn(ColumnName = "SubSystemId")] - public int SubSystemId { get; set; } -} \ No newline at end of file + [SugarColumn(ColumnName = "EnStatus")] + public string EnStatus { get; set; } = null!; + + /// + /// 是否完结 + /// + [SugarColumn(ColumnName = "IsCompleted")] + public bool IsCompleted { get; set; } + + /// + /// 是否广播 + /// + [SugarColumn(ColumnName = "IsToMq")] + public bool IsToMq { get; set; } +} diff --git a/src/SJZY.Track.Domain/Aggregates/TrackTemplateAggregate/ITrackTemplateRepository.cs b/src/SJZY.Track.Domain/Aggregates/TrackTemplateAggregate/ITrackTemplateRepository.cs index 1f36d840..e8a50f2d 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackTemplateAggregate/ITrackTemplateRepository.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackTemplateAggregate/ITrackTemplateRepository.cs @@ -1,5 +1,4 @@ -using SJZY.Expand.ABP.Core.PublicMethords; -using SJZY.Track.Domain.Dtos.TrackTemplate; +using SJZY.Track.Domain.Dtos.TrackTemplate; namespace SJZY.Track.Domain.Aggregates.TrackTemplateAggregate; @@ -22,7 +21,7 @@ public interface ITrackTemplateRepository : IBasicRepository /// /// - Task GetContentDetailAsync(int id); + Task GetContentDetailAsync(int id); Task IsContentAnyAsync(Expression> whereExpression); @@ -39,7 +38,15 @@ public interface ITrackTemplateRepository : IBasicRepository UpdateContentRangeAsync(List updateObjs); - Task ContentMaxAsync(Expression> columns, Expression> whereExpression); + Task ContentMaxAsync(Expression> columns, + Expression> whereExpression); - Task UpdateContentAsync(Expression> columns, Expression> whereExpression); -} \ No newline at end of file + Task UpdateContentAsync(Expression> columns, + Expression> whereExpression); + + Task> GetTrackTemplateListAsync(GetTrackTemplateListInputVo input); + + Task> GetPageTrackTemplateListAsync(GetPageTrackTemplateListInputVo input); + + Task> GetContentByTemplateCodes(string[] codes, int systemId); +} diff --git a/src/SJZY.Track.Domain/Aggregates/TrackTemplateAggregate/TrackTemplateContentEntity.cs b/src/SJZY.Track.Domain/Aggregates/TrackTemplateAggregate/TrackTemplateContentEntity.cs index 3d8ba38a..f8874401 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackTemplateAggregate/TrackTemplateContentEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackTemplateAggregate/TrackTemplateContentEntity.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Aggregates.TrackTemplateAggregate; +namespace SJZY.Track.Domain.Aggregates.TrackTemplateAggregate; /// /// 轨迹模板内容表(1:N) @@ -12,18 +12,6 @@ public class TrackTemplateContentEntity : IFullAuditedBasicEntitys, IEntity [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] public int Id { get; set; } - /// - /// 是否可删 - /// - [SugarColumn(ColumnName = "IsCanDelete")] - public bool IsCanDelete { get; set; } - - /// - /// 是否对外 - /// - [SugarColumn(ColumnName = "IsExternal")] - public bool IsExternal { get; set; } - /// /// 排序 /// @@ -41,4 +29,4 @@ public class TrackTemplateContentEntity : IFullAuditedBasicEntitys, IEntity /// [SugarColumn(ColumnName = "TrackTemplateId")] public int TrackTemplateId { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Aggregates/TrackTemplateAggregate/TrackTemplateEntity.cs b/src/SJZY.Track.Domain/Aggregates/TrackTemplateAggregate/TrackTemplateEntity.cs index f99eaec0..d525300f 100644 --- a/src/SJZY.Track.Domain/Aggregates/TrackTemplateAggregate/TrackTemplateEntity.cs +++ b/src/SJZY.Track.Domain/Aggregates/TrackTemplateAggregate/TrackTemplateEntity.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Aggregates.TrackTemplateAggregate; +namespace SJZY.Track.Domain.Aggregates.TrackTemplateAggregate; /// /// 轨迹模板表 @@ -31,8 +31,14 @@ public class TrackTemplateEntity : IFullAuditedBasicEntitys, IAggregateRoot public int SubSystemId { get; set; } /// - /// 显示原轨迹 + /// 分类id /// - [SugarColumn(ColumnName = "ShowOrigin")] - public bool ShowOrigin { get; set; } -} \ No newline at end of file + [SugarColumn(ColumnName = "CategoryId")] + public int CategoryId { get; set; } + + /// + /// 客户id + /// + [SugarColumn(ColumnName = "CustomerId")] + public int CustomerId { get; set; } +} diff --git a/src/SJZY.Track.Domain/Consts/GlobalConst.ES.cs b/src/SJZY.Track.Domain/Consts/GlobalConst.ES.cs index 3dd246c4..0a0a5d9c 100644 --- a/src/SJZY.Track.Domain/Consts/GlobalConst.ES.cs +++ b/src/SJZY.Track.Domain/Consts/GlobalConst.ES.cs @@ -3,12 +3,22 @@ namespace SJZY.Track.Domain.Consts; public partial class GlobalConst { /// - /// 轨迹明细 es索引名称(模板) + /// 轨迹明细 es索引名称(模板按天) /// - public const string TrackIndex = "sjzy_track_details"; + public const string TrackDetailsIndex = "sjzy_track_details"; /// - /// 轨迹推送记录 es索引名称(模板) + /// 轨迹推送记录 es索引名称(模板按天) /// - public const string TrackPushRecordsIndex = "sjzy_track_push_records"; -} \ No newline at end of file + public const string TrackPushRecordIndex = "sjzy_track_push_records"; + + /// + /// 运输时效预警记录 es索引名称(模板按天) + /// + public const string TrackWarningRecordIndex = "sjzy_track_warning_records"; + + /// + /// 订单操作记录 es索引名称(模板按天) + /// + public const string OrderOperationRecordIndex = "sjzy_track_order_operation_records"; +} diff --git a/src/SJZY.Track.Domain/Consts/GlobalConst.MQ.cs b/src/SJZY.Track.Domain/Consts/GlobalConst.MQ.cs index 378f0b89..93b5b277 100644 --- a/src/SJZY.Track.Domain/Consts/GlobalConst.MQ.cs +++ b/src/SJZY.Track.Domain/Consts/GlobalConst.MQ.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Consts; +namespace SJZY.Track.Domain.Consts; public partial class GlobalConst { @@ -12,11 +12,6 @@ public partial class GlobalConst /// public const string TrackUpsertForRefreshSubscribe = "SJZY.Track.TrackUpsertForRefresh"; - /// - /// 无法映射的轨迹新增 - /// - public const string TrackInsertForNotMappedEventSubscribe = "SJZY.Track.TrackInsertForNotMapped"; - /// /// 轨迹删除 /// @@ -37,6 +32,11 @@ public partial class GlobalConst /// public const string TrackManualPushSubscribe = "SJZY.Track.TrackManualPush"; + /// + /// 接口通交换机 + /// + public const string InterfaceRelayExchange = "sjzy.interface.relay.direct"; + /// /// 轨迹推送完成(接口通回调) /// @@ -48,12 +48,17 @@ public partial class GlobalConst public const string TrackChangeAfterUpdateOrderSubscribe = "SJZY.Track.TrackChangeAfterUpdateOrder"; /// - /// 轨迹推送后触发更新订单主表 + /// 预警计算任务 /// - public const string TrackPushAfterUpdateOrderSubscribe = "SJZY.Track.TrackPushAfterUpdateOrder"; + public const string TrackWarningCalcSubscribe = "SJZY.Track.TrackWarningCalc"; /// - /// 关联订单后补轨迹 + /// 轨迹变更通知交换机 /// - public const string OrderLinkAfterFillTrack = "SJZY.Track.OrderLinkAfterFillTrack"; -} \ No newline at end of file + public const string TrackChangeExchange = "sjzy.track.on_track_change_ex"; + + /// + /// 轨迹推送通知交换机 + /// + public const string TrackPushExchange = "sjzy.track.on_track_push_ex"; +} diff --git a/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs b/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs index e2ca18ae..918762fe 100644 --- a/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs +++ b/src/SJZY.Track.Domain/Consts/GlobalConst.Redis.cs @@ -21,4 +21,54 @@ public partial class GlobalConst /// 轨迹拉取配置信息redis key前缀 /// public const string TrackPullContentKeyPrefix = "TrackPullContent"; -} \ No newline at end of file + + /// + /// 预警通知set redis key + /// + public const string ForewarningNotifySetKey = "ForewarningNotifySet"; + + /// + /// 预警通知定时任务罚时 redis key + /// + public const string ForewarningNotifyCheckKey = "ForewarningNotifyCheck"; + + /// + /// 订单拉取状态扫描罚时 redis key + /// + public const string OrderPullStatusScanCheckKey = "OrderPullStatusScanCheck"; + + /// + /// kpi区域redis key前缀 + /// + public const string KpiAreaKeyPrefix = "KpiArea"; + + /// + /// 城市时区redis key前缀 + /// + public const string CityTimezoneKeyPrefix = "CityTimezone"; + + /// + /// 港口时区redis key前缀 + /// + public const string PortTimezoneKeyPrefix = "PortTimezone"; + + /// + /// 发布订阅通知频道Key + /// + public const string PublishNotifyChannelKey = "PublishNotifyChannel"; + + /// + /// 轨迹区域reids key + /// + public const string TrackAreaKeyPrefix = "TrackArea"; + + /// + /// 轨迹预警数据redis key前缀 + /// + public const string TrackWarningKeyPrefix = "TrackWarning"; + + /// + /// 轨迹推送预警redis key前缀 + /// + public const string TrackPushWaringKeyPrefix = "TrackPushWaring"; +} diff --git a/src/SJZY.Track.Domain/Consts/GlobalConst.Track.cs b/src/SJZY.Track.Domain/Consts/GlobalConst.Track.cs new file mode 100644 index 00000000..3ffed645 --- /dev/null +++ b/src/SJZY.Track.Domain/Consts/GlobalConst.Track.cs @@ -0,0 +1,16 @@ +using System.Collections.Immutable; + +namespace SJZY.Track.Domain.Consts; + +public partial class GlobalConst +{ + /// + /// 轨迹数据来源:1外部服务商创建,2内部系统创建,3人工创建 + /// + public static readonly ImmutableHashSet SupportTrackSources = ImmutableHashSet.Create(1, 2, 3); + + /// + /// 最大更新轨迹重试次数 + /// + public const int MaxUpdateTrackRetryCount = 3; +} diff --git a/src/SJZY.Track.Domain/Consts/GlobalConst.cs b/src/SJZY.Track.Domain/Consts/GlobalConst.cs index 22beb8e1..f081cacc 100644 --- a/src/SJZY.Track.Domain/Consts/GlobalConst.cs +++ b/src/SJZY.Track.Domain/Consts/GlobalConst.cs @@ -1,8 +1,22 @@ -namespace SJZY.Track.Domain.Consts; +namespace SJZY.Track.Domain.Consts; public partial class GlobalConst { + public const string MainDataKey_OrderType = "TrackOrderType"; + public const string MainDataKey_TrackQuestionType = "TrackQuestionType"; + public const string HTTP_HEADER_SUBSYSTEMID = "Subsystemid"; public const string SystemUser = "系统"; public const string EmptyString = "--"; public const int ChunkSize = 100; -} \ No newline at end of file + public const int SafelyLimit = 10000; + public const int NormalLimit = 10000; + public const int NotExistId = -9999; + + public const float NoneTrackTimeZone = 99999; + + public const string SuccessCode = "200"; + + public const string CapNoRetryErrorCode = "599"; + + public static DateTime MaxDateTime = new DateTime(2999, 1, 1, 0, 0, 0); +} diff --git a/src/SJZY.Track.Domain/Consts/InterfaceRelayConst.cs b/src/SJZY.Track.Domain/Consts/InterfaceRelayConst.cs deleted file mode 100644 index 24743a5b..00000000 --- a/src/SJZY.Track.Domain/Consts/InterfaceRelayConst.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace SJZY.Track.Domain.Consts; - -/// -/// 接口通常量 -/// -public class InterfaceRelayConst -{ - /// - /// 接口通成功代码 - /// - public const string SuccessCode = "200"; - - /// - /// 获取轨迹接口代码 - /// - public const string GetTrackInterfaceCode = "A012"; - - /// - /// 推送轨迹接口代码 - /// - public const string PushTrackInterfaceCode = "A024"; - - /// - /// 更新轨迹接口代码 - /// - public const string TrackUpdateInterfaceCode = "A040"; -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Common/CityTimezoneDto.cs b/src/SJZY.Track.Domain/Dtos/Common/CityTimezoneDto.cs new file mode 100644 index 00000000..998ad0c6 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Common/CityTimezoneDto.cs @@ -0,0 +1,14 @@ +namespace SJZY.Track.Domain.Dtos.Common; + +public class CityTimezoneDto +{ + /// + /// 城市英文名称 + /// + public string? CityEnName { get; set; } + + /// + /// 时区 + /// + public string Timezone { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/Common/IdWithNameDto.cs b/src/SJZY.Track.Domain/Dtos/Common/IdWithNameDto.cs new file mode 100644 index 00000000..ad19228d --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Common/IdWithNameDto.cs @@ -0,0 +1,8 @@ +namespace SJZY.Track.Domain.Dtos.Common; + +public class IdWithNameDto +{ + public int Id { get; set; } + + public string Name { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/Common/KeywordsInputVO.cs b/src/SJZY.Track.Domain/Dtos/Common/KeywordsInputVO.cs index 8cbe4413..f509edbe 100644 --- a/src/SJZY.Track.Domain/Dtos/Common/KeywordsInputVO.cs +++ b/src/SJZY.Track.Domain/Dtos/Common/KeywordsInputVO.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Dtos.Common; +namespace SJZY.Track.Domain.Dtos.Common; public class KeywordsInputVO : PageInfoInput { @@ -16,4 +16,4 @@ public class KeywordsInputVO : PageInfoInput /// 选中项 /// public List? SelectedIds { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Dtos/Common/PortTimezoneDto.cs b/src/SJZY.Track.Domain/Dtos/Common/PortTimezoneDto.cs new file mode 100644 index 00000000..321b575f --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Common/PortTimezoneDto.cs @@ -0,0 +1,14 @@ +namespace SJZY.Track.Domain.Dtos.Common; + +public class PortTimezoneDto +{ + /// + /// 城市英文名称 + /// + public string? PortCode { get; set; } + + /// + /// 时区 + /// + public string Timezone { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/Demo/DemoValueObject.cs b/src/SJZY.Track.Domain/Dtos/Demo/DemoValueObject.cs deleted file mode 100644 index aa5db1e2..00000000 --- a/src/SJZY.Track.Domain/Dtos/Demo/DemoValueObject.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace SJZY.Track.Domain.Dtos.Demo; - -public class DemoValueObject -{ - public string Name { get; set; } - - /// - /// 当前页码 - /// - public int PageIndex { get; set; } - - /// - /// 每页大小 - /// - public int PageSize { get; set; } -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/AddRuleAreaInfoRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/AddRuleAreaInfoRequest.cs new file mode 100644 index 00000000..4b914187 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/AddRuleAreaInfoRequest.cs @@ -0,0 +1,44 @@ +using System.ComponentModel.DataAnnotations; + +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class AddRuleAreaInfoRequest +{ + /// + /// 国家二字码,必填项。 + /// + [Required] + public string CountryCode { get; set; } + + /// + /// 国家名称 + /// + [Required] + public string CountryName { get; set; } + + /// + /// 省份名称,可为空。 + /// + public string? Province { get; set; } + + /// + /// 城市名称,可为空。 + /// + public string? City { get; set; } + + /// + /// 左侧邮政编码,可为空。 + /// + public string? LeftPostCode { get; set; } + + /// + /// 右侧邮政编码,可为空。 + /// + public string? RightPostCode { get; set; } + + /// + /// 区域ID,必填项。 + /// + [Required] + public int AreaId { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/AreaDto.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/AreaDto.cs new file mode 100644 index 00000000..cfce4f93 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/AreaDto.cs @@ -0,0 +1,29 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class AreaDto +{ + /// + /// 区域id + /// + public int Id { get; set; } + + /// + /// 子系统id + /// + public int SubSystemId { get; set; } + + /// + /// 系统名称 + /// + public string SystemName { get; set; } + + /// + /// 区域名称 + /// + public string Name { get; set; } + + /// + /// 更新时间 + /// + public DateTime UpdateTime { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/AreaInfoDto.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/AreaInfoDto.cs new file mode 100644 index 00000000..b52978de --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/AreaInfoDto.cs @@ -0,0 +1,46 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class RuleAreaInfoDto +{ + /// + /// 分区信息id + /// + public int Id { get; set; } + + /// + /// 分区id + /// + public int AreaId { get; set; } + + /// + /// 国家或地区 二字码 + /// + public string CountryCode { get; set; } + + /// + /// 国家名称 + /// + public string CountryName { get; set; } + + /// + /// 国家id + /// + public int CountryId { get; set; } + + /// + /// 省份 + /// + public string Province { get; set; } + + /// + /// 城市 + /// + public string City { get; set; } + + /// + /// 开始邮编 + /// + public string LeftPostcode { get; set; } + + public string RightPostcode { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/CreateRuleAreaRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/CreateRuleAreaRequest.cs new file mode 100644 index 00000000..2dc8bdf3 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/CreateRuleAreaRequest.cs @@ -0,0 +1,18 @@ +using System.ComponentModel.DataAnnotations; + +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class CreateRuleAreaRequest +{ + /// + /// 系统id + /// + [Required] + public int SystemId { get; set; } + + /// + /// 名称 + /// + [Required] + public string Name { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/GetOrderWarningPageListVo.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/GetOrderWarningPageListVo.cs new file mode 100644 index 00000000..557fddca --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/GetOrderWarningPageListVo.cs @@ -0,0 +1,48 @@ +using System.ComponentModel.DataAnnotations; +using SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class GetOrderWarningPageListVo : PageInfoInput +{ + /// + /// 子系统id + /// + public int? SubSystemId { get; set; } + + /// + /// 订单号 + /// + [MaxLength(500)] + public List? OrderNos { get; set; } + + /// + /// 预警状态 + /// + public WarningStatus? WarningStatus { get; set; } + + /// + /// 客户id + /// + public int? CustomId { get; set; } + + /// + /// 预警名称 + /// + public string? WarningName { get; set; } + + /// + /// 通知用户id + /// + public int? NotifyUserId { get; set; } + + /// + /// 创建时间开始 + /// + public DateTime? StartTime { get; set; } + + /// + /// 创建时间结束 + /// + public DateTime? EndTime { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/GetOrderWarningPageOutput.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/GetOrderWarningPageOutput.cs new file mode 100644 index 00000000..ec260c30 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/GetOrderWarningPageOutput.cs @@ -0,0 +1,78 @@ +using SJZY.Track.Domain.Aggregates.ForewarningAggregate; + +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class GetOrderWarningPageOutput +{ + /// + /// 子系统id + /// + public int SubSystemId { get; set; } + + /// + /// 子系统name + /// + public string SubSystemName { get; set; } + + /// + /// 预警名称 + /// + public string WarningName { get; set; } = null!; + + /// + /// 客户简称 + /// + public string CustomName { get; set; } + + /// + /// 预警规则 + /// + public string Rule { get; set; } = null!; + + /// + /// 预警次数 + /// + public int Counter { get; set; } + + /// + /// 是否最后一次 + /// + public bool IsLast { get; set; } + + /// + /// 预警状态 + /// + public WarningStatus WarningStatus { get; set; } + + /// + /// 通知用户 + /// + public string NotifyUser { get; set; } + + /// + /// 最新轨迹内容(异步维护) + /// + public string? LatestTrackContent { get; set; } + + /// + /// 最新轨迹时间(异步维护) + /// + public DateTime? LatestTrackTime { get; set; } + + /// + /// 最新轨迹发生地(异步维护) + /// + public string? LatestTrackPlace { get; set; } + + /// + /// 创建时间 + /// + public DateTime CreateTime { get; set; } + + public string OrderNo { get; set; } + + /// + /// 订单类型(主数据枚举TrackOrderType) + /// + public int OrderType { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/GetWarningNotifiesVo.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/GetWarningNotifiesVo.cs new file mode 100644 index 00000000..1d917c96 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/GetWarningNotifiesVo.cs @@ -0,0 +1,160 @@ +using System.Text; +using NUglify.Helpers; +using SJZY.Track.Domain.Enums; + +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class GetWarningNotifiesVo +{ + /// + /// 子系统id + /// + public int SubSystemId { get; set; } + + /// + /// 子系统name + /// + public string SubSystemName { get; set; } + + /// + /// 规则 id + /// + public int RuleId { get; set; } + + /// + /// 预警名称 + /// + public string WarningName { get; set; } = null!; + + /// + /// 客户id + /// + public int CustomId { get; set; } + + /// + /// 客户简称 + /// + public string CustomName { get; set; } + + /// + /// 时效(小时) + /// + public float TotalTimeSpan { get; set; } + + /// + /// 提醒的时间(小时) + /// + public float WarnTimeSpan { get; set; } + + /// + /// 提醒次数(总次数) + /// + public int WarnCount { get; set; } + + /// + /// 起始轨迹状态(冗余) + /// + public string StartTrackStatus { get; set; } = null!; + + /// + /// 终止轨迹状态(冗余) + /// + public string EndTrackStatus { get; set; } = null!; + + /// + /// 货物类型 + /// + public string? CargoType { get; set; } + + /// + /// 月份 + /// + public string? Months { get; set; } + + /// + /// 区域 + /// + public string? AreaName { get; set; } + + /// + /// 是否中转 + /// + public bool? IsTransit { get; set; } + + /// + /// 起运港口 + /// + public string? LeavePort { get; set; } + + /// + /// 产品编码 + /// + public string? ProductCode { get; set; } + + /// + /// 通知方式(多个逗号拼接) + /// + public string NotifyMode { get; set; } + + /// + /// 通知用户(json多个) + /// + public string NotifyUser { get; set; } + + public List NotifyUsers { get; set; } + + /// + /// 因素类型排序 + /// + public string FactorTypeSort { get; set; } = null!; + + public override string ToString() + { + // {起飞-落地+普货+1/2/3/4+美国 时效9,预警时效7,次数3} + var res = new StringBuilder(); + res.Append('{'); + res.Append($"{StartTrackStatus}-{EndTrackStatus}"); + FactorTypeSort.Split(",").Select(Enum.Parse).ForEach(factorType => + { + switch (factorType) + { + case RuleFactorType.CargoType: + res.Append($"+{CargoType}"); + break; + case RuleFactorType.Months: + res.Append($"+{Months}"); + break; + case RuleFactorType.Area: + res.Append($"+{AreaName}"); + break; + case RuleFactorType.IsTransit: + res.Append($"+{(IsTransit ?? false ? "中转" : "直飞")}"); + break; + case RuleFactorType.LeavePort: + res.Append($"+{LeavePort}"); + break; + case RuleFactorType.ProductCode: + res.Append($"+{ProductCode}"); + break; + default: + throw new ArgumentOutOfRangeException(nameof(factorType), factorType, null); + } + }); + res.Append($" 时效{TotalTimeSpan},预警时效{WarnTimeSpan},次数{WarnCount}}}"); + + return res.ToString(); + } +} + +public class NotifyUserVo +{ + /// + /// 用户id + /// + public int UserId { get; set; } + + /// + /// 用户名 + /// + public string UserName { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/GetWarningPageInputVo.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/GetWarningPageInputVo.cs new file mode 100644 index 00000000..3939f83a --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/GetWarningPageInputVo.cs @@ -0,0 +1,14 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class GetWarningPageInputVo : PageInfoInput +{ + /// + /// 子系统id + /// + public int? SystemId { get; set; } + + /// + /// 关键字(客户or名称) + /// + public string? KeyWord { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/GetWarningRuleListInput.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/GetWarningRuleListInput.cs new file mode 100644 index 00000000..acc67261 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/GetWarningRuleListInput.cs @@ -0,0 +1,19 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class GetWarningRuleListInput : PageInfoInput +{ + /// + /// kpi 预警规则模板id + /// + public int RuleId { get; set; } + + /// + /// 排序方式,不填不排序 + /// + public string? SortField { get; set; } + + /// + /// 排序方式 + /// + public bool IsAsc { get; set; } = false; +} diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/IForewarningFactorValue.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/IForewarningFactorValue.cs new file mode 100644 index 00000000..4d6272ec --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/IForewarningFactorValue.cs @@ -0,0 +1,16 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public interface IForewarningFactorValue +{ + public string? CargoType { get; set; } + + public int? Month { get; set; } + + public int? Area { get; set; } + + public bool? IsTransit { get; set; } + + public string? LeavePort { get; set; } + + public string? ProductCode { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/KpiAreaInfo.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/KpiAreaInfo.cs new file mode 100644 index 00000000..7df79baf --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/KpiAreaInfo.cs @@ -0,0 +1,31 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class KpiAreaInfo +{ + public int AreaId { get; set; } + + /// + /// 国家或地区 + /// + public string Country { get; set; } = null!; + + /// + /// 省份 + /// + public string? Province { get; set; } + + /// + /// 城市 + /// + public string? City { get; set; } + + /// + /// 开始邮编 + /// + public string? LeftPostcode { get; set; } + + /// + /// 截止邮编 + /// + public string? RightPostcode { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/QueryAreaInfoRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/QueryAreaInfoRequest.cs new file mode 100644 index 00000000..4f551d67 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/QueryAreaInfoRequest.cs @@ -0,0 +1,9 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class QueryAreaInfoRequest : PageInfoInput +{ + /// + /// 区域id + /// + public int AreaId { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/QueryAreaRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/QueryAreaRequest.cs new file mode 100644 index 00000000..7bd8524f --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/QueryAreaRequest.cs @@ -0,0 +1,14 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class QueryAreaRequest : PageInfoInput +{ + /// + /// 分区名称 + /// + public string? Name { get; set; } + + /// + /// 子系统id + /// + public int? SystemId { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/RuleAreaBaseInfoVo.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/RuleAreaBaseInfoVo.cs new file mode 100644 index 00000000..3590a56d --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/RuleAreaBaseInfoVo.cs @@ -0,0 +1,17 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class RuleAreaBaseInfoVo +{ + public RuleAreaBaseInfoVo() + { + } + + public RuleAreaBaseInfoVo(int systemId, int customerId) + { + SystemId = systemId; + CustomerId = customerId; + } + + public int SystemId { get; set; } + public int CustomerId { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/RuleCollectRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/RuleCollectRequest.cs new file mode 100644 index 00000000..efd86df6 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/RuleCollectRequest.cs @@ -0,0 +1,6 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class RuleCollectRequest +{ + public string Name { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/UpdateRuleAreaInfoRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/UpdateRuleAreaInfoRequest.cs new file mode 100644 index 00000000..30b23150 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/UpdateRuleAreaInfoRequest.cs @@ -0,0 +1,46 @@ +using System.ComponentModel.DataAnnotations; + +namespace SJZY.Track.Domain.Dtos.Forewarning; + +/// +/// 更新规则区域信息请求 +/// +public class UpdateRuleAreaInfoRequest +{ + /// + /// 区域信息ID + /// + public int Id { get; set; } + + /// + /// 国家二字码,必填项。 + /// + [Required] + public string CountryCode { get; set; } + + /// + /// 国家名称,必填项。 + /// + [Required] + public string CountryName { get; set; } + + /// + /// 省份名称,可为空。 + /// + public string? Province { get; set; } + + /// + /// 城市名称,可为空。 + /// + public string? City { get; set; } + + /// + /// 左侧邮政编码,可为空。 + /// + public string? LeftPostCode { get; set; } + + /// + /// 右侧邮政编码,可为空。 + /// + public string? RightPostCode { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/UpdateRuleAreaRequest.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/UpdateRuleAreaRequest.cs new file mode 100644 index 00000000..89831ba3 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/UpdateRuleAreaRequest.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; + +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class UpdateRuleAreaRequest +{ + /// + /// 名称 + /// + [Required] + public string Name { get; set; } + + /// + /// 区域id + /// + public int Id { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/WarningPageOutput.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/WarningPageOutput.cs new file mode 100644 index 00000000..3a1f06da --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/WarningPageOutput.cs @@ -0,0 +1,34 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class WarningPageOutput +{ + /// + /// 预警id + /// + public int Id { get; set; } + + /// + /// 子系统 + /// + public string SubSystem { get; set; } = null!; + + /// + /// 客户 + /// + public string Custom { get; set; } = null!; + + /// + /// 规则模板名称,KPI名称 + /// + public string Name { get; set; } = null!; + + /// + /// 是否启用,默认否 + /// + public bool IsEnable { get; set; } + + /// + /// 更新时间 + /// + public DateTime? UpdateTime { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/WarningRuleCacheDto.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/WarningRuleCacheDto.cs new file mode 100644 index 00000000..bbdbd03d --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/WarningRuleCacheDto.cs @@ -0,0 +1,26 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class WarningRuleCacheDto +{ + public int Id { get; set; } + public int SystemId { get; set; } + public int CustomerId { get; set; } + + /// + /// 客户简称 + /// + public string CustomName { get; set; } + + public int WarningId { get; set; } + public float TotalTimeSpan { get; set; } + public float WarnTimeSpan { get; set; } + public int WarnCount { get; set; } + public int StartTrackStatusId { get; set; } + public int EndTrackStatusId { get; set; } + public string? CargoType { get; set; } + public string? Months { get; set; } + public int? AreaId { get; set; } + public bool? IsTransit { get; set; } + public string? LeavePort { get; set; } + public string? ProductCode { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/Forewarning/WarningRuleVo.cs b/src/SJZY.Track.Domain/Dtos/Forewarning/WarningRuleVo.cs new file mode 100644 index 00000000..bda6b4ba --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Forewarning/WarningRuleVo.cs @@ -0,0 +1,64 @@ +namespace SJZY.Track.Domain.Dtos.Forewarning; + +public class WarningRuleVo +{ + /// + /// 自增主键 + /// + public int Id { get; set; } + + /// + /// 时效(小时) + /// + public float TotalTimeSpan { get; set; } + + /// + /// 提醒的时间(小时) + /// + public float WarnTimeSpan { get; set; } + + /// + /// 提醒次数 + /// + public int WarnCount { get; set; } + + /// + /// 起始轨迹状态 + /// + public string StartTrackStatus { get; set; } = null!; + + /// + /// 终止轨迹状态 + /// + public string EndTrackStatus { get; set; } = null!; + + /// + /// 货物类型 + /// + public string? CargoType { get; set; } + + /// + /// 月份 + /// + public string? Months { get; set; } + + /// + /// 区域 + /// + public string? Area { get; set; } + + /// + /// 是否中转 + /// + public bool? IsTransit { get; set; } + + /// + /// 起运港口 + /// + public string? LeavePort { get; set; } + + /// + /// 销售产品 + /// + public string? ProductCode { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/Order/GetOrderDetailsInputVO.cs b/src/SJZY.Track.Domain/Dtos/Order/GetOrderDetailsInputVO.cs deleted file mode 100644 index 082b245a..00000000 --- a/src/SJZY.Track.Domain/Dtos/Order/GetOrderDetailsInputVO.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SJZY.Track.Domain.Dtos.Order -{ - public class GetOrderDetailsInputVO - { - - } - - public class TrackOrderDetailVO - { - - } -} diff --git a/src/SJZY.Track.Domain/Dtos/Order/GetPageTrackOrderInputVO.cs b/src/SJZY.Track.Domain/Dtos/Order/GetPageTrackOrderInputVO.cs index 5f164841..b57037a0 100644 --- a/src/SJZY.Track.Domain/Dtos/Order/GetPageTrackOrderInputVO.cs +++ b/src/SJZY.Track.Domain/Dtos/Order/GetPageTrackOrderInputVO.cs @@ -1,151 +1,156 @@ -namespace SJZY.Track.Domain.Dtos.Order +namespace SJZY.Track.Domain.Dtos.Order; + +public class GetPageTrackOrderInputVO : PageInfoInput { - public class GetPageTrackOrderInputVO : PageInfoInput - { - /// - /// 子系统id - /// - public int SubSystemId { get; set; } - - /// - /// 当tab选中 0 全部 1 异常 2 警告 - /// - public int TabType { get; set; } - - /// - /// 订单类型 - /// - public int? TrackOrderType { get; set; } - - /// - /// 客户id - /// - public int? CustomerId { get; set; } - - ///// - ///// 单号 - ///// - //public string? OrderNos { get; set; } - - /// - /// 单号 - /// - public List? OrderNos { get; set; } - - /// - /// 创建时间开始 - /// - public DateTime? CreateTimeStart { get; set; } - - /// - /// 创建时间截止 - /// - public DateTime? CreateTimeEnd { get; set; } - } + /// + /// 子系统id + /// + public int SubSystemId { get; set; } /// - /// 轨迹订单VO + /// 当tab选中 0 全部 1 异常 2 警告 /// - public class TrackOrderVO - { - /// - /// 轨迹订单id - /// - public int Id { get; set; } + public int TabType { get; set; } - /// - /// 订单类型id - /// - public int OrderType { get; set; } + /// + /// 订单类型 + /// + public int? TrackOrderType { get; set; } - /// - /// 订单类型名称 - /// - public string? OrderTypeName { get; set; } + /// + /// 客户id + /// + public int? CustomerId { get; set; } - /// - /// 订单号 - /// - public string? OrderNumber { get; set; } + ///// + ///// 单号 + ///// + //public string? OrderNos { get; set; } - /// - /// 轨迹模版 - /// - public string? TrackTemplateNames { get; set; } + /// + /// 单号 + /// + public List? OrderNos { get; set; } - /// - /// 客户简称 - /// - public string? CustomerShortName { get; set; } + /// + /// 创建时间开始 + /// + public DateTime? CreateTimeStart { get; set; } - /// - /// 客户代码 - /// - public string? CustomerCode { get; set; } + /// + /// 创建时间截止 + /// + public DateTime? CreateTimeEnd { get; set; } +} - /// - /// 客户id - /// - public int CustomerId { get; set; } +/// +/// 轨迹订单VO +/// +public class TrackOrderVO +{ + /// + /// 轨迹订单id + /// + public int Id { get; set; } - ///// - ///// 订单明细(json) - ///// - //public string? OrderDetails { get; set; } + /// + /// 订单类型id + /// + public int OrderType { get; set; } - /// - /// 最新轨迹内容 - /// - public string? NewestTrackContent { get; set; } + /// + /// 订单类型名称 + /// + public string? OrderTypeName { get; set; } - /// - /// 最新轨迹内容英文 - /// - public string? NewestTrackEnContent { get; set; } + /// + /// 订单号 + /// + public string? OrderNumber { get; set; } - /// - /// 最新轨迹发生地 - /// - public string? NewestTrackPlace { get; set; } - /// - /// 最新轨迹时间 - /// - public DateTime? NewestTrackTime { get; set; } + /// + /// 客户简称 + /// + public string? CustomerShortName { get; set; } - /// - /// 是否完结 - /// - public bool IsFinish { get; set; } + /// + /// 客户代码 + /// + public string? CustomerCode { get; set; } - /// - /// 创建时间 - /// - public DateTime? CreateTime { get; set; } + /// + /// 客户id + /// + public int CustomerId { get; set; } - /// - /// 子系统 - /// - public string? SubSystem { get; set; } + ///// + ///// 订单明细(json) + ///// + //public string? OrderDetails { get; set; } - /// - /// 子系统id - /// - public int SubSystemId { get; set; } + /// + /// 最新轨迹内容 + /// + public string? NewestTrackContent { get; set; } - /// - /// 轨迹模板Id数组 - /// - public List? TrackTemplateIds { get; set; } + /// + /// 最新轨迹内容英文 + /// + public string? NewestTrackEnContent { get; set; } - /// - /// 问题类型(主数据枚举TrackQuestionType) - /// - public int QuestionType { get; set; } + /// + /// 最新轨迹发生地 + /// + public string? NewestTrackPlace { get; set; } - /// - /// 问题类型名称 - /// - public string? QuestionTypeName { get; set; } - } -} \ No newline at end of file + /// + /// 最新轨迹时间 + /// + public DateTime? NewestTrackTime { get; set; } + + /// + /// 是否完结 + /// + public bool IsFinish { get; set; } + + /// + /// 创建时间 + /// + public DateTime? CreateTime { get; set; } + + /// + /// 子系统 + /// + public string? SubSystem { get; set; } + + /// + /// 子系统id + /// + public int SubSystemId { get; set; } + + /// + /// 问题类型(主数据枚举TrackQuestionType) + /// + public int QuestionType { get; set; } + + /// + /// 问题类型名称 + /// + public string? QuestionTypeName { get; set; } + + /// + /// 预计到达时间 + /// + public DateTime? EstimatedDeliveryDate { get; set; } + + /// + /// 目的地时区 + /// + public float? DestinationTimeZone { get; set; } + + /// + /// 第三方单号,服务商-轨迹0000000、轨迹服务商-0000000 + /// + public string? ThirdPartyOrderNumber { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/Order/GetTrackCounterVO.cs b/src/SJZY.Track.Domain/Dtos/Order/GetTrackCounterVO.cs index 67cc8496..64794434 100644 --- a/src/SJZY.Track.Domain/Dtos/Order/GetTrackCounterVO.cs +++ b/src/SJZY.Track.Domain/Dtos/Order/GetTrackCounterVO.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Dtos.Order; +namespace SJZY.Track.Domain.Dtos.Order; public class GetTrackCounterVO { @@ -11,4 +11,4 @@ public class GetTrackCounterVO /// 总条数 /// public int Count { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Dtos/Order/LinkedOrderVO.cs b/src/SJZY.Track.Domain/Dtos/Order/LinkedOrderVO.cs index 23299e30..2bc90ca0 100644 --- a/src/SJZY.Track.Domain/Dtos/Order/LinkedOrderVO.cs +++ b/src/SJZY.Track.Domain/Dtos/Order/LinkedOrderVO.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Dtos.Order; +namespace SJZY.Track.Domain.Dtos.Order; public class LinkedOrderVO { @@ -31,4 +31,4 @@ public class LinkedOrderVO /// 客户id /// public int CustomId { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Dtos/Order/OrderIdentifier.cs b/src/SJZY.Track.Domain/Dtos/Order/OrderIdentifier.cs index 248ec7e9..fc4a22c4 100644 --- a/src/SJZY.Track.Domain/Dtos/Order/OrderIdentifier.cs +++ b/src/SJZY.Track.Domain/Dtos/Order/OrderIdentifier.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Dtos.Order; +namespace SJZY.Track.Domain.Dtos.Order; /// /// 订单标识符 @@ -20,4 +20,4 @@ public readonly struct OrderIdentifier /// 订单号 /// public string OrderNo { get; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Dtos/Order/OrderTemplateLinkDto.cs b/src/SJZY.Track.Domain/Dtos/Order/OrderTemplateLinkDto.cs index 6ca82ed3..6d6f4528 100644 --- a/src/SJZY.Track.Domain/Dtos/Order/OrderTemplateLinkDto.cs +++ b/src/SJZY.Track.Domain/Dtos/Order/OrderTemplateLinkDto.cs @@ -11,4 +11,4 @@ public class OrderTemplateLinkDto /// 模板id /// public int TemplateId { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Dtos/Order/OrderTemplateVO.cs b/src/SJZY.Track.Domain/Dtos/Order/OrderTemplateVO.cs new file mode 100644 index 00000000..26c110a0 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Order/OrderTemplateVO.cs @@ -0,0 +1,13 @@ +namespace SJZY.Track.Domain.Dtos.Order; + +/// +/// 订单关联的模板模型 +/// +public class OrderTemplateVO +{ + public int OrderId { get; set; } + + public string OrderNo { get; set; } + + public string? TemplateCodes { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/Order/OrderTransportDto.cs b/src/SJZY.Track.Domain/Dtos/Order/OrderTransportDto.cs new file mode 100644 index 00000000..360e3bce --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Order/OrderTransportDto.cs @@ -0,0 +1,10 @@ +namespace SJZY.Track.Domain.Dtos.Order; + +public class OrderTransportDto +{ + public int OrderId { get; set; } + + public int ServiceProviderId { get; set; } + + public int SubSystemId { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/Order/OrderWithServiceProviderVO.cs b/src/SJZY.Track.Domain/Dtos/Order/OrderWithServiceProviderVO.cs index a5c9ad32..b3f6488a 100644 --- a/src/SJZY.Track.Domain/Dtos/Order/OrderWithServiceProviderVO.cs +++ b/src/SJZY.Track.Domain/Dtos/Order/OrderWithServiceProviderVO.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Dtos.Order; +namespace SJZY.Track.Domain.Dtos.Order; public class OrderWithServiceProviderVO { @@ -9,20 +9,18 @@ public class OrderWithServiceProviderVO /// public int OrderType { get; set; } - public int ServiceProviderId { get; set; } - /// /// 服务商code /// public string ServiceProviderCode { get; set; } = null!; - /// - /// 服务商name - /// - public string ServiceProviderName { get; set; } = null!; - /// /// 子系统id /// public int SubSystemId { get; set; } -} \ No newline at end of file + + /// + /// 子系统code + /// + public string SubSystemCode { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/Order/UpdateOrderPullConfigForServiceProviderInputVo.cs b/src/SJZY.Track.Domain/Dtos/Order/UpdateOrderPullConfigForServiceProviderInputVo.cs new file mode 100644 index 00000000..73c1943d --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/Order/UpdateOrderPullConfigForServiceProviderInputVo.cs @@ -0,0 +1,34 @@ +namespace SJZY.Track.Domain.Dtos.Order; + +public class UpdateOrderPullConfigsInputVo +{ + /// + /// 订单id + /// + public int[] OrderIds { get; set; } + + /// + /// 服务商code + /// + public string ServiceCode { get; set; } + + /// + /// 开始轨迹code + /// + public string? StartCode { get; set; } + + /// + /// 结束轨迹code + /// + public string? EndCode { get; set; } + + /// + /// 静默多久后拉取(小时) + /// + public int SilenceTime { get; set; } + + /// + /// 结束多久后停止拉取(小时) + /// + public int StopTime { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackContents/GetPageTrackContentVO.cs b/src/SJZY.Track.Domain/Dtos/TrackContents/GetPageTrackContentVO.cs index aa506d9e..2c9ef883 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackContents/GetPageTrackContentVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackContents/GetPageTrackContentVO.cs @@ -1,88 +1,107 @@ -namespace SJZY.Track.Domain.Dtos.TrackContents +namespace SJZY.Track.Domain.Dtos.TrackContents; + +public class GetPageTrackContentVO : PageInfoInput { - public class GetPageTrackContentVO : PageInfoInput - { - /// - /// 子系统id - /// - public int SubSystemId { get; set; } + /// + /// 子系统id + /// + public int SubSystemId { get; set; } - /// - /// 关键字 - /// - public string? Keywords { get; set; } + /// + /// 关键字 + /// + public string? Keywords { get; set; } - /// - /// 轨迹状态id - /// - public int TrackStatusId { get; set; } + /// + /// 轨迹状态id + /// + public int TrackStatusId { get; set; } - /// - /// 选中的轨迹内容id - /// - public List? SelectIds { get; set; } - } + /// + /// 选中的轨迹内容id + /// + public List? SelectIds { get; set; } +} - public class GetTrackContentListVO - { - /// - /// Id - /// - public int Id { get; set; } +public class GetTrackContentListVO +{ + /// + /// Id + /// + public int Id { get; set; } - /// - /// 子系统 - /// - public string SubSystem { get; set; } + /// + /// 子系统 + /// + public string SubSystem { get; set; } - /// - /// 轨迹内容代码 - /// - public string Code { get; set; } + /// + /// 轨迹内容代码 + /// + public string Code { get; set; } - /// - /// 轨迹内容 - /// - public string Content { get; set; } + /// + /// 轨迹内容 + /// + public string Content { get; set; } - /// - /// 轨迹内容英文 - /// - public string EnContent { get; set; } + /// + /// 轨迹内容英文 + /// + public string EnContent { get; set; } - /// - /// 所属状态 - /// - public string TrackStatus { get; set; } + /// + /// 所属状态 + /// + public string TrackStatus { get; set; } - /// - /// 所属节点 - /// - public string Node { get; set; } + /// + /// 所属节点 + /// + public string Node { get; set; } - /// - /// 轨迹标记 - /// - public string TrackFlag { get; set; } + /// + /// 轨迹标记 + /// + public string TrackFlag { get; set; } - /// - /// 创建时间 - /// - public DateTime? CreateTime { get; set; } + /// + /// 是否对外 + /// + public bool IsExternal { get; set; } - /// - /// 创建人 - /// - public string CreateUser { get; set; } + /// + /// 创建时间 + /// + public DateTime? CreateTime { get; set; } - /// - /// 修改时间 - /// - public DateTime? UpdateTime { get; set; } + /// + /// 创建人 + /// + public string CreateUser { get; set; } - /// - /// 修改人 - /// - public string UpdateUser { get; set; } - } -} \ No newline at end of file + /// + /// 修改时间 + /// + public DateTime? UpdateTime { get; set; } + + /// + /// 修改人 + /// + public string UpdateUser { get; set; } + + /// + /// 是否可重复 + /// + public bool IsRepeatable { get; set; } + + /// + /// 是否允许手动修改 + /// + public bool IsAllowManuallyUpdate { get; set; } + + /// + /// 是否允许手动创建 + /// + public bool IsAllowManuallyCreate { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackContents/GetTrackContentDetailVO.cs b/src/SJZY.Track.Domain/Dtos/TrackContents/GetTrackContentDetailVO.cs index 19113d90..fe5b29d2 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackContents/GetTrackContentDetailVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackContents/GetTrackContentDetailVO.cs @@ -1,55 +1,73 @@ -namespace SJZY.Track.Domain.Dtos.TrackContents +namespace SJZY.Track.Domain.Dtos.TrackContents; + +public class GetTrackContentDetailVO { - public class GetTrackContentDetailVO - { - /// - /// Id - /// - public int Id { get; set; } + /// + /// Id + /// + public int Id { get; set; } - /// - /// 子系统id - /// - public int SubSystemId { get; set; } + /// + /// 子系统id + /// + public int SubSystemId { get; set; } - /// - /// 子系统 - /// - public string SubSystem { get; set; } + /// + /// 子系统 + /// + public string SubSystem { get; set; } - /// - /// 所属轨迹状态id - /// - public int TrackStatusId { get; set; } + /// + /// 所属轨迹状态id + /// + public int TrackStatusId { get; set; } - /// - /// 所属轨迹状态 - /// - public string TrackStatus { get; set; } + /// + /// 所属轨迹状态 + /// + public string TrackStatus { get; set; } - /// - /// 轨迹内容代码 - /// - public string Code { get; set; } + /// + /// 轨迹内容代码 + /// + public string Code { get; set; } - /// - /// 轨迹内容 - /// - public string Content { get; set; } + /// + /// 轨迹内容 + /// + public string Content { get; set; } - /// - /// 轨迹内容英文 - /// - public string EnContent { get; set; } + /// + /// 轨迹内容英文 + /// + public string EnContent { get; set; } - /// - /// 轨迹标记id - /// - public int TrackFlagId { get; set; } + /// + /// 轨迹标记id + /// + public string? TrackFlagId { get; set; } - /// - /// 轨迹标记 - /// - public string TrackFlag { get; set; } - } -} \ No newline at end of file + /// + /// 轨迹标记ids + /// + public List? TrackFlagIds { get; set; } + + /// + /// 是否对外 + /// + public bool IsExternal { get; set; } + /// + /// 是否可重复 + /// + public bool IsRepeatable { get; set; } + + /// + /// 是否允许手动修改 + /// + public bool IsAllowManuallyUpdate { get; set; } + + /// + /// 是否允许手动创建 + /// + public bool IsAllowManuallyCreate { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackContents/GetTrackContentMapDetailOutputVO.cs b/src/SJZY.Track.Domain/Dtos/TrackContents/GetTrackContentMapDetailOutputVO.cs index dce4eff9..f7372508 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackContents/GetTrackContentMapDetailOutputVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackContents/GetTrackContentMapDetailOutputVO.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Dtos.TrackContents; +namespace SJZY.Track.Domain.Dtos.TrackContents; public class GetTrackContentMapDetailOutputVO { @@ -53,4 +53,4 @@ public class GetTrackContentMapDetailOutputVO /// 映射轨迹内容代码 /// public string MapTrackContentCode { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackContents/GetTrackContentMapPageInputVO.cs b/src/SJZY.Track.Domain/Dtos/TrackContents/GetTrackContentMapPageInputVO.cs index e6cd19e6..16a35377 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackContents/GetTrackContentMapPageInputVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackContents/GetTrackContentMapPageInputVO.cs @@ -1,4 +1,4 @@ -using SJZY.Track.Domain.Dtos.Common; +using SJZY.Track.Domain.Dtos.Common; namespace SJZY.Track.Domain.Dtos.TrackContents; @@ -8,4 +8,4 @@ public class GetTrackContentMapPageInputVO : KeywordsInputVO /// 映射子系统id /// public int? MapSubSystemId { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackContents/GetTrackContentMapPageOutputVO.cs b/src/SJZY.Track.Domain/Dtos/TrackContents/GetTrackContentMapPageOutputVO.cs index e291b71f..c98f653e 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackContents/GetTrackContentMapPageOutputVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackContents/GetTrackContentMapPageOutputVO.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Dtos.TrackContents; +namespace SJZY.Track.Domain.Dtos.TrackContents; public class GetTrackContentMapPageOutputVO { @@ -53,4 +53,4 @@ public class GetTrackContentMapPageOutputVO /// 轨迹状态 /// public string TrackStatus { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackContents/TrackCodeMapVO.cs b/src/SJZY.Track.Domain/Dtos/TrackContents/TrackCodeMapVO.cs new file mode 100644 index 00000000..c06fc740 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/TrackContents/TrackCodeMapVO.cs @@ -0,0 +1,27 @@ +namespace SJZY.Track.Domain.Dtos.TrackContents; + +/// +/// 轨迹代码映射 +/// +public sealed class TrackCodeMapVO +{ + /// + /// 源子系统id + /// + public int SubSystemId { get; set; } + + /// + /// 源轨迹内容code + /// + public string TrackContentCode { get; set; } = null!; + + /// + /// 映射子系统id + /// + public int MapSubSystemId { get; set; } + + /// + /// 映射轨迹内容code + /// + public string MapTrackContentCode { get; set; } = null!; +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackContents/TrackContentVO.cs b/src/SJZY.Track.Domain/Dtos/TrackContents/TrackContentVO.cs index d44e75c8..f9a126fb 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackContents/TrackContentVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackContents/TrackContentVO.cs @@ -1,12 +1,32 @@ -namespace SJZY.Track.Domain.Dtos.TrackContents; +namespace SJZY.Track.Domain.Dtos.TrackContents; public class TrackContentVO { + /// + /// 子系统Id + /// + public int SubSystemId { get; set; } + + /// + /// 子系统代码 + /// + public string SubSystemCode { get; set; } + + /// + /// 轨迹状态Id + /// + public int TrackStatusId { get; set; } + /// /// 轨迹状态 /// public string TrackStatus { get; set; } = null!; + /// + /// 轨迹内容Id + /// + public int TrackContentId { get; set; } + /// /// 轨迹内容 /// @@ -16,4 +36,44 @@ public class TrackContentVO /// 轨迹内容英文 /// public string TrackEnContent { get; set; } = null!; -} \ No newline at end of file + + /// + /// 是否完成态 + /// + public bool IsCompleted { get; set; } + + /// + /// 轨迹状态代码 + /// + public string TrackStatusCode { get; set; } + + /// + /// 是否可重复 + /// + public bool IsRepeatable { get; set; } + + /// + /// 是否允许手动修改 + /// + public bool IsAllowManuallyUpdate { get; set; } + + /// + /// 是否允许手动创建 + /// + public bool IsAllowManuallyCreate { get; set; } + + /// + /// 是否广播 + /// + public bool IsToMq { get; set; } + + /// + /// 是否对外 + /// + public bool IsExternal { get; set; } + + /// + /// 轨迹内容code + /// + public string TrackContentCode { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackDetails/MatchTrackContentDto.cs b/src/SJZY.Track.Domain/Dtos/TrackDetails/MatchTrackContentDto.cs deleted file mode 100644 index 23c27bfe..00000000 --- a/src/SJZY.Track.Domain/Dtos/TrackDetails/MatchTrackContentDto.cs +++ /dev/null @@ -1,34 +0,0 @@ -namespace SJZY.Track.Domain.Dtos.TrackDetails; - -public class MatchTrackContentDto -{ - /// - /// 订单Id - /// - public int OrderId { get; set; } - - /// - /// 轨迹内容code - /// - public string TrackCode { get; set; } = null!; - - /// - /// 轨迹内容 - /// - public string Content { get; set; } = null!; - - /// - /// 轨迹内容英文 - /// - public string EnContent { get; set; } = null!; - - /// - /// 轨迹状态 - /// - public string Status { get; set; } = null!; - - /// - /// 是否可删 - /// - public bool IsCanDelete { get; set; } -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/TrackDetails/MatchTrackContentsDto.cs b/src/SJZY.Track.Domain/Dtos/TrackDetails/MatchTrackContentsDto.cs deleted file mode 100644 index 14441bc6..00000000 --- a/src/SJZY.Track.Domain/Dtos/TrackDetails/MatchTrackContentsDto.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace SJZY.Track.Domain.Dtos.TrackDetails; - -public class MatchTrackContentsDto -{ - /// - /// 轨迹代码 - /// - public string TrackCode { get; set; } = null!; - - /// - /// 是否支持删除 - /// - public bool IsCanDelete { get; set; } -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/TrackDetails/TrackDetailsQueryInput.cs b/src/SJZY.Track.Domain/Dtos/TrackDetails/TrackDetailsQueryInput.cs deleted file mode 100644 index 3a7b4d0d..00000000 --- a/src/SJZY.Track.Domain/Dtos/TrackDetails/TrackDetailsQueryInput.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace SJZY.Track.Domain.Dtos.TrackDetails; - -public class TrackDetailsQueryInput : PageInfoInput -{ - /// - /// 单号 - /// - public List OrderNos { get; set; } = new(); -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Dtos/TrackFlags/GetPageTrackFlagVO.cs b/src/SJZY.Track.Domain/Dtos/TrackFlags/GetPageTrackFlagVO.cs index f838b37d..230b04f1 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackFlags/GetPageTrackFlagVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackFlags/GetPageTrackFlagVO.cs @@ -1,74 +1,67 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SJZY.Track.Domain.Dtos.TrackFlags; -namespace SJZY.Track.Domain.Dtos.TrackFlags +public class GetPageTrackFlagVO : PageInfoInput { - public class GetPageTrackFlagVO : PageInfoInput - { - /// - /// 子系统id - /// - public int SubSystemId { get; set; } + /// + /// 子系统id + /// + public int SubSystemId { get; set; } - /// - /// 选中的轨迹标记id - /// - public List? SelectIds { get; set; } + /// + /// 选中的轨迹标记id + /// + public List? SelectIds { get; set; } - /// - /// 关键字 - /// - public string? Keywords { get; set; } - } - - public class GetTrackFlagListVO - { - /// - /// Id - /// - public int Id { get; set; } - - /// - /// 子系统 - /// - public string SubSystem { get; set; } - - /// - /// 代码 - /// - public string Code { get; set; } - - /// - /// 标记 - /// - public string Flag { get; set; } - - ///// - ///// 是否完结 - ///// - //public bool IsFinish { get; set; } - - /// - /// 创建时间 - /// - public DateTime? CreateTime { get; set; } - - /// - /// 创建人 - /// - public string CreateUser { get; set; } - - /// - /// 修改时间 - /// - public DateTime? UpdateTime { get; set; } - - /// - /// 修改人 - /// - public string UpdateUser { get; set; } - } + /// + /// 关键字 + /// + public string? Keywords { get; set; } +} + +public class GetTrackFlagListVO +{ + /// + /// Id + /// + public int Id { get; set; } + + /// + /// 子系统 + /// + public string SubSystem { get; set; } + + /// + /// 代码 + /// + public string Code { get; set; } + + /// + /// 标记 + /// + public string Flag { get; set; } + + /// + /// 是否广播 + /// + public bool IsToMq { get; set; } + + /// + /// 创建时间 + /// + public DateTime? CreateTime { get; set; } + + /// + /// 创建人 + /// + public string CreateUser { get; set; } + + /// + /// 修改时间 + /// + public DateTime? UpdateTime { get; set; } + + /// + /// 修改人 + /// + public string UpdateUser { get; set; } } diff --git a/src/SJZY.Track.Domain/Dtos/TrackFlags/GetTrackFlagDetailVO.cs b/src/SJZY.Track.Domain/Dtos/TrackFlags/GetTrackFlagDetailVO.cs index d2984d4a..566ee661 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackFlags/GetTrackFlagDetailVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackFlags/GetTrackFlagDetailVO.cs @@ -1,41 +1,34 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SJZY.Track.Domain.Dtos.TrackFlags; -namespace SJZY.Track.Domain.Dtos.TrackFlags +public class GetTrackFlagDetailVO { - public class GetTrackFlagDetailVO - { - /// - /// Id - /// - public int Id { get; set; } + /// + /// Id + /// + public int Id { get; set; } - /// - /// 子系统id - /// - public int SubSystemId { get; set; } + /// + /// 子系统id + /// + public int SubSystemId { get; set; } - /// - /// 子系统 - /// - public string SubSystem { get; set; } + /// + /// 子系统 + /// + public string SubSystem { get; set; } - /// - /// 代码 - /// - public string Code { get; set; } + /// + /// 代码 + /// + public string Code { get; set; } - /// - /// - /// - public string Flag { get; set; } + /// + /// + /// + public string Flag { get; set; } - ///// - ///// 是否完结 - ///// - //public bool IsFinish { get; set; } - } + /// + /// 是否广播 + /// + public bool IsToMq { get; set; } } diff --git a/src/SJZY.Track.Domain/Dtos/TrackNode/TrackNodeDicDto.cs b/src/SJZY.Track.Domain/Dtos/TrackNode/TrackNodeDicDto.cs new file mode 100644 index 00000000..fd54eb6a --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/TrackNode/TrackNodeDicDto.cs @@ -0,0 +1,19 @@ +namespace SJZY.Track.Domain.Dtos.TrackNode; + +public class TrackNodeDicDto +{ + /// + /// 节点id + /// + public long Id { get; set; } + + /// + /// 名称 + /// + public string NodeName { get; set; } + + /// + /// 名称 + /// + public string EnName { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackNode/TrackNodeDto.cs b/src/SJZY.Track.Domain/Dtos/TrackNode/TrackNodeDto.cs new file mode 100644 index 00000000..fbb8e783 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/TrackNode/TrackNodeDto.cs @@ -0,0 +1,61 @@ +namespace SJZY.Track.Domain.Dtos.TrackNode; + +/// +/// 轨迹节点主表 DTO +/// +public class TrackNodeDto +{ + /// + /// 自增主键 + /// + public long Id { get; set; } + + /// + /// 子系统id + /// + public int SubSystemId { get; set; } + + /// + /// 系统名称 + /// + public string? SystemName { get; set; } + + /// + /// 节点名称 + /// + public string? NodeName { get; set; } + + /// + /// 节点英文名称 + /// + public string? NodeEnName { get; set; } + + /// + /// 是否删除 + /// + public bool IsDeleted { get; set; } + + /// + /// 创建人id + /// + public int CreateUserId { get; set; } + + /// + /// 创建时间 + /// + public DateTime CreateTime { get; set; } + + /// + /// 更新人 + /// + public int? UpdateUserId { get; set; } + + /// + /// 更新时间 + /// + public DateTime? UpdateTime { get; set; } + + public string? CreateUserName { get; set; } + + public string? UpdateUserName { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackNode/TrackNodePageDto.cs b/src/SJZY.Track.Domain/Dtos/TrackNode/TrackNodePageDto.cs new file mode 100644 index 00000000..9de6342e --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/TrackNode/TrackNodePageDto.cs @@ -0,0 +1,14 @@ +namespace SJZY.Track.Domain.Dtos.TrackNode; + +public class TrackNodePageDto : PageInfoInput +{ + /// + /// 关键字,节点中文和英文 + /// + public string? KeyWord { get; set; } + + /// + /// 子系统id + /// + public long? SystemId { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullConfigDetailOutputVO.cs b/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullConfigDetailOutputVO.cs index c52c081b..cccf0c49 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullConfigDetailOutputVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullConfigDetailOutputVO.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Dtos.TrackPull; +namespace SJZY.Track.Domain.Dtos.TrackPull; public class GetTrackPullConfigDetailOutputVO { @@ -19,23 +19,23 @@ public class GetTrackPullConfigDetailOutputVO /// public int PullInterval { get; set; } - /// - /// 服务商 - /// - public string ServiceProvider { get; set; } - /// /// 服务商id /// public int ServiceProviderId { get; set; } + /// + /// 服务商code + /// + public string ServiceProviderCode { get; set; } + /// /// 子系统 /// public string SubSystem { get; set; } /// - /// 子系统id + /// 子系统code /// public int SubSystemId { get; set; } @@ -78,4 +78,4 @@ public class GetTrackPullConfigDetailOutputVO /// 轨迹明细路径 /// public string TrackDetailsPath { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullConfigPageOutputVO.cs b/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullConfigPageOutputVO.cs index bd73f920..7090affb 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullConfigPageOutputVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullConfigPageOutputVO.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Dtos.TrackPull; +namespace SJZY.Track.Domain.Dtos.TrackPull; public class GetTrackPullConfigPageOutputVO { @@ -23,4 +23,4 @@ public class GetTrackPullConfigPageOutputVO /// 子系统id /// public int SubSystemId { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullContentDetailOutputVO.cs b/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullContentDetailOutputVO.cs index 05d748fe..952c02ef 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullContentDetailOutputVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullContentDetailOutputVO.cs @@ -1,18 +1,18 @@ -namespace SJZY.Track.Domain.Dtos.TrackPull; +namespace SJZY.Track.Domain.Dtos.TrackPull; public class GetTrackPullContentDetailOutputVO { - /// - /// 轨迹内容代码 - /// - public string Code { get; set; } = null!; - public int Id { get; set; } /// - /// 拉取轨迹内容代码 + /// 轨迹代码 /// - public string? TrackContentCodeValue { get; set; } + public string Code { get; set; } + + /// + /// 轨迹拉取配置id + /// + public int TrackPullConfigId { get; set; } /// /// 轨迹内容id @@ -20,9 +20,14 @@ public class GetTrackPullContentDetailOutputVO public int TrackContentId { get; set; } /// - /// 拉取轨迹内容 + /// 服务商轨迹状态参数值 /// - public string? TrackContentValue { get; set; } + public string? TrackStatusValue { get; set; } + + /// + /// 服务商轨迹状态参数值 + /// + public List? TrackStatusValues { get; set; } /// /// 拉取轨迹关键字(正向) @@ -50,22 +55,7 @@ public class GetTrackPullContentDetailOutputVO public int? TrackPlaceValue { get; set; } /// - /// 轨迹拉取配置id + /// 轨迹时区兜底地址值 /// - public int TrackPullConfigId { get; set; } - - /// - /// 拉取轨迹状态 - /// - public string? TrackStatusValue { get; set; } - - /// - /// 拉取轨迹时区 - /// - public double? TrackTimeZone { get; set; } - - /// - /// 是否完结 - /// - public bool IsCompleted { get; set; } -} \ No newline at end of file + public int? TrackTimePlaceValue { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullContentListCacheVO.cs b/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullContentListCacheVO.cs index 047431d9..100b9577 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullContentListCacheVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullContentListCacheVO.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Dtos.TrackPull; +namespace SJZY.Track.Domain.Dtos.TrackPull; public class GetTrackPullContentListCacheVO { @@ -12,16 +12,6 @@ public class GetTrackPullContentListCacheVO /// public string? TrackStatusValue { get; set; } - /// - /// 服务商轨迹代码参数值 - /// - public string? TrackContentCodeValue { get; set; } - - /// - /// 服务商轨迹内容参数值 - /// - public string? TrackContentValue { get; set; } - /// /// 轨迹关键词(正向),多个逗分隔 /// @@ -33,17 +23,27 @@ public class GetTrackPullContentListCacheVO public string? TrackKeywordReverse { get; set; } /// - /// 轨迹发生地参数值(主数据枚举) + /// 服务商轨迹状态参数值 + /// + public List TrackStatusValues { get; set; } = new(); + + /// + /// 轨迹关键词(正向) + /// + public List TrackKeywords { get; set; } = new(); + + /// + /// 轨迹关键词(反向) + /// + public List TrackKeywordReverses { get; set; } = new(); + + /// + /// 兜底轨迹发生地参数值 /// public int? TrackPlaceValue { get; set; } /// - /// 轨迹时区GMT + /// 兜底轨迹时区所属发生地参数值 /// - public float? TrackTimeZone { get; set; } - - /// - /// 订单是否完成(由轨迹刷新配置决定) - /// - public bool IsCompleted { get; set; } -} \ No newline at end of file + public int? TrackZonePlaceValue { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullContentPageInputVO.cs b/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullContentPageInputVO.cs index ca31153a..6367be32 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullContentPageInputVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullContentPageInputVO.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Dtos.TrackPull; +namespace SJZY.Track.Domain.Dtos.TrackPull; public class GetTrackPullContentPageInputVO : PageInfoInput { @@ -6,4 +6,4 @@ public class GetTrackPullContentPageInputVO : PageInfoInput /// 轨迹拉取配置id /// public int TrackPullConfigId { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullContentPageOutputVO.cs b/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullContentPageOutputVO.cs index a1c52026..2fac5ae1 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullContentPageOutputVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackPull/GetTrackPullContentPageOutputVO.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Dtos.TrackPull; +namespace SJZY.Track.Domain.Dtos.TrackPull; public class GetTrackPullContentPageOutputVO { @@ -48,4 +48,4 @@ public class GetTrackPullContentPageOutputVO /// 拉取轨迹状态 /// public string? TrackStatusValue { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackPullConfigDto.cs b/src/SJZY.Track.Domain/Dtos/TrackPull/TrackPullConfigVo.cs similarity index 52% rename from src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackPullConfigDto.cs rename to src/SJZY.Track.Domain/Dtos/TrackPull/TrackPullConfigVo.cs index 10f78964..1a28568d 100644 --- a/src/SJZY.Track.Application.Contract/Dtos/TrackPull/TrackPullConfigDto.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackPull/TrackPullConfigVo.cs @@ -1,6 +1,6 @@ -namespace SJZY.Track.Application.Contract.Dtos.TrackPull; +namespace SJZY.Track.Domain.Dtos.TrackPull; -public class TrackPullConfigDto +public class TrackPullConfigVo { /// /// 服务商拉取频率(分钟) @@ -12,8 +12,18 @@ public class TrackPullConfigDto /// public int ServiceProviderId { get; set; } + /// + /// 服务商code + /// + public string ServiceProviderCode { get; set; } + + /// + /// 子系统code + /// + public string SubSystemCode { get; set; } + /// /// 子系统id /// public int SubSystemId { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackPush/GetTrackPushConfigDetailOutputVO.cs b/src/SJZY.Track.Domain/Dtos/TrackPush/GetTrackPushConfigDetailOutputVO.cs index ef8ea329..f8cff929 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackPush/GetTrackPushConfigDetailOutputVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackPush/GetTrackPushConfigDetailOutputVO.cs @@ -1,4 +1,6 @@ -namespace SJZY.Track.Domain.Dtos.TrackPush; +using SJZY.Track.Domain.Enums; + +namespace SJZY.Track.Domain.Dtos.TrackPush; public class GetTrackPushConfigDetailOutputVO { @@ -20,14 +22,9 @@ public class GetTrackPushConfigDetailOutputVO public bool IsAutoPush { get; set; } /// - /// 服务商 + /// 服务商code /// - public string ServiceProvider { get; set; } - - /// - /// 服务商id - /// - public int ServiceProviderId { get; set; } + public string ServiceProviderCode { get; set; } /// /// 子系统 @@ -53,4 +50,24 @@ public class GetTrackPushConfigDetailOutputVO /// 是否全量推送 /// public bool IsAllPush { get; set; } -} \ No newline at end of file + + /// + /// 是否全量推送(最新轨迹) + /// + public bool IsAllPushWithLatest { get; set; } + + /// + /// 时间格式枚举 + /// + public DateTimeFormatEnum? DateTimeFormatType { get; set; } + + /// + /// 日期时间格式模板 + /// + public string? DateTimeFormat { get; set; } + + /// + /// 时区格式格式模板 + /// + public string? TimezoneFormat { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackPush/GetTrackPushConfigPageOutputVO.cs b/src/SJZY.Track.Domain/Dtos/TrackPush/GetTrackPushConfigPageOutputVO.cs index 01550b7f..8ec22d34 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackPush/GetTrackPushConfigPageOutputVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackPush/GetTrackPushConfigPageOutputVO.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Dtos.TrackPush; +namespace SJZY.Track.Domain.Dtos.TrackPush; public class GetTrackPushConfigPageOutputVO { @@ -23,4 +23,4 @@ public class GetTrackPushConfigPageOutputVO /// 子系统id /// public int SubSystemId { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackPush/GetTrackPushContentDetailOutputVO.cs b/src/SJZY.Track.Domain/Dtos/TrackPush/GetTrackPushContentDetailOutputVO.cs index 3656b6f6..7ef7e9f8 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackPush/GetTrackPushContentDetailOutputVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackPush/GetTrackPushContentDetailOutputVO.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Dtos.TrackPush; +namespace SJZY.Track.Domain.Dtos.TrackPush; public class GetTrackPushContentDetailOutputVO { @@ -61,4 +61,4 @@ public class GetTrackPushContentDetailOutputVO /// 推送扩展字段 /// public string ExpandFieldsValue { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackPush/GetTrackPushContentListVo.cs b/src/SJZY.Track.Domain/Dtos/TrackPush/GetTrackPushContentListVo.cs new file mode 100644 index 00000000..f2261703 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/TrackPush/GetTrackPushContentListVo.cs @@ -0,0 +1,36 @@ +namespace SJZY.Track.Domain.Dtos.TrackPush; + +public class GetTrackPushContentListVo +{ + public int Id { get; set; } + + /// + /// 轨迹代码 + /// + public string Code { get; set; } + + /// + /// 推送单号类型 + /// + public int OrderType { get; set; } + + /// + /// 服务商轨迹代码 + /// + public string ServiceCode { get; set; } + + /// + /// 服务商轨迹状态 + /// + public string Status { get; set; } + + /// + /// 服务商轨迹内容 + /// + public string Content { get; set; } + + /// + /// 服务商轨迹内容英文 + /// + public string ContentEn { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackPush/GetTrackPushContentPageInputVO.cs b/src/SJZY.Track.Domain/Dtos/TrackPush/GetTrackPushContentPageInputVO.cs index f0558e95..57bf0626 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackPush/GetTrackPushContentPageInputVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackPush/GetTrackPushContentPageInputVO.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Dtos.TrackPush; +namespace SJZY.Track.Domain.Dtos.TrackPush; public class GetTrackPushContentPageInputVO : PageInfoInput { @@ -6,4 +6,4 @@ public class GetTrackPushContentPageInputVO : PageInfoInput /// 轨迹推送配置id /// public int TrackPushConfigId { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackPush/GetTrackPushContentPageOutputVO.cs b/src/SJZY.Track.Domain/Dtos/TrackPush/GetTrackPushContentPageOutputVO.cs index b3ae2d3f..6b730f2b 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackPush/GetTrackPushContentPageOutputVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackPush/GetTrackPushContentPageOutputVO.cs @@ -7,6 +7,11 @@ public class GetTrackPushContentPageOutputVO /// public string Code { get; set; } + /// + /// 轨迹内容id + /// + public int ContentId { get; set; } + /// /// 轨迹内容 /// @@ -53,4 +58,4 @@ public class GetTrackPushContentPageOutputVO /// 推送轨迹状态 /// public string TrackStatusValue { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackPush/QueryTrackPullMappingsInfoVO.cs b/src/SJZY.Track.Domain/Dtos/TrackPush/QueryTrackPullMappingsInfoVO.cs index 26f7b4a8..170e127c 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackPush/QueryTrackPullMappingsInfoVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackPush/QueryTrackPullMappingsInfoVO.cs @@ -1,60 +1,53 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SJZY.Track.Domain.Dtos.TrackPush; -namespace SJZY.Track.Domain.Dtos.TrackPush +/// +/// 查询轨迹推送关系入参 +/// +public class QueryTrackPullMappingsInfoVO { /// - /// 查询轨迹推送关系入参 + /// 轨迹代码 /// - public class QueryTrackPullMappingsInfoVO - { - /// - /// 轨迹代码 - /// - public string? Code { get; set; } - - /// - /// 订单类型 - /// - public int OrderType { get; set; } - - /// - /// 服务商轨迹代码 - /// - public string? ServiceCode { get; set; } - - /// - /// 服务商轨迹状态 - /// - public string? Status { get; set; } - - /// - /// 服务商轨迹内容 - /// - public string? Content { get; set; } - - /// - /// 服务商轨迹内容英文 - /// - public string? ContentEn { get; set; } - } + public string? Code { get; set; } /// - /// 查询轨迹推送关系返参项 + /// 订单类型 /// - public class QueryTrackPullMappingsInputVO - { - /// - /// 子系统id - /// - public int SubsystemsId { get; set; } + public int OrderType { get; set; } - /// - /// 客户id - /// - public int CustomerId { get; set; } - } + /// + /// 服务商轨迹代码 + /// + public string? ServiceCode { get; set; } + + /// + /// 服务商轨迹状态 + /// + public string? Status { get; set; } + + /// + /// 服务商轨迹内容 + /// + public string? Content { get; set; } + + /// + /// 服务商轨迹内容英文 + /// + public string? ContentEn { get; set; } +} + +/// +/// 查询轨迹推送关系返参项 +/// +public class QueryTrackPullMappingsInputVO +{ + /// + /// 子系统id + /// + public int SubsystemsId { get; set; } + + /// + /// 客户id + /// + public int CustomerId { get; set; } } diff --git a/src/SJZY.Track.Domain/Dtos/TrackPush/TrackPushContentConfigVO.cs b/src/SJZY.Track.Domain/Dtos/TrackPush/TrackPushContentConfigVO.cs index 6ec62e85..66db8889 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackPush/TrackPushContentConfigVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackPush/TrackPushContentConfigVO.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Dtos.TrackPush; +namespace SJZY.Track.Domain.Dtos.TrackPush; public class TrackPushContentConfigVO { @@ -66,4 +66,4 @@ public class TrackPushContentConfigVO /// 扩展字段参数值 /// public string? ExpandFieldsValue { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackStatus/GetPageTrackStatusVO.cs b/src/SJZY.Track.Domain/Dtos/TrackStatus/GetPageTrackStatusVO.cs index f19fb8c5..2b288d02 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackStatus/GetPageTrackStatusVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackStatus/GetPageTrackStatusVO.cs @@ -1,6 +1,6 @@ -namespace SJZY.Track.Domain.Dtos.TrackStatus; +namespace SJZY.Track.Domain.Dtos.TrackStatus; -public class GetPageTrackStatusVO : PageInfoInput +public class GetPagedTrackStatusVO : PageInfoInput { /// /// 子系统id @@ -15,5 +15,5 @@ public class GetPageTrackStatusVO : PageInfoInput /// /// 选中的轨迹状态id /// - public List? SelectIds { get; set; } -} \ No newline at end of file + public List? SelectIds { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackStatus/GetTrackStatusDetailVO.cs b/src/SJZY.Track.Domain/Dtos/TrackStatus/GetTrackStatusDetailVO.cs index 66de23a9..c72d5e64 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackStatus/GetTrackStatusDetailVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackStatus/GetTrackStatusDetailVO.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Dtos.TrackStatus; +namespace SJZY.Track.Domain.Dtos.TrackStatus; public class GetTrackStatusDetailVO { @@ -35,5 +35,20 @@ public class GetTrackStatusDetailVO /// /// 轨迹内容英文 /// - public string EntrackStatus { get; set; } -} \ No newline at end of file + public string EnTrackStatus { get; set; } + + /// + /// 节点名称 + /// + public string? NodeName { get; set; } + + /// + /// 是否完结 + /// + public bool IsCompleted { get; set; } + + /// + /// 是否广播 + /// + public bool IsToMq { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackStatus/GetTrackStatusListVO.cs b/src/SJZY.Track.Domain/Dtos/TrackStatus/GetTrackStatusListVO.cs index ff570fc0..f5d157c9 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackStatus/GetTrackStatusListVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackStatus/GetTrackStatusListVO.cs @@ -1,67 +1,69 @@ -using SJZY.Expand.ABP.Core.PublicMethords; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SJZY.Track.Domain.Dtos.TrackStatus; -namespace SJZY.Track.Domain.Dtos.TrackStatus +public class GetTrackStatusListVO { - public class GetTrackStatusListVO - { - /// - /// Id - /// - public int Id { get; set; } + /// + /// Id + /// + public int Id { get; set; } - /// - /// 子系统 - /// - public string SubSystem { get; set; } + /// + /// 子系统 + /// + public string SubSystem { get; set; } - /// - /// 节点id - /// - public int NodeId { get; set; } + /// + /// 节点id + /// + public int NodeId { get; set; } - /// - /// 所属节点 - /// - public string Node { get; set; } + /// + /// 所属节点 + /// + public string Node { get; set; } - /// - /// 所属轨迹状态 - /// - public string TrackStatus { get; set; } + /// + /// 轨迹状态 + /// + public string TrackStatus { get; set; } - /// - /// 轨迹状态代码 - /// - public string Code { get; set; } + /// + /// 轨迹状态代码 + /// + public string Code { get; set; } - /// - /// 轨迹内容英文 - /// - public string EntrackStatus { get; set; } + /// + /// 轨迹内容英文 + /// + public string EnTrackStatus { get; set; } - /// - /// 创建人 - /// - public string CreateUser { get; set; } + /// + /// 是否完结 + /// + public bool IsCompleted { get; set; } - /// - /// 创建时间 - /// - public DateTime? CreateTime { get; set; } + /// + /// 是否广播 + /// + public bool IsToMq { get; set; } - /// - /// 修改人 - /// - public string UpdateUser { get; set; } + /// + /// 创建人 + /// + public string CreateUser { get; set; } - /// - /// 修改时间 - /// - public DateTime? UpdateTime { get; set; } - } + /// + /// 创建时间 + /// + public DateTime? CreateTime { get; set; } + + /// + /// 修改人 + /// + public string UpdateUser { get; set; } + + /// + /// 修改时间 + /// + public DateTime? UpdateTime { get; set; } } diff --git a/src/SJZY.Track.Domain/Dtos/TrackTemplate/CanDeleteTrackCodeVO.cs b/src/SJZY.Track.Domain/Dtos/TrackTemplate/CanDeleteTrackCodeVO.cs index b4376fe5..c2714285 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackTemplate/CanDeleteTrackCodeVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackTemplate/CanDeleteTrackCodeVO.cs @@ -1,7 +1,7 @@ -namespace SJZY.Track.Domain.Dtos.TrackTemplate; +namespace SJZY.Track.Domain.Dtos.TrackTemplate; public class CanDeleteTrackCodeVO { public int OrderId { get; set; } public string TrackCode { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetPageTrackTemplateListInputVo.cs b/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetPageTrackTemplateListInputVo.cs new file mode 100644 index 00000000..f801ffdc --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetPageTrackTemplateListInputVo.cs @@ -0,0 +1,29 @@ +namespace SJZY.Track.Domain.Dtos.TrackTemplate; + +public class GetPageTrackTemplateListInputVo : PageInfoInput +{ + /// + /// 子系统id + /// + public int SubSystemId { get; set; } + + /// + /// 客户id + /// + public int? CustomerId { get; set; } + + /// + /// 模版分类 + /// + public int? TemplateType { get; set; } + + /// + /// 模板code + /// + public string? TemplateCode { get; set; } + + /// + /// 关键字 + /// + public string? KeyWord { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetPageTrackTemplateVO.cs b/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetPageTrackTemplateVO.cs index 35c4fe8a..d82741d0 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetPageTrackTemplateVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetPageTrackTemplateVO.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Dtos.TrackTemplate; +namespace SJZY.Track.Domain.Dtos.TrackTemplate; public class GetPageTrackTemplateVO : PageInfoInput { @@ -12,7 +12,8 @@ public class GetPageTrackTemplateVO : PageInfoInput /// public string? Keywords { get; set; } + /// /// 选中的轨迹模版id /// public List? SelectIds { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTemplateContentAttributeValueInputVO.cs b/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTemplateContentAttributeValueInputVO.cs deleted file mode 100644 index d8b295a9..00000000 --- a/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTemplateContentAttributeValueInputVO.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SJZY.Track.Domain.Dtos.TrackTemplate -{ - public class GetTemplateContentAttributeValueInputVO - { - /// - /// 子系统id - /// - public int SubSystemId { get; set; } - - /// - /// 轨迹代码 - /// - public List? TrackCodes { get; set; } - - /// - /// 轨迹模板Id - /// - public List? TrackTemplateIds { get; set; } - - ///// - ///// 订单id - ///// - //public int OrderId { get; set; } - } - - public class GetTemplateContentAttributeValueVO - { - /// - /// 轨迹内容id - /// - public int TrackContenId { get; set; } - - /// - /// 模版id - /// - public int TrackTemplateId { get; set; } - - /// - /// 轨迹内容代码 - /// - public string TrackCode { get; set; } - - /// - /// 子系统id - /// - public int SubSystemId { get; set; } - - /// - /// 是否可删 - /// - public bool IsCanDelete { get; set; } - - /// - /// 是否对外 - /// - public bool IsExternal { get; set; } - } -} diff --git a/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTrackTemplateContentDetailOutputVO.cs b/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTrackTemplateContentDetailOutputVo.cs similarity index 78% rename from src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTrackTemplateContentDetailOutputVO.cs rename to src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTrackTemplateContentDetailOutputVo.cs index c4474ba2..f8c1d629 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTrackTemplateContentDetailOutputVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTrackTemplateContentDetailOutputVo.cs @@ -1,6 +1,6 @@ -namespace SJZY.Track.Domain.Dtos.TrackTemplate; +namespace SJZY.Track.Domain.Dtos.TrackTemplate; -public class GetTrackTemplateContentDetailOutputVO +public class GetTrackTemplateContentDetailOutputVo { public int Id { get; set; } @@ -22,7 +22,7 @@ public class GetTrackTemplateContentDetailOutputVO /// /// 轨迹内容 /// - public string TrackContent { get; set; } + public string TrackContent { get; set; } = null!; /// /// 轨迹内容id @@ -32,7 +32,7 @@ public class GetTrackTemplateContentDetailOutputVO /// /// 轨迹状态 /// - public string TrackStatus { get; set; } + public string TrackStatus { get; set; } = null!; /// /// 轨迹状态id @@ -43,4 +43,4 @@ public class GetTrackTemplateContentDetailOutputVO /// 轨迹模板id /// public int TrackTemplateId { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTrackTemplateContentPageInputVO.cs b/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTrackTemplateContentPageInputVO.cs index 09e8f51f..4d5bc0db 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTrackTemplateContentPageInputVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTrackTemplateContentPageInputVO.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Dtos.TrackTemplate; +namespace SJZY.Track.Domain.Dtos.TrackTemplate; public class GetTrackTemplateContentPageInputVO : PageInfoInput { @@ -6,4 +6,4 @@ public class GetTrackTemplateContentPageInputVO : PageInfoInput /// 轨迹模板id /// public List TrackTemplateIds { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTrackTemplateContentPageOutputVO.cs b/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTrackTemplateContentPageOutputVO.cs index b6d43291..64de62bb 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTrackTemplateContentPageOutputVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTrackTemplateContentPageOutputVO.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Dtos.TrackTemplate; +namespace SJZY.Track.Domain.Dtos.TrackTemplate; public class GetTrackTemplateContentPageOutputVO { @@ -73,4 +73,4 @@ public class GetTrackTemplateContentPageOutputVO /// 轨迹内容id /// public int TrackContentId { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTrackTemplateDetailVO.cs b/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTrackTemplateDetailVO.cs index c5230b7e..1fa2b4a0 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTrackTemplateDetailVO.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTrackTemplateDetailVO.cs @@ -31,9 +31,14 @@ public class GetTrackTemplateDetailVO public string Code { get; set; } /// - /// 显示原轨迹 + /// 分类id /// - public bool ShowOrigin { get; set; } + public int CategoryId { get; set; } + + /// + /// 客户id + /// + public int CustomerId { get; set; } } /// @@ -70,4 +75,4 @@ public class GetTrackTemplateListVO /// 创建时间 /// public DateTime? CreateTime { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTrackTemplateListInputVo.cs b/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTrackTemplateListInputVo.cs new file mode 100644 index 00000000..a2f111a7 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTrackTemplateListInputVo.cs @@ -0,0 +1,24 @@ +namespace SJZY.Track.Domain.Dtos.TrackTemplate; + +public class GetTrackTemplateListInputVo +{ + /// + /// 子系统id + /// + public int SubSystemId { get; set; } + + /// + /// 客户id + /// + public int? CustomerId { get; set; } + + /// + /// 模版分类 + /// + public int? TemplateType { get; set; } + + /// + /// 模板code + /// + public string? TemplateCode { get; set; } +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackTemplate/OrderedTrackCodeDto.cs b/src/SJZY.Track.Domain/Dtos/TrackTemplate/OrderedTrackCodeDto.cs index 43805324..0a5e25a2 100644 --- a/src/SJZY.Track.Domain/Dtos/TrackTemplate/OrderedTrackCodeDto.cs +++ b/src/SJZY.Track.Domain/Dtos/TrackTemplate/OrderedTrackCodeDto.cs @@ -21,4 +21,4 @@ public class OrderedTrackCodeDto /// 显示原轨迹 /// public bool ShowOrigin { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Dtos/TrackTemplate/TrackTemplateOutputVo.cs b/src/SJZY.Track.Domain/Dtos/TrackTemplate/TrackTemplateOutputVo.cs new file mode 100644 index 00000000..9996c9b7 --- /dev/null +++ b/src/SJZY.Track.Domain/Dtos/TrackTemplate/TrackTemplateOutputVo.cs @@ -0,0 +1,62 @@ +namespace SJZY.Track.Domain.Dtos.TrackTemplate; + +public class TrackTemplateOutputVo +{ + /// + /// 模版id + /// + public int Id { get; set; } + + /// + /// 模版名称 + /// + public string TemplateName { get; set; } + + /// + /// 模版code + /// + public string TemplateCode { get; set; } + + /// + /// 模版内容 + /// + public List TemplateContents { get; set; } +} + +public class TemplateContentDtoVo +{ + /// + /// 模版id + /// + public int TemplateId { get; set; } + + /// + /// 轨迹code + /// + public string Code { get; set; } + + /// + /// 轨迹内容中文 + /// + public string ContentCn { get; set; } + + /// + /// 轨迹内容中文 + /// + public string ContentEn { get; set; } + + /// + /// 轨迹状态 + /// + public string Status { get; set; } + + /// + /// 轨迹节点 + /// + public string Node { get; set; } + + /// + /// 排序键 + /// + public int Sort { get; set; } +} diff --git a/src/SJZY.Track.Domain/Enums/DateTimeFormatEnum.cs b/src/SJZY.Track.Domain/Enums/DateTimeFormatEnum.cs new file mode 100644 index 00000000..a54e6ece --- /dev/null +++ b/src/SJZY.Track.Domain/Enums/DateTimeFormatEnum.cs @@ -0,0 +1,22 @@ +namespace SJZY.Track.Domain.Enums; + +/// +/// 时间样式枚举 +/// +public enum DateTimeFormatEnum +{ + /// + /// 默认 + /// + None = 0, + + /// + /// 时间戳 + /// + Timestamp = 1, + + /// + /// 时间加时区 + /// + DateTimeAndTimezone = 2 +} diff --git a/src/SJZY.Track.Domain/Enums/EnumPropertyEnums.cs b/src/SJZY.Track.Domain/Enums/EnumPropertyEnums.cs index b26a4303..35bcc3ae 100644 --- a/src/SJZY.Track.Domain/Enums/EnumPropertyEnums.cs +++ b/src/SJZY.Track.Domain/Enums/EnumPropertyEnums.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; namespace SJZY.Track.Domain.Enums; @@ -21,4 +21,4 @@ public enum EnumPropertyEnums /// 轨迹发生地 /// [Description("TrackLocationValue")] 轨迹发生地 -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Enums/NotifyMode.cs b/src/SJZY.Track.Domain/Enums/NotifyMode.cs new file mode 100644 index 00000000..a10dec40 --- /dev/null +++ b/src/SJZY.Track.Domain/Enums/NotifyMode.cs @@ -0,0 +1,14 @@ +namespace SJZY.Track.Domain.Enums; + +public enum NotifyMode +{ + /// + /// 站内信 + /// + SiteInternal = 1, + + /// + /// 飞书 + /// + FeiShu = 2 +} diff --git a/src/SJZY.Track.Domain/Enums/OrderType.cs b/src/SJZY.Track.Domain/Enums/OrderType.cs index 79a97c52..25bf3c5a 100644 --- a/src/SJZY.Track.Domain/Enums/OrderType.cs +++ b/src/SJZY.Track.Domain/Enums/OrderType.cs @@ -1,18 +1,14 @@ -using System.ComponentModel; +using System.ComponentModel; namespace SJZY.Track.Domain.Enums; public enum OrderType { - [Description("干线提单")] - 干线提单 = 1, + [Description("干线提单")] 干线提单 = 1, - [Description("小包运单")] - 小包运单 = 2, + [Description("小包运单")] 小包运单 = 2, - [Description("箱/袋单")] - 箱袋单 = 3, + [Description("箱/袋单")] 箱袋单 = 3, - [Description("FBA订单")] - FBA订单 = 4, -} \ No newline at end of file + [Description("FBA订单")] FBA订单 = 4, +} diff --git a/src/SJZY.Track.Domain/Enums/RuleFactorType.cs b/src/SJZY.Track.Domain/Enums/RuleFactorType.cs new file mode 100644 index 00000000..5a492230 --- /dev/null +++ b/src/SJZY.Track.Domain/Enums/RuleFactorType.cs @@ -0,0 +1,37 @@ +namespace SJZY.Track.Domain.Enums; + +/// +/// 枚举表示不同类型的规则因素。 +/// +public enum RuleFactorType +{ + /// + /// 表示货物类型。 + /// + CargoType = 1, + + /// + /// 表示月份。 + /// + Months, + + /// + /// 表示分区或区域。 + /// + Area, + + /// + /// 指示货物是否中转。 + /// + IsTransit, + + /// + /// 表示起运港口。 + /// + LeavePort, + + /// + /// 表示销售产品。 + /// + ProductCode +} diff --git a/src/SJZY.Track.Domain/Enums/TimezoneSourceEnum.cs b/src/SJZY.Track.Domain/Enums/TimezoneSourceEnum.cs new file mode 100644 index 00000000..17c55bb5 --- /dev/null +++ b/src/SJZY.Track.Domain/Enums/TimezoneSourceEnum.cs @@ -0,0 +1,37 @@ +namespace SJZY.Track.Domain.Enums; + +/// +/// 推送轨迹时区来源 +/// +public enum TimezoneSourceEnum +{ + /// + /// 起运城市 + /// + DeliverCity = 1, + + /// + /// 接收城市 + /// + ReceiveCity = 2, + + /// + /// 起运港口 + /// + DeliverPort = 3, + + /// + /// 接收港口 + /// + ReceivePort = 4, + + /// + /// 起运国家 + /// + DeliverCountry = 5, + + /// + /// 接收国家 + /// + ReceiveCountry = 6 +} diff --git a/src/SJZY.Track.Domain/Enums/TrackLocationValue.cs b/src/SJZY.Track.Domain/Enums/TrackLocationValue.cs index 2aae150e..61259829 100644 --- a/src/SJZY.Track.Domain/Enums/TrackLocationValue.cs +++ b/src/SJZY.Track.Domain/Enums/TrackLocationValue.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.Enums; +namespace SJZY.Track.Domain.Enums; public enum TrackLocationValue { @@ -8,4 +8,4 @@ public enum TrackLocationValue LeaveCountry = 5, ArriveCity = 6, LeaveCity = 7 -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Enums/TrackProblemType.cs b/src/SJZY.Track.Domain/Enums/TrackProblemType.cs index 92369b84..ef7ba7bf 100644 --- a/src/SJZY.Track.Domain/Enums/TrackProblemType.cs +++ b/src/SJZY.Track.Domain/Enums/TrackProblemType.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; namespace SJZY.Track.Domain.Enums; @@ -8,18 +8,15 @@ public enum TrackProblemType /// /// 没问题 /// - [Description("无")] - None = 0, + [Description("无")] None = 0, /// /// 异常 /// - [Description("异常")] - Error = 1, + [Description("异常")] Error = 1, /// /// 预警 /// - [Description("预警")] - Warn = 2, -} \ No newline at end of file + [Description("预警")] Warn = 2, +} diff --git a/src/SJZY.Track.Domain/Enums/TrackSourceEnum.cs b/src/SJZY.Track.Domain/Enums/TrackSourceEnum.cs new file mode 100644 index 00000000..a0107979 --- /dev/null +++ b/src/SJZY.Track.Domain/Enums/TrackSourceEnum.cs @@ -0,0 +1,24 @@ +using System.ComponentModel; + +namespace SJZY.Track.Domain.Enums; + +/// +/// 轨迹来源 +/// +public enum TrackSourceEnum +{ + /// + /// 外部服务商 + /// + [Description("外部服务商")] ExternalServiceProvide = 1, + + /// + /// 内部系统 + /// + [Description("内部系统")] InternalService = 2, + + /// + /// 人工 + /// + [Description("人工")] Artificial = 3, +} diff --git a/src/SJZY.Track.Domain/FodyWeavers.xml b/src/SJZY.Track.Domain/FodyWeavers.xml new file mode 100644 index 00000000..510b255f --- /dev/null +++ b/src/SJZY.Track.Domain/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + diff --git a/src/SJZY.Track.Domain/FodyWeavers.xsd b/src/SJZY.Track.Domain/FodyWeavers.xsd new file mode 100644 index 00000000..d1150002 --- /dev/null +++ b/src/SJZY.Track.Domain/FodyWeavers.xsd @@ -0,0 +1,31 @@ + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all + weavers have been executed. + + + + + + A comma-separated list of error codes that can be safely ignored in assembly + verification. + + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + + diff --git a/src/SJZY.Track.Domain/GlobalUsings.cs b/src/SJZY.Track.Domain/GlobalUsings.cs index deaf0047..48225d4e 100644 --- a/src/SJZY.Track.Domain/GlobalUsings.cs +++ b/src/SJZY.Track.Domain/GlobalUsings.cs @@ -1,10 +1,10 @@ // Global using directives -global using SJZY.Expand.ABP.Core.Common.Dto; -global using SJZY.Expand.ABP.Core.SqlSugar.Entitys; -global using SqlSugar; global using System; global using System.Collections.Generic; global using System.Linq.Expressions; global using System.Threading.Tasks; -global using SJZY.Track.Domain.SeedWork; \ No newline at end of file +global using SJZY.Expand.ABP.Core.Common.Dto; +global using SJZY.Expand.ABP.Core.SqlSugar.Entitys; +global using SJZY.Track.Domain.SeedWork; +global using SqlSugar; diff --git a/src/SJZY.Track.Domain/IBasicRepository.cs b/src/SJZY.Track.Domain/IBasicRepository.cs index 3824c2eb..9d6a4796 100644 --- a/src/SJZY.Track.Domain/IBasicRepository.cs +++ b/src/SJZY.Track.Domain/IBasicRepository.cs @@ -1,4 +1,4 @@ -using SJZY.Track.Domain.Queries; +using SJZY.Track.Domain.Queries; namespace SJZY.Track.Domain; @@ -64,4 +64,4 @@ public interface IBasicRepository : IBasicQuery where T : IAggregateRoot /// /// Task InsertRangeAsync(List entities); -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Queries/IBasicQuery.cs b/src/SJZY.Track.Domain/Queries/IBasicQuery.cs index d2bddef3..d34cd63a 100644 --- a/src/SJZY.Track.Domain/Queries/IBasicQuery.cs +++ b/src/SJZY.Track.Domain/Queries/IBasicQuery.cs @@ -9,6 +9,13 @@ public interface IBasicQuery where T : IEntity /// Task GetFirstAsync(Expression> whereExpression); + /// + /// top 1 select fields + /// + /// + /// + /// + /// Task GetFirstAsync(Expression> whereExpression, Expression> resultExpression); @@ -19,9 +26,23 @@ public interface IBasicQuery where T : IEntity /// Task> GetListAsync(Expression> whereExpression); + /// + /// get list select fields + /// + /// + /// + /// + /// Task> GetListAsync(Expression> whereExpression, Expression> resultExpression); + /// + /// get list select fields, return arrary + /// + /// + /// + /// + /// Task GetArrayAsync(Expression> whereExpression, Expression> resultExpression); @@ -38,4 +59,4 @@ public interface IBasicQuery where T : IEntity /// /// Task IsAnyAsync(Expression> exp); -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/Queries/IProvideQueries.cs b/src/SJZY.Track.Domain/Queries/IProvideQueries.cs index 34e99ae9..d955ffda 100644 --- a/src/SJZY.Track.Domain/Queries/IProvideQueries.cs +++ b/src/SJZY.Track.Domain/Queries/IProvideQueries.cs @@ -1,7 +1,6 @@ using SJZY.Track.Domain.Dtos.Order; using SJZY.Track.Domain.Dtos.TrackContents; -using SJZY.Track.Domain.Dtos.TrackDetails; -using SJZY.Track.Domain.Dtos.TrackTemplate; +using SJZY.Track.Domain.Dtos.TrackPull; namespace SJZY.Track.Domain.Queries; @@ -10,37 +9,6 @@ namespace SJZY.Track.Domain.Queries; /// public interface IProvideQueries { - /// - /// 根据订单号,获取订单模板 - /// - /// 订单类型 - /// 订单号 - /// - Task> GetOrderTemplateLinksAsync(int orderType, List orderNumbers); - - /// - /// 根据订单模板,获取有序的轨迹code - /// - /// 模板id - /// - Task> GetOrderedTrackCodesAsync(List templateIds); - - /// - /// 根据订单id找到订单模板,匹配模板命中的轨迹内容 - /// - /// 订单ids - /// 轨迹代码 - /// - Task> MatchTrackContentAsync(int[] orderIds, string code); - - /// - /// 获取可删除的订单轨迹代码 - /// - /// - /// - /// - Task> GetCanDeleteTrackCodesAsync(List orderIds, List trackCodes); - /// /// 根据子系统内容映射,得到映射后的轨迹code /// @@ -50,22 +18,58 @@ public interface IProvideQueries /// Task> MapTrackCodesAsync(int upSubSystemId, int subSystemId, params string[] trackCodes); + /// + /// 获取子系统内容Code映射 + /// + /// + /// + /// + /// + Task> GetTrackCodeMapsAsync(int upSubSystemId, int subSystemId, params string[] trackCodes); /// /// 根据订单模板找对应服务商 /// + /// /// /// - Task> FindOrderWithServiceProviderAsync(List orderNos); + Task> FindOrderWithServiceProviderAsync(int subSystemId, List orderNos); /// /// 获取服务商下所有单(未完成的) /// - /// + /// 服务商代码 /// /// /// - Task> FindOrderWithServiceProviderAsync(int serviceProvider, int pageIndex, + Task> FindOrderWithServiceProviderAsync(string serviceProviderCode, int pageIndex, int pageSize = 1000); - Task GetTrackContentAsync(int subSystemId, string trackCode); -} \ No newline at end of file + /// + /// 获取轨迹内容 + /// + /// + /// + /// + Task GetTrackContentAsync(int subSystemId, string trackCode); + + /// + /// 获取轨迹内容 + /// + /// 子系统ids + /// 轨迹代码集合 + /// + Task> GetTrackContentsAsync(int[] subSystemIds, string[] trackCodes); + + /// + /// 获取所有拉取配置 + /// + /// + Task> GetAllPullConfigsAsync(); + + /// + /// 子系统id换code + /// + /// + /// + Task SubSystemId2CodeAsync(int subSystemId); +} diff --git a/src/SJZY.Track.Domain/Queries/ITimezoneQueries.cs b/src/SJZY.Track.Domain/Queries/ITimezoneQueries.cs new file mode 100644 index 00000000..400cf6eb --- /dev/null +++ b/src/SJZY.Track.Domain/Queries/ITimezoneQueries.cs @@ -0,0 +1,18 @@ +namespace SJZY.Track.Domain.Queries; + +public interface ITimezoneQueries +{ + /// + /// 通过城市英文名称获取时区 + /// + /// + /// + Task GetCityTimezone(string cityEnName); + + /// + /// 通过港口三字码获取时区 + /// + /// + /// + Task GetPortTimezone(string airCode); +} diff --git a/src/SJZY.Track.Domain/Queries/ITrackOrderQueries.cs b/src/SJZY.Track.Domain/Queries/ITrackOrderQueries.cs deleted file mode 100644 index b521d97d..00000000 --- a/src/SJZY.Track.Domain/Queries/ITrackOrderQueries.cs +++ /dev/null @@ -1,19 +0,0 @@ -using SJZY.Track.Domain.Dtos.Order; - -namespace SJZY.Track.Domain.Queries; - -public interface ITrackOrderQueries -{ - /// - /// 获取分页的轨迹订单 - /// - /// - /// - Task> GetPageTrackOrder(GetPageTrackOrderInputVO input); - - /// - /// 获取轨迹各个问题数 - /// - /// - Task> GetTrackProblemCountsAsync(); -} \ No newline at end of file diff --git a/src/SJZY.Track.Domain/Queries/IVSystemQueries.cs b/src/SJZY.Track.Domain/Queries/IVSystemQueries.cs new file mode 100644 index 00000000..0f1b201a --- /dev/null +++ b/src/SJZY.Track.Domain/Queries/IVSystemQueries.cs @@ -0,0 +1,7 @@ +using SJZY.Track.Domain.VEntities; + +namespace SJZY.Track.Domain.Queries; + +public interface IVSystemQueries : IBasicQuery +{ +} diff --git a/src/SJZY.Track.Domain/Queries/IWarningQueries.cs b/src/SJZY.Track.Domain/Queries/IWarningQueries.cs new file mode 100644 index 00000000..ce4ecb0e --- /dev/null +++ b/src/SJZY.Track.Domain/Queries/IWarningQueries.cs @@ -0,0 +1,35 @@ +using SJZY.Track.Domain.Dtos.Common; +using SJZY.Track.Domain.Dtos.Forewarning; + +namespace SJZY.Track.Domain.Queries; + +public interface IWarningQueries +{ + /// + /// 获取预警通知数据 + /// + /// + /// + Task> GetWarningNotifyRulesAsync(List ruleIds); + + + /// + /// 获取预警规则列表 + /// + /// + Task?> GetWarningRule(int systemId, int customerId); + + /// + /// 获取预警规则基础信息 + /// + /// + /// + Task> GetWarningRuleByAreaId(int areaId); + + /// + /// 订单id换name + /// + /// + /// + Task> GetOrderNoByIdsAsync(int[] orderIds); +} diff --git a/src/SJZY.Track.Domain/SJZY.Track.Domain.csproj b/src/SJZY.Track.Domain/SJZY.Track.Domain.csproj index d086d460..d3ab704d 100644 --- a/src/SJZY.Track.Domain/SJZY.Track.Domain.csproj +++ b/src/SJZY.Track.Domain/SJZY.Track.Domain.csproj @@ -6,7 +6,7 @@ net7.0 True - + diff --git a/src/SJZY.Track.Domain/SJZYTrackDomainModule.cs b/src/SJZY.Track.Domain/SJZYTrackDomainModule.cs index 792e7844..ad164017 100644 --- a/src/SJZY.Track.Domain/SJZYTrackDomainModule.cs +++ b/src/SJZY.Track.Domain/SJZYTrackDomainModule.cs @@ -1,7 +1,7 @@ -using Volo.Abp.Modularity; +using Volo.Abp.Modularity; namespace SJZY.Track.Domain; public class SjzyTrackDomainModule : AbpModule { -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/SeedWork/IAggregateRoot.cs b/src/SJZY.Track.Domain/SeedWork/IAggregateRoot.cs index 613c8055..57fb7b63 100644 --- a/src/SJZY.Track.Domain/SeedWork/IAggregateRoot.cs +++ b/src/SJZY.Track.Domain/SeedWork/IAggregateRoot.cs @@ -1,5 +1,5 @@ -namespace SJZY.Track.Domain.SeedWork; +namespace SJZY.Track.Domain.SeedWork; public interface IAggregateRoot : IEntity { -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/SeedWork/IEntity.cs b/src/SJZY.Track.Domain/SeedWork/IEntity.cs index 06cf92fc..e0db5fea 100644 --- a/src/SJZY.Track.Domain/SeedWork/IEntity.cs +++ b/src/SJZY.Track.Domain/SeedWork/IEntity.cs @@ -1,5 +1,5 @@ -namespace SJZY.Track.Domain.SeedWork; +namespace SJZY.Track.Domain.SeedWork; public interface IEntity { -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/TransactionHelper.cs b/src/SJZY.Track.Domain/TransactionHelper.cs index fa8baac4..dfe40bcb 100644 --- a/src/SJZY.Track.Domain/TransactionHelper.cs +++ b/src/SJZY.Track.Domain/TransactionHelper.cs @@ -1,4 +1,4 @@ -using System.Transactions; +using System.Transactions; namespace SJZY.Track.Domain; @@ -11,7 +11,10 @@ public class TransactionHelper public static TransactionScope GetReadCommitted() { return new TransactionScope(TransactionScopeOption.Required, - new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }, + new TransactionOptions + { + IsolationLevel = IsolationLevel.ReadCommitted + }, TransactionScopeAsyncFlowOption.Enabled); } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/VEntities/VAirportEntity.cs b/src/SJZY.Track.Domain/VEntities/VAirportEntity.cs new file mode 100644 index 00000000..4120c0b4 --- /dev/null +++ b/src/SJZY.Track.Domain/VEntities/VAirportEntity.cs @@ -0,0 +1,89 @@ +namespace SJZY.Track.Domain.VEntities; + +/// +/// 空港 +/// +[SugarTable("v_airport", "空港")] +public class VAirportEntity : IFullAuditedBasicEntitys +{ + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 空运航线id + /// + [SugarColumn(ColumnName = "AirRouteId")] + public int AirRouteId { get; set; } + + /// + /// 城市id + /// + [SugarColumn(ColumnName = "CityId")] + public int CityId { get; set; } + + /// + /// 主港口,空港id + /// + [SugarColumn(ColumnName = "MId", IsNullable = true)] + public int? MId { get; set; } + + /// + /// 中文名 + /// + [SugarColumn(ColumnName = "CnName")] + public string CnName { get; set; } + + /// + /// 英文名 + /// + [SugarColumn(ColumnName = "EnName")] + public string EnName { get; set; } + + /// + /// 代码 + /// + [SugarColumn(ColumnName = "Code", IsNullable = true)] + public string Code { get; set; } + + /// + /// 海关代码 + /// + [SugarColumn(ColumnName = "CustomsCode", IsNullable = true)] + public string CustomsCode { get; set; } + + /// + /// 海关名称 + /// + [SugarColumn(ColumnName = "CustomsName", IsNullable = true)] + public string CustomsName { get; set; } + + /// + /// 离境口岸代码 + /// + [SugarColumn(ColumnName = "DeparturePortCode", IsNullable = true)] + public string DeparturePortCode { get; set; } + + /// + /// 离境口岸名称 + /// + [SugarColumn(ColumnName = "DeparturePortName", IsNullable = true)] + public string DeparturePortName { get; set; } + + /// + /// 国内排序 + /// + [SugarColumn(ColumnName = "DomcSort")] + public int DomcSort { get; set; } + + /// + /// 国外排序 + /// + [SugarColumn(ColumnName = "OverSort")] + public int OverSort { get; set; } + + /// + /// 备注 + /// + [SugarColumn(ColumnName = "Remark", IsNullable = true)] + public string Remark { get; set; } +} diff --git a/src/SJZY.Track.Domain/VEntities/VCityEntity.cs b/src/SJZY.Track.Domain/VEntities/VCityEntity.cs new file mode 100644 index 00000000..040fdf19 --- /dev/null +++ b/src/SJZY.Track.Domain/VEntities/VCityEntity.cs @@ -0,0 +1,107 @@ +namespace SJZY.Track.Domain.VEntities; + +[SugarTable("v_city")] +public class VCityEntity : IFullAuditedBasicEntitys +{ + /// + /// 主键 + /// + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 国家id + /// + [SugarColumn(ColumnName = "CountryId")] + public int CountryId { get; set; } + + /// + /// 省份id + /// + [SugarColumn(ColumnName = "ProvinceId", IsNullable = true)] + public int? ProvinceId { get; set; } + + /// + /// 中文名 + /// + [SugarColumn(ColumnName = "CnName")] + public string CnName { get; set; } + + /// + /// 英文名 + /// + [SugarColumn(ColumnName = "EnName")] + public string EnName { get; set; } + + /// + /// 联合国code + /// + [SugarColumn(ColumnName = "UnCode", IsNullable = true)] + public string UnCode { get; set; } + + /// + /// 所区分组(1华南,2华东,3华北,4 西南,5华中) + /// + [SugarColumn(ColumnName = "CityType", IsNullable = true)] + public int? CityType { get; set; } + + /// + /// 时区 + /// + [SugarColumn(ColumnName = "TimeZone", IsNullable = true)] + public string TimeZone { get; set; } + + /// + /// 排序 + /// + [SugarColumn(ColumnName = "Sort")] + public int Sort { get; set; } + + /// + /// 备注 + /// + [SugarColumn(ColumnName = "Remark", IsNullable = true)] + public string Remark { get; set; } + + /// + /// 国家统计局统计用区划代码 + /// + [SugarColumn(ColumnName = "StatisticalZoningCode", IsNullable = true)] + public string StatisticalZoningCode { get; set; } + + /// + /// 维护时区 + /// + [SugarColumn(ColumnName = "MaintainTimeZone", IsNullable = true)] + public decimal? MaintainTimeZone { get; set; } + + /// + /// 经度 + /// + [SugarColumn(ColumnName = "Longitude", IsNullable = true)] + public string Longitude { get; set; } + + /// + /// 纬度 + /// + [SugarColumn(ColumnName = "Latitude", IsNullable = true)] + public string Latitude { get; set; } + + /// + /// 海拔 + /// + [SugarColumn(ColumnName = "Elevation", IsNullable = true)] + public string Elevation { get; set; } + + /// + /// 语言 + /// + [SugarColumn(ColumnName = "Language", IsNullable = true)] + public string Language { get; set; } + + /// + /// timezoneURL + /// + [SugarColumn(ColumnName = "TimezoneURL", IsNullable = true)] + public string TimezoneURL { get; set; } +} diff --git a/src/SJZY.Track.Domain/VEntities/VCountryEntity.cs b/src/SJZY.Track.Domain/VEntities/VCountryEntity.cs new file mode 100644 index 00000000..126cbd18 --- /dev/null +++ b/src/SJZY.Track.Domain/VEntities/VCountryEntity.cs @@ -0,0 +1,77 @@ +namespace SJZY.Track.Domain.VEntities; + +[SugarTable("v_country")] +public class VCountryEntity : IFullAuditedBasicEntitys +{ + /// + /// 主键 + /// + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 区域id + /// + [SugarColumn(ColumnName = "AreaId")] + public int AreaId { get; set; } + + /// + /// 币种id + /// + [SugarColumn(ColumnName = "CurrencyId", IsNullable = true)] + public int? CurrencyId { get; set; } + + /// + /// 中文名 + /// + [SugarColumn(ColumnName = "CnName")] + public string CnName { get; set; } + + /// + /// 英文名 + /// + [SugarColumn(ColumnName = "EnName")] + public string EnName { get; set; } + + /// + /// 二字代码 + /// + [SugarColumn(ColumnName = "Digit2Code")] + public string Digit2Code { get; set; } + + /// + /// 三字代码 + /// + [SugarColumn(ColumnName = "Digit3Code", IsNullable = true)] + public string Digit3Code { get; set; } + + /// + /// 企业代码类型 + /// + [SugarColumn(ColumnName = "EnterpriseCodeType", IsNullable = true)] + public string EnterpriseCodeType { get; set; } + + /// + /// 区号 + /// + [SugarColumn(ColumnName = "CountryCode", IsNullable = true)] + public int? CountryCode { get; set; } + + /// + /// 时差 + /// + [SugarColumn(ColumnName = "JetLag")] + public int JetLag { get; set; } + + /// + /// 城市名 + /// + [SugarColumn(ColumnName = "CountryName", IsNullable = true)] + public string CountryName { get; set; } + + /// + /// 是否不可使用 + /// + [SugarColumn(ColumnName = "IsUnusable", IsNullable = false)] + public bool IsUnusable { get; set; } +} diff --git a/src/SJZY.Track.Domain/VEntities/VEnumValueInfo.cs b/src/SJZY.Track.Domain/VEntities/VEnumValueInfo.cs index cfefa5c6..eca94a79 100644 --- a/src/SJZY.Track.Domain/VEntities/VEnumValueInfo.cs +++ b/src/SJZY.Track.Domain/VEntities/VEnumValueInfo.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.VEntities; +namespace SJZY.Track.Domain.VEntities; /// /// 主数据枚举 @@ -47,4 +47,4 @@ public class VEnumValueInfoEntity : IFullAuditedBasicEntitys /// [SugarColumn(ColumnName = "Remark")] public string Remark { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/VEntities/VExternalSubjectEntity.cs b/src/SJZY.Track.Domain/VEntities/VExternalSubjectEntity.cs index 51bea216..376ae476 100644 --- a/src/SJZY.Track.Domain/VEntities/VExternalSubjectEntity.cs +++ b/src/SJZY.Track.Domain/VEntities/VExternalSubjectEntity.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Repository.VData.Entitys; +namespace SJZY.Track.Domain.VEntities; /// /// 外部主体 @@ -125,4 +125,10 @@ public class VExternalSubjectEntity : IFullAuditedBasicEntitys /// [SugarColumn(ColumnName = "VerifiedName")] public string VerifiedName { get; set; } -} \ No newline at end of file + + /// + /// api服务商代码 + /// + [SugarColumn(ColumnName = "ApiServiceCode")] + public string ApiServiceCode { get; set; } +} diff --git a/src/SJZY.Track.Domain/VEntities/VServiceProviderEntity.cs b/src/SJZY.Track.Domain/VEntities/VServiceProviderEntity.cs index 737fbb0f..3bf955c1 100644 --- a/src/SJZY.Track.Domain/VEntities/VServiceProviderEntity.cs +++ b/src/SJZY.Track.Domain/VEntities/VServiceProviderEntity.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.VEntities; +namespace SJZY.Track.Domain.VEntities; /// /// 服务商主表 @@ -71,4 +71,4 @@ public class VServiceProviderEntity : IFullAuditedBasicEntitys /// [SugarColumn(ColumnName = "Types")] public string Types { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/VEntities/VSystemEntity.cs b/src/SJZY.Track.Domain/VEntities/VSystemEntity.cs index eb0030be..b5a84874 100644 --- a/src/SJZY.Track.Domain/VEntities/VSystemEntity.cs +++ b/src/SJZY.Track.Domain/VEntities/VSystemEntity.cs @@ -1,10 +1,10 @@ -namespace SJZY.Track.Domain.VEntities; +namespace SJZY.Track.Domain.VEntities; /// /// /// [SugarTable("v_system")] -public class VSystemEntity : IFullAuditedBasicEntitys +public class VSystemEntity : IFullAuditedBasicEntitys, IEntity { /// /// 子系统id @@ -149,4 +149,4 @@ public class VSystemEntity : IFullAuditedBasicEntitys /// [SugarColumn(ColumnName = "Token")] public string Token { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Domain/VEntities/VUserEntity.cs b/src/SJZY.Track.Domain/VEntities/VUserEntity.cs index 71a52664..82daae59 100644 --- a/src/SJZY.Track.Domain/VEntities/VUserEntity.cs +++ b/src/SJZY.Track.Domain/VEntities/VUserEntity.cs @@ -1,4 +1,4 @@ -namespace SJZY.Track.Domain.VEntities; +namespace SJZY.Track.Domain.VEntities; /// /// 用户信息表 @@ -101,4 +101,4 @@ public class VUserEntity : IFullAuditedBasicEntitys /// [SugarColumn(ColumnName = "UserOrigin")] public bool? UserOrigin { get; set; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Repository/DataBaseContext.cs b/src/SJZY.Track.Repository/DataBaseContext.cs index 88539836..00429345 100644 --- a/src/SJZY.Track.Repository/DataBaseContext.cs +++ b/src/SJZY.Track.Repository/DataBaseContext.cs @@ -1,4 +1,4 @@ -using SJZY.UserCenter.HttpApi.Services; +using SJZY.UserCenter.HttpApi.Services; #pragma warning disable 1591 @@ -20,21 +20,20 @@ public class DataBaseContext //新增 if (entityInfo.OperationType == DataFilterType.InsertByObject) { + var time = DateTime.Now; + var userId = CurrentUserRequest.CurrentUser.UserId; + if (entityInfo.PropertyName == nameof(ICreateBaicEntity.CreateTime)) - entityInfo.SetValue(DateTime.Now); - if (entityInfo.PropertyName == nameof(ICreateBaicEntity.CreateUserId)) + entityInfo.SetValue(time); + else if (entityInfo.PropertyName == nameof(IUpdateBasicEntity.UpdateTime)) + entityInfo.SetValue(time); + else if (entityInfo.PropertyName == nameof(ICreateBaicEntity.CreateUserId)) { - if (oldValue == null || (int)oldValue == 0) - { - try - { - entityInfo.SetValue(CurrentUserRequest.CurrentUser?.UserId); - } - catch - { - } - } - //entityInfo.SetValue(CurrentUserRequest.CurrentUser.UserId); + entityInfo.SetValue(userId); + } + else if (entityInfo.PropertyName == nameof(IUpdateBasicEntity.UpdateUserId)) + { + entityInfo.SetValue(userId); } } //修改 @@ -44,17 +43,7 @@ public class DataBaseContext entityInfo.SetValue(DateTime.Now); else if (entityInfo.PropertyName == nameof(IUpdateBasicEntity.UpdateUserId)) { - if (oldValue == null || (int)oldValue == 1) - { - try - { - entityInfo.SetValue(CurrentUserRequest.CurrentUser.UserId); - } - catch - { - } - } - //entityInfo.SetValue(CurrentUserRequest.CurrentUser.UserId); + entityInfo.SetValue(CurrentUserRequest.CurrentUser.UserId); } //删除 else if (entityInfo.PropertyName == nameof(IDeleteBasicEntity.IsDeleted)) @@ -74,4 +63,4 @@ public class DataBaseContext } #endregion 审计属性自动赋值 -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Repository/EsExtensions.cs b/src/SJZY.Track.Repository/EsExtensions.cs index b926f93b..1a02be94 100644 --- a/src/SJZY.Track.Repository/EsExtensions.cs +++ b/src/SJZY.Track.Repository/EsExtensions.cs @@ -1,10 +1,19 @@ -using Nest; +using Nest; using SJZY.Expand.ElasticSearch; namespace SJZY.Track.Repository; +/// +/// es extensions +/// public static class EsExtensions { + /// + /// return list with id + /// + /// + /// + /// public static List ToIdList(this ISearchResponse response) where T : IdBaseIndex { var dtos = new List(); @@ -19,4 +28,4 @@ public static class EsExtensions return dtos; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Repository/GlobalUsing.cs b/src/SJZY.Track.Repository/GlobalUsing.cs index bb8c080a..30edf0ad 100644 --- a/src/SJZY.Track.Repository/GlobalUsing.cs +++ b/src/SJZY.Track.Repository/GlobalUsing.cs @@ -1,7 +1,6 @@ -global using SJZY.Expand.ABP.Core; +global using SJZY.Expand.ABP.Core; global using SJZY.Expand.ABP.Core.Common.Dto; global using SJZY.Expand.ABP.Core.SqlSugar; global using SJZY.Expand.ABP.Core.SqlSugar.Entitys; -global using SJZY.Expand.ABP.Core.SqlSugar.Tools; global using SqlSugar; -global using Volo.Abp.DependencyInjection; \ No newline at end of file +global using Volo.Abp.DependencyInjection; diff --git a/src/SJZY.Track.Repository/Queries/BasicQuery.cs b/src/SJZY.Track.Repository/Queries/BasicQuery.cs index 23a3abf1..7842754a 100644 --- a/src/SJZY.Track.Repository/Queries/BasicQuery.cs +++ b/src/SJZY.Track.Repository/Queries/BasicQuery.cs @@ -1,33 +1,39 @@ -using System.Linq.Expressions; +using System.Linq.Expressions; using SJZY.Track.Domain.Queries; using SJZY.Track.Domain.SeedWork; namespace SJZY.Track.Repository.Queries; -#pragma warning disable CS8613 +/// +/// basic queries +/// +/// public class BasicQuery : SimpleClient, IBasicQuery where T : class, IEntity, new() -#pragma warning restore CS8613 { + /// public BasicQuery() { Context = SqlsugarScopeBasic.GetContextSafely("default"); } + /// public async Task GetFirstAsync(Expression> whereExpression, Expression> resultExpression) { return await Context.Queryable().Where(whereExpression).Select(resultExpression).FirstAsync(); } + /// public async Task> GetListAsync(Expression> whereExpression, Expression> resultExpression) { return await Context.Queryable().Where(whereExpression).Select(resultExpression).ToListAsync(); } + /// public async Task GetArrayAsync(Expression> whereExpression, Expression> resultExpression) { return await Context.Queryable().Where(whereExpression).Select(resultExpression).ToArrayAsync(); } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Repository/Queries/ProvideQueries.cs b/src/SJZY.Track.Repository/Queries/ProvideQueries.cs index f2a9f25c..81d6703e 100644 --- a/src/SJZY.Track.Repository/Queries/ProvideQueries.cs +++ b/src/SJZY.Track.Repository/Queries/ProvideQueries.cs @@ -1,92 +1,29 @@ using SJZY.Track.Domain.Aggregates.OrderAggregate; using SJZY.Track.Domain.Aggregates.TrackContentAggregate; +using SJZY.Track.Domain.Aggregates.TrackFlagAggregate; +using SJZY.Track.Domain.Aggregates.TrackPullAggregate; using SJZY.Track.Domain.Aggregates.TrackStatusAggregate; -using SJZY.Track.Domain.Aggregates.TrackTemplateAggregate; using SJZY.Track.Domain.Dtos.Order; using SJZY.Track.Domain.Dtos.TrackContents; -using SJZY.Track.Domain.Dtos.TrackDetails; -using SJZY.Track.Domain.Dtos.TrackTemplate; +using SJZY.Track.Domain.Dtos.TrackPull; using SJZY.Track.Domain.Queries; using SJZY.Track.Domain.VEntities; namespace SJZY.Track.Repository.Queries; -public class ProvideQueries : ISugarRepository, IProvideQueries, - ITransientDependency +/// +/// 提供服务相关查询 +/// +public class ProvideQueries : ISugarRepository, IProvideQueries, ITransientDependency { - public ISqlSugarClient Context { get; set; } - + /// + /// ctor + /// public ProvideQueries() { Context = SqlsugarScopeBasic.GetContextSafely("default"); } - public async Task> GetOrderTemplateLinksAsync(int orderType, List orderNumbers) - { - return await Context.Queryable() - .LeftJoin((a, b) => a.Id == b.OrderId) - .Where(a => a.OrderType == orderType && orderNumbers.Contains(a.OrderNo)) - .Select((a, b) => new OrderTemplateLinkDto - { - OrderNo = a.OrderNo, - TemplateId = b.TrackTemplateId - }) - .ToListAsync(); - } - - public async Task> GetOrderedTrackCodesAsync(List templateIds) - { - return await Context.Queryable() - .LeftJoin((a, b) => a.Id == b.TrackTemplateId) - .LeftJoin((a, b, c) => b.TrackContentId == c.Id) - .Where(a => templateIds.Contains(a.Id)) - .OrderBy((a, b) => b.Sort) - .Select((a, b, c) => new OrderedTrackCodeDto - { - TemplateId = a.Id, - ShowOrigin = a.ShowOrigin, - Code = c.Code, - IsExternal = b.IsExternal - }) - .ToListAsync(); - } - - public async Task> MatchTrackContentAsync(int[] orderIds, string code) - { - if (orderIds.Length == 0) return new List(); - return await Context.Queryable() - .LeftJoin((x, a) => x.TrackTemplateId == a.TrackTemplateId) - .LeftJoin((x, a, b) => a.TrackContentId == b.Id) - .LeftJoin((x, a, b, c) => b.TrackStatusId == c.Id) - .Where((x, a, b) => orderIds.Contains(x.OrderId) && b.Code == code) - .Select((x, a, b, c) => new MatchTrackContentDto - { - OrderId = x.OrderId, - TrackCode = b.Code, - Content = b.Content, - EnContent = b.EnContent, - Status = c.Status, - IsCanDelete = a.IsCanDelete - }) - .ToListAsync(); - } - - public async Task> GetCanDeleteTrackCodesAsync(List orderIds, - List trackCodes) - { - return await Context.Queryable() - .LeftJoin((x, a) => x.TrackTemplateId == a.TrackTemplateId && a.IsCanDelete) - .LeftJoin((x, a, b) => a.TrackContentId == b.Id) - .Where((x, a, b) => orderIds.Contains(x.OrderId) - && trackCodes.Contains(b.Code) && a.IsCanDelete) - .Select((x, a, b) => new CanDeleteTrackCodeVO - { - OrderId = x.OrderId, - TrackCode = b.Code - }) - .ToListAsync(); - } - public async Task> MapTrackCodesAsync(int upSubSystemId, int subSystemId, params string[] trackCodes) { // 根据上游code得到下游code @@ -97,57 +34,149 @@ public class ProvideQueries : ISugarRepository, IProvideQueries, .ToListAsync(); } - - public async Task> FindOrderWithServiceProviderAsync(List orderNos) + public async Task> GetTrackCodeMapsAsync(int upSubSystemId, int subSystemId, params string[] trackCodes) { - return await Context.Queryable() - .LeftJoin((a, b) => a.Id == b.OrderId) - .LeftJoin((a, b, c) => b.ServiceProviderId == c.Id) - .Where(a => !a.IsCompleted && orderNos.Contains(a.OrderNo)) - .Select((a, b, c) => new OrderWithServiceProviderVO + // 根据上游code得到下游code + return await Context.Queryable() + .Where(x => x.SubSystemId == subSystemId && x.MapSubSystemId == upSubSystemId && + trackCodes.Contains(x.MapTrackContentCode)) + .Select(x => new TrackCodeMapVO() { - OrderNo = a.OrderNo, - OrderType = a.OrderType, - ServiceProviderId = b.ServiceProviderId, - ServiceProviderCode = c.Code, - ServiceProviderName = c.Name, - SubSystemId = a.SubSystemId + SubSystemId = x.SubSystemId, + TrackContentCode = x.TrackContentCode, + MapSubSystemId = x.MapSubSystemId, + MapTrackContentCode = x.MapTrackContentCode }) .ToListAsync(); } - public async Task> FindOrderWithServiceProviderAsync(int serviceProvider, + /// + public async Task> FindOrderWithServiceProviderAsync(int subSystemId, + List orderNos) + { + return await Context.Queryable() + .InnerJoin((a, b) => a.Id == b.OrderId) + .LeftJoin((a, b, c) => a.SubSystemId == c.Id) + .WhereIF(subSystemId > 0, a => a.SubSystemId == subSystemId) + .Where((a, b) => !a.IsCompleted && orderNos.Contains(a.OrderNo) + && b.StartTime <= DateTime.Now && b.EndTime >= DateTime.Now) + .Select((a, b, c) => new OrderWithServiceProviderVO + { + //优先使用第三方的订单号,为空时才使用主单号 + OrderNo = b.OrderNo ?? a.OrderNo, + OrderType = a.OrderType, + SubSystemId = a.SubSystemId, + ServiceProviderCode = b.ServiceProviderCode, + SubSystemCode = c.Key + }) + .ToListAsync(); + } + + public async Task> FindOrderWithServiceProviderAsync( + string serviceProviderCode, int pageIndex, int pageSize = 1000) { return await Context.Queryable() - .RightJoin((a, b) => a.Id == b.OrderId) - .LeftJoin((a, b, c) => b.ServiceProviderId == c.Id) - .Where((a, b) => b.ServiceProviderId == serviceProvider && !a.IsCompleted) - .Select((a, b, c) => new OrderWithServiceProviderVO + .InnerJoin((a, b) => a.Id == b.OrderId) + .Where((a, b) => b.ServiceProviderCode == serviceProviderCode && !a.IsCompleted + && b.StartTime <= DateTime.Now && + b.EndTime >= DateTime.Now) + .Select((a, b) => new OrderWithServiceProviderVO { - OrderNo = a.OrderNo, + //优先使用第三方的订单号,为空时才使用主单号 + OrderNo = b.OrderNo ?? a.OrderNo, OrderType = a.OrderType, - ServiceProviderId = b.ServiceProviderId, - ServiceProviderCode = c.Code, - ServiceProviderName = c.Name, - SubSystemId = a.SubSystemId + SubSystemId = a.SubSystemId, + ServiceProviderCode = b.ServiceProviderCode }) .Skip((pageIndex - 1) * pageSize) .Take(pageSize) .ToListAsync(); } - public async Task GetTrackContentAsync(int subSystemId, string trackCode) + /// + public async Task GetTrackContentAsync(int subSystemId, string trackCode) { return await Context.Queryable() .LeftJoin((x, y) => x.TrackStatusId == y.Id) + .LeftJoin((x, y, z) => x.SubSystemId == z.Id) + .LeftJoin((x, y, z, k) => x.SubSystemId == k.SubSystemId && k.Code == x.Code) .Where(x => x.SubSystemId == subSystemId && x.Code == trackCode) - .Select((x, y) => new TrackContentVO + .Select((x, y, z, k) => new TrackContentVO { + SubSystemId = x.SubSystemId, + SubSystemCode = z.Key, + TrackStatusId = x.TrackStatusId, TrackStatus = y.Status, + TrackStatusCode = y.Code, + TrackContentCode = x.Code, + TrackContentId = x.Id, TrackContent = x.Content, - TrackEnContent = x.EnContent + TrackEnContent = x.EnContent, + IsCompleted = y.IsCompleted, + IsRepeatable = x.IsRepeatable, + IsExternal = x.IsExternal, + IsAllowManuallyUpdate = x.IsAllowManuallyUpdate, + IsAllowManuallyCreate = x.IsAllowManuallyCreate, + IsToMq = y.IsToMq || k.IsToMq, }) .FirstAsync(); } -} \ No newline at end of file + + public async Task> GetTrackContentsAsync(int[] subSystemIds, string[] trackCodes) + { + return await Context.Queryable() + .LeftJoin((x, y) => x.TrackStatusId == y.Id) + .LeftJoin((x, y, z) => x.SubSystemId == z.Id) + .LeftJoin((x, y, z, k) => x.SubSystemId == k.SubSystemId && k.Code == x.Code) + .Where(x => subSystemIds.Contains(x.SubSystemId) && trackCodes.Contains(x.Code)) + .Select((x, y, z, k) => new TrackContentVO + { + SubSystemId = x.SubSystemId, + SubSystemCode = z.Key, + TrackStatusId = x.TrackStatusId, + TrackStatus = y.Status, + TrackStatusCode = y.Code, + TrackContentCode = x.Code, + TrackContentId = x.Id, + TrackContent = x.Content, + TrackEnContent = x.EnContent, + IsCompleted = y.IsCompleted, + IsRepeatable = x.IsRepeatable, + IsExternal = x.IsExternal, + IsAllowManuallyUpdate = x.IsAllowManuallyUpdate, + IsAllowManuallyCreate = x.IsAllowManuallyCreate, + IsToMq = y.IsToMq || k.IsToMq, + }) + .ToListAsync(); + } + + public async Task> GetAllPullConfigsAsync() + { + return await Context.Queryable() + .LeftJoin((a, b) => a.ServiceProviderId == b.Id) + .LeftJoin((a, b, c) => a.SubSystemId == c.Id) + .Select((a, b, c) => new TrackPullConfigVo + { + PullInterval = a.PullInterval, + ServiceProviderId = a.ServiceProviderId, + ServiceProviderCode = b.Code, + SubSystemCode = c.Key, + SubSystemId = c.Id + }) + .ToListAsync(); + } + + public async Task SubSystemId2CodeAsync(int subSystemId) + { + return await Context.Queryable() + .Where(x => x.Id == subSystemId) + .Select(x => x.Key) + .FirstAsync(); + } + + /// + /// db context + /// + public ISqlSugarClient Context { get; set; } +} diff --git a/src/SJZY.Track.Repository/Queries/TimezoneQueries.cs b/src/SJZY.Track.Repository/Queries/TimezoneQueries.cs new file mode 100644 index 00000000..3694fb10 --- /dev/null +++ b/src/SJZY.Track.Repository/Queries/TimezoneQueries.cs @@ -0,0 +1,103 @@ +using SJZY.Track.Domain.Consts; +using SJZY.Track.Domain.Dtos.Common; +using SJZY.Track.Domain.Queries; +using SJZY.Track.Domain.VEntities; + +namespace SJZY.Track.Repository.Queries; + +/// +/// 时区查询 +/// +public class TimezoneQueries : ITimezoneQueries, ISugarRepository, ITransientDependency +{ + public TimezoneQueries() + { + Context = SqlsugarScopeBasic.GetContextSafely("default"); + } + + public ISqlSugarClient Context { get; set; } + + /// + /// 获取城市时区 + /// + /// 城市英文名称 + /// 时区 + public async Task GetCityTimezone(string cityEnName) + { + var key = GetCityKey(cityEnName); + var timezone = RedisHelper.Client.Get(key); + if (!string.IsNullOrEmpty(timezone)) + { + return timezone; + } + + var cityTimezone = await GetTimezoneByCityName(cityEnName); + if (cityTimezone == null!) + { + await RedisHelper.Client.SetAsync(key, string.Empty, TimeSpan.FromSeconds(20)); + return string.Empty; + } + + await RedisHelper.Client.SetAsync(key, cityTimezone.Timezone, TimeSpan.FromHours(24)); + return cityTimezone.Timezone; + } + + /// + /// 获取港口时区 + /// + /// 港口三字码 + /// 时区 + public async Task GetPortTimezone(string airCode) + { + var key = GetPortKey(airCode); + var timezone = RedisHelper.Client.Get(key); + if (!string.IsNullOrEmpty(timezone)) + { + return timezone; + } + + var portTimezone = await GetTimezoneByPortCode(airCode); + if (portTimezone == null!) + { + await RedisHelper.Client.SetAsync(key, string.Empty, TimeSpan.FromSeconds(20)); + return string.Empty; + } + + await RedisHelper.Client.SetAsync(key, portTimezone.Timezone, TimeSpan.FromHours(24)); + return portTimezone.Timezone; + } + + private string GetCityKey(string cityEnName) + { + return $"{GlobalConst.CityTimezoneKeyPrefix}:{cityEnName}"; + } + + private string GetPortKey(string airCode) + { + return $"{GlobalConst.PortTimezoneKeyPrefix}:{airCode}"; + } + + private Task GetTimezoneByCityName(string cityEnName) + { + return Context.Queryable().Where(val => !val.IsDeleted && val.EnName == cityEnName) + .Select(val => new CityTimezoneDto() + { + CityEnName = val.EnName, + Timezone = val.TimeZone + }) + .FirstAsync(); + } + + private Task GetTimezoneByPortCode(string airCode) + { + return Context.Queryable() + .InnerJoin((city, airport) => city.Id == airport.CityId) + .Where((city, airport) => !airport.IsDeleted && !city.IsDeleted && airport.Code == airCode) + .Select((city, airport) => new PortTimezoneDto() + { + PortCode = airport.Code, + Timezone = city.TimeZone + }) + .FirstAsync(); + } +} diff --git a/src/SJZY.Track.Repository/Queries/TrackOrderQueries.cs b/src/SJZY.Track.Repository/Queries/TrackOrderQueries.cs deleted file mode 100644 index 841a3555..00000000 --- a/src/SJZY.Track.Repository/Queries/TrackOrderQueries.cs +++ /dev/null @@ -1,97 +0,0 @@ -using SJZY.Track.Domain.Aggregates.OrderAggregate; -using SJZY.Track.Domain.Aggregates.TrackTemplateAggregate; -using SJZY.Track.Domain.Dtos.Order; -using SJZY.Track.Domain.Enums; -using SJZY.Track.Domain.Queries; -using SJZY.Track.Domain.VEntities; -using SJZY.Track.Repository.VData.Entitys; - -namespace SJZY.Track.Repository.Queries; - -public class TrackOrderQueries : ISugarRepository, ITrackOrderQueries, - ITransientDependency -{ - public ISqlSugarClient Context { get; set; } - - public TrackOrderQueries() - { - Context = SqlsugarScopeBasic.GetContextSafely("default"); - } - - /// - /// 获取分页的轨迹订单 - /// - /// - /// - public async Task> GetPageTrackOrder(GetPageTrackOrderInputVO input) - { - var pageList = await Context.Queryable() - .LeftJoin((a, b) => a.CustomId == b.Id && b.IsDeleted == false) - .LeftJoin((a, b, c) => a.SubSystemId == c.Id && c.IsDeleted == false) - .WhereIF(input.SubSystemId > 0, (a, b, c) => a.SubSystemId == input.SubSystemId) - .WhereIF(!input.OrderNos.IsNullOrEmpty(), (a, b, c) => input.OrderNos!.Contains(a.OrderNo)) - .WhereIF(input.CreateTimeStart.HasValue && input.CreateTimeEnd.HasValue, - (a, b, c) => a.CreateTime >= input.CreateTimeStart && a.CreateTime <= input.CreateTimeEnd) - .WhereIF(input.CreateTimeStart.HasValue && (!input.CreateTimeEnd.HasValue), - (a, b, c) => a.CreateTime >= input.CreateTimeStart) - .WhereIF((!input.CreateTimeStart.HasValue) && input.CreateTimeEnd.HasValue, - (a, b, c) => a.CreateTime <= input.CreateTimeEnd) - .WhereIF(input.CustomerId > 0, (a, b, c) => a.CustomId == input.CustomerId) - .WhereIF(input.TrackOrderType > 0, (a, b, c) => a.OrderType == input.TrackOrderType) - .WhereIF(input.TabType > 0, (a, b, c) => a.QuestionType == input.TabType) - .WhereIF(input.TabType == (int)TrackProblemType.Warn, (a, b, c) => !a.IsCompleted) - .OrderByDescending((a, b, c) => a.CreateTime) - .Select((a, b, c) => new TrackOrderVO - { - Id = a.Id, - OrderNumber = a.OrderNo, - OrderType = a.OrderType, - QuestionType = a.QuestionType, - CustomerShortName = b.Abbreviation, - CustomerCode = b.Code, - CustomerId = a.CustomId, - NewestTrackContent = a.LatestTrackContent, - NewestTrackEnContent = a.LatestTrackEnContent, - NewestTrackPlace = a.LatestTrackPlace, - NewestTrackTime = a.LatestTrackTime, - IsFinish = a.IsCompleted, - CreateTime = a.CreateTime, - SubSystem = c.CnName, - SubSystemId = c.Id - }) - .ToPagedListAsync(input.PageIndex, input.PageSize); - - if (pageList.List.Any()) - { - //查询也需要最新的轨迹 - var orderIds = pageList.List.Select(a => a.Id).ToList(); - //查询轨迹模版 - var trackTemplateList = await Context.Queryable() - .LeftJoin((a, b) => a.TrackTemplateId == b.Id) - .Where((a, b) => orderIds.Contains(a.OrderId)) - .Select((a, b) => new { a.OrderId, b.Name, TemplateId = b.Id }) - .ToListAsync(); - pageList.List.ForEach(a => - { - a.TrackTemplateNames = trackTemplateList.Where(b => b.OrderId == a.Id).Select(x => x.Name) - .JoinAsString(","); - a.TrackTemplateIds = trackTemplateList.Where(b => b.OrderId == a.Id).Where(b => b.TemplateId > 0) - .Select(x => x.TemplateId).ToList(); - }); - } - - return pageList; - } - - public async Task> GetTrackProblemCountsAsync() - { - return await Context.Queryable() - .GroupBy(x => x.QuestionType) - .Select(x => new GetTrackCounterVO - { - ProblemType = x.QuestionType, - Count = SqlFunc.AggregateCount(1) - }) - .ToListAsync(); - } -} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/Queries/VSystemQueries.cs b/src/SJZY.Track.Repository/Queries/VSystemQueries.cs new file mode 100644 index 00000000..872f9ea2 --- /dev/null +++ b/src/SJZY.Track.Repository/Queries/VSystemQueries.cs @@ -0,0 +1,8 @@ +using SJZY.Track.Domain.Queries; +using SJZY.Track.Domain.VEntities; + +namespace SJZY.Track.Repository.Queries; + +public class VSystemQueries : BasicQuery, IVSystemQueries, ITransientDependency +{ +} diff --git a/src/SJZY.Track.Repository/Queries/WarningQueries.cs b/src/SJZY.Track.Repository/Queries/WarningQueries.cs new file mode 100644 index 00000000..41bd3884 --- /dev/null +++ b/src/SJZY.Track.Repository/Queries/WarningQueries.cs @@ -0,0 +1,111 @@ +using Newtonsoft.Json; +using SJZY.Track.Domain.Aggregates.ForewarningAggregate; +using SJZY.Track.Domain.Aggregates.KPIAreaAggregate; +using SJZY.Track.Domain.Aggregates.OrderAggregate; +using SJZY.Track.Domain.Dtos.Common; +using SJZY.Track.Domain.Dtos.Forewarning; +using SJZY.Track.Domain.Queries; +using SJZY.Track.Domain.VEntities; + +namespace SJZY.Track.Repository.Queries; + +public class WarningQueries : ISugarRepository, IWarningQueries, + ITransientDependency +{ + public ISqlSugarClient Context { get; set; } = SqlsugarScopeBasic.GetContextSafely("default"); + + public async Task> GetWarningNotifyRulesAsync(List ruleIds) + { + return await Context.Queryable() + .LeftJoin((w, wr) => w.Id == wr.WarningId) + .LeftJoin((w, wr, a) => wr.AreaId == a.Id) + .LeftJoin((w, wr, a, wn) => + wr.WarningId == wn.WarningId && wr.StartTrackStatusId == wn.StartTrackStatusId && + wr.EndTrackStatusId == wn.EndTrackStatusId) + .LeftJoin((w, wr, a, wn, cus) => w.CustomerId == cus.Id) + .LeftJoin((w, wr, a, wn, cus, system) => w.SubSystemId == system.Id) + .Filter(null, true) // 支持历史规则 + .Where((w, wr) => ruleIds.Contains(wr.Id)) + .Select((w, wr, a, wn, cus, system) => new GetWarningNotifiesVo + { + SubSystemId = w.SubSystemId, + SubSystemName = system.CnName, + RuleId = wr.Id, + WarningName = w.Name, + CustomId = w.CustomerId, + CustomName = cus.Name, + TotalTimeSpan = wr.TotalTimeSpan, + WarnTimeSpan = wr.WarnTimeSpan, + WarnCount = wr.WarnCount, + StartTrackStatus = wr.StartTrackStatus, + EndTrackStatus = wr.EndTrackStatus, + CargoType = wr.CargoType, + Months = wr.Months, + AreaName = a.Name, + IsTransit = wr.IsTransit, + LeavePort = wr.LeavePort, + ProductCode = wr.ProductCode, + NotifyMode = wn.NotifyMode, + NotifyUser = wn.NotifyUser, + FactorTypeSort = w.FactorTypeSort + }) + .Mapper(rule => + { + rule.NotifyUsers = JsonConvert.DeserializeObject>(rule.NotifyUser) ?? + new List(); + }) + .ToListAsync(); + } + + public Task?> GetWarningRule(int systemId, int customerId) + { + return Context.Queryable() + .InnerJoin((a, b) => a.WarningId == b.Id) + .Where((a, b) => b.IsEnable && b.SubSystemId == systemId && b.CustomerId == customerId) + .Select((a, b) => new WarningRuleCacheDto + { + Id = a.Id, + WarningId = a.WarningId, + TotalTimeSpan = a.TotalTimeSpan, + WarnTimeSpan = a.WarnTimeSpan, + WarnCount = a.WarnCount, + StartTrackStatusId = a.StartTrackStatusId, + EndTrackStatusId = a.EndTrackStatusId, + CargoType = a.CargoType, + Months = a.Months, + AreaId = a.AreaId, + IsTransit = a.IsTransit, + LeavePort = a.LeavePort, + ProductCode = a.ProductCode, + CustomerId = b.CustomerId, + SystemId = b.SubSystemId + }) + .ToListAsync(); + } + + public Task> GetWarningRuleByAreaId(int areaId) + { + return Context.Queryable() + .InnerJoin((a, b) => a.WarningId == b.Id) + .Where((a, b) => b.IsEnable && a.AreaId == areaId) + .Select((a, b) => new RuleAreaBaseInfoVo + { + CustomerId = b.CustomerId, + SystemId = b.SubSystemId + }) + .ToListAsync(); + } + + public async Task> GetOrderNoByIdsAsync(int[] orderIds) + { + return await Context.Queryable() + .Where(x => orderIds.Contains(x.Id)) + .Select(x => new IdWithNameDto + { + Id = x.Id, + Name = x.OrderNo + }) + .Filter(null, true) + .ToListAsync(); + } +} diff --git a/src/SJZY.Track.Repository/Repositories/BasicRepository.cs b/src/SJZY.Track.Repository/Repositories/BasicRepository.cs index 965bd5d7..83e2052d 100644 --- a/src/SJZY.Track.Repository/Repositories/BasicRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/BasicRepository.cs @@ -1,4 +1,4 @@ -using System.Linq.Expressions; +using System.Linq.Expressions; using SJZY.Track.Domain; using SJZY.Track.Domain.SeedWork; using SJZY.Track.Repository.Queries; @@ -52,4 +52,4 @@ public class BasicRepository : BasicQuery, IBasicRepository where T : c .SetColumns(nameof(ISoftDeleteBasicEntity.IsDeleted), 1) .ExecuteCommandHasChangeAsync(); } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Repository/Repositories/DemoRepository.cs b/src/SJZY.Track.Repository/Repositories/DemoRepository.cs deleted file mode 100644 index 8334ea44..00000000 --- a/src/SJZY.Track.Repository/Repositories/DemoRepository.cs +++ /dev/null @@ -1,208 +0,0 @@ -using System.Transactions; -using SJZY.Track.Domain.Aggregates.DemoAggregate; -using SJZY.Track.Domain.Dtos.Demo; - -namespace SJZY.Track.Repository.Repositories; - -public class DemoRepository : BasicRepository, IDemoRepository, IScopedDependency -{ - /* - 一般情况下常规的增删改方法不需要自己实现,只需要按照 BasicRepository 中的格式原封不动的暴露出去即可, - 比如这里接口 只声明了 UpdateAsync 和 InsertReturnIdentityAsync 接口的定义,但是这两个方法的实现我们不用写,直接交给父类实现即可 - */ - - #region 根据主键获取单条数据 - - /// - /// 根据主键获取单条数据 - /// - /// - /// - public Task GetById1(int id) - { - /* - - //以下两种方法都不会因为没找到数据而抛异常 - var model1 = base.GetFirst(m => m.Id == 0); - var model = base.GetSingle(m => m.Id == 0); - - - - //同样的写法在linq下,如果不加 OrDefault 一定会报错 - var model = base.GetList().Single(m => m.Id == 0); - var model1 = base.GetList().First(m => m.Id == 0); - - */ - return base.GetSingleAsync(it => it.Id == id); - } - - #endregion - - #region 分页获取 - - /// - /// 分页获取 - /// - /// - /// - public async Task> GetListByPage(int pageSize, int pageindex, string name) - { - var list = await AsQueryable() - .WhereIF(!string.IsNullOrEmpty(name), a => a.Name.Contains(name)) - .ToPagedListAsync(pageindex, pageSize); - - return list; - } - - #endregion - - #region 参数为实体 - - /// - /// 参数很多的时候,定义模型接受参数 - /// - /// - /// - public async Task> InputToValueObject(DemoValueObject obj) - { - var list = await AsQueryable().ToListAsync(); - return list; - } - - #endregion - - #region 执行原生sql语句 - - /// - /// 执行原生sql语句 - /// - /// - /// - public async Task> OriginalSql(DemoValueObject obj) - { - var parameters = new List(); - var sql = @$" - select - a.id, - a.Name, - a.Age, - a.Description - from t_demo a - where 1=1 - {" and a.Name like @Name ".WhereIF(!string.IsNullOrEmpty(obj.Name), obj.Name, ref parameters)} - order by a.id desc "; - - var list = await Context.SqlQueryable(sql) - .AddParameters(parameters) - .ToPagedListAsync(obj.PageIndex, obj.PageSize); - - return list; - } - - #endregion - - #region 简单事务 - - public async Task Transaction() - { - using (var ts = new TransactionScope()) - { - await base.InsertAsync(new DemoEntity { Name = "1111" }); - await base.InsertAsync(new DemoEntity { Name = "222" }); - await base.InsertAsync(new DemoEntity { Name = "3333" }); - - //throw new BusinessException("E05632","手动抛异常"); - await base.InsertAsync(new DemoEntity { Name = "4444" }); - - ts.Complete(); - } - } - - #endregion - - #region 夸方法事务 - - public async Task MultipleMethodTrans1() - { - await base.InsertAsync(new DemoEntity { Name = "---" }); - await base.InsertAsync(new DemoEntity { Name = "+++" }); - } - - public async Task MultipleMethodTrans2() - { - //throw new BusinessException(message: "手动抛出异常"); - await base.InsertAsync(new DemoEntity { Name = "xxx" }); - } - - #endregion - - #region 事务嵌套 - - public async Task InternalTrans() - { - using (var ts = new TransactionScope()) - { - await Transaction(); - await MultipleMethodTrans1(); - //throw new BusinessException(message: "手动抛出异常"); - await base.InsertAsync(new DemoEntity { Name = "xxx" }); - - ts.Complete(); - } - } - - #endregion - - #region 局部更新 - - public async Task UpdatePartColumns(DemoEntity entity) - { - Context.Updateable(entity).UpdateColumns(m => new { m.Description, m.Name }).ExecuteCommand(); - // UPDATE `test` SET `Name`= 'string',`Description`= 'string' WHERE `id`= 5 - - Context.Updateable(entity).IgnoreColumns(m => new { m.CreateUserId, m.Age }).ExecuteCommand(); - // UPDATE `test` SET`IsDeleted`= 0,`Name`= 'string',`Description`= 'string',`EnabledMark`= 0,`DeleteUserId`= 0,`DeleteTime`= '2022/8/13 23:42:36',`CreateTime`= '2015/5/12 0:00:00',`UpdateUserId`= 0,`UpdateTime`= '2022/8/13 23:55:27' WHERE `id`= 5 - } - - #endregion - - #region 导航属性 - - /// - /// 导航属性 - /// - /// - /// - /// - public async Task EntityRelationSave(DemoEntity entity) - { - var res = await Context.InsertNav(entity).Include(m => m.DemoDetailList).ExecuteCommandAsync(); - return res; - } - - #endregion - - #region 缓存 - - /// - /// 获取数据包含缓存 - /// - /// - /// - public async Task GetDataCache(int id) - { - var redisKey = $"Demo:Endity:{id}"; - var demo = await RedisHelper.Client.GetAsync(redisKey); - if (demo != null) - return demo; - - var aa = Context.Ado.Connection; - demo = await base.GetSingleAsync(m => m.Id == id); - - await RedisHelper.Client.SetAsync(redisKey, demo, 60 * 20); - - return demo; - } - - #endregion -} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/Repositories/KpiAreaInfoRepository.cs b/src/SJZY.Track.Repository/Repositories/KpiAreaInfoRepository.cs new file mode 100644 index 00000000..864ae98b --- /dev/null +++ b/src/SJZY.Track.Repository/Repositories/KpiAreaInfoRepository.cs @@ -0,0 +1,5 @@ +namespace SJZY.Track.Repository.Repositories; + +public class KpiAreaInfoRepository +{ +} diff --git a/src/SJZY.Track.Repository/Repositories/KpiAreaRepository.cs b/src/SJZY.Track.Repository/Repositories/KpiAreaRepository.cs new file mode 100644 index 00000000..1563b770 --- /dev/null +++ b/src/SJZY.Track.Repository/Repositories/KpiAreaRepository.cs @@ -0,0 +1,113 @@ +using SJZY.Track.Domain; +using SJZY.Track.Domain.Aggregates.KPIAreaAggregate; +using SJZY.Track.Domain.Dtos.Forewarning; +using SJZY.Track.Domain.VEntities; + +namespace SJZY.Track.Repository.Repositories; + +public class KpiAreaRepository : BasicRepository, IKpiAreaRepository, ITransientDependency +{ + public async ValueTask CreateAreaAsync(RuleAreaEntity entity) + { + return await InsertReturnIdentityAsync(entity); + } + + public async ValueTask AddAreaInfoAsync(RuleAreaInfoEntity entity) + { + return await Context.Insertable(entity).ExecuteReturnIdentityAsync(); + } + + public async ValueTask DeleteArea(int areaId) + { + using var transaction = TransactionHelper.GetReadCommitted(); + await DeleteByIdAsync(areaId); + await Context.Deleteable().Where(x => x.AreaId == areaId).ExecuteCommandAsync(); + transaction.Complete(); + } + + public Task DeleteAreaInfo(int areaInfoId) + { + return Context.Deleteable().Where(val => val.Id == areaInfoId).ExecuteCommandAsync(); + } + + public Task UpdateAreaInfoAsync(RuleAreaInfoEntity entity) + { + return Context.Updateable(entity).ExecuteCommandAsync(); + } + + /// + /// 获取分区 + /// + /// + /// + public async Task> GetAreas(QueryAreaRequest query) + { + return await Context.Queryable() + .InnerJoin((area, sys) => area.SubSystemId == sys.Id) + .WhereIF(!string.IsNullOrEmpty(query.Name), (area, sys) => area.Name.Contains(query.Name)) + .WhereIF(query.SystemId.HasValue, (area, sys) => area.SubSystemId == query.SystemId.Value) + .OrderBy((area, sys) => area.UpdateTime, OrderByType.Desc) + .Select((area, sys) => new AreaDto() + { + Id = area.Id, + Name = area.Name, + SystemName = sys.CnName, + SubSystemId = area.SubSystemId, + UpdateTime = area.CreateTime + }) + .ToPagedListAsync(query.PageIndex, query.PageSize); + } + + /// + /// 获得分区信息 + /// + /// + /// + public async Task> GetAreaInfos(QueryAreaInfoRequest query) + { + return await Context.Queryable() + .InnerJoin((x, c) => x.CountryCode == c.Digit2Code) + .Where(x => x.AreaId == query.AreaId) + .OrderBy(x => x.UpdateTime, OrderByType.Desc) + .Select((x, c) => new RuleAreaInfoDto() + { + Id = x.Id, + AreaId = x.AreaId, + City = x.City, + CountryId = c.Id, + CountryCode = x.CountryCode, + CountryName = x.CountryName, + LeftPostcode = x.LeftPostcode, + RightPostcode = x.RightPostcode, + Province = x.Province + }) + .ToPagedListAsync(query.PageIndex, query.PageSize); + } + + public Task GetAreaInfoById(int id) + { + return Context.Queryable() + .FirstAsync(val => val.Id == id)!; + } + + /// + /// 获取所有区域信息 + /// + /// + public List GetAreaInfosByAreaId(int areaId) + { + return Context.Queryable() + .InnerJoin((r, i) => r.AreaId == i.Id) + .Where((r, i) => r.AreaId == areaId) + .Select((r, i) => new KpiAreaInfo + { + AreaId = r.AreaId, + Country = r.CountryCode, + LeftPostcode = r.LeftPostcode, + City = r.City, + Province = r.Province, + RightPostcode = r.RightPostcode + }) + .ToList(); + } +} diff --git a/src/SJZY.Track.Repository/Repositories/OrderOperationRecordEsRepository.cs b/src/SJZY.Track.Repository/Repositories/OrderOperationRecordEsRepository.cs new file mode 100644 index 00000000..7230d375 --- /dev/null +++ b/src/SJZY.Track.Repository/Repositories/OrderOperationRecordEsRepository.cs @@ -0,0 +1,74 @@ +using Nest; +using SJZY.Expand.ABP.Core.Logger; +using SJZY.Expand.ElasticSearch.Services; +using SJZY.Track.Domain.Aggregates.OrderAggregate; +using SJZY.Track.Domain.Consts; + +namespace SJZY.Track.Repository.Repositories; + +public class OrderOperationRecordEsRepository : ElasticSearchContextAbstract, + IOrderOperationRecordEsRepository, + ITransientDependency +{ + public OrderOperationRecordEsRepository(ConnectionFactory connectionFactory) : base(connectionFactory) + { + } + + public async Task AddAsync(OrderOperationRecordIndex index) + { + index.IndexName = $"{GlobalConst.OrderOperationRecordIndex}-{DateTime.Now:yyyy.MM.dd}"; + index.CreateTime = DateTime.Now; + // 按天写入es + var r = await Context.IndexAsync(index, request => request + .Index(index.IndexName) + ); + + if (!r.IsValid) + { + LogHelper.Error($"订单操作记录写入es失败,原因:{r.DebugInformation}。"); + } + } + + public async Task AddManyAsync(List indexes) + { + // 按天写入es + var indexName = $"{GlobalConst.OrderOperationRecordIndex}-{DateTime.Now:yyyy.MM.dd}"; + indexes.ForEach(x => + { + x.IndexName = indexName; + x.CreateTime = DateTime.Now; + }); + + var r = await Context.IndexManyAsync(indexes, indexName); + + if (!r.IsValid) + { + throw new InvalidOperationException($"{indexes.Count}条订单变更记录写入失败,原因:{r.DebugInformation}。"); + } + } + + public async Task DeleteOperationRecordByIdAsync(string id, string indexName) + { + var r = await Context.DeleteAsync(id, u => u + .Index(indexName) + ); + + if (!r.IsValid) + { + throw new InvalidOperationException($"轨迹操作记录失败,id:{indexName},原因:{r.DebugInformation}。"); + } + } + + public async Task> GetOrderOperationsByIdAsync(int orderId) + { + var data = await Context.SearchAsync(x => x + .Index(GlobalConst.OrderOperationRecordIndex) + .Query(q => + q.Term(t => t.OrderId, orderId) + ) + .Size(GlobalConst.NormalLimit) + .Sort(s => s.Field(f => f.CreateTime, SortOrder.Descending))); + + return data.ToIdList(); + } +} diff --git a/src/SJZY.Track.Repository/Repositories/OrderRepository.cs b/src/SJZY.Track.Repository/Repositories/OrderRepository.cs index 85faff5d..3e5bc514 100644 --- a/src/SJZY.Track.Repository/Repositories/OrderRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/OrderRepository.cs @@ -1,22 +1,307 @@ -using SJZY.Track.Domain; +using Microsoft.Extensions.Caching.Memory; +using SJZY.Expand.ABP.Core.Logger; +using SJZY.Track.Domain; using SJZY.Track.Domain.Aggregates.OrderAggregate; +using SJZY.Track.Domain.Consts; using SJZY.Track.Domain.Dtos.Order; +using SJZY.Track.Domain.Enums; +using SJZY.Track.Domain.VEntities; namespace SJZY.Track.Repository.Repositories; public class OrderRepository : BasicRepository, IOrderRepository, ITransientDependency { - public async Task CreateOrderAsync(OrderEntity order) + //tips:后期提供缓存清理接口 + //MemoryCache本身线程安全简单使用,短暂数据不一致可以容忍,每过固定时间强制清除缓存 + private static readonly MemoryCache _memoryCache = new(new MemoryCacheOptions()); + private static readonly Dictionary _empty = new(); + private static readonly Dictionary> _empty2 = new(); + private static readonly TimeSpan _thirdPartyOrderNumberCacheTimeSpan = TimeSpan.FromMinutes(3); + private static readonly TimeSpan _mainDataEnumCacheTimeSpan = TimeSpan.FromMinutes(5); + + private async Task> GetThirdPartyOrderNumberForCacheAsync(int[] orderIds) + { + const string key = "ThirdPartyOrderNumber"; + if (orderIds.Length == 0) return _empty; + + var dict = _memoryCache.Get>(key); + + orderIds = orderIds.Distinct().ToArray(); + if (dict != null && dict.Count != 0 && !orderIds.Except(dict.Keys).Any()) return dict; + + var orders = await Context.Queryable() + .Includes(a => a.OrderPlatformNumbers) + .LeftJoin((a, b) => a.Id == b.OrderId && b.IsDeleted == false) + .Where((a, b) => orderIds.Contains(a.Id)) + .Select(a => new OrderEntity() + { + Id = a.Id, + OrderPlatformNumbers = a.OrderPlatformNumbers + }) + .ToListAsync(); + + if (orders.Count == 0) + return _empty; + + orders = orders.DistinctBy(x => x.Id).ToList(); + + dict = orders.ToDictionary(x => x.Id, x => BuildThirdPartyOrderNumber(x.OrderPlatformNumbers)); + + _memoryCache.Set(key, dict, new MemoryCacheEntryOptions + { + AbsoluteExpirationRelativeToNow = _thirdPartyOrderNumberCacheTimeSpan, + Size = dict.Count + }); + return dict; + } + + private async Task>> GetMainDataEnumForCacheAsync(List orderTypes, List questTypes) + { + const string key = "EnumForMainData"; + if (orderTypes.Count == 0 && questTypes.Count == 0) return _empty2; + + var dict = _memoryCache.Get>>(key); + if (dict != null && dict.Count != 0 + && !orderTypes.Except(dict[GlobalConst.MainDataKey_OrderType].Keys).Any() + && !questTypes.Except(dict[GlobalConst.MainDataKey_TrackQuestionType].Keys).Any()) + { + return dict; + } + + //从主数据中心查询类型描述 + dict = (await Context.Queryable() + .Where(x => + (x.Property == GlobalConst.MainDataKey_OrderType && orderTypes.Contains(x.Enumkey)) + || (x.Property == GlobalConst.MainDataKey_TrackQuestionType && questTypes.Contains(x.Enumkey)) + ) + .Select(x => new + { + x.Property, + x.Enumkey, + x.Disp + }) + .ToListAsync() + ) + .GroupBy(x => x.Property) + .ToDictionary( + g => g.Key, + y => y.ToDictionary(x => x.Enumkey, x => x.Disp) + ); + + if (dict.Count == 0) + return _empty2; + + _memoryCache.Set(key, dict, new MemoryCacheEntryOptions + { + AbsoluteExpirationRelativeToNow = _mainDataEnumCacheTimeSpan, + Size = dict.Count + }); + return dict; + } + + public async Task> GetTrackOrderPagedList(GetPageTrackOrderInputVO input) + { + //查询完去重 + UnifyPageResultDto pageList; + //没传递单号时 + if (input.OrderNos.IsNullOrEmpty()) + { + pageList = await Context.Queryable() + .LeftJoin((a, b) => a.CustomId == b.Id && b.IsDeleted == false) + .LeftJoin((a, b, c) => a.SubSystemId == c.Id && c.IsDeleted == false) + .WhereIF(input.SubSystemId > 0, (a, b, c) => a.SubSystemId == input.SubSystemId) + .WhereIF(input.CreateTimeStart.HasValue && input.CreateTimeEnd.HasValue, + (a, b, c) => a.CreateTime >= input.CreateTimeStart && a.CreateTime <= input.CreateTimeEnd) + .WhereIF(input.CreateTimeStart.HasValue && (!input.CreateTimeEnd.HasValue), + (a, b, c) => a.CreateTime >= input.CreateTimeStart) + .WhereIF((!input.CreateTimeStart.HasValue) && input.CreateTimeEnd.HasValue, + (a, b, c) => a.CreateTime <= input.CreateTimeEnd) + .WhereIF(input.CustomerId > 0, (a, b, c) => a.CustomId == input.CustomerId) + .WhereIF(input.TrackOrderType > 0, (a, b, c) => a.OrderType == input.TrackOrderType) + .WhereIF(input.TabType > 0, (a, b, c) => a.QuestionType == input.TabType) + .WhereIF(input.TabType == (int) TrackProblemType.Warn, (a, b, c) => !a.IsCompleted) + .OrderByDescending((a, b, c) => a.CreateTime) + .Select((a, b, c) => new TrackOrderVO + { + Id = a.Id, + OrderNumber = a.OrderNo, + OrderType = a.OrderType, + QuestionType = a.QuestionType, + CustomerShortName = b.Abbreviation, + CustomerCode = b.Code, + CustomerId = a.CustomId, + NewestTrackContent = a.LatestTrackContent, + NewestTrackEnContent = a.LatestTrackEnContent, + NewestTrackPlace = a.LatestTrackPlace, + NewestTrackTime = a.LatestTrackTime, + IsFinish = a.IsCompleted, + CreateTime = a.CreateTime, + SubSystem = c.CnName, + SubSystemId = c.Id, + DestinationTimeZone = a.DestinationTimeZone, + EstimatedDeliveryDate = a.EstimatedDeliveryDate + }) + .ToPagedListAsync(input.PageIndex, input.PageSize); + } + //传递单号时 + else + { + var orderNos = input.OrderNos!.Distinct().ToList(); + + //匹配主单 + var orderIds = await Context.Queryable() + .Where(x => orderNos.Contains(x.OrderNo)) + .Select(x => x.Id) + .ToListAsync(); + + //匹配外部单 + var orderIdsForThirdParty = await Context.Queryable() + .Where(x => !string.IsNullOrWhiteSpace(x.OrderNumber) && orderNos.Contains(x.OrderNumber)) + .Select(x => x.OrderId) + .ToListAsync(); + + var orderHashset = orderIds.ToHashSet(); + orderHashset.UnionWith(orderIdsForThirdParty); + orderIds = orderHashset.ToList(); + + //没有任何单 + if (orderIds.Count == 0) + { + return new UnifyPageResultDto + { + List = new List(), + Pagination = new PageInfoOutput() + { + PageIndex = input.PageIndex, + PageSize = input.PageSize, + Total = 0 + } + }; + } + + pageList = await Context.Queryable() + .Where(x => orderIds.Contains(x.Id)) + .LeftJoin((a, b) => a.CustomId == b.Id && b.IsDeleted == false) + .LeftJoin((a, b, c) => a.SubSystemId == c.Id && c.IsDeleted == false) + .WhereIF(input.SubSystemId > 0, (a, b, c) => a.SubSystemId == input.SubSystemId) + .WhereIF(input.CreateTimeStart.HasValue && input.CreateTimeEnd.HasValue, + (a, b, c) => a.CreateTime >= input.CreateTimeStart && a.CreateTime <= input.CreateTimeEnd) + .WhereIF(input.CreateTimeStart.HasValue && (!input.CreateTimeEnd.HasValue), + (a, b, c) => a.CreateTime >= input.CreateTimeStart) + .WhereIF((!input.CreateTimeStart.HasValue) && input.CreateTimeEnd.HasValue, + (a, b, c) => a.CreateTime <= input.CreateTimeEnd) + .WhereIF(input.CustomerId > 0, (a, b, c) => a.CustomId == input.CustomerId) + .WhereIF(input.TrackOrderType > 0, (a, b, c) => a.OrderType == input.TrackOrderType) + .WhereIF(input.TabType > 0, (a, b, c) => a.QuestionType == input.TabType) + .WhereIF(input.TabType == (int) TrackProblemType.Warn, (a, b, c) => !a.IsCompleted) + .OrderByDescending((a, b, c) => a.CreateTime) + .Select((a, b, c) => new TrackOrderVO + { + Id = a.Id, + OrderNumber = a.OrderNo, + OrderType = a.OrderType, + QuestionType = a.QuestionType, + CustomerShortName = b.Abbreviation, + CustomerCode = b.Code, + CustomerId = a.CustomId, + NewestTrackContent = a.LatestTrackContent, + NewestTrackEnContent = a.LatestTrackEnContent, + NewestTrackPlace = a.LatestTrackPlace, + NewestTrackTime = a.LatestTrackTime, + IsFinish = a.IsCompleted, + CreateTime = a.CreateTime, + SubSystem = c.CnName, + SubSystemId = c.Id, + DestinationTimeZone = a.DestinationTimeZone, + EstimatedDeliveryDate = a.EstimatedDeliveryDate, + }) + .ToPagedListAsync(input.PageIndex, input.PageSize); + } + + + //补三方单号,从缓存中加速查 + var orderIdArr = pageList.List.Select(x => x.Id).ToArray(); + var thirdPartyOrderNumbers = await GetThirdPartyOrderNumberForCacheAsync(orderIdArr); + pageList.List.ForEach(x => x.ThirdPartyOrderNumber = thirdPartyOrderNumbers[x.Id]); + + //查询订单类型描述,从缓存中加速查 + var orderTypes = pageList.List.Select(x => x.OrderType).Distinct().ToList(); + var questTypes = pageList.List.Select(x => x.QuestionType).Distinct().ToList(); + var typeDisplayDict = await GetMainDataEnumForCacheAsync(orderTypes, questTypes); + + //填充数描述信息 + pageList.List.ForEach(x => + { + x.OrderTypeName = typeDisplayDict.TryGetValue(GlobalConst.MainDataKey_OrderType, out var orderTypeDisplayDict) + ? orderTypeDisplayDict.TryGetValue(x.OrderType, out var orderTypeDisplay) + ? orderTypeDisplay + : $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_OrderType}] " + : $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_OrderType}] EnumKey:[{x.OrderType}]"; + + x.QuestionTypeName = typeDisplayDict.TryGetValue(GlobalConst.MainDataKey_TrackQuestionType, out var questDisplayDict) + ? questDisplayDict.TryGetValue(x.QuestionType, out var questDisplay) + ? questDisplay + : $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_OrderType}]" + : $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_TrackQuestionType}] EnumKey:[{x.OrderType}]"; + }); + + return pageList; + } + + public async Task<(int MainOrderId, int CustomId)> GetTrackOrderByProviderAndOrderNo(string serviceProviderCode, string orderNo) + { + var orderList = await Context.Queryable() + .LeftJoin((a, b) => a.Id == b.OrderId && b.IsDeleted == false) + .Where((a, b) => a.OrderNo == orderNo + || (b.Platform == serviceProviderCode && b.OrderNumber == orderNo)) + .Select((a, b) => new + { + a.Id, + a.CustomId, + b.Platform, + b.OrderNumber + }) + .ToListAsync(); + + if (orderList.Count == 0) + { + return default; + } + + var order = orderList.First(); + //当出现了多条记录匹配,优先使用外部单匹配提升精确度 + var matchOrder = orderList.FirstOrDefault(x => x.Platform == serviceProviderCode && x.OrderNumber == orderNo); + return matchOrder != null + ? (matchOrder.Id, matchOrder.CustomId) + : (order.Id, order.CustomId); + } + + public async Task CreateOrderAsync(OrderEntity order) { using var tran = TransactionHelper.GetReadCommitted(); var orderId = await InsertReturnIdentityAsync(order); - order.OrderTemplates.ForEach(x => x.OrderId = orderId); - await Context.Insertable(order.OrderTemplates).ExecuteCommandAsync(); order.OrderFlights.ForEach(x => x.OrderId = orderId); await Context.Insertable(order.OrderFlights).ExecuteCommandAsync(); + order.OrderPullStatus.ForEach(x => x.OrderId = orderId); + await Context.Insertable(order.OrderPullStatus).ExecuteCommandAsync(); + order.OrderPlatformNumbers.ForEach(x => x.OrderId = orderId); + await Context.Insertable(order.OrderPlatformNumbers).ExecuteCommandAsync(); tran.Complete(); + + return orderId; + } + + public Task UpdateBatchIdsAsync(List ids, int newValue) + { + var idsString = string.Join(",", ids); + return Context.Ado.ExecuteCommandAsync( + $"UPDATE `t_order` SET `DeficiencyTag` = @newValue ,UpdateTime= current_timestamp WHERE `Id` IN ({idsString})", + new + { + newValue + }); } public async Task UpdateOrderAsync(OrderEntity order) @@ -24,12 +309,21 @@ public class OrderRepository : BasicRepository, IOrderRepository, I using var tran = TransactionHelper.GetReadCommitted(); // 更新订单主表 - await UpdateAsync(order, x => new { x.CustomId, x.SubSystemId }); + await UpdateAsync(order, x => new + { + x.CustomId, + x.SubSystemId + }); // 更新订单模板 - await Context.Deleteable().Where(x => x.OrderId == order.Id).ExecuteCommandAsync(); - order.OrderTemplates.ForEach(x => x.OrderId = order.Id); - await Context.Insertable(order.OrderTemplates).ExecuteCommandAsync(); + await Context.Deleteable().Where(x => x.OrderId == order.Id).ExecuteCommandAsync(); + order.OrderPullStatus.ForEach(x => x.OrderId = order.Id); + await Context.Insertable(order.OrderPullStatus).ExecuteCommandAsync(); + + // 更新订单三方关联 + await Context.Deleteable().Where(x => x.OrderId == order.Id).ExecuteCommandAsync(); + order.OrderPlatformNumbers.ForEach(x => x.OrderId = order.Id); + await Context.Insertable(order.OrderPlatformNumbers).ExecuteCommandAsync(); // 更新订单航班 await Context.Deleteable().Where(x => x.OrderId == order.Id).ExecuteCommandAsync(); @@ -46,23 +340,126 @@ public class OrderRepository : BasicRepository, IOrderRepository, I // 软删订单主表 await SoftDeleteAsync(x => x.Id == orderId); - // 软删订单模板 // 软删订单航班 // 软删订单关联关系 + // 软删订单拉取状态 tran.Complete(); } - public async Task PushWarnOrdersAsync() + /// + /// 更新推送预警单 + /// + /// + /// + /// + /// + public async Task PushWarnOrdersAsync(int subSystemId, int pageSize, int pageindex) { - return await Context.Ado.ExecuteCommandAsync(@"UPDATE `t_track_push_config` `a` -LEFT JOIN `t_order` `b` ON `a`.`SubSystemId` = `b`.`SubSystemId` AND `a`.`CustomId` = `b`.`CustomId` -SET `b`.`QuestionType` = CASE - WHEN `b`.`LatestPushTime` IS NULL THEN 2 - WHEN `b`.`LatestPushTime` < DATE_SUB(NOW(), INTERVAL 12 HOUR) THEN 2 - ELSE 0 END -WHERE `b`.`IsCompleted` = 0 AND `b`.`QuestionType` != 1 AND `b`.`CreateTime` < DATE_SUB(NOW(), INTERVAL 12 HOUR) -AND `a`.`IsDeleted` = 0 AND `b`.`IsDeleted` = 0;"); + var ordersToUpdate = await Context.Queryable() + .Where(b => b.SubSystemId == subSystemId && !b.IsCompleted && b.QuestionType != 1) + .Select(b => new + { + b.LatestPushTime, + b.Id, + b.QuestionType + }) + .ToPageListAsync(pageindex, pageSize); + + var latestPushTimeIds = new List(); + var questionZeroIds = new List(); + foreach (var item in ordersToUpdate) + { + var questionType = !item.LatestPushTime.HasValue || item.LatestPushTime < DateTime.Now.AddHours(-12) + ? 2 + : 0; + if (item.QuestionType == questionType) continue; + if (questionType == 2) latestPushTimeIds.AddLast(item.Id); + else questionZeroIds.AddLast(item.Id); + } + + if (latestPushTimeIds.Count > 0) UpdateOrderQuestionType(2, latestPushTimeIds); + if (questionZeroIds.Count > 0) UpdateOrderQuestionType(0, questionZeroIds); + return ordersToUpdate.Count; + } + + public async Task> GetSubSystemListByCodesAsync(List codes) + { + var res = await Context.Queryable() + .Where(x => codes.Contains(x.Key)) + .Select(x => new + { + x.Key, + x.Id + }) + .ToListAsync(); + + return res.Select(x => (x.Key, x.Id)).ToList(); + } + + public Task> GetOrderTemplateAsync(int[] orderId) + { + return Context.Queryable() + .Where(x => orderId.Contains(x.Id)) + .Select(a => new OrderTemplateVO + { + OrderId = a.Id, + OrderNo = a.OrderNo, + TemplateCodes = a.TemplateCodes + }) + .ToListAsync(); + } + + public Task> GetOrderTemplateAsync(int subSystemId, int orderType, List orderNos) + { + return Context.Queryable() + .Where(x => orderNos.Contains(x.OrderNo) && x.SubSystemId == subSystemId && x.OrderType == orderType) + .Select(a => new OrderTemplateVO + { + OrderId = a.Id, + OrderNo = a.OrderNo, + TemplateCodes = a.TemplateCodes + }) + .ToListAsync(); + } + + public Task GetSystemInfoById(int id) + { + return Context.Queryable().FirstAsync(m => m.IsDeleted == false && m.Id == id); + } + + public Task GetUserById(int id) + { + return Context.Queryable().FirstAsync(m => m.IsDeleted == false && m.Id == id); + } + + private int UpdateOrderQuestionType(int questionType, IEnumerable ids) + { + var idsString = string.Join(",", ids); + return Context.Ado.ExecuteCommand( + $"UPDATE `t_order` SET `QuestionType` = @questionType ,UpdateTime= current_timestamp WHERE `Id` IN ({idsString})", + new + { + questionType + }); + } + + /// + /// 拼接多个三方单号,默认使用分隔符默认(、) + /// 第三方单号展示: 0000000(服务商)、0000000(服务商) + /// + /// + /// + public string BuildThirdPartyOrderNumber(List orderPlatformNumberEntities) + { + if (orderPlatformNumberEntities.Count == 0) return GlobalConst.EmptyString; + const string separator = "、"; + var thirdPartyOrderNumbers = orderPlatformNumberEntities + .Where(x => !string.IsNullOrWhiteSpace(x.OrderNumber)) + .Select(x => $"{x.OrderNumber}({x.Platform})") + .ToList(); + if (thirdPartyOrderNumbers.Count == 0) return GlobalConst.EmptyString; + return string.Join(separator, thirdPartyOrderNumbers); } #region 订单关联 @@ -84,6 +481,26 @@ AND `a`.`IsDeleted` = 0 AND `b`.`IsDeleted` = 0;"); .ToListAsync(); } + public async Task> GetLinkedOrdersAsync(int orderId, int linkSubSystemId, int linkOrderType) + { + return await Context.Queryable() + .LeftJoin((a, b) => a.LinkOrderId == b.Id) + .Where((a, b) => orderId == a.OrderId && b.SubSystemId == linkSubSystemId && b.OrderType == linkOrderType) + .Select((a, b) => b.OrderNo) + .ToListAsync(); + } + + public async Task> GetLinkedOrdersAsync(int orderId, int linkSubSystemId, int linkOrderType, + List linkOrderNos) + { + return await Context.Queryable() + .LeftJoin((a, b) => a.LinkOrderId == b.Id) + .Where((a, b) => orderId == a.OrderId && b.SubSystemId == linkSubSystemId && b.OrderType == linkOrderType + && linkOrderNos.Contains(b.OrderNo)) + .Select((a, b) => a.Id) + .ToListAsync(); + } + public async Task LinkOrderAsync(List orderLinkEntities) { await Context.Insertable(orderLinkEntities).ExecuteCommandAsync(); @@ -91,8 +508,108 @@ AND `a`.`IsDeleted` = 0 AND `b`.`IsDeleted` = 0;"); public async Task UnLinkByIdsAsync(List linkIds) { - await Context.Deleteable(linkIds).ExecuteCommandAsync(); + await Context.Deleteable(linkIds).ExecuteCommandAsync(); } #endregion -} \ No newline at end of file + + + #region 订单拉取 + + public async Task UpdatePullStatusToSilenceAsync(List orderIds, string trackCode) + { + // var status = await Context.Queryable() + // .Where(x => orderIds.Contains(x.OrderId) && x.StartTrackCode == trackCode) + // .Where(x => x.PullStatus == TrackPullStatus.Init || x.PullStatus == TrackPullStatus.Pulling) + // .Select(x => new + // { + // x.Id, + // x.PullStatus, + // x.SilenceBeforeStart, + // x.SilenceAfterEnd, + // x.StartTime, + // x.EndTime + // }) + // .ToListAsync(); + // + // // 初始态-》静默前、拉取中-》静默后 + // var changes = status.Select(x => new + // { + // x.Id, + // PullStatus = x.PullStatus == TrackPullStatus.Init + // ? x.SilenceBeforeStart > 0 + // ? TrackPullStatus.SilenceBeforeStart + // : TrackPullStatus.Pulling + // : x.SilenceAfterEnd > 0 + // ? TrackPullStatus.SilenceAfterEnd + // : TrackPullStatus.Completed, + // StartTime = + // x.PullStatus == TrackPullStatus.Init ? DateTime.Now.AddHours(x.SilenceBeforeStart) : x.StartTime, + // EndTime = x.PullStatus == TrackPullStatus.Pulling ? DateTime.Now.AddHours(x.SilenceAfterEnd) : x.EndTime + // }); + // await Context.Updateable(changes).ExecuteCommandAsync(); + + // 初始态-》静默前 + await Context.Updateable() + .SetColumns(x => x.PullStatus == TrackPullStatus.SilenceBeforeStart) + .SetColumns(x => x.StartTime == DateTime.Now.AddHours(x.SilenceBeforeStart)) + .Where(x => orderIds.Contains(x.OrderId) && x.StartTrackCode == trackCode) + .Where(x => x.PullStatus == TrackPullStatus.Init) + .ExecuteCommandAsync(); + + // 拉取中-》静默后 + await Context.Updateable() + .SetColumns(x => x.PullStatus == TrackPullStatus.SilenceAfterEnd) + .SetColumns(x => x.EndTime == DateTime.Now.AddHours(x.SilenceAfterEnd)) // >0才有意义 + .Where(x => orderIds.Contains(x.OrderId) && x.EndTrackCode == trackCode) + .Where(x => x.PullStatus == TrackPullStatus.Pulling) + .ExecuteCommandAsync(); + } + + public async Task UpdatePullStatusBySilenceAsync() + { + var cnt1 = await Context.Updateable() + .SetColumns(x => x.PullStatus == TrackPullStatus.Pulling) + .Where(x => x.PullStatus == TrackPullStatus.SilenceBeforeStart && x.StartTime < DateTime.Now) + .ExecuteCommandAsync(); + LogHelper.Info( + $"{cnt1}条订单的拉取状态由{nameof(TrackPullStatus.SilenceBeforeStart)}更新为{nameof(TrackPullStatus.Pulling)}"); + + var cnt2 = await Context.Updateable() + .SetColumns(x => x.PullStatus == TrackPullStatus.Completed) + .Where(x => x.PullStatus == TrackPullStatus.SilenceAfterEnd && x.EndTime < DateTime.Now) + .ExecuteCommandAsync(); + LogHelper.Info( + $"{cnt2}条订单的拉取状态由{nameof(TrackPullStatus.SilenceAfterEnd)}更新为{nameof(TrackPullStatus.Completed)}"); + + return cnt1 + cnt2; + } + + public async Task ClearPullStatusAsync() + { + var time = DateTime.Now.Subtract(TimeSpan.FromDays(30)); + return await Context.Deleteable().Where(x => + x.PullStatus == TrackPullStatus.Completed || x.StartTime < time) + .ExecuteCommandAsync(); + } + + public async Task UpdateOrderPullConfigForServiceProviderAsync( + UpdateOrderPullConfigsInputVo inputVo) + { + // tips:如此更新,影响范围是否可控?状态是否正确? + return await Context.Updateable() + .SetColumns(x => x.ServiceProviderCode == inputVo.ServiceCode) + .SetColumns(x => x.StartTrackCode == inputVo.StartCode) + .SetColumns(x => x.EndTrackCode == inputVo.EndCode) + .SetColumns(x => x.SilenceBeforeStart == inputVo.SilenceTime) + .SetColumns(x => x.SilenceAfterEnd == inputVo.StopTime) + // 直接将订单拉取状态更新为拉取中,不再考虑性能 + .SetColumns(x => x.StartTime == DateTime.Now) + .SetColumns(x => x.EndTime == GlobalConst.MaxDateTime) + .SetColumns(x => x.PullStatus == TrackPullStatus.Pulling) + .Where(x => inputVo.OrderIds.Contains(x.OrderId)) + .ExecuteCommandAsync(); + } + + #endregion +} diff --git a/src/SJZY.Track.Repository/Repositories/TrackContentRepository.cs b/src/SJZY.Track.Repository/Repositories/TrackContentRepository.cs index 53b23855..2c49ff0e 100644 --- a/src/SJZY.Track.Repository/Repositories/TrackContentRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/TrackContentRepository.cs @@ -1,20 +1,15 @@ -using System.Linq.Expressions; +using System.Linq.Expressions; using SJZY.Track.Domain.Aggregates.TrackContentAggregate; using SJZY.Track.Domain.Aggregates.TrackFlagAggregate; using SJZY.Track.Domain.Aggregates.TrackStatusAggregate; using SJZY.Track.Domain.Aggregates.TrackTemplateAggregate; using SJZY.Track.Domain.Dtos.TrackContents; -using SJZY.Track.Domain.Dtos.TrackTemplate; using SJZY.Track.Domain.VEntities; namespace SJZY.Track.Repository.Repositories; public class TrackContentRepository : BasicRepository, ITrackContentRepository, IScopedDependency { - public TrackContentRepository() - { - } - /// /// 获取轨迹内容明细 /// @@ -24,10 +19,9 @@ public class TrackContentRepository : BasicRepository, ITrac { var detail = await Context.Queryable() .LeftJoin((a, b) => a.TrackStatusId == b.Id && b.IsDeleted == false) - .LeftJoin((a, b, c) => a.TrackFlagId == c.Id && c.IsDeleted == false) - .LeftJoin((a, b, c, d) => a.SubSystemId == d.Id && d.IsDeleted == false) - .Where((a, b, c, d) => a.Id == id) - .Select((a, b, c, d) => new GetTrackContentDetailVO + .LeftJoin((a, b, d) => a.SubSystemId == d.Id && d.IsDeleted == false) + .Where((a, b, d) => a.Id == id) + .Select((a, b, d) => new GetTrackContentDetailVO { Id = a.Id, SubSystemId = a.SubSystemId, @@ -38,8 +32,12 @@ public class TrackContentRepository : BasicRepository, ITrac Content = a.Content, EnContent = a.EnContent, TrackFlagId = a.TrackFlagId, - TrackFlag = c.Name + IsExternal = a.IsExternal, + IsRepeatable = a.IsRepeatable, + IsAllowManuallyUpdate = a.IsAllowManuallyUpdate, + IsAllowManuallyCreate = a.IsAllowManuallyCreate }) + .Mapper(x => { x.TrackFlagIds = x.TrackFlagId?.Split(',').Select(int.Parse).ToList(); }) .FirstAsync(); return detail; } @@ -51,23 +49,21 @@ public class TrackContentRepository : BasicRepository, ITrac /// public async Task> GetPageTrackContent(GetPageTrackContentVO input) { - UnifyPageResultDto pagedList = new UnifyPageResultDto(); - pagedList = await Context.Queryable() + var pagedList = await Context.Queryable() .LeftJoin((a, b) => a.TrackStatusId == b.Id && b.IsDeleted == false) - .LeftJoin((a, b, c) => a.TrackFlagId == c.Id && c.IsDeleted == false) - .LeftJoin((a, b, c, d) => a.SubSystemId == d.Id && d.IsDeleted == false) - .LeftJoin((a, b, c, d, e) => a.CreateUserId == e.Id && e.IsDeleted == false) - .LeftJoin((a, b, c, d, e, f) => a.UpdateUserId == f.Id && f.IsDeleted == false) - .WhereIF(input.SubSystemId > 0, (a, b, c, d, e, f) => a.SubSystemId == input.SubSystemId) + .LeftJoin((a, b, d) => a.SubSystemId == d.Id && d.IsDeleted == false) + .LeftJoin((a, b, d, e) => a.CreateUserId == e.Id && e.IsDeleted == false) + .LeftJoin((a, b, d, e, f) => a.UpdateUserId == f.Id && f.IsDeleted == false) + .WhereIF(input.SubSystemId > 0, (a, b, d, e, f) => a.SubSystemId == input.SubSystemId) .WhereIF(!input.Keywords.IsNullOrWhiteSpace(), - (a, b, c, d, e, f) => a.Code.Contains(input.Keywords) || a.Content.Contains(input.Keywords) - || a.EnContent.Contains(input.Keywords)) - .WhereIF(input.TrackStatusId > 0, (a, b, c, d, e, f) => a.TrackStatusId == input.TrackStatusId) - .OrderByIF(input.SelectIds.IsNullOrEmpty(), (a, b, c, d, e, f) => a.CreateTime, OrderByType.Desc) + (a, b, d, e, f) => a.Code.Contains(input.Keywords) || a.Content.Contains(input.Keywords) + || a.EnContent.Contains(input.Keywords)) + .WhereIF(input.TrackStatusId > 0, (a, b, d, e, f) => a.TrackStatusId == input.TrackStatusId) + .OrderByIF(input.SelectIds.IsNullOrEmpty(), (a, b, d, e, f) => a.CreateTime, OrderByType.Desc) .OrderByIF(!input.SelectIds.IsNullOrEmpty(), - (a, b, c, d, e, f) => SqlFunc.IIF(input.SelectIds.Contains(a.Id), SqlFunc.DateAdd(SqlFunc.GetDate(), 1), + (a, b, d, e, f) => SqlFunc.IIF(input.SelectIds.Contains(a.Id), SqlFunc.DateAdd(SqlFunc.GetDate(), 1), a.CreateTime), OrderByType.Desc) - .Select((a, b, c, d, e, f) => new GetTrackContentListVO + .Select((a, b, d, e, f) => new GetTrackContentListVO { Id = a.Id, SubSystem = d.CnName, @@ -75,50 +71,27 @@ public class TrackContentRepository : BasicRepository, ITrac Content = a.Content, EnContent = a.EnContent, TrackStatus = b.Status, + IsExternal = a.IsExternal, Node = SqlFunc.IF(b.Node == 1).Return("揽收").ElseIF(b.Node == 2).Return("清关").ElseIF(b.Node == 3) .Return("干线") .ElseIF(b.Node == 4).Return("派送").ElseIF(b.Node == 5).Return("其他") .End(""), - TrackFlag = c.Name, + TrackFlag = SqlFunc.Subqueryable() + .Where(x => SqlFunc.SplitIn(a.TrackFlagId, x.Id.ToString())) + .SelectStringJoin(x => x.Name, ","), CreateTime = a.CreateTime, CreateUser = e.Name, UpdateTime = a.UpdateTime, UpdateUser = f.Name, + IsRepeatable = a.IsRepeatable, + IsAllowManuallyUpdate = a.IsAllowManuallyUpdate, + IsAllowManuallyCreate = a.IsAllowManuallyCreate }) .ToPagedListAsync(input.PageIndex, input.PageSize); return pagedList; } - /// - /// 获取轨迹内容属性值 - /// - /// - public async Task> GetTrackContentAttributeValue( - GetTemplateContentAttributeValueInputVO input) - { - var list = await Context.Queryable() - .LeftJoin((a, b) => - a.Id == b.TrackContentId && b.TrackTemplateId > 0 && b.IsDeleted == false) - .LeftJoin((a, b, c) => b.TrackTemplateId == c.Id && c.IsDeleted == false) - .WhereIF(!input.TrackCodes.IsNullOrEmpty(), (a, b, c) => input.TrackCodes!.Contains(a.Code)) - .WhereIF(input.SubSystemId > 0, (a, b, c) => a.SubSystemId == input.SubSystemId) - .WhereIF(!input.TrackTemplateIds.IsNullOrEmpty(), (a, b, c) => input.TrackTemplateIds!.Contains(c.Id)) - .Where((a, b, c) => c.Id > 0) - //.OrderByIF(!input.TrackTemplateIds.IsNullOrEmpty(), (a, b, c) => SqlFunc.IIF(input.TrackTemplateIds.Contains(a.Id), SqlFunc.DateAdd(SqlFunc.GetDate(), 1), c.CreateTime), OrderByType.Desc) - .Select((a, b, c) => new GetTemplateContentAttributeValueVO - { - IsCanDelete = b.IsCanDelete, - IsExternal = b.IsExternal, - SubSystemId = a.SubSystemId, - TrackCode = a.Code, - TrackContenId = a.Id, - TrackTemplateId = c.Id - }).ToListAsync(); - - return list; - } - /// /// 获取轨迹模版是否存在 /// @@ -146,7 +119,6 @@ public class TrackContentRepository : BasicRepository, ITrac return false; } - public async Task> GetMapPageAsync( GetTrackContentMapPageInputVO input) { @@ -253,4 +225,52 @@ public class TrackContentRepository : BasicRepository, ITrac return await Context.Updateable().SetColumns(columns).Where(whereExpression) .ExecuteCommandAsync() > 0; } -} \ No newline at end of file + + public Task GetByCodeAsync(int systemId, string code) + { + return Context.Queryable().FirstAsync(m => m.SubSystemId == systemId && m.Code == code); + } + + public Task> GetListBySystemIdAsync(int systemId) + { + return Context.Queryable() + .Where(content => content.SubSystemId == systemId && !content.IsDeleted) + .Select((content) => new TrackContentEntity + { + Id = content.Id, + Code = content.Code, + IsExternal = content.IsExternal, + EnContent = content.EnContent, + Content = content.Content, + IsRepeatable = content.IsRepeatable, + IsAllowManuallyCreate = content.IsAllowManuallyCreate, + IsAllowManuallyUpdate = content.IsAllowManuallyUpdate, + }) + .ToListAsync(); + } + + public Task> GetTrackContentBySyetemIdAsync(int subSystemId) + { + return Context.Queryable() + .LeftJoin((x, y) => x.TrackStatusId == y.Id) + .LeftJoin((x, y, z) => x.SubSystemId == z.Id) + .Where(x => x.SubSystemId == subSystemId) + .Select((x, y, z) => new TrackContentVO + { + SubSystemCode = z.Key, + TrackStatusId = x.TrackStatusId, + TrackStatus = y.Status, + TrackStatusCode = y.Code, + TrackContentId = x.Id, + TrackContent = x.Content, + TrackContentCode = x.Code, + TrackEnContent = x.EnContent, + IsCompleted = y.IsCompleted, + IsRepeatable = x.IsRepeatable, + IsAllowManuallyUpdate = x.IsAllowManuallyUpdate, + IsAllowManuallyCreate = x.IsAllowManuallyCreate, + IsToMq = y.IsToMq, + IsExternal = x.IsExternal + }).ToListAsync(); + } +} diff --git a/src/SJZY.Track.Repository/Repositories/TrackDetailsEsRepository.cs b/src/SJZY.Track.Repository/Repositories/TrackDetailsEsRepository.cs new file mode 100644 index 00000000..46f97255 --- /dev/null +++ b/src/SJZY.Track.Repository/Repositories/TrackDetailsEsRepository.cs @@ -0,0 +1,609 @@ +using Nest; +using SJZY.Expand.ABP.Core.PublicMethords; +using SJZY.Expand.ElasticSearch.Services; +using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; +using SJZY.Track.Domain.Consts; +using SJZY.Track.Domain.Enums; + +namespace SJZY.Track.Repository.Repositories; + +public class TrackDetailsEsRepository : ElasticSearchContextAbstract, ITrackDetailsEsRepository, + ITransientDependency +{ + const int SafelyLimit = GlobalConst.SafelyLimit; + + public TrackDetailsEsRepository(ConnectionFactory connectionFactory) : base(connectionFactory) + { + } + + public async Task> GetListAsync(int[] orderIds, string trackCode, + bool forUpsert = false) + { + var r = forUpsert + ? await Context.SearchAsync(s => s + .Index(GlobalConst.TrackDetailsIndex) + .Source() + .Size(SafelyLimit) + .Query(q => q + .Bool(b => b + .Must( + mu => mu.Terms(t => t.Field(f => f.OrderId).Terms(orderIds)), + mu => mu.Term(t => t.Field(f => f.TrackCode.Suffix("keyword")).Value(trackCode)) + ) + ) + ) + ) + : await Context.SearchAsync(s => s + .Index(GlobalConst.TrackDetailsIndex) + .Source(s2 => s2.Includes(fd => fd + .Field(f => f.IndexName) + .Field(f => f.OrderId) + .Field(f => f.TrackTime) + .Field(f => f.TrackPlace) + )) + .Size(SafelyLimit) + .Query(q => q + .Bool(b => b + .Must( + mu => mu.Terms(t => t.Field(f => f.OrderId).Terms(orderIds)), + mu => mu.Term(t => t.Field(f => f.TrackCode.Suffix("keyword")).Value(trackCode)) + ) + ) + ) + ); + + if (!r.IsValid) + { + throw new InvalidOperationException( + $"轨迹查询失败,orderIds:[{orderIds.JoinAsString(", ")}],trackCode:{trackCode},原因:{r.DebugInformation}。"); + } + + return r.ToIdList(); + } + + public async Task> GetLatestListAsync(int[] orderIds, List trackCodes) + { + var excludeTrackCodes = trackCodes.ToList(); + excludeTrackCodes.Add(GlobalConst.EmptyString); + var r = await Context.SearchAsync(x => x + .Index(GlobalConst.TrackDetailsIndex) + .Source(s => s.Includes(fd => fd + .Field(f => f.TrackEnContent) + .Field(f => f.TrackContent) + .Field(f => f.TrackPlace) + .Field(f => f.TrackTime) + .Field(f => f.TrackTimeZone) + .Field(f => f.OrderId) + .Field(f => f.TrackCode) + .Field(f => f.Id) + .Field(f => f.IndexName) + )) + .Query(q => q + .Bool(b => b + .Must( + mu => mu.Terms(t => t.Field(f => f.OrderId).Terms(orderIds)) + ) + .MustNot(mn => mn + .Terms(t => t + .Field(f => f.TrackCode.Suffix("keyword")) + .Terms(excludeTrackCodes) + ) + ) + ) + ) + .Size(SafelyLimit) + .Aggregations(a => a + .Terms("orders", t => t + .Field(f => f.OrderId) + .Aggregations(aa => aa + .TopHits("latest_track", th => th + .Size(1) + .Sort(so => so + .Field(f => f.ZeroTrackTime, SortOrder.Descending) + ) + .Source(s2 => s2.Includes(fd2 => fd2 + .Field(f => f.TrackEnContent) + .Field(f => f.TrackContent) + .Field(f => f.TrackPlace) + .Field(f => f.TrackTime) + .Field(f => f.TrackTimeZone) + .Field(f => f.OrderId) + .Field(f => f.TrackCode) + .Field(f => f.Id) + .Field(f => f.IndexName) + )) + ) + ) + ) + ) + ); + + if (!r.IsValid) + { + throw new InvalidOperationException( + $"最新轨迹查询失败,orderIds:[{orderIds.JoinAsString(", ")}],trackCodes:[{trackCodes.JoinAsString(", ")}],原因:{r.DebugInformation}。"); + } + + return r.Documents.ToList(); + } + + public async Task AnyAsync(int orderId, string originTrackDataHash) + { + var r = await Context.SearchAsync(x => x + .Index(GlobalConst.TrackDetailsIndex) + .Source(s => s.Includes(fd => fd.Field(f => f.TrackCode))) + .Query(q => + q.Term(f => f.OrderId, orderId) + && q.Term(f => f.OriginTrackDataHash.Suffix("keyword"), originTrackDataHash) + ) + ); + + if (!r.IsValid) + { + throw new InvalidOperationException( + $"轨迹查询失败,orderId:{orderId},hash:{originTrackDataHash},原因:{r.DebugInformation}。"); + } + + return r.Hits.Count > 0; + } + + + public async Task UpdateAsync(TrackDetailsIndex track) + { + var r = await Context.UpdateAsync(track.Id, u => u + .Index(track.IndexName) + .Doc(new + { + track.TrackPlace, + track.TrackTime, + track.TrackTimeZone, + track.UpdateUser, + UpdateTime = DateTime.Now, + track.TrackContent, + track.TrackEnContent, + track.IsVisibility, + track.IsExternal, + track.Remarks, + track.Files, + track.TrackPlaceCity, + track.TrackPlaceCityId, + track.TrackPlaceProvince, + track.TrackPlaceProvinceId, + track.TrackPlaceNation, + track.TrackPlaceNationId, + track.TrackPlacePostcode, + track.DestinationTimeZone, + track.EstimatedDeliveryDate, + Extra = track.Extra + }) + ); + + if (!r.IsValid) + { + throw new InvalidOperationException($"轨迹更新失败,track:{track.ToJson()},原因:{r.DebugInformation}。"); + } + } + + //#4001批量更新时只会将所有id匹配的记录更新为同一内容,后续需要支持差异化更新 + public async Task UpdateManyAsync(List indexes, int maxRetries = 3) + { + var retryCount = 0; + var updateSuccessful = false; + var track = indexes.First(); + + while (retryCount < maxRetries && !updateSuccessful) + { + var response = await Context.UpdateByQueryAsync(u => u + .Index(GlobalConst.TrackDetailsIndex) + .Query(q => q + .Ids(t => t.Values(indexes.Select(x => x.Id))) + ) + .Script(s => s + .Source(@" + ctx._source.trackPlace = params.trackPlace; + ctx._source.trackTime = params.trackTime; + ctx._source.trackTimeZone = params.trackTimeZone; + ctx._source.updateUser = params.updateUser; + ctx._source.updateTime = params.updateTime; + ctx._source.trackContent = params.trackContent; + ctx._source.trackEnContent = params.trackEnContent; + ctx._source.isVisibility = params.isVisibility; + ctx._source.isExternal = params.isExternal; + ctx._source.remarks = params.remarks; + ctx._source.files = params.files; + ctx._source.trackPlaceCity = params.trackPlaceCity; + ctx._source.trackPlaceCityId = params.trackPlaceCityId; + ctx._source.trackPlaceProvince = params.trackPlaceProvince; + ctx._source.trackPlaceProvinceId = params.trackPlaceProvinceId; + ctx._source.trackPlaceNation = params.trackPlaceNation; + ctx._source.trackPlaceNationId = params.trackPlaceNationId; + ctx._source.trackPlacePostcode = params.trackPlacePostcode; + ctx._source.destinationTimeZone = params.destinationTimeZone; + ctx._source.estimatedDeliveryDate = params.estimatedDeliveryDate; + ctx._source.extra = params.extra; + ") + .Params(p => p + .Add("trackPlace", track.TrackPlace) + .Add("trackTime", track.TrackTime) + .Add("trackTimeZone", track.TrackTimeZone) + .Add("updateUser", track.UpdateUser) + .Add("updateTime", DateTime.Now) + //S06新增字段更新 + .Add("trackContent", track.TrackContent) + .Add("trackEnContent", track.TrackEnContent) + .Add("isVisibility", track.IsVisibility) + .Add("isExternal", track.IsExternal) + .Add("remarks", track.Remarks) + .Add("files", track.Files) + .Add("trackPlaceCity", track.TrackPlaceCity) + .Add("trackPlaceCityId", track.TrackPlaceCityId) + .Add("trackPlaceProvince", track.TrackPlaceProvince) + .Add("trackPlaceProvinceId", track.TrackPlaceProvinceId) + .Add("trackPlaceNation", track.TrackPlaceNation) + .Add("trackPlaceNationId", track.TrackPlaceNationId) + .Add("trackPlacePostcode", track.TrackPlacePostcode) + .Add("destinationTimeZone", track.DestinationTimeZone) + .Add("estimatedDeliveryDate", track.EstimatedDeliveryDate) + .Add("extra", track.Extra) + ) + ) + ); + + if (response.IsValid) + { + updateSuccessful = true; + } + else if (response.ServerError?.Status == 409) // 409 表示版本冲突 + { + retryCount++; + if (retryCount >= maxRetries) + { + throw new InvalidOperationException( + $"轨迹更新冲突达到最大次数,track:{indexes.Count}条,原因:{response.DebugInformation}。"); + } + } + else + { + throw new InvalidOperationException($"轨迹更新失败,track:{indexes.Count}条,原因:{response.DebugInformation}。"); + } + } + } + + public async Task BulkUpdateAsync(List indexes, int maxRetries = 3) + { + if (indexes.Count == 0) return; + + //构建批量更新操作描述符 + var desc = new BulkDescriptor().UpdateMany(indexes, + (u, track) => + u.Id(track.Id) + .Index(track.IndexName) + .Script(s => s.Source(@" + ctx._source.trackPlace = params.trackPlace; + ctx._source.trackTime = params.trackTime; + ctx._source.trackTimeZone = params.trackTimeZone; + ctx._source.updateUser = params.updateUser; + ctx._source.updateTime = params.updateTime; + ctx._source.trackContent = params.trackContent; + ctx._source.trackEnContent = params.trackEnContent; + ctx._source.isVisibility = params.isVisibility; + ctx._source.isExternal = params.isExternal; + ctx._source.remarks = params.remarks; + ctx._source.files = params.files; + ctx._source.trackPlaceCity = params.trackPlaceCity; + ctx._source.trackPlaceCityId = params.trackPlaceCityId; + ctx._source.trackPlaceProvince = params.trackPlaceProvince; + ctx._source.trackPlaceProvinceId = params.trackPlaceProvinceId; + ctx._source.trackPlaceNation = params.trackPlaceNation; + ctx._source.trackPlaceNationId = params.trackPlaceNationId; + ctx._source.trackPlacePostcode = params.trackPlacePostcode; + ctx._source.destinationTimeZone = params.destinationTimeZone; + ctx._source.estimatedDeliveryDate = params.estimatedDeliveryDate; + ctx._source.extra = params.extra; + ").Params(p => p + .Add("trackPlace", track.TrackPlace) + .Add("trackTime", track.TrackTime) + .Add("trackTimeZone", track.TrackTimeZone) + .Add("updateUser", track.UpdateUser) + .Add("updateTime", DateTime.Now) + //S06新增字段更新 + .Add("trackContent", track.TrackContent) + .Add("trackEnContent", track.TrackEnContent) + .Add("isVisibility", track.IsVisibility) + .Add("isExternal", track.IsExternal) + .Add("remarks", track.Remarks) + .Add("files", track.Files) + .Add("trackPlaceCity", track.TrackPlaceCity) + .Add("trackPlaceCityId", track.TrackPlaceCityId) + .Add("trackPlaceProvince", track.TrackPlaceProvince) + .Add("trackPlaceProvinceId", track.TrackPlaceProvinceId) + .Add("trackPlaceNation", track.TrackPlaceNation) + .Add("trackPlaceNationId", track.TrackPlaceNationId) + .Add("trackPlacePostcode", track.TrackPlacePostcode) + .Add("destinationTimeZone", track.DestinationTimeZone) + .Add("estimatedDeliveryDate", track.EstimatedDeliveryDate) + .Add("extra", track.Extra) + ))); + + var retryCount = 0; + var updateSuccessful = false; + while (retryCount < maxRetries && !updateSuccessful) + { + var response = await Context.BulkAsync(desc); + if (response.IsValid) + { + updateSuccessful = true; + } + else if (response.ServerError?.Status == 409) // 409 表示版本冲突 + { + retryCount++; + if (retryCount >= maxRetries) + { + throw new InvalidOperationException( + $"轨迹更新冲突达到最大次数,track:{indexes.Count}条,原因:{response.DebugInformation}。"); + } + } + else + { + throw new InvalidOperationException($"轨迹更新失败,track:{indexes.Count}条,原因:{response.DebugInformation}。"); + } + } + } + + public async Task AddManyAsync(List tracks) + { + // 按天写入es + var indexName = $"{GlobalConst.TrackDetailsIndex}-{DateTime.Now:yyyy.MM.dd}"; + tracks.ForEach(x => x.IndexName = indexName); + + var r = await Context.IndexManyAsync(tracks, indexName); + + if (!r.IsValid) + { + throw new InvalidOperationException($"{tracks.Count}条轨迹新增失败,原因:{r.DebugInformation}。"); + } + } + + public async Task AddAsync(TrackDetailsIndex track) + { + // 按天写入es + var indexName = $"{GlobalConst.TrackDetailsIndex}-{DateTime.Now:yyyy.MM.dd}"; + track.IndexName = indexName; + var r = await Context.IndexAsync(track, s => s.Index(indexName)); + + if (!r.IsValid) + { + throw new InvalidOperationException($"轨迹新增失败,track:{track.ToJson()},原因:{r.DebugInformation}。"); + } + } + + public async Task> GetListAsync(int subSystemId, int orderType, List orderNos, List? trackCodes = null) + { + if (orderNos.Count < 1) return new List(); + + var musts = new List, QueryContainer>> + { + mu => mu.Term(f => f.SubSystemId, subSystemId), + mu => mu + .Terms(t => t + .Field(f => f.OrderNo.Suffix("keyword")) + .Terms(orderNos) + ), + mu => mu + .Term(f => f.OrderType, orderType) + }; + + if (trackCodes != null && trackCodes.Count > 0) + { + musts.Add(mu => mu + .Terms(t => t + .Field(f => f.TrackCode.Suffix("keyword")) + .Terms(trackCodes) + )); + } + + + var r = await Context.SearchAsync(x => x + .Index(GlobalConst.TrackDetailsIndex) + .Source() + .Query(q => + q.Bool(b => b + .Must(musts) + // tips:对外不暴露服务商轨迹 + .MustNot(mn => mn + .Term(t => t.TrackCode.Suffix("keyword"), GlobalConst.EmptyString) + ) + ) + ) + .Size(SafelyLimit) + ); + + if (!r.IsValid) + { + throw new InvalidOperationException( + $"轨迹查询失败,orderType:{orderType},orderNos:{orderNos},原因:{r.DebugInformation}。"); + } + + return r.ToIdList(); + } + + public async Task> GetListAsync(int orderId) + { + var r = await Context.SearchAsync(x => x + .Index(GlobalConst.TrackDetailsIndex) + .Query(q => + q.Term(t => t.OrderId, orderId) + ) + .Size(SafelyLimit) + .Sort(s => s + .Field(f => f.ZeroTrackTime, SortOrder.Descending) + .Field(f => f.CreateTime, SortOrder.Descending) + )); + + if (!r.IsValid) + { + throw new InvalidOperationException($"轨迹查询失败,orderId:{orderId},原因:{r.DebugInformation}。"); + } + + return r.ToIdList(); + } + + public async Task> GetListAsync(int[] orderIds, List? trackCodes = null, TrackSourceEnum? source = null) + { + var query = new QueryContainer(); + + if (orderIds.Length > 0) + { + query &= Query.Terms(t => t.Field(f => f.OrderId).Terms(orderIds)); + } + + if (trackCodes != null && trackCodes.Count > 0) + { + query &= Query.Terms(t => t.Field(f => f.TrackCode.Suffix("keyword")).Terms(trackCodes)); + } + + if (source.HasValue) + { + query &= Query.Term(t => t.Field(f => f.Source).Value(source.Value)); + } + + var r = await Context.SearchAsync(x => x + .Index(GlobalConst.TrackDetailsIndex) + .Query(q => query) + .Size(SafelyLimit) + .Sort(s => s + .Field(f => f.ZeroTrackTime, SortOrder.Descending) + .Field(f => f.CreateTime, SortOrder.Descending)) + ); + + if (!r.IsValid) + { + throw new InvalidOperationException($"轨迹查询失败,orderIds:[{string.Join(',', orderIds)}],原因:{r.DebugInformation}。"); + } + + return r.ToIdList(); + } + + public async Task> DeleteTrackAsync(int[] orderIds, List trackCodes) + { + // var deleteResponse = await Context.DeleteByQueryAsync(d => d + // .Index($"{GlobalConst.TrackDetailsIndex}-*") // 使用通配符匹配所有相关索引 + // .Query(q => + // q.Terms(t => t.Field(f => f.OrderId).Terms(orderIds)) + // && q.Terms(t => t.Field(f => f.TrackCode.Suffix("keyword")).Terms(trackCodes)) + // ) + // ); + // + // if (!deleteResponse.IsValid) + // { + // throw new InvalidOperationException( + // $"删除轨迹失败,orderIds:[{string.Join(", ", orderIds)}],trackCodes:[{string.Join(", ", trackCodes)}],原因:{deleteResponse.DebugInformation}。"); + // } + + var search = await Context.SearchAsync(x => x + .Index(GlobalConst.TrackDetailsIndex) + .Source(s => s.Includes(fd => fd + .Field(f => f.IndexName) + .Field(f => f.OrderId) + .Field(f => f.TrackCode) + )) + .Size(SafelyLimit) + .Query(q => + q.Terms(t => t.Field(f => f.OrderId).Terms(orderIds)) + && q.Terms(t => t.Field(f => f.TrackCode.Suffix("keyword")).Terms(trackCodes)) + ) + ); + + if (!search.IsValid) + { + throw new InvalidOperationException( + $"轨迹查询失败,orderIds:[{orderIds.JoinAsString(", ")}],trackCodes:[{trackCodes.JoinAsString(", ")}],原因:{search.DebugInformation}。"); + } + + //按订单id和code分组,只删除组元素数量为1的轨迹 + var tracks = search.ToIdList().GroupBy(doc => new + { + doc.OrderId, + doc.TrackCode + }) + .Where(g => g.Count() == 1) + .Select(g => g.First()) // 只保留每组的第一个元素 + .ToList(); + + foreach (var track in tracks) + { + await DeleteTrackByIdAsync(track.Id, track.IndexName); + } + + return tracks.Select(x => x.OrderId).ToList(); + } + + + public async Task DeleteTrackByIdAsync(string id, string indexName) + { + var r = await Context.DeleteAsync(id, u => u + .Index(indexName) + ); + + if (!r.IsValid) + { + throw new InvalidOperationException($"轨迹删除失败,id:{indexName},原因:{r.DebugInformation}。"); + } + } + + public async Task> GetDataByIds(string[] ids) + { + var res = await Context.SearchAsync(m => m + .Index(GlobalConst.TrackDetailsIndex) + .Query( + q => q.Ids(i => i.Values(ids)) + )); + + return res.ToIdList(); + } + + public async Task GetDetailAsync(string orderNo, string trackCode, int orderType, int subSystemId, DateTime trackTime) + { + var res = await Context.SearchAsync(s => s + .Index("sjzy_track_details") + .Query(q => q + .Bool(b => b + .Must(mu => mu + .Terms(t => t + .Field(f => f.OrderNo.Suffix("keyword")) + .Terms(orderNo)), + mu => mu + .Terms(t => t + .Field(f => f.TrackCode.Suffix("keyword")) + .Terms(trackCode)), + mu => mu + .Terms(t => t + .Field(f => f.OrderType) + .Terms(orderType)), + mu => mu + .Terms(t => t + .Field(f => f.SubSystemId) + .Terms(subSystemId)), + mu => mu + .Terms(t => t + .Field(f => f.TrackTime) + .Terms(trackTime)) // 注意:这里你重复了OrderType的查询,你可能需要移除重复的查询 + ) + ) + ) + ); + + return res.Documents.FirstOrDefault(); + } + + public async Task MigrateAsync() + { + await Context.MapAsync(m => m + .AutoMap()); + //字段迁移,isVisibility => isExternal + await Context.UpdateByQueryAsync(u => u + .Query(q => q.MatchAll()) + .Script(s=>s.Source("ctx._source.isExternal = ctx._source.isVisibility")) + ); + } +} diff --git a/src/SJZY.Track.Repository/Repositories/TrackDetailsRepository.cs b/src/SJZY.Track.Repository/Repositories/TrackDetailsRepository.cs deleted file mode 100644 index 4f798cb2..00000000 --- a/src/SJZY.Track.Repository/Repositories/TrackDetailsRepository.cs +++ /dev/null @@ -1,306 +0,0 @@ -using Nest; -using SJZY.Expand.ElasticSearch.Services; -using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; -using SJZY.Track.Domain.Consts; -using SJZY.Track.Domain.Dtos.TrackDetails; - -namespace SJZY.Track.Repository.Repositories; - -internal class TrackDetailsRepository : ElasticSearchContextAbstract, ITrackDetailsRepository, - ITransientDependency -{ - public TrackDetailsRepository(ConnectionFactory connectionFactory) : base(connectionFactory) - { - } - - public async Task> GetListAsync(int[] orderIds, string trackCode, - bool forUpsert = false) - { - var r = !forUpsert - ? await Context.SearchAsync(s => s - .Source() - .Size(1000) - .Query(q => q - .Bool(b => b - .Must( - mu => mu.Terms(t => t.Field(f => f.OrderId).Terms(orderIds)), - mu => mu.Term(t => t.Field(f => f.TrackCode.Suffix("keyword")).Value(trackCode)) - ) - ) - ) - ) - : await Context.SearchAsync(s => s - .Source(s2 => s2.Includes(fd => fd - .Field(f => f.IndexName) - .Field(f => f.OrderId) - )) - .Size(1000) - .Query(q => q - .Bool(b => b - .Must( - mu => mu.Terms(t => t.Field(f => f.OrderId).Terms(orderIds)), - mu => mu.Term(t => t.Field(f => f.TrackCode.Suffix("keyword")).Value(trackCode)) - ) - ) - ) - ); - - if (!r.IsValid) - { - throw new Exception($"轨迹查询异常,原因:{r.DebugInformation}。"); - } - - return r.ToIdList(); - } - - public async Task> GetLatestListAsync(int[] orderIds, List trackCodes) - { - var excludeTrackCodes = trackCodes.ToList(); - excludeTrackCodes.Add(GlobalConst.EmptyString); - var r = await Context.SearchAsync(x => x - .Source(s => s.Includes(fd => fd - .Field(f => f.TrackEnContent) - .Field(f => f.TrackContent) - .Field(f => f.TrackPlace) - .Field(f => f.TrackTime) - .Field(f => f.TrackTimeZone) - .Field(f => f.OrderId) - .Field(f => f.TrackCode) - )) - .Query(q => q - .Bool(b => b - .Must( - mu => mu.Terms(t => t.Field(f => f.OrderId).Terms(orderIds)) - ) - .MustNot(mn => mn - .Terms(t => t - .Field(f => f.TrackCode.Suffix("keyword")) - .Terms(excludeTrackCodes) - ) - ) - ) - ) - .Size(orderIds.Length) - .Aggregations(a => a - .Terms("orders", t => t - .Field(f => f.OrderId) - .Aggregations(aa => aa - .TopHits("latest_track", th => th - .Size(1) - .Sort(so => so - .Field(f => f.ZeroTrackTime, SortOrder.Descending) - ) - ) - ) - ) - ) - ); - - if (!r.IsValid) - { - throw new Exception($"轨迹查询异常,原因:{r.DebugInformation}。"); - } - - return r.Documents.ToList(); - } - - public async Task AnyAsync(int orderId, DateTime trackTime) - { - var r = await Context.SearchAsync(x => x - .Source(s => s.Includes(fd => fd.Field(f => f.TrackCode))) - .Query(q => - q.Term(f => f.OrderId, orderId) - && q.Term(f => f.TrackTime, trackTime) - ) - ); - - if (!r.IsValid) - { - throw new Exception($"轨迹查询异常,原因:{r.DebugInformation}。"); - } - - return r.Hits.Count > 0; - } - - public async Task AnyAsync(int orderId, string originTrackData) - { - var r = await Context.SearchAsync(x => x - .Source(s => s.Includes(fd => fd.Field(f => f.TrackCode))) - .Query(q => - q.Term(f => f.OrderId, orderId) - && q.Term(f => f.OriginTrackData.Suffix("keyword"), originTrackData) - ) - ); - - if (!r.IsValid) - { - throw new Exception($"轨迹查询异常,原因:{r.DebugInformation}。"); - } - - return r.Hits.Count > 0; - } - - public async Task AnyByCodeAsync(int orderId, string trackCode) - { - var r = await Context.SearchAsync(x => x - .Source(s => s.Includes(fd => fd.Field(f => f.TrackCode))) - .Query(q => - q.Term(f => f.OrderId, orderId) - && q.Term(f => f.TrackCode.Suffix("keyword"), trackCode) - ) - ); - - if (!r.IsValid) - { - throw new Exception($"轨迹查询异常,原因:{r.DebugInformation}。"); - } - - return r.Hits.Count > 0; - } - - - public async Task UpdateAsync(TrackDetailsIndex track) - { - var r = await Context.UpdateAsync(track.Id, u => u - .Index(track.IndexName) - .Doc(new - { - track.TrackPlace, - track.TrackTime, - track.TrackTimeZone, - track.UpdateUser, - UpdateTime = DateTime.Now, - }) - ); - - if (!r.IsValid) - { - throw new Exception($"轨迹更新失败,原因:{r.DebugInformation}。"); - } - } - - public async Task AddManyAsync(List tracks) - { - if (!tracks.Any()) return; - // 按天写入es - var indexName = $"{GlobalConst.TrackIndex}-{DateTime.Now:yyyy.MM.dd}"; - tracks.ForEach(x => x.IndexName = indexName); - - var r = await Context.IndexManyAsync(tracks, indexName); - - if (!r.IsValid) - { - throw new Exception($"{tracks.Count}条轨迹新增失败,原因:{r.DebugInformation}。"); - } - } - - public async Task AddAsync(TrackDetailsIndex track) - { - // 按天写入es - var indexName = $"{GlobalConst.TrackIndex}-{DateTime.Now:yyyy.MM.dd}"; - track.IndexName = indexName; - var r = await Context.IndexAsync(track, s => s.Index(indexName)); - - if (!r.IsValid) - { - throw new Exception($"轨迹新增失败,原因:{r.DebugInformation}。"); - } - } - - public async Task> GetListAsync(int orderType, List orderNos) - { - if (orderNos.Count < 1) return new List(); - - var r = await Context.SearchAsync(x => x - .Source(s => s.Includes(fd => fd - .Field(f => f.OrderNo) - .Field(f => f.TrackStatus) - .Field(f => f.TrackCode) - .Field(f => f.TrackContent) - .Field(f => f.OriginTrackContent) - .Field(f => f.TrackPlace) - .Field(f => f.TrackTime) - .Field(f => f.TrackTimeZone) - )) - .Query(q => - q.Terms(t => t - .Field(f => f.OrderNo.Suffix("keyword")) - .Terms(orderNos)) - && q.Term(f => f.OrderType, orderType) - ) - .Size(1000) - ); - - if (!r.IsValid) - { - throw new Exception($"轨迹查询异常,原因:{r.DebugInformation}。"); - } - - return r.Documents.ToList(); - } - - public async Task> GetListAsync(int orderId) - { - var r = await Context.SearchAsync(x => x - .Query(q => - q.Term(t => t.OrderId, orderId) - ) - .Size(1000) - .Sort(s => s.Field(f => f.ZeroTrackTime, SortOrder.Descending))); - - if (!r.IsValid) - { - throw new Exception($"轨迹查询异常,原因:{r.DebugInformation}。"); - } - - return r.Documents.ToList(); - } - - public async Task DeleteTrackAsync(int[] orderIds, List trackCodes) - { - var search = await Context.SearchAsync(x => x - .Source(s => s.Includes(fd => fd.Field(f => f.IndexName))) - .Size(orderIds.Length * trackCodes.Count * 2) - .Query(q => - q.Terms(t => t.Field(f => f.OrderId).Terms(orderIds)) - && q.Terms(t => t.Field(f => f.TrackCode.Suffix("keyword")).Terms(trackCodes)) - ) - ); - - if (!search.IsValid) - { - throw new Exception($"轨迹查询异常,原因:{search.DebugInformation}。"); - } - - var tracks = search.ToIdList(); - - foreach (var track in tracks) - { - await Context.DeleteAsync(track.Id, u => u - .Index(track.IndexName) - ); - } - } - - public async Task<(List list, long total)> GetListAsync(TrackDetailsQueryInput input) - { - if (input.OrderNos.Count < 1) return default; - - var distinctOrderNumbers = input.OrderNos.Distinct(); - var finalSize = input.PageSize > 500 ? 500 : input.PageSize; - - var data = await Context.SearchAsync(x => x - .Query(q => - q.Terms(t => t - .Field(f => f.OrderNo) - .Terms(distinctOrderNumbers)) - ) - .Sort(s => s.Field(f => f.CreateTime, SortOrder.Descending)) - .From((input.PageIndex - 1) * input.PageSize) - .Size(finalSize) - .TrackTotalHits() // todo: 聚合获取匹配查询条件的文档总数,而不受"index.max_result_window"的限制 - ); - - return (data.Documents.ToList(), data.Total); - } -} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/Repositories/TrackFlagRepository.cs b/src/SJZY.Track.Repository/Repositories/TrackFlagRepository.cs index ed92d283..72f588e6 100644 --- a/src/SJZY.Track.Repository/Repositories/TrackFlagRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/TrackFlagRepository.cs @@ -26,8 +26,8 @@ public class TrackFlagRepository : BasicRepository, ITrackFlagR SubSystemId = a.SubSystemId, SubSystem = b.CnName, Code = a.Code, - Flag = a.Name - //,IsFinish=a.IsCompleted + Flag = a.Name, + IsToMq = a.IsToMq }) .FirstAsync(); return detail; @@ -48,14 +48,16 @@ public class TrackFlagRepository : BasicRepository, ITrackFlagR .WhereIF(input.SubSystemId > 0, (a, b, c, d) => a.SubSystemId == input.SubSystemId) .WhereIF(!input.Keywords.IsNullOrWhiteSpace(), (a, b, c, d) => SqlFunc.Contains(a.Code, input.Keywords)) .OrderByIF(input.SelectIds.IsNullOrEmpty(), (a, b, c, d) => a.CreateTime, OrderByType.Desc) - .OrderByIF(!input.SelectIds.IsNullOrEmpty(), (a, b, c, d) => SqlFunc.IIF(input.SelectIds!.Contains(a.Id), SqlFunc.DateAdd(SqlFunc.GetDate(), 1), a.CreateTime), OrderByType.Desc) + .OrderByIF(!input.SelectIds.IsNullOrEmpty(), + (a, b, c, d) => SqlFunc.IIF(input.SelectIds!.Contains(a.Id), SqlFunc.DateAdd(SqlFunc.GetDate(), 1), + a.CreateTime), OrderByType.Desc) .Select((a, b, c, d) => new GetTrackFlagListVO { Id = a.Id, SubSystem = b.CnName, Code = a.Code, Flag = a.Name, - //IsFinish=a.IsCompleted, + IsToMq = a.IsToMq, CreateTime = a.CreateTime, CreateUser = c.Name, UpdateTime = a.UpdateTime, @@ -65,4 +67,4 @@ public class TrackFlagRepository : BasicRepository, ITrackFlagR return pagedList; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Repository/Repositories/TrackNodeRepository.cs b/src/SJZY.Track.Repository/Repositories/TrackNodeRepository.cs new file mode 100644 index 00000000..fcee8c2e --- /dev/null +++ b/src/SJZY.Track.Repository/Repositories/TrackNodeRepository.cs @@ -0,0 +1,81 @@ +using SJZY.Track.Domain.Aggregates.TrackNodeAggregate; +using SJZY.Track.Domain.Dtos.TrackNode; +using SJZY.Track.Domain.VEntities; + +namespace SJZY.Track.Repository.Repositories; + +public class TrackNodeRepository : BasicRepository, ITrackNodeRepository, IScopedDependency +{ + public async Task> GetPageList(TrackNodePageDto queryParam) + { + var result = await Context.Queryable() + .LeftJoin((t, u1) => t.CreateUserId == u1.Id) + .LeftJoin((t, u1, u2) => t.UpdateUserId == u2.Id) + .LeftJoin((t, u1, u2, u3) => t.SubSystemId == u3.Id) + .Where((t, u1, u2) => !t.IsDeleted && !u1.IsDeleted && !u2.IsDeleted) + .WhereIF(!string.IsNullOrEmpty(queryParam.KeyWord), + (t, u1, u2) => t.NodeName!.Contains(queryParam.KeyWord) || t.NodeEnName!.Contains(queryParam.KeyWord)) + .WhereIF(queryParam.SystemId.HasValue, (t, u1, u2) => t.SubSystemId == queryParam.SystemId.Value) + .Select((t, u1, u2, u3) => new TrackNodeDto() + { + Id = t.Id, + NodeName = t.NodeName, + NodeEnName = t.NodeEnName, + SubSystemId = t.SubSystemId, + UpdateTime = t.UpdateTime, + CreateTime = t.CreateTime, + UpdateUserId = t.UpdateUserId, + UpdateUserName = u2.Name, + CreateUserName = u1.Name, + SystemName = u3.CnName + }).ToPagedListAsync(queryParam.PageIndex, queryParam.PageSize); + + return result; + } + + public async Task> GetPageDicList(TrackNodePageDto queryParam) + { + var result = await Context.Queryable() + .Where((t) => !t.IsDeleted) + .WhereIF(!string.IsNullOrEmpty(queryParam.KeyWord), + (t) => t.NodeName!.Contains(queryParam.KeyWord) || t.NodeEnName!.Contains(queryParam.KeyWord)) + .WhereIF(queryParam.SystemId.HasValue, (t) => t.SubSystemId == queryParam.SystemId.Value) + .Select(t => new TrackNodeDicDto() + { + Id = t.Id, + NodeName = t.NodeName, + EnName = t.NodeEnName, + }) + .ToPagedListAsync(queryParam.PageIndex, queryParam.PageSize); + + return result; + } + + public Task DeleteById(long inputId) + { + return Context.Deleteable().Where(val => val.Id == inputId).ExecuteCommandAsync(); + } + + public async Task GetDetail(long id) + { + var result = await Context.Queryable() + .LeftJoin((t, u1) => t.CreateUserId == u1.Id) + .LeftJoin((t, u1, u2) => t.UpdateUserId == u2.Id) + .LeftJoin((t, u1, u2, u3) => t.SubSystemId == u3.Id) + .Where((t, u1, u2) => !t.IsDeleted && !u1.IsDeleted && !u2.IsDeleted && t.Id == id) + .Select((t, u1, u2, u3) => new TrackNodeDto() + { + Id = t.Id, + NodeName = t.NodeName, + NodeEnName = t.NodeEnName, + SubSystemId = t.SubSystemId, + UpdateTime = t.UpdateTime, + CreateTime = t.CreateTime, + UpdateUserId = t.UpdateUserId, + UpdateUserName = u2.Name, + CreateUserName = u1.Name, + SystemName = u3.CnName + }).FirstAsync(); + return result; + } +} diff --git a/src/SJZY.Track.Repository/Repositories/TrackPullConfigRepository.cs b/src/SJZY.Track.Repository/Repositories/TrackPullConfigRepository.cs index b3267e8a..821557e2 100644 --- a/src/SJZY.Track.Repository/Repositories/TrackPullConfigRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/TrackPullConfigRepository.cs @@ -1,7 +1,8 @@ -using System.Linq.Expressions; +using System.Linq.Expressions; using SJZY.Expand.ABP.Core.PublicMethords; using SJZY.Track.Domain.Aggregates.TrackContentAggregate; using SJZY.Track.Domain.Aggregates.TrackPullAggregate; +using SJZY.Track.Domain.Aggregates.TrackStatusAggregate; using SJZY.Track.Domain.Dtos.Common; using SJZY.Track.Domain.Dtos.TrackPull; using SJZY.Track.Domain.Enums; @@ -14,13 +15,12 @@ public class TrackPullConfigRepository : BasicRepository, { public async Task> GetPageAsync(KeywordsInputVO input) { - return await AsQueryable() - .LeftJoin((trackPull, system) => trackPull.SubSystemId == system.Id && !system.IsDeleted) - .LeftJoin((trackPull, system, service) => trackPull.ServiceProviderId == service.Id && !service.IsDeleted) - .Filter(null, true) - .Where(trackPull => !trackPull.IsDeleted) + return await Context.Queryable() + .LeftJoin((trackPull, system) => trackPull.SubSystemId == system.Id) + .LeftJoin((trackPull, system, service) => trackPull.ServiceProviderId == service.Id) .WhereIF(input.SubSystemId.HasValue, trackPull => trackPull.SubSystemId == input.SubSystemId) - .WhereIF(!input.Keywords.IsNullOrWhiteSpace(), (trackPull, system, service) => service.Name.Contains(input.Keywords!)) + .WhereIF(!input.Keywords.IsNullOrWhiteSpace(), + (trackPull, system, service) => service.Name.Contains(input.Keywords!)) .OrderByDescending(trackPull => trackPull.CreateTime) .Select((trackPull, system, service) => new GetTrackPullConfigPageOutputVO { @@ -33,18 +33,23 @@ public class TrackPullConfigRepository : BasicRepository, .ToPagedListAsync(input.PageIndex, input.PageSize); } - public async Task> GetContentPageAsync(GetTrackPullContentPageInputVO input) + public async Task> GetContentPageAsync( + GetTrackPullContentPageInputVO input) { return await Context.Queryable() .InnerJoin((pullContent, trackContent) => pullContent.TrackContentId == trackContent.Id) - .LeftJoin((pullContent, trackContent, enumValue) => enumValue.Property == EnumPropertyEnums.轨迹发生地.GetDescription() && pullContent.TrackPlaceValue == enumValue.Enumkey) + .LeftJoin((pullContent, trackContent, enumValue) => + enumValue.Property == EnumPropertyEnums.轨迹发生地.GetDescription() && + pullContent.TrackPlaceValue == enumValue.Enumkey) .Where(pullContent => pullContent.TrackPullConfigId == input.TrackPullConfigId) .OrderBy(pullContent => pullContent.CreateTime) - .Select((pullContent, trackContent, enumValue) => new GetTrackPullContentPageOutputVO - { - Id = pullContent.Id, - TrackPlaceValue = enumValue.Disp - }, true) + .Select( + (pullContent, trackContent, enumValue) => + new GetTrackPullContentPageOutputVO + { + Id = pullContent.Id, + TrackPlaceValue = enumValue.Disp + }, true) .ToPagedListAsync(input.PageIndex, input.PageSize); } @@ -52,29 +57,46 @@ public class TrackPullConfigRepository : BasicRepository, { return await Context.Queryable() .InnerJoin((pullContent, trackContent) => pullContent.TrackContentId == trackContent.Id) + .LeftJoin((pullContent, trackContent, trackStutas) => + trackContent.TrackStatusId == trackStutas.Id) .Where(pullContent => pullContent.TrackPullConfigId == trackPullConfigId) - .Select((pullContent, trackContent) => new GetTrackPullContentListCacheVO + .Select( + (pullContent, trackContent, trackStutas) => + new GetTrackPullContentListCacheVO + { + TrackContentCode = trackContent.Code, + }, true) + .Mapper(x => { - TrackContentCode = trackContent.Code - }, true) + x.TrackKeywords = x.TrackKeyword.IsNullOrWhiteSpace() + ? new List() + : x.TrackKeyword!.Split(',').ToList(); + x.TrackKeywordReverses = x.TrackKeywordReverse.IsNullOrWhiteSpace() + ? new List() + : x.TrackKeywordReverse!.Split(',').ToList(); + x.TrackStatusValues = x.TrackStatusValue.IsNullOrWhiteSpace() + ? new List() + : x.TrackStatusValue!.Split(',').ToList(); + }) .ToListAsync(); } - public async Task GetDetailAsync(int id) + public async Task GetDetailAsync(int id) { return await AsQueryable() - .LeftJoin((trackPull, system) => trackPull.SubSystemId == system.Id && !system.IsDeleted) - .LeftJoin((trackPull, system, service) => trackPull.ServiceProviderId == service.Id && !service.IsDeleted) - .InnerJoin((trackPull, system, service, paramsConfig) => trackPull.Id == paramsConfig.PullOrPushConfigId && !paramsConfig.IsPush && !paramsConfig.IsDeleted) - .Filter(null, true) - .Where(trackPull => trackPull.Id == id && !trackPull.IsDeleted) - .Select((trackPull, system, service, paramsConfig) => new GetTrackPullConfigDetailOutputVO - { - Id = trackPull.Id, - SubSystem = system.CnName, - ServiceProvider = service.Name - }, true) - .SingleAsync(); + .LeftJoin((trackPull, system) => trackPull.SubSystemId == system.Id) + .LeftJoin((trackPull, system, service) => trackPull.ServiceProviderId == service.Id) + .Where(trackPull => trackPull.Id == id) + .Select( + (trackPull, system, service) => new GetTrackPullConfigDetailOutputVO + { + Id = trackPull.Id, + SubSystem = system.CnName, + SubSystemId = system.Id, + ServiceProviderId = service.Id, + ServiceProviderCode = service.Code, + }, true) + .FirstAsync(); } public async Task GetContentDetailAsync(int id) @@ -82,39 +104,34 @@ public class TrackPullConfigRepository : BasicRepository, return await Context.Queryable() .InnerJoin((pullContent, trackContent) => pullContent.TrackContentId == trackContent.Id) .Where(pullContent => pullContent.Id == id) - .Select((pullContent, trackContent) => new GetTrackPullContentDetailOutputVO - { - Id = pullContent.Id, - Code = trackContent.Code + "-" + trackContent.Content, - }, true) + .Select( + (pullContent, trackContent) => new GetTrackPullContentDetailOutputVO + { + Id = pullContent.Id, + Code = trackContent.Code + "-" + trackContent.Content, + TrackTimePlaceValue = pullContent.TrackZonePlaceValue, + }, true) .Mapper(x => { - x.TrackKeywords = x.TrackKeyword?.Split(',').ToList(); - x.TrackKeywordReverses = x.TrackKeywordReverse?.Split(',').ToList(); + x.TrackKeywords = x.TrackKeyword.IsNullOrWhiteSpace() + ? new List() + : x.TrackKeyword!.Split(',').ToList(); + x.TrackKeywordReverses = x.TrackKeywordReverse.IsNullOrWhiteSpace() + ? new List() + : x.TrackKeywordReverse!.Split(',').ToList(); + x.TrackStatusValues = x.TrackStatusValue.IsNullOrWhiteSpace() + ? new List() + : x.TrackStatusValue!.Split(',').ToList(); }) .SingleAsync(); } - public async Task InsertParamsAsync(TrackPushPullParamsConfigEntity insertObj) - { - return await Context.Insertable(insertObj).ExecuteCommandAsync() > 0; - } public async Task InsertContentAsync(TrackPullContentConfigEntity insertObj) { return await Context.Insertable(insertObj).ExecuteCommandAsync() > 0; } - public async Task GetParamsSingleAsync(Expression> whereExpression) - { - return await Context.Queryable().SingleAsync(whereExpression); - } - - public async Task UpdateParamsAsync(TrackPushPullParamsConfigEntity updateObj) - { - return await Context.Updateable(updateObj).ExecuteCommandHasChangeAsync(); - } - public async Task SoftDeleteContentAsync(Expression> whereExpression) { return await Context.Updateable() @@ -123,13 +140,6 @@ public class TrackPullConfigRepository : BasicRepository, .ExecuteCommandHasChangeAsync(); } - public async Task SoftDeleteParamsAsync(Expression> whereExpression) - { - return await Context.Updateable() - .Where(whereExpression) - .SetColumns(nameof(ISoftDeleteBasicEntity.IsDeleted), true) - .ExecuteCommandHasChangeAsync(); - } public async Task GetContentByIdAsync(int id) { @@ -145,4 +155,13 @@ public class TrackPullConfigRepository : BasicRepository, { return await Context.Queryable().Where(whereExpression).AnyAsync(); } -} \ No newline at end of file + + public async Task FindIdAsync(int subSystemId, string serviceProviderCode) + { + return await AsQueryable() + .LeftJoin((trackPull, service) => trackPull.ServiceProviderId == service.Id) + .Where((trackPull, service) => trackPull.SubSystemId == subSystemId && service.Code == serviceProviderCode) + .Select(trackPull => trackPull.Id) + .FirstAsync(); + } +} diff --git a/src/SJZY.Track.Repository/Repositories/TrackPushConfigRepository.cs b/src/SJZY.Track.Repository/Repositories/TrackPushConfigRepository.cs index c7e21820..050d7d9e 100644 --- a/src/SJZY.Track.Repository/Repositories/TrackPushConfigRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/TrackPushConfigRepository.cs @@ -1,4 +1,4 @@ -using System.Linq.Expressions; +using System.Linq.Expressions; using SJZY.Expand.ABP.Core.PublicMethords; using SJZY.Track.Domain.Aggregates.TrackContentAggregate; using SJZY.Track.Domain.Aggregates.TrackPushAggregate; @@ -6,7 +6,6 @@ using SJZY.Track.Domain.Dtos.Common; using SJZY.Track.Domain.Dtos.TrackPush; using SJZY.Track.Domain.Enums; using SJZY.Track.Domain.VEntities; -using SJZY.Track.Repository.VData.Entitys; namespace SJZY.Track.Repository.Repositories; @@ -47,12 +46,14 @@ public class TrackPushConfigRepository : BasicRepository, pushContent.OrderNoType == enumValue.Enumkey && !enumValue.IsDeleted) .Where(pushContent => pushContent.TrackPushConfigId == input.TrackPushConfigId) .OrderBy(pushContent => pushContent.Sort) - .Select((pushContent, trackContent, enumValue) => new GetTrackPushContentPageOutputVO - { - Id = pushContent.Id, - Sort = pushContent.Sort, - OrderNoType = enumValue.Disp - }, true) + .Select( + (pushContent, trackContent, enumValue) => new GetTrackPushContentPageOutputVO + { + Id = pushContent.Id, + Sort = pushContent.Sort, + OrderNoType = enumValue.Disp, + ContentId = pushContent.TrackContentId, + }, true) .ToPagedListAsync(input.PageIndex, input.PageSize); } @@ -62,17 +63,22 @@ public class TrackPushConfigRepository : BasicRepository, .LeftJoin((trackPush, system) => trackPush.SubSystemId == system.Id && !system.IsDeleted) .LeftJoin((trackPush, system, externalSubject) => trackPush.CustomId == externalSubject.Id && !externalSubject.IsDeleted) - .LeftJoin((trackPush, system, externalSubject, service) => - trackPush.ServiceProviderId == service.Id && !service.IsDeleted) .Filter(null, true) .Where(trackPush => trackPush.Id == id && !trackPush.IsDeleted) - .Select((trackPush, system, externalSubject, service) => new GetTrackPushConfigDetailOutputVO - { - Id = trackPush.Id, - SubSystem = system.CnName, - CustomName = externalSubject.Abbreviation, - ServiceProvider = service.Name, - }, true) + .Select( + (trackPush, system, externalSubject) => new GetTrackPushConfigDetailOutputVO + { + Id = trackPush.Id, + SubSystem = system.CnName, + CustomName = externalSubject.Abbreviation, + ServiceProviderCode = trackPush.ServiceProviderCode, + DateTimeFormat = trackPush.DateTimeFormat, + DateTimeFormatType = + trackPush.DateTimeFormatType == DateTimeFormatEnum.None + ? null + : trackPush.DateTimeFormatType, + TimezoneFormat = trackPush.TimezoneFormat + }, true) .SingleAsync(); } @@ -119,17 +125,16 @@ public class TrackPushConfigRepository : BasicRepository, { return await Context.Queryable() .LeftJoin((a, b) => a.Id == b.TrackPushConfigId) - .LeftJoin((a, b, c) => a.ServiceProviderId == c.Id) - .LeftJoin((a, b, c, d) => b.TrackContentId == d.Id) - .LeftJoin((a, b, c, d, e) => b.SwapTrackContentId == e.Id) + .LeftJoin((a, b, d) => b.TrackContentId == d.Id) + .LeftJoin((a, b, d, e) => b.SwapTrackContentId == e.Id) .Where(a => a.Id == configId) .OrderBy((a, b) => b.Sort) - .Select((a, b, c, d, e) => new TrackPushContentConfigVO + .Select((a, b, d, e) => new TrackPushContentConfigVO { IsAutoPush = a.IsAutoPush, IsCanUpdate = a.IsCanUpdate, IsAllPush = a.IsAllPush, - ServiceProviderCode = c.Code, + ServiceProviderCode = a.ServiceProviderCode, OrderType = b.OrderNoType, TrackCode = d.Code, SwapTrackCode = e.Code, @@ -172,23 +177,53 @@ public class TrackPushConfigRepository : BasicRepository, /// /// /// - public async Task> QueryTrackPullMappingsAsync(QueryTrackPullMappingsInputVO input) + public async Task> QueryTrackPullMappingsAsync( + QueryTrackPullMappingsInputVO input) { - var result = await Context.Queryable().LeftJoin((a, b) => a.Id == b.TrackPushConfigId && !b.IsDeleted) - .LeftJoin((a, b, c) => b.TrackContentId == c.Id && !c.IsDeleted) - .Where((a, b, c) => !a.IsDeleted) - .Where((a, b, c) => a.SubSystemId == input.SubsystemsId && a.CustomId == input.CustomerId) - .Select((a, b, c) => new QueryTrackPullMappingsInfoVO - { - Code = c.Code, - OrderType = b.OrderNoType, - ServiceCode = b.TrackContentCodeValue, - Status = b.TrackStatusValue, - Content = b.TrackContentValue, - ContentEn = b.TrackEnContentValue - }) - .ToListAsync(); + var result = await Context.Queryable() + .LeftJoin((a, b) => a.Id == b.TrackPushConfigId && !b.IsDeleted) + .LeftJoin((a, b, c) => b.TrackContentId == c.Id && !c.IsDeleted) + .Where((a, b, c) => !a.IsDeleted) + .Where((a, b, c) => a.SubSystemId == input.SubsystemsId && a.CustomId == input.CustomerId) + .Select((a, b, c) => new QueryTrackPullMappingsInfoVO + { + Code = c.Code, + OrderType = b.OrderNoType, + ServiceCode = b.TrackContentCodeValue, + Status = b.TrackStatusValue, + Content = b.TrackContentValue, + ContentEn = b.TrackEnContentValue + }) + .ToListAsync(); return result; } -} \ No newline at end of file + + public async Task> GetTrackPushContentListAsync(int subSystemId, int customerId) + { + return await Context.Queryable() + .LeftJoin((a, b) => a.Id == b.TrackPushConfigId) + .LeftJoin((a, b, c) => b.TrackContentId == c.Id) + .Where(a => a.SubSystemId == subSystemId && a.CustomId == customerId) + .OrderBy((a, b) => b.Sort) + .Select((a, b, c) => new GetTrackPushContentListVo + { + Id = a.Id, + Code = c.Code, + OrderType = b.OrderNoType, + ServiceCode = b.TrackContentCodeValue, + Status = b.TrackStatusValue, + Content = b.TrackContentValue, + ContentEn = b.TrackEnContentValue + }) + .ToListAsync(); + } + + public async Task GetServiceCodeByCustomerIdAsync(int customerId) + { + return await Context.Queryable() + .Where(x => x.Id == customerId) + .Select(x => x.ApiServiceCode) + .FirstAsync(); + } +} diff --git a/src/SJZY.Track.Repository/Repositories/TrackPushRecordEsRepository.cs b/src/SJZY.Track.Repository/Repositories/TrackPushRecordEsRepository.cs new file mode 100644 index 00000000..3cbef97d --- /dev/null +++ b/src/SJZY.Track.Repository/Repositories/TrackPushRecordEsRepository.cs @@ -0,0 +1,113 @@ +using Nest; +using SJZY.Expand.ABP.Core.Logger; +using SJZY.Expand.ElasticSearch.Services; +using SJZY.Track.Domain.Aggregates.TrackPushAggregate; +using SJZY.Track.Domain.Consts; + +namespace SJZY.Track.Repository.Repositories; + +public class TrackPushRecordEsRepository : ElasticSearchContextAbstract, + ITrackPushRecordEsRepository, + ITransientDependency +{ + public TrackPushRecordEsRepository(ConnectionFactory connectionFactory) : base(connectionFactory) + { + } + + public async Task AddAsync(TrackPushRecordIndex index) + { + index.IndexName = $"{GlobalConst.TrackPushRecordIndex}-{DateTime.Now:yyyy.MM.dd}"; + index.CreateTime = DateTime.Now; + // 按天写入es + var r = await Context.IndexAsync(index, request => request + .Index(index.IndexName) + // .Refresh(Refresh.True) // 可选:立即刷新索引使更改立即可见 + ); + + if (!r.IsValid) + { + LogHelper.Error($"轨迹推送记录写入es失败,原因:{r.DebugInformation}。"); + } + } + + public async Task AddManyAsync(List records) + { + if (!records.Any()) return; + // 按天写入es + var indexName = $"{GlobalConst.TrackPushRecordIndex}-{DateTime.Now:yyyy.MM.dd}"; + records.ForEach(x => x.IndexName = indexName); + + var r = await Context.IndexManyAsync(records, indexName); + + if (!r.IsValid) + { + throw new Exception($"{records.Count}条轨迹推送记录写入失败,原因:{r.DebugInformation}。"); + } + } + + public async Task DeletePushRecordByIdAsync(string id, string indexName) + { + var r = await Context.DeleteAsync(id, u => u + .Index(indexName) + ); + + if (!r.IsValid) + { + throw new InvalidOperationException($"轨迹推送记录失败,id:{indexName},原因:{r.DebugInformation}。"); + } + } + + + public async Task> GetTrackPushRecordsAsync(int orderId) + { + var data = await Context.SearchAsync(x => x + .Index(GlobalConst.TrackPushRecordIndex) + .Query(q => + q.Term(t => t.OrderId, orderId) + ) + .Size(1000) + .Sort(s => s.Field(f => f.CreateTime, SortOrder.Descending))); + + return data.ToIdList(); + } + + public async Task GetLatestTrackPushRecordAsync(int orderId, bool isSuccess = false) + { + var musts = new List, QueryContainer>> + { + mu => mu.Term(t => t.OrderId, orderId), + }; + + if (isSuccess) + musts.Add(mu => mu.Term(t => t.IsSuccess, true)); + + var data = await Context.SearchAsync(x => x + .Index(GlobalConst.TrackPushRecordIndex) + .Query(q => + q.Bool(b => + b.Must(musts)) + ) + .Size(1000) + .Sort(s => s.Field(f => f.CreateTime, SortOrder.Descending))); + + return data.Documents.FirstOrDefault(); + } + + public async Task> GetHistorySuccessTrackPushRecordAsync(int orderId) + { + var data = await Context.SearchAsync(x => x + .Index(GlobalConst.TrackPushRecordIndex) + .Source(s => + s.Excludes(fs => + fs.Field(f => f.PushContent))) + .Query(q => q.Bool(b => + b.Must( + mu => mu.Term(t => t.IsSuccess, true), + mu => mu.Term(t => t.OrderId, orderId) + )) + ) + .Size(1000) + .Sort(s => s.Field(f => f.CreateTime, SortOrder.Descending))); + return data.ToIdList(); + } +} diff --git a/src/SJZY.Track.Repository/Repositories/TrackPushRecordsRepository.cs b/src/SJZY.Track.Repository/Repositories/TrackPushRecordsRepository.cs deleted file mode 100644 index 044f8753..00000000 --- a/src/SJZY.Track.Repository/Repositories/TrackPushRecordsRepository.cs +++ /dev/null @@ -1,74 +0,0 @@ -using Nest; -using SJZY.Expand.ABP.Core.Logger; -using SJZY.Expand.ElasticSearch.Services; -using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; -using SJZY.Track.Domain.Aggregates.TrackPushAggregate; -using SJZY.Track.Domain.Consts; - -namespace SJZY.Track.Repository.Repositories; - -public class TrackPushRecordsRepository : ElasticSearchContextAbstract, ITrackPushRecordsRepository, - ITransientDependency -{ - public TrackPushRecordsRepository(ConnectionFactory connectionFactory) : base(connectionFactory) - { - } - - public async Task AddAsync(TrackPushRecordIndex index) - { - index.IndexName = $"{GlobalConst.TrackPushRecordsIndex}-{DateTime.Now:yyyy.MM.dd}"; - index.CreateTime = DateTime.Now; - // 按天写入es - var r = await Context.IndexAsync(index, request => request - .Index(index.IndexName) - //.Refresh(Refresh.True) // 可选:立即刷新索引使更改立即可见 - ); - - if (!r.IsValid) - { - LogHelper.Error($"轨迹推送记录写入es失败,原因:{r.DebugInformation}。"); - } - } - - public async Task AddManyAsync(List records) - { - if (!records.Any()) return; - // 按天写入es - var indexName = $"{GlobalConst.TrackIndex}-{DateTime.Now:yyyy.MM.dd}"; - records.ForEach(x => x.IndexName = indexName); - - var r = await Context.IndexManyAsync(records, indexName); - - if (!r.IsValid) - { - throw new Exception($"{records.Count}条轨迹推送记录写入失败,原因:{r.DebugInformation}。"); - } - } - - - public async Task> GetTrackPushRecordsAsync(int orderId) - { - var data = await Context.SearchAsync(x => x - .Index(GlobalConst.TrackPushRecordsIndex) - .Query(q => - q.Term(t => t.OrderId, orderId) - ) - .Size(1000) - .Sort(s => s.Field(f => f.CreateTime, SortOrder.Descending))); - - return data.Documents.ToList(); - } - - public async Task GetLatestTrackPushRecordAsync(int orderId) - { - var data = await Context.SearchAsync(x => x - .Index(GlobalConst.TrackPushRecordsIndex) - .Query(q => - q.Term(t => t.OrderId, orderId) - ) - .Size(1000) - .Sort(s => s.Field(f => f.CreateTime, SortOrder.Descending))); - - return data.Documents.FirstOrDefault(); - } -} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/Repositories/TrackStatusRepository.cs b/src/SJZY.Track.Repository/Repositories/TrackStatusRepository.cs index a4abd5b5..eaf191fc 100644 --- a/src/SJZY.Track.Repository/Repositories/TrackStatusRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/TrackStatusRepository.cs @@ -1,3 +1,4 @@ +using SJZY.Track.Domain.Aggregates.TrackNodeAggregate; using SJZY.Track.Domain.Aggregates.TrackStatusAggregate; using SJZY.Track.Domain.Dtos.TrackStatus; using SJZY.Track.Domain.VEntities; @@ -14,17 +15,21 @@ public class TrackStatusRepository : BasicRepository, ITrackS public async Task GetDetailAsync(int id) { var detail = await Context.Queryable() - .LeftJoin((a, b) => a.SubSystemId == b.Id&&b.IsDeleted==false) - .Where((a, b) => a.Id == id) - .Select((a, b) => new GetTrackStatusDetailVO + .InnerJoin((a, t) => a.Node == t.Id) + .LeftJoin((a, t, b) => a.SubSystemId == b.Id && b.IsDeleted == false) + .Where((a, t, b) => a.Id == id) + .Select((a, t, b) => new GetTrackStatusDetailVO { Id = a.Id, SubSystemId = a.SubSystemId, SubSystem = b.CnName, Code = a.Code, - EntrackStatus = a.EnStatus, + EnTrackStatus = a.EnStatus, NodeId = a.Node, - TrackStatus = a.Status + TrackStatus = a.Status, + NodeName = t.NodeName, + IsCompleted = a.IsCompleted, + IsToMq = a.IsToMq }) .FirstAsync(); return detail; @@ -35,35 +40,39 @@ public class TrackStatusRepository : BasicRepository, ITrackS /// /// /// - public async Task> GetPageTrackStatus(GetPageTrackStatusVO input) + public async Task> GetPageTrackStatus(GetPagedTrackStatusVO input) { - UnifyPageResultDto pagedList = await Context.Queryable() + var pagedList = await Context.Queryable() .LeftJoin((a, b) => a.SubSystemId == b.Id && b.IsDeleted == false) .LeftJoin((a, b, c) => a.CreateUserId == c.Id && c.IsDeleted == false) .LeftJoin((a, b, c, d) => a.UpdateUserId == d.Id && d.IsDeleted == false) + .InnerJoin((a, b, c, d, e) => a.Node == e.Id && a.SubSystemId == e.SubSystemId) .WhereIF(input.SubSystemId > 0, (a, b, c, d) => a.SubSystemId == input.SubSystemId) .WhereIF(!input.Keywords.IsNullOrWhiteSpace(), (a, b, c, d) => a.Status.Contains(input.Keywords) || a.EnStatus.Contains(input.Keywords) || a.Code.Contains(input.Keywords)) .OrderByIF(input.SelectIds.IsNullOrEmpty(), (a, b, c, d) => a.CreateTime, OrderByType.Desc) - .OrderByIF(!input.SelectIds.IsNullOrEmpty(), (a, b, c, d) => SqlFunc.IIF(input.SelectIds.Contains(a.Id), SqlFunc.DateAdd(SqlFunc.GetDate(), 1), a.CreateTime), OrderByType.Desc) - .Select((a, b, c, d) => new GetTrackStatusListVO + .OrderByIF(!input.SelectIds.IsNullOrEmpty(), + (a, b, c, d) => SqlFunc.IIF(input.SelectIds.Contains(a.Id), SqlFunc.DateAdd(SqlFunc.GetDate(), 1), + a.CreateTime), OrderByType.Desc) + .Select((a, b, c, d, e) => new GetTrackStatusListVO { Id = a.Id, Code = a.Code, - EntrackStatus = a.EnStatus, + EnTrackStatus = a.EnStatus, TrackStatus = a.Status, NodeId = a.Node, - Node = SqlFunc.IF(a.Node == 1).Return("揽收").ElseIF(a.Node == 2).Return("清关").ElseIF(a.Node == 3) - .Return("干线").ElseIF(a.Node == 4).Return("派送").ElseIF(a.Node == 5).Return("其他").End(""), + Node = e.NodeName!, CreateTime = a.CreateTime, CreateUser = c.Name, UpdateTime = a.UpdateTime, UpdateUser = d.Name, - SubSystem = b.CnName + SubSystem = b.CnName, + IsCompleted = a.IsCompleted, + IsToMq = a.IsToMq }) .ToPagedListAsync(input.PageIndex, input.PageSize); return pagedList; } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Repository/Repositories/TrackTemplateRepository.cs b/src/SJZY.Track.Repository/Repositories/TrackTemplateRepository.cs index e14bea79..2f9b4a2d 100644 --- a/src/SJZY.Track.Repository/Repositories/TrackTemplateRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/TrackTemplateRepository.cs @@ -1,12 +1,14 @@ -using System.Linq.Expressions; +using System.Linq.Expressions; using SJZY.Expand.ABP.Core.PublicMethords; using SJZY.Track.Domain.Aggregates.TrackContentAggregate; using SJZY.Track.Domain.Aggregates.TrackFlagAggregate; +using SJZY.Track.Domain.Aggregates.TrackNodeAggregate; using SJZY.Track.Domain.Aggregates.TrackStatusAggregate; using SJZY.Track.Domain.Aggregates.TrackTemplateAggregate; using SJZY.Track.Domain.Dtos.TrackTemplate; using SJZY.Track.Domain.Enums; using SJZY.Track.Domain.VEntities; +using SJZY.Expand.ABP.Core.SqlSugar.Tools; namespace SJZY.Track.Repository.Repositories; @@ -22,16 +24,16 @@ public class TrackTemplateRepository : BasicRepository, ITr var detail = await Context.Queryable() .LeftJoin((a, b) => a.SubSystemId == b.Id && b.IsDeleted == false) .Where((a, b) => a.Id == id) - .Select((a, b) => new - GetTrackTemplateDetailVO - { - Id = a.Id, - Code = a.Code, - Name = a.Name, - SubSystemId = a.SubSystemId, - SubSystem = b.CnName, - ShowOrigin = a.ShowOrigin - }).FirstAsync(); + .Select((a, b) => new GetTrackTemplateDetailVO + { + Id = a.Id, + Code = a.Code, + Name = a.Name, + SubSystemId = a.SubSystemId, + SubSystem = b.CnName, + CustomerId = a.CustomerId, + CategoryId = a.CategoryId, + }).FirstAsync(); return detail; } @@ -43,14 +45,14 @@ public class TrackTemplateRepository : BasicRepository, ITr /// public async Task> GetPageTrackTemplate(GetPageTrackTemplateVO input) { - UnifyPageResultDto pagedList = await Context.Queryable() + var pagedList = await Context.Queryable() .LeftJoin((a, b) => a.SubSystemId == b.Id && b.IsDeleted == false) .WhereIF(input.SubSystemId > 0, (a, b) => a.SubSystemId == input.SubSystemId) .WhereIF(!input.Keywords.IsNullOrWhiteSpace(), - (a, b) => a.Name.Contains(input.Keywords) || a.Code.Contains(input.Keywords)) + (a, b) => a.Name.Contains(input.Keywords!) || a.Code.Contains(input.Keywords!)) .OrderByIF(input.SelectIds.IsNullOrEmpty(), (a, b) => a.CreateTime, OrderByType.Desc) .OrderByIF(!input.SelectIds.IsNullOrEmpty(), - (a, b) => SqlFunc.IIF(input.SelectIds.Contains(a.Id), SqlFunc.DateAdd(SqlFunc.GetDate(), 1), + (a, b) => SqlFunc.IIF(input.SelectIds!.Contains(a.Id), SqlFunc.DateAdd(SqlFunc.GetDate(), 1), a.CreateTime), OrderByType.Desc) .Select((a, b) => new GetTrackTemplateListVO { @@ -68,16 +70,6 @@ public class TrackTemplateRepository : BasicRepository, ITr return pagedList; } - /// - /// 获取轨迹内容属性值 - /// - /// - public async Task GetTrackContentAttributeValue( - GetTemplateContentAttributeValueInputVO input) - { - return null; - } - /// public async Task> GetContentPageAsync( GetTrackTemplateContentPageInputVO input) @@ -90,23 +82,23 @@ public class TrackTemplateRepository : BasicRepository, ITr .LeftJoin((templateContent, trackContent, trackStatus, enumValue) => enumValue.Property == EnumPropertyEnums.节点.GetDescription() && trackStatus.Node == enumValue.Enumkey && !enumValue.IsDeleted) - .LeftJoin((templateContent, trackContent, trackStatus, enumValue, trackFlag) => - trackContent.TrackFlagId == trackFlag.Id && !trackFlag.IsDeleted) - .LeftJoin((templateContent, trackContent, trackStatus, enumValue, trackFlag, createUser) => + .LeftJoin((templateContent, trackContent, trackStatus, enumValue, createUser) => templateContent.CreateUserId == createUser.Id && !createUser.IsDeleted) .LeftJoin( - (templateContent, trackContent, trackStatus, enumValue, trackFlag, createUser, updateUser) => + (templateContent, trackContent, trackStatus, enumValue, createUser, updateUser) => templateContent.UpdateUserId == updateUser.Id && !updateUser.IsDeleted) .Filter(null, true) .Where(templateContent => input.TrackTemplateIds.Contains(templateContent.TrackTemplateId) && !templateContent.IsDeleted) - .Select((templateContent, trackContent, trackStatus, enumValue, trackFlag, createUser, updateUser) => + .Select((templateContent, trackContent, trackStatus, enumValue, createUser, updateUser) => new GetTrackTemplateContentPageOutputVO { Id = templateContent.Id, TrackStatus = trackStatus.Status, Node = enumValue.Disp, - TrackFlag = trackFlag.Name, + TrackFlag = SqlFunc.Subqueryable() + .Where(x => SqlFunc.SplitIn(trackContent.TrackFlagId, x.Id.ToString())) + .SelectStringJoin(x => x.Name, ","), CreateTime = templateContent.CreateTime, CreateUser = createUser.Name, UpdateTime = templateContent.UpdateTime, @@ -117,7 +109,7 @@ public class TrackTemplateRepository : BasicRepository, ITr } /// - public async Task GetContentDetailAsync(int id) + public async Task GetContentDetailAsync(int id) { return await Context.Queryable() .InnerJoin((templateContent, trackContent) => @@ -126,12 +118,13 @@ public class TrackTemplateRepository : BasicRepository, ITr trackContent.TrackStatusId == trackStatus.Id && !trackStatus.IsDeleted) .Filter(null, true) .Where(templateContent => templateContent.Id == id && !templateContent.IsDeleted) - .Select((templateContent, trackContent, trackStatus) => new GetTrackTemplateContentDetailOutputVO - { - Id = templateContent.Id, - TrackContent = trackContent.Code + "-" + trackContent.Content, - TrackStatus = trackStatus.Status - }, true) + .Select( + (templateContent, trackContent, trackStatus) => new GetTrackTemplateContentDetailOutputVo + { + Id = templateContent.Id, + TrackContent = trackContent.Code + "-" + trackContent.Content, + TrackStatus = trackStatus.Status + }, true) .SingleAsync(); } @@ -191,4 +184,117 @@ public class TrackTemplateRepository : BasicRepository, ITr return await Context.Updateable().SetColumns(columns).Where(whereExpression) .ExecuteCommandHasChangeAsync(); } -} \ No newline at end of file + + public async Task> GetTrackTemplateListAsync(GetTrackTemplateListInputVo input) + { + var templates = await Context.Queryable() + .Where(x => x.SubSystemId == input.SubSystemId) + .WhereIF(input.CustomerId.HasValue, x => x.CustomerId == input.CustomerId) + .WhereIF(input.TemplateType.HasValue, x => x.CategoryId == input.TemplateType) + .WhereIF(!input.TemplateCode.IsNullOrWhiteSpace(), x => x.Code == input.TemplateCode) + .Select(x => new TrackTemplateOutputVo + { + Id = x.Id, + TemplateName = x.Name, + TemplateCode = x.Code, + }) + .ToListAsync(); + + if (templates == default) return new List(); + var templateIds = templates.Select(x => x.Id).ToArray(); + var contents = await Context.Queryable() + .LeftJoin((a, b) => a.TrackContentId == b.Id) + .LeftJoin((a, b, c) => b.TrackStatusId == c.Id) + .LeftJoin((a, b, c, d) => c.Node == d.Id) + .Where(a => templateIds.Contains(a.TrackTemplateId)) + .Select((a, b, c, d) => new TemplateContentDtoVo + { + TemplateId = a.TrackTemplateId, + Code = b.Code, + ContentCn = b.Content, + ContentEn = b.EnContent, + Status = c.Status, + Node = d.NodeName, + Sort = a.Sort + }) + .ToListAsync(); + + foreach (var template in templates) + { + var templateContents = contents.Where(x => x.TemplateId == template.Id).ToList(); + + //根据排序键排序 + template.TemplateContents = templateContents.OrderBy(x => x.Sort).ToList(); + } + + return templates; + } + + public async Task> GetPageTrackTemplateListAsync(GetPageTrackTemplateListInputVo input) + { + var templates = await Context.Queryable() + .Where(x => x.SubSystemId == input.SubSystemId) + .WhereIF(input.CustomerId.HasValue, x => x.CustomerId == input.CustomerId) + .WhereIF(input.TemplateType.HasValue, x => x.CategoryId == input.TemplateType) + .WhereIF(!input.TemplateCode.IsNullOrWhiteSpace(), x => x.Code == input.TemplateCode) + .Select(x => new TrackTemplateOutputVo + { + Id = x.Id, + TemplateName = x.Name, + TemplateCode = x.Code, + }) + .ToListAsync(); + + if (templates == default) return new UnifyPageResultDto(); + var templateIds = templates.Select(x => x.Id).ToArray(); + var contents = await Context.Queryable() + .LeftJoin((a, b) => a.TrackContentId == b.Id) + .LeftJoin((a, b, c) => b.TrackStatusId == c.Id) + .LeftJoin((a, b, c, d) => c.Node == d.Id) + .Where(a => templateIds.Contains(a.TrackTemplateId)) + .WhereIF(!input.KeyWord.IsNullOrWhiteSpace(), (a, b, c, d) => + b.Code.Contains(input.KeyWord!) + || b.EnContent.Contains(input.KeyWord!) + || b.Content.Contains(input.KeyWord!) + ) + .Select((a, b, c, d) => new TemplateContentDtoVo + { + TemplateId = a.TrackTemplateId, + Code = b.Code, + ContentCn = b.Content, + ContentEn = b.EnContent, + Status = c.Status, + Node = d.NodeName, + Sort = a.Sort + }) + .ToPagedListAsync(input.PageIndex, input.PageSize); + + //返回轨迹模板内容时按排序键排序 + contents.List = contents.List.OrderBy(x => x.Sort).ToList(); + return contents; + } + + public async Task> GetContentByTemplateCodes(string[] codes, int systemId) + { + var sql = @$" + select + distinct + c.Code + from t_track_template a + left join t_track_template_content b on a.id = b.TrackTemplateId and b.IsDeleted = 0 + left join t_track_content c on b.TrackContentId = c.Id and c.IsDeleted = 0 + where + a.SubSystemId = {systemId} + and a.Code in (@codes) + and a.IsDeleted = 0 + "; + + + var list = Context.Ado.SqlQuery(sql, new + { + codes = codes + }).ToList(); + + return list; + } +} diff --git a/src/SJZY.Track.Repository/Repositories/WarningRecordEsRepository.cs b/src/SJZY.Track.Repository/Repositories/WarningRecordEsRepository.cs new file mode 100644 index 00000000..eccbec0c --- /dev/null +++ b/src/SJZY.Track.Repository/Repositories/WarningRecordEsRepository.cs @@ -0,0 +1,112 @@ +using Nest; +using SJZY.Expand.ABP.Core.Logger; +using SJZY.Expand.ElasticSearch.Services; +using SJZY.Track.Domain.Aggregates.ForewarningAggregate; +using SJZY.Track.Domain.Consts; +using SJZY.Track.Domain.Dtos.Forewarning; + +namespace SJZY.Track.Repository.Repositories; + +public class WarningRecordEsRepository : ElasticSearchContextAbstract, IWarningRecordEsRepository, + ITransientDependency +{ + public WarningRecordEsRepository(ConnectionFactory connectionFactory) : base(connectionFactory) + { + } + + public async Task AddAsync(WarningRecordIndex index) + { + index.IndexName = $"{GlobalConst.TrackWarningRecordIndex}-{DateTime.Now:yyyy.MM.dd}"; + index.CreateTime = DateTime.Now; + // 按天写入es + var r = await Context.IndexAsync(index, request => request + .Index(index.IndexName) + ); + + if (!r.IsValid) + { + LogHelper.Error($"运输时效预警记录写入es失败,原因:{r.DebugInformation}。"); + } + } + + public async Task BulkInsertAsync(List warningRecords) + { + if (!warningRecords.Any()) return; + // 按天写入es + var indexName = $"{GlobalConst.TrackWarningRecordIndex}-{DateTime.Now:yyyy.MM.dd}"; + warningRecords.ForEach(x => x.IndexName = indexName); + + var r = await Context.IndexManyAsync(warningRecords, indexName); + + if (!r.IsValid) + { + throw new InvalidOperationException($"{warningRecords.Count}条运输时效预警记录新增失败,原因:{r.DebugInformation}。"); + } + } + + public async Task BulkUpdateAsync(List<(int ruleId, int orderId, int counter)> rules) + { + foreach (var group in rules.GroupBy(x => new + { + x.ruleId, + x.orderId + })) + { + var rule = group.First(); + + // 这里需要使用_update_by_query API,因为可能已经发生了多条预警记录,需要一次性更新 + var r = await Context.UpdateByQueryAsync(u => u + .Index(GlobalConst.TrackWarningRecordIndex) + .Query(q => + q.Term(f => f.RuleId, rule.ruleId) + && q.Term(f => f.OrderId, rule.orderId) + ) + .Script(s => s.Source("ctx._source.warningStatus = params.warningStatus") + .Params(p => p.Add("warningStatus", (int) WarningStatus.Processed)) + ) + ); + + if (!r.IsValid) + { + throw new InvalidOperationException( + $"运输时效预警记录更新失败,ruleId:{rule.ruleId},orderId:{rule.orderId},原因:{r.DebugInformation}。"); + } + } + } + + public async Task<(List list, long total)> GetOrderWarningPageListAsync( + GetOrderWarningPageListVo input) + { + Func, QueryContainer> query = q => + (input.SubSystemId.HasValue ? q.Term(f => f.SubSystemId, input.SubSystemId) : null) + && (!input.OrderNos.IsNullOrEmpty() + ? q.Terms(t => t + .Field(f => f.OrderNo.Suffix("keyword")) + .Terms(input.OrderNos)) + : null) + && (input.WarningStatus.HasValue ? q.Term(f => f.WarningStatus, input.WarningStatus) : null) + && (input.CustomId.HasValue ? q.Term(f => f.CustomId, input.CustomId) : null) + && (!input.WarningName.IsNullOrWhiteSpace() + ? q.Wildcard(w => w.WarningName, $"*{input.WarningName}*") + : null) + && (input.NotifyUserId.HasValue ? q.Term(f => f.NotifyUserId, input.NotifyUserId) : null) + && (input.StartTime.HasValue + ? q.DateRange(r => r.Field(f => f.CreateTime).GreaterThanOrEquals(input.StartTime)) + : null) + && (input.EndTime.HasValue + ? q.DateRange(r => r.Field(f => f.CreateTime).LessThanOrEquals(input.EndTime)) + : null); + + var data = await Context.SearchAsync(x => x + .Index(GlobalConst.TrackWarningRecordIndex) + .Source() + .Query(query) + .Sort(s => s.Field(f => f.CreateTime, SortOrder.Descending)) + .From((input.PageIndex - 1) * input.PageSize) + .Size(input.PageSize) + .TrackTotalHits() + ); + + return (data.Documents.ToList(), data.Total); + } +} diff --git a/src/SJZY.Track.Repository/Repositories/WarningRepository.cs b/src/SJZY.Track.Repository/Repositories/WarningRepository.cs new file mode 100644 index 00000000..e986ce33 --- /dev/null +++ b/src/SJZY.Track.Repository/Repositories/WarningRepository.cs @@ -0,0 +1,144 @@ +using SJZY.Track.Domain; +using SJZY.Track.Domain.Aggregates.ForewarningAggregate; +using SJZY.Track.Domain.Aggregates.KPIAreaAggregate; +using SJZY.Track.Domain.Aggregates.TrackStatusAggregate; +using SJZY.Track.Domain.Dtos.Forewarning; +using SJZY.Track.Domain.VEntities; + +namespace SJZY.Track.Repository.Repositories; + +/// +/// 预警仓储 +/// +public class WarningRepository : BasicRepository, IWarningRepository, ITransientDependency +{ + /// + public async Task CreateForewarningAsync(WarningEntity warning) + { + using var tran = TransactionHelper.GetReadCommitted(); + + var ruleId = await InsertReturnIdentityAsync(warning); + warning.WarningNotifies.ForEach(x => x.WarningId = ruleId); + warning.WarningFactors.ForEach(x => x.WarningId = ruleId); + warning.WarningRules.ForEach(x => x.WarningId = ruleId); + + await Context.Insertable(warning.WarningFactors).ExecuteCommandAsync(); + await Context.Insertable(warning.WarningNotifies).ExecuteCommandAsync(); + await Context.Insertable(warning.WarningRules).ExecuteCommandAsync(); + tran.Complete(); + return ruleId; + } + + /// + public Task CopyForewarning(int warningId) + { + throw new NotImplementedException(); + } + + /// + public Task> GetWarningPageListAsync(GetWarningPageInputVo input) + { + var query = Context.Queryable() + .LeftJoin((a, b) => a.SubSystemId == b.Id) + .LeftJoin((a, b, c) => a.CustomerId == c.Id) + .WhereIF(input.SystemId.HasValue, (a, b) => a.SubSystemId == input.SystemId) + .WhereIF(!string.IsNullOrEmpty(input.KeyWord), + (a, b, c) => a.Name.Contains(input.KeyWord!) || c.Name.Contains(input.KeyWord!)) + .OrderBy(a => a.UpdateTime, OrderByType.Desc); + + return query + .Select((a, b, c) => new WarningPageOutput + { + Id = a.Id, + SubSystem = b.CnName, + Custom = c.Name, + Name = a.Name, + IsEnable = a.IsEnable, + UpdateTime = a.UpdateTime + }) + .ToPagedListAsync(input.PageIndex, input.PageSize); + } + + /// + public async Task> GetWarningRuleListAsync(int warningId) + { + return await Context.Queryable() + .LeftJoin((a, b) => a.StartTrackStatusId == b.Id) + .LeftJoin((a, b, c) => a.EndTrackStatusId == c.Id) + .LeftJoin((a, b, c, d) => a.AreaId == d.Id) + .Where(a => a.WarningId == warningId) + .Select( + (a, b, c, d) => + new WarningRuleVo + { + StartTrackStatus = b.Status, + EndTrackStatus = c.Status, + Area = d.Name + }, true) + .ToListAsync(); + } + + /// + public async Task UpdateForewarningAsync(WarningEntity warning) + { + using var tran = TransactionHelper.GetReadCommitted(); + + await Context.Updateable(warning).ExecuteCommandAsync(); + await Context.Updateable(warning.WarningNotifies) + .UpdateColumns(x => new + { + x.NotifyMode, + x.NotifyUser, + x.UpdateTime, + x.UpdateUserId + }) + .ExecuteCommandAsync(); + + tran.Complete(); + } + + /// + public async Task ModifyTimeSpansAsync(List rules) + { + return await Context.Updateable(rules) + .UpdateColumns(x => new + { + x.TotalTimeSpan, + x.WarnTimeSpan, + x.WarnCount, + x.UpdateTime, + x.UpdateUserId + }) + .ExecuteCommandAsync(); + } + + /// + public async Task TurnWarningAsync(WarningEntity warning) + { + return await Context.Updateable(warning) + .UpdateColumns(x => new + { + x.IsEnable, + x.UpdateTime, + x.UpdateUserId + }) + .ExecuteCommandAsync() > 0; + } + + /// + public async Task GetByIdAsync(int warningId) + { + var warning = await GetFirstAsync(x => x.Id == warningId); + + if (warning == null) return null; + + warning.WarningFactors = await Context.Queryable() + .Where(x => x.WarningId == warningId) + .ToListAsync(); + warning.WarningNotifies = await Context.Queryable() + .Where(x => x.WarningId == warningId) + .ToListAsync(); + + return warning; + } +} diff --git a/src/SJZY.Track.Repository/SJZY.Track.Repository.csproj b/src/SJZY.Track.Repository/SJZY.Track.Repository.csproj index 35617f6a..4718739b 100644 --- a/src/SJZY.Track.Repository/SJZY.Track.Repository.csproj +++ b/src/SJZY.Track.Repository/SJZY.Track.Repository.csproj @@ -3,14 +3,14 @@ net7.0 True + CS8613 - + - - + diff --git a/src/SJZY.Track.Repository/SjzyTrackRepositoryModule.cs b/src/SJZY.Track.Repository/SjzyTrackRepositoryModule.cs index e7ca3b6b..056d0690 100644 --- a/src/SJZY.Track.Repository/SjzyTrackRepositoryModule.cs +++ b/src/SJZY.Track.Repository/SjzyTrackRepositoryModule.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using SJZY.Expand.ABP.Core.SqlSugar.Options; using SJZY.Expand.ElasticSearch; @@ -31,7 +31,8 @@ public class SjzyTrackRepositoryModule : AbpModule ConnectionString = configuration["ConnectionStrings:DefaultConnection"]!, DbType = DbType.MySql, IsAutoCloseConnection = true, - ConfigId = "default", OpenSqlLog = true + ConfigId = "default", + OpenSqlLog = true } } ); @@ -43,6 +44,7 @@ public class SjzyTrackRepositoryModule : AbpModule { options.ShowLogInfo = true; } + options.NodeUrls = configuration.GetSection("ElasticSearch:NodeUrls").Get>()!; options.LoginName = configuration["ElasticSearch:LoginName"]!; options.Password = configuration["ElasticSearch:Password"]!; @@ -56,4 +58,4 @@ public class SjzyTrackRepositoryModule : AbpModule context.Services.AddTransient(typeof(IBasicQuery<>), typeof(BasicQuery<>)); context.Services.AddTransient(typeof(IBasicRepository<>), typeof(BasicRepository<>)); } -} \ No newline at end of file +} diff --git a/src/SJZY.Track.Repository/TrackPushRecord/Entitys/TrackPushRecordEntity.cs b/src/SJZY.Track.Repository/TrackPushRecord/Entitys/TrackPushRecordEntity.cs deleted file mode 100644 index b3c2ff5b..00000000 --- a/src/SJZY.Track.Repository/TrackPushRecord/Entitys/TrackPushRecordEntity.cs +++ /dev/null @@ -1,59 +0,0 @@ -using SJZY.Track.Domain.SeedWork; - -namespace SJZY.Track.Repository.TrackPushRecord.Entitys -{ - /// - /// 轨迹推送记录 - /// - [SugarTable("t_track_push_record")] - public class TrackPushRecordEntity : IAggregateRoot - { - /// - /// 自增主键 - /// - [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] - public int Id { get; set; } - - /// - /// 创建时间(推送时间) - /// - [SugarColumn(ColumnName = "CreateTime")] - public DateTime CreateTime { get; set; } - - /// - /// 创建人(推送人) - /// - [SugarColumn(ColumnName = "CreateUserId")] - public int CreateUserId { get; set; } - - /// - /// 是否自动推送 - /// - [SugarColumn(ColumnName = "IsAutoPush")] - public bool IsAutoPush { get; set; } - - /// - /// 推送内容 - /// - [SugarColumn(ColumnName = "PushContent")] - public string PushContent { get; set; } = null!; - - /// - /// 接口通请求id - /// - [SugarColumn(ColumnName = "RequestId")] - public string RequestId { get; set; } = null!; - - /// - /// 服务商id - /// - [SugarColumn(ColumnName = "ServiceProviderId")] - public int ServiceProviderId { get; set; } - - /// - /// 推送轨迹总数 - /// - [SugarColumn(ColumnName = "TrackTotal")] - public int TrackTotal { get; set; } - } -} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/TrackPushRecord/Services/ITrackPushRecordRepository.cs b/src/SJZY.Track.Repository/TrackPushRecord/Services/ITrackPushRecordRepository.cs deleted file mode 100644 index 686a3402..00000000 --- a/src/SJZY.Track.Repository/TrackPushRecord/Services/ITrackPushRecordRepository.cs +++ /dev/null @@ -1,8 +0,0 @@ -using SJZY.Track.Repository.TrackPushRecord.Entitys; - -namespace SJZY.Track.Repository.TrackPushRecord.Services -{ - public interface ITrackPushRecordRepository : ISimpleClient - { - } -} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/TrackPushRecord/Services/TrackPushRecordRepository.cs b/src/SJZY.Track.Repository/TrackPushRecord/Services/TrackPushRecordRepository.cs deleted file mode 100644 index e8e16ab9..00000000 --- a/src/SJZY.Track.Repository/TrackPushRecord/Services/TrackPushRecordRepository.cs +++ /dev/null @@ -1,10 +0,0 @@ -using SJZY.Track.Repository.Repositories; -using SJZY.Track.Repository.TrackPushRecord.Entitys; - -namespace SJZY.Track.Repository.TrackPushRecord.Services -{ - public class TrackPushRecordRepository : BasicRepository, ITrackPushRecordRepository, IScopedDependency - { - - } -} diff --git a/src/SJZY.Track.Repository/TrackPushRecordDetails/Entitys/TrackPushRecordDetailsEntity.cs b/src/SJZY.Track.Repository/TrackPushRecordDetails/Entitys/TrackPushRecordDetailsEntity.cs deleted file mode 100644 index 64208102..00000000 --- a/src/SJZY.Track.Repository/TrackPushRecordDetails/Entitys/TrackPushRecordDetailsEntity.cs +++ /dev/null @@ -1,47 +0,0 @@ -using SJZY.Track.Domain.SeedWork; - -namespace SJZY.Track.Repository.TrackPushRecordDetails.Entitys -{ - /// - /// 轨迹推送明细表 - /// - [SugarTable("t_track_push_record_details")] - public class TrackPushRecordDetailsEntity : IAggregateRoot - { - /// - /// 自增主键 - /// - [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)] - public int Id { get; set; } - - /// - /// 创建时间(消费完成时间) - /// - [SugarColumn(ColumnName = "CreateTime")] - public DateTime CreateTime { get; set; } - - /// - /// 异常信息 - /// - [SugarColumn(ColumnName = "ErrorMessage")] - public string ErrorMessage { get; set; } - - /// - /// 是否成功 - /// - [SugarColumn(ColumnName = "IsSuccess")] - public bool IsSuccess { get; set; } - - /// - /// 订单id - /// - [SugarColumn(ColumnName = "OrderId")] - public int OrderId { get; set; } - - /// - /// 推送记录id - /// - [SugarColumn(ColumnName = "PushRecordId")] - public int PushRecordId { get; set; } - } -} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/TrackPushRecordDetails/Services/ITrackPushRecordDetailsRepository.cs b/src/SJZY.Track.Repository/TrackPushRecordDetails/Services/ITrackPushRecordDetailsRepository.cs deleted file mode 100644 index f84fafa7..00000000 --- a/src/SJZY.Track.Repository/TrackPushRecordDetails/Services/ITrackPushRecordDetailsRepository.cs +++ /dev/null @@ -1,8 +0,0 @@ -using SJZY.Track.Repository.TrackPushRecordDetails.Entitys; - -namespace SJZY.Track.Repository.TrackPushRecordDetails.Services -{ - public interface ITrackPushRecordDetailsRepository : ISimpleClient - { - } -} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/TrackPushRecordDetails/Services/TrackPushRecordDetailsRepository.cs b/src/SJZY.Track.Repository/TrackPushRecordDetails/Services/TrackPushRecordDetailsRepository.cs deleted file mode 100644 index 3a8c025b..00000000 --- a/src/SJZY.Track.Repository/TrackPushRecordDetails/Services/TrackPushRecordDetailsRepository.cs +++ /dev/null @@ -1,10 +0,0 @@ -using SJZY.Track.Repository.Repositories; -using SJZY.Track.Repository.TrackPushRecordDetails.Entitys; - -namespace SJZY.Track.Repository.TrackPushRecordDetails.Services -{ - public class TrackPushRecordDetailsRepository : BasicRepository, ITrackPushRecordDetailsRepository, IScopedDependency - { - - } -} diff --git a/test/SJZY.Track.Test/Startup.cs b/test/SJZY.Track.Test/Startup.cs index 27397eb3..73fe7c3a 100644 --- a/test/SJZY.Track.Test/Startup.cs +++ b/test/SJZY.Track.Test/Startup.cs @@ -1,21 +1,20 @@ -using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using SJZY.Track.Test; -namespace SJZY.OpenApi.Test -{ - public class Startup - { - public void ConfigureServices(IServiceCollection services) - { - services.AddApplication(); - } +namespace SJZY.OpenApi.Test; - public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) - { - app.InitializeApplication(); - } +public class Startup +{ + public void ConfigureServices(IServiceCollection services) + { + services.AddApplication(); + } + + public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) + { + app.InitializeApplication(); } } diff --git a/test/SJZY.Track.Test/TestModule.cs b/test/SJZY.Track.Test/TestModule.cs index aa5f8d90..31af0048 100644 --- a/test/SJZY.Track.Test/TestModule.cs +++ b/test/SJZY.Track.Test/TestModule.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using SJZY.Track.Api; using SJZY.Track.Application; @@ -61,4 +61,4 @@ public class TestModule : AbpModule } }); } -} \ No newline at end of file +} diff --git a/test/SJZY.Track.Test/TestModuleTestBase.cs b/test/SJZY.Track.Test/TestModuleTestBase.cs index c05bf867..9c025b6e 100644 --- a/test/SJZY.Track.Test/TestModuleTestBase.cs +++ b/test/SJZY.Track.Test/TestModuleTestBase.cs @@ -1,16 +1,13 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Volo.Abp.AspNetCore.TestBase; -namespace SJZY.OpenApi.Test +namespace SJZY.OpenApi.Test; + +public class TestModuleTestBase : AbpAspNetCoreIntegratedTestBase { - public class TestModuleTestBase : AbpAspNetCoreIntegratedTestBase + protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) { - protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) - { - base.ConfigureServices(context, services); - } - - + base.ConfigureServices(context, services); } } diff --git a/test/SJZY.Track.Test/Usings.cs b/test/SJZY.Track.Test/Usings.cs index 8c927eb7..c802f448 100644 --- a/test/SJZY.Track.Test/Usings.cs +++ b/test/SJZY.Track.Test/Usings.cs @@ -1 +1 @@ -global using Xunit; \ No newline at end of file +global using Xunit;