diff --git a/Directory.Packages.props b/Directory.Packages.props
index 0c030dad2..ff9567ced 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -255,6 +255,7 @@
+
diff --git a/aspnet-core/LINGYUN.MicroService.SingleProject.sln b/aspnet-core/LINGYUN.MicroService.SingleProject.sln
index 8ebc11483..e5aecae7e 100644
--- a/aspnet-core/LINGYUN.MicroService.SingleProject.sln
+++ b/aspnet-core/LINGYUN.MicroService.SingleProject.sln
@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
-VisualStudioVersion = 17.14.36616.10 d17.14
+VisualStudioVersion = 17.14.36616.10
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "modules", "modules", "{0B58AA48-665A-443F-A6A8-751FB9629DAF}"
EndProject
@@ -700,6 +700,26 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.WeChat.Work.OA"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Quartz.PostgresSqlInstaller", "modules\task-management\LINGYUN.Abp.Quartz.PostgresSqlInstaller\LINGYUN.Abp.Quartz.PostgresSqlInstaller.csproj", "{CD7B8501-57B7-6C0E-472F-4E9B894ED6C2}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ai", "ai", "{E87F876B-EEC8-4A3B-9FF0-15EB38B4A7BC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.AI.Core", "modules\ai\LINGYUN.Abp.AI.Core\LINGYUN.Abp.AI.Core.csproj", "{72083C13-32E8-1122-7761-CE7C0B64AABA}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.AI.Agent", "modules\ai\LINGYUN.Abp.AI.Agent\LINGYUN.Abp.AI.Agent.csproj", "{F80E583B-93F3-C1E6-A83D-AC83132DBC5F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.AIManagement.Domain.Shared", "modules\ai\LINGYUN.Abp.AIManagement.Domain.Shared\LINGYUN.Abp.AIManagement.Domain.Shared.csproj", "{D8E28DB1-D8C8-C46C-A93E-CA3A0D90065B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.AIManagement.Domain", "modules\ai\LINGYUN.Abp.AIManagement.Domain\LINGYUN.Abp.AIManagement.Domain.csproj", "{7D372713-5117-82F2-7591-C0AE09BA04CF}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.AIManagement.Application.Contracts", "modules\ai\LINGYUN.Abp.AIManagement.Application.Contracts\LINGYUN.Abp.AIManagement.Application.Contracts.csproj", "{479D24D3-D01D-6655-87E8-5A236B3BA371}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.AIManagement.Application", "modules\ai\LINGYUN.Abp.AIManagement.Application\LINGYUN.Abp.AIManagement.Application.csproj", "{62A90887-34B9-1BDE-8851-9CC926AEBBBE}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.AIManagement.EntityFrameworkCore", "modules\ai\LINGYUN.Abp.AIManagement.EntityFrameworkCore\LINGYUN.Abp.AIManagement.EntityFrameworkCore.csproj", "{5AFC464A-9B1F-7415-2D2E-320D567ED818}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.AIManagement.HttpApi", "modules\ai\LINGYUN.Abp.AIManagement.HttpApi\LINGYUN.Abp.AIManagement.HttpApi.csproj", "{3B618981-F1CB-9AEC-E90B-4B05B982C1FC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.AIManagement.HttpApi.Client", "modules\ai\LINGYUN.Abp.AIManagement.HttpApi.Client\LINGYUN.Abp.AIManagement.HttpApi.Client.csproj", "{44957812-548A-D14C-6C92-F9902DADDCDA}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -1866,6 +1886,42 @@ Global
{CD7B8501-57B7-6C0E-472F-4E9B894ED6C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CD7B8501-57B7-6C0E-472F-4E9B894ED6C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CD7B8501-57B7-6C0E-472F-4E9B894ED6C2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {72083C13-32E8-1122-7761-CE7C0B64AABA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {72083C13-32E8-1122-7761-CE7C0B64AABA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {72083C13-32E8-1122-7761-CE7C0B64AABA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {72083C13-32E8-1122-7761-CE7C0B64AABA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F80E583B-93F3-C1E6-A83D-AC83132DBC5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F80E583B-93F3-C1E6-A83D-AC83132DBC5F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F80E583B-93F3-C1E6-A83D-AC83132DBC5F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F80E583B-93F3-C1E6-A83D-AC83132DBC5F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D8E28DB1-D8C8-C46C-A93E-CA3A0D90065B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D8E28DB1-D8C8-C46C-A93E-CA3A0D90065B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D8E28DB1-D8C8-C46C-A93E-CA3A0D90065B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D8E28DB1-D8C8-C46C-A93E-CA3A0D90065B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7D372713-5117-82F2-7591-C0AE09BA04CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7D372713-5117-82F2-7591-C0AE09BA04CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7D372713-5117-82F2-7591-C0AE09BA04CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7D372713-5117-82F2-7591-C0AE09BA04CF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {479D24D3-D01D-6655-87E8-5A236B3BA371}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {479D24D3-D01D-6655-87E8-5A236B3BA371}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {479D24D3-D01D-6655-87E8-5A236B3BA371}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {479D24D3-D01D-6655-87E8-5A236B3BA371}.Release|Any CPU.Build.0 = Release|Any CPU
+ {62A90887-34B9-1BDE-8851-9CC926AEBBBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {62A90887-34B9-1BDE-8851-9CC926AEBBBE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {62A90887-34B9-1BDE-8851-9CC926AEBBBE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {62A90887-34B9-1BDE-8851-9CC926AEBBBE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5AFC464A-9B1F-7415-2D2E-320D567ED818}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5AFC464A-9B1F-7415-2D2E-320D567ED818}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5AFC464A-9B1F-7415-2D2E-320D567ED818}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5AFC464A-9B1F-7415-2D2E-320D567ED818}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3B618981-F1CB-9AEC-E90B-4B05B982C1FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3B618981-F1CB-9AEC-E90B-4B05B982C1FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3B618981-F1CB-9AEC-E90B-4B05B982C1FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3B618981-F1CB-9AEC-E90B-4B05B982C1FC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {44957812-548A-D14C-6C92-F9902DADDCDA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {44957812-548A-D14C-6C92-F9902DADDCDA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {44957812-548A-D14C-6C92-F9902DADDCDA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {44957812-548A-D14C-6C92-F9902DADDCDA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -2207,6 +2263,16 @@ Global
{C996D147-5B81-49D9-949B-F3BC185B2CD4} = {91867618-0D86-4410-91C6-B1166A9ACDF9}
{AB207B2A-C8E7-977D-98E6-66527CBB2B7F} = {91867618-0D86-4410-91C6-B1166A9ACDF9}
{CD7B8501-57B7-6C0E-472F-4E9B894ED6C2} = {91EE5D5B-B6DF-43F1-BC09-1A982719A34B}
+ {E87F876B-EEC8-4A3B-9FF0-15EB38B4A7BC} = {0B58AA48-665A-443F-A6A8-751FB9629DAF}
+ {72083C13-32E8-1122-7761-CE7C0B64AABA} = {E87F876B-EEC8-4A3B-9FF0-15EB38B4A7BC}
+ {F80E583B-93F3-C1E6-A83D-AC83132DBC5F} = {E87F876B-EEC8-4A3B-9FF0-15EB38B4A7BC}
+ {D8E28DB1-D8C8-C46C-A93E-CA3A0D90065B} = {E87F876B-EEC8-4A3B-9FF0-15EB38B4A7BC}
+ {7D372713-5117-82F2-7591-C0AE09BA04CF} = {E87F876B-EEC8-4A3B-9FF0-15EB38B4A7BC}
+ {479D24D3-D01D-6655-87E8-5A236B3BA371} = {E87F876B-EEC8-4A3B-9FF0-15EB38B4A7BC}
+ {62A90887-34B9-1BDE-8851-9CC926AEBBBE} = {E87F876B-EEC8-4A3B-9FF0-15EB38B4A7BC}
+ {5AFC464A-9B1F-7415-2D2E-320D567ED818} = {E87F876B-EEC8-4A3B-9FF0-15EB38B4A7BC}
+ {3B618981-F1CB-9AEC-E90B-4B05B982C1FC} = {E87F876B-EEC8-4A3B-9FF0-15EB38B4A7BC}
+ {44957812-548A-D14C-6C92-F9902DADDCDA} = {E87F876B-EEC8-4A3B-9FF0-15EB38B4A7BC}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {711A43C0-A2F8-4E5C-9B9F-F2551E4B3FF1}
diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/MessageServiceMigrationsEntityFrameworkCoreModule.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/MessageServiceMigrationsEntityFrameworkCoreModule.cs
index 016447de6..171994888 100644
--- a/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/MessageServiceMigrationsEntityFrameworkCoreModule.cs
+++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/MessageServiceMigrationsEntityFrameworkCoreModule.cs
@@ -4,6 +4,7 @@ using LINGYUN.Abp.Notifications.EntityFrameworkCore;
using LINGYUN.Abp.Quartz.PostgresSqlInstaller;
using LINGYUN.Abp.Saas.EntityFrameworkCore;
using LINGYUN.Abp.TextTemplating.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using Volo.Abp.EntityFrameworkCore;
diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/Migrations/20260320092811_Add-Notification-Send-Record.Designer.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/Migrations/20260320092811_Add-Notification-Send-Record.Designer.cs
new file mode 100644
index 000000000..a17c59781
--- /dev/null
+++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/Migrations/20260320092811_Add-Notification-Send-Record.Designer.cs
@@ -0,0 +1,812 @@
+//
+using System;
+using LINGYUN.Abp.MicroService.MessageService;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using Volo.Abp.EntityFrameworkCore;
+
+#nullable disable
+
+namespace LINGYUN.Abp.MicroService.MessageService.Migrations
+{
+ [DbContext(typeof(MessageServiceMigrationsDbContext))]
+ [Migration("20260320092811_Add-Notification-Send-Record")]
+ partial class AddNotificationSendRecord
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql)
+ .HasAnnotation("ProductVersion", "10.0.0")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("LINGYUN.Abp.MessageService.Chat.UserChatCard", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Age")
+ .HasColumnType("integer");
+
+ b.Property("AvatarUrl")
+ .HasMaxLength(512)
+ .HasColumnType("character varying(512)");
+
+ b.Property("Birthday")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("character varying(40)")
+ .HasColumnName("ConcurrencyStamp");
+
+ b.Property("CreationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uuid")
+ .HasColumnName("CreatorId");
+
+ b.Property("Description")
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("ExtraProperties")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("uuid")
+ .HasColumnName("LastModifierId");
+
+ b.Property("LastOnlineTime")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("NickName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("Sex")
+ .HasColumnType("integer");
+
+ b.Property("Sign")
+ .HasMaxLength(30)
+ .HasColumnType("character varying(30)");
+
+ b.Property("State")
+ .HasColumnType("integer");
+
+ b.Property("TenantId")
+ .HasColumnType("uuid")
+ .HasColumnName("TenantId");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.Property("UserName")
+ .IsRequired()
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TenantId", "UserId");
+
+ b.ToTable("AppUserChatCards", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.MessageService.Chat.UserChatFriend", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Black")
+ .HasColumnType("boolean");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("character varying(40)")
+ .HasColumnName("ConcurrencyStamp");
+
+ b.Property("CreationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uuid")
+ .HasColumnName("CreatorId");
+
+ b.Property("Description")
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("DontDisturb")
+ .HasColumnType("boolean");
+
+ b.Property("ExtraProperties")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("FrientId")
+ .HasColumnType("uuid");
+
+ b.Property("IsStatic")
+ .HasColumnType("boolean");
+
+ b.Property("RemarkName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("SpecialFocus")
+ .HasColumnType("boolean");
+
+ b.Property("Status")
+ .HasColumnType("smallint");
+
+ b.Property("TenantId")
+ .HasColumnType("uuid")
+ .HasColumnName("TenantId");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TenantId", "UserId", "FrientId");
+
+ b.ToTable("AppUserChatFriends", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.MessageService.Chat.UserChatSetting", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("AllowAddFriend")
+ .HasColumnType("boolean");
+
+ b.Property("AllowAnonymous")
+ .HasColumnType("boolean");
+
+ b.Property("AllowReceiveMessage")
+ .HasColumnType("boolean");
+
+ b.Property("AllowSendMessage")
+ .HasColumnType("boolean");
+
+ b.Property("RequireAddFriendValition")
+ .HasColumnType("boolean");
+
+ b.Property("TenantId")
+ .HasColumnType("uuid")
+ .HasColumnName("TenantId");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TenantId", "UserId");
+
+ b.ToTable("AppUserChatSettings", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.MessageService.Chat.UserMessage", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("character varying(40)")
+ .HasColumnName("ConcurrencyStamp");
+
+ b.Property("Content")
+ .IsRequired()
+ .HasMaxLength(1048576)
+ .HasColumnType("character varying(1048576)");
+
+ b.Property("CreationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uuid")
+ .HasColumnName("CreatorId");
+
+ b.Property("ExtraProperties")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("MessageId")
+ .HasColumnType("bigint");
+
+ b.Property("ReceiveUserId")
+ .HasColumnType("uuid");
+
+ b.Property("SendUserName")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)");
+
+ b.Property("Source")
+ .HasColumnType("integer");
+
+ b.Property("State")
+ .HasColumnType("smallint");
+
+ b.Property("TenantId")
+ .HasColumnType("uuid")
+ .HasColumnName("TenantId");
+
+ b.Property("Type")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TenantId", "ReceiveUserId");
+
+ b.ToTable("AppUserMessages", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.ChatGroup", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Address")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("AdminUserId")
+ .HasColumnType("uuid");
+
+ b.Property("AllowAnonymous")
+ .HasColumnType("boolean");
+
+ b.Property("AllowSendMessage")
+ .HasColumnType("boolean");
+
+ b.Property("AvatarUrl")
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)");
+
+ b.Property("CreationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uuid")
+ .HasColumnName("CreatorId");
+
+ b.Property("Description")
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)");
+
+ b.Property("GroupId")
+ .HasColumnType("bigint");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("uuid")
+ .HasColumnName("LastModifierId");
+
+ b.Property("MaxUserCount")
+ .HasColumnType("integer");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("character varying(20)");
+
+ b.Property("Notice")
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)");
+
+ b.Property("Tag")
+ .HasMaxLength(512)
+ .HasColumnType("character varying(512)");
+
+ b.Property("TenantId")
+ .HasColumnType("uuid")
+ .HasColumnName("TenantId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TenantId", "Name");
+
+ b.ToTable("AppChatGroups", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.GroupChatBlack", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("CreationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uuid")
+ .HasColumnName("CreatorId");
+
+ b.Property("GroupId")
+ .HasColumnType("bigint");
+
+ b.Property("ShieldUserId")
+ .HasColumnType("uuid");
+
+ b.Property("TenantId")
+ .HasColumnType("uuid")
+ .HasColumnName("TenantId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TenantId", "GroupId");
+
+ b.ToTable("AppGroupChatBlacks", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.GroupMessage", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("character varying(40)")
+ .HasColumnName("ConcurrencyStamp");
+
+ b.Property("Content")
+ .IsRequired()
+ .HasMaxLength(1048576)
+ .HasColumnType("character varying(1048576)");
+
+ b.Property("CreationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uuid")
+ .HasColumnName("CreatorId");
+
+ b.Property("ExtraProperties")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("GroupId")
+ .HasColumnType("bigint");
+
+ b.Property("MessageId")
+ .HasColumnType("bigint");
+
+ b.Property("SendUserName")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)");
+
+ b.Property("Source")
+ .HasColumnType("integer");
+
+ b.Property("State")
+ .HasColumnType("smallint");
+
+ b.Property("TenantId")
+ .HasColumnType("uuid")
+ .HasColumnName("TenantId");
+
+ b.Property("Type")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TenantId", "GroupId");
+
+ b.ToTable("AppGroupMessages", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.UserChatGroup", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("CreationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uuid")
+ .HasColumnName("CreatorId");
+
+ b.Property("GroupId")
+ .HasColumnType("bigint");
+
+ b.Property("TenantId")
+ .HasColumnType("uuid")
+ .HasColumnName("TenantId");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TenantId", "GroupId", "UserId");
+
+ b.ToTable("AppUserChatGroups", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.MessageService.Groups.UserGroupCard", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("character varying(40)")
+ .HasColumnName("ConcurrencyStamp");
+
+ b.Property("CreationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uuid")
+ .HasColumnName("CreatorId");
+
+ b.Property("ExtraProperties")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("IsAdmin")
+ .HasColumnType("boolean");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("uuid")
+ .HasColumnName("LastModifierId");
+
+ b.Property("NickName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("SilenceEnd")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("TenantId")
+ .HasColumnType("uuid")
+ .HasColumnName("TenantId");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TenantId", "UserId");
+
+ b.ToTable("AppUserGroupCards", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.Notifications.Notification", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("ContentType")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasDefaultValue(0);
+
+ b.Property("CreationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("CreationTime");
+
+ b.Property("ExpirationTime")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ExtraProperties")
+ .HasColumnType("text")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("NotificationId")
+ .HasColumnType("bigint");
+
+ b.Property("NotificationName")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("NotificationTypeName")
+ .IsRequired()
+ .HasMaxLength(512)
+ .HasColumnType("character varying(512)");
+
+ b.Property("Severity")
+ .HasColumnType("smallint");
+
+ b.Property("TenantId")
+ .HasColumnType("uuid")
+ .HasColumnName("TenantId");
+
+ b.Property("Type")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TenantId", "NotificationName");
+
+ b.ToTable("AppNotifications", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.Notifications.NotificationDefinitionGroupRecord", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uuid");
+
+ b.Property("AllowSubscriptionToClients")
+ .HasColumnType("boolean");
+
+ b.Property("Description")
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("DisplayName")
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("ExtraProperties")
+ .HasColumnType("text")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.HasKey("Id");
+
+ b.ToTable("AppNotificationDefinitionGroups", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.Notifications.NotificationDefinitionRecord", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uuid");
+
+ b.Property("AllowSubscriptionToClients")
+ .HasColumnType("boolean");
+
+ b.Property("ContentType")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasDefaultValue(0);
+
+ b.Property("Description")
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("DisplayName")
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("ExtraProperties")
+ .HasColumnType("text")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("GroupName")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("NotificationLifetime")
+ .HasColumnType("integer");
+
+ b.Property("NotificationType")
+ .HasColumnType("integer");
+
+ b.Property("Providers")
+ .HasMaxLength(200)
+ .HasColumnType("character varying(200)");
+
+ b.Property("Template")
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)");
+
+ b.HasKey("Id");
+
+ b.ToTable("AppNotificationDefinitions", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.Notifications.NotificationSendRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("NotificationId")
+ .HasColumnType("bigint");
+
+ b.Property("NotificationName")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("Provider")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("Reason")
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("SendTime")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("State")
+ .HasColumnType("integer");
+
+ b.Property("TenantId")
+ .HasColumnType("uuid")
+ .HasColumnName("TenantId");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.Property("UserName")
+ .IsRequired()
+ .ValueGeneratedOnAdd()
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)")
+ .HasDefaultValue("/");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TenantId", "NotificationName")
+ .HasDatabaseName("IX_Tenant_Send_Notification_Name");
+
+ b.ToTable("AppNotificationSendRecords", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.Notifications.UserNotification", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("NotificationId")
+ .HasColumnType("bigint");
+
+ b.Property("ReadStatus")
+ .HasColumnType("integer");
+
+ b.Property("TenantId")
+ .HasColumnType("uuid")
+ .HasColumnName("TenantId");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TenantId", "UserId", "NotificationId")
+ .HasDatabaseName("IX_Tenant_User_Notification_Id");
+
+ b.ToTable("AppUserNotifications", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.Notifications.UserSubscribe", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("CreationTime")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("CreationTime");
+
+ b.Property("NotificationName")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("TenantId")
+ .HasColumnType("uuid")
+ .HasColumnName("TenantId");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.Property("UserName")
+ .IsRequired()
+ .ValueGeneratedOnAdd()
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)")
+ .HasDefaultValue("/");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TenantId", "UserId", "NotificationName")
+ .IsUnique()
+ .HasDatabaseName("IX_Tenant_User_Notification_Name");
+
+ b.ToTable("AppUserSubscribes", (string)null);
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/Migrations/20260320092811_Add-Notification-Send-Record.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/Migrations/20260320092811_Add-Notification-Send-Record.cs
new file mode 100644
index 000000000..f5d88f390
--- /dev/null
+++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/Migrations/20260320092811_Add-Notification-Send-Record.cs
@@ -0,0 +1,49 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace LINGYUN.Abp.MicroService.MessageService.Migrations
+{
+ ///
+ public partial class AddNotificationSendRecord : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "AppNotificationSendRecords",
+ columns: table => new
+ {
+ Id = table.Column(type: "bigint", nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ TenantId = table.Column(type: "uuid", nullable: true),
+ Provider = table.Column(type: "character varying(50)", maxLength: 50, nullable: false),
+ SendTime = table.Column(type: "timestamp with time zone", nullable: false),
+ UserId = table.Column(type: "uuid", nullable: false),
+ UserName = table.Column(type: "character varying(128)", maxLength: 128, nullable: false, defaultValue: "/"),
+ NotificationId = table.Column(type: "bigint", nullable: false),
+ NotificationName = table.Column(type: "character varying(255)", maxLength: 255, nullable: false),
+ State = table.Column(type: "integer", nullable: false),
+ Reason = table.Column(type: "character varying(255)", maxLength: 255, nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AppNotificationSendRecords", x => x.Id);
+ });
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Tenant_Send_Notification_Name",
+ table: "AppNotificationSendRecords",
+ columns: new[] { "TenantId", "NotificationName" });
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "AppNotificationSendRecords");
+ }
+ }
+}
diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/Migrations/MessageServiceMigrationsDbContextModelSnapshot.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/Migrations/MessageServiceMigrationsDbContextModelSnapshot.cs
index d1b513018..2aebeadd1 100644
--- a/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/Migrations/MessageServiceMigrationsDbContextModelSnapshot.cs
+++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService.EntityFrameworkCore/Migrations/MessageServiceMigrationsDbContextModelSnapshot.cs
@@ -19,7 +19,7 @@ namespace LINGYUN.Abp.MicroService.MessageService.Migrations
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql)
- .HasAnnotation("ProductVersion", "9.0.5")
+ .HasAnnotation("ProductVersion", "10.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
@@ -682,6 +682,59 @@ namespace LINGYUN.Abp.MicroService.MessageService.Migrations
b.ToTable("AppNotificationDefinitions", (string)null);
});
+ modelBuilder.Entity("LINGYUN.Abp.Notifications.NotificationSendRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("NotificationId")
+ .HasColumnType("bigint");
+
+ b.Property("NotificationName")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("Provider")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("Reason")
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.Property("SendTime")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("State")
+ .HasColumnType("integer");
+
+ b.Property("TenantId")
+ .HasColumnType("uuid")
+ .HasColumnName("TenantId");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.Property("UserName")
+ .IsRequired()
+ .ValueGeneratedOnAdd()
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)")
+ .HasDefaultValue("/");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TenantId", "NotificationName")
+ .HasDatabaseName("IX_Tenant_Send_Notification_Name");
+
+ b.ToTable("AppNotificationSendRecords", (string)null);
+ });
+
modelBuilder.Entity("LINGYUN.Abp.Notifications.UserNotification", b =>
{
b.Property("Id")
diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/BackgroundJobs/NotificationPublishJob.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/BackgroundJobs/NotificationPublishJob.cs
index d4f1ccba9..c0b26073f 100644
--- a/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/BackgroundJobs/NotificationPublishJob.cs
+++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/BackgroundJobs/NotificationPublishJob.cs
@@ -1,25 +1,34 @@
using LINGYUN.Abp.Notifications;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
+using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.DependencyInjection;
+using Volo.Abp.Timing;
namespace LINGYUN.Abp.MicroService.MessageService.BackgroundJobs;
public class NotificationPublishJob : AsyncBackgroundJob, ITransientDependency
{
+ protected IClock Clock { get; }
protected AbpNotificationsPublishOptions Options { get; }
protected IServiceScopeFactory ServiceScopeFactory { get; }
+ protected INotificationStore NotificationStore { get; }
protected INotificationDataSerializer NotificationDataSerializer { get; }
public NotificationPublishJob(
+ IClock clock,
IOptions options,
IServiceScopeFactory serviceScopeFactory,
+ INotificationStore notificationStore,
INotificationDataSerializer notificationDataSerializer)
{
+ Clock = clock;
Options = options.Value;
ServiceScopeFactory = serviceScopeFactory;
+ NotificationStore = notificationStore;
NotificationDataSerializer = notificationDataSerializer;
}
@@ -33,9 +42,65 @@ public class NotificationPublishJob : AsyncBackgroundJob();
var notification = await store.GetNotificationOrNullAsync(args.TenantId, args.NotificationId);
notification.Data = NotificationDataSerializer.Serialize(notification.Data);
-
- await publishProvider.PublishAsync(notification, args.UserIdentifiers);
+
+ var sendInfo = OnPublishing(publishProvider, notification, args.UserIdentifiers);
+
+ try
+ {
+ if (await publishProvider.CanPublishAsync(notification))
+ {
+ var context = new NotificationPublishContext(notification, args.UserIdentifiers);
+ // 发布
+ await publishProvider.PublishAsync(context);
+
+ sendInfo.Sent(context.Exception);
+
+ if (context.Exception == null && !context.Reason.IsNullOrWhiteSpace())
+ {
+ sendInfo.Cancel(context.Reason);
+ }
+
+ Logger.LogDebug($"Send notification {notification.Name} with provider {publishProvider.Name} was successful");
+ }
+ else
+ {
+ sendInfo.Disbaled();
+ }
+
+ await OnPublished(sendInfo);
+ }
+ catch (Exception ex)
+ {
+ Logger.LogWarning($"Send notification error with provider {publishProvider.Name}");
+ Logger.LogWarning($"Error message:{ex.Message}");
+
+ try
+ {
+ sendInfo.Sent(ex);
+ await OnPublished(sendInfo);
+ }
+ catch { }
+
+ throw;
+ }
}
}
}
+
+ protected virtual NotificationSendInfo OnPublishing(
+ INotificationPublishProvider provider,
+ NotificationInfo notification,
+ IEnumerable identifiers)
+ {
+ return new NotificationSendInfo(
+ provider.Name,
+ Clock.Now,
+ notification,
+ identifiers);
+ }
+
+ protected async Task OnPublished(NotificationSendInfo sendInfo)
+ {
+ await NotificationStore.InsertSendStateAsync(sendInfo);
+ }
}
diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/Handlers/Distributed/NotificationEventHandler.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/Handlers/Distributed/NotificationEventHandler.cs
index d7ba789a6..8ba419705 100644
--- a/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/Handlers/Distributed/NotificationEventHandler.cs
+++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.MessageService/Handlers/Distributed/NotificationEventHandler.cs
@@ -19,6 +19,7 @@ using Volo.Abp.Localization;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Settings;
using Volo.Abp.TextTemplating;
+using Volo.Abp.Timing;
using Volo.Abp.Uow;
namespace LINGYUN.Abp.MicroService.MessageService.Handlers.Distributed
@@ -44,6 +45,10 @@ namespace LINGYUN.Abp.MicroService.MessageService.Handlers.Distributed
///
protected AbpNotificationsPublishOptions Options { get; }
///
+ /// Reference to .
+ ///
+ protected IClock Clock { get; }
+ ///
/// Reference to .
///
protected ISettingProvider SettingProvider { get; }
@@ -100,6 +105,7 @@ namespace LINGYUN.Abp.MicroService.MessageService.Handlers.Distributed
/// Initializes a new instance of the class.
///
public NotificationEventHandler(
+ IClock clock,
ICurrentTenant currentTenant,
ISettingProvider settingProvider,
ITenantConfigurationCache tenantConfigurationCache,
@@ -115,6 +121,7 @@ namespace LINGYUN.Abp.MicroService.MessageService.Handlers.Distributed
INotificationSubscriptionManager notificationSubscriptionManager,
INotificationPublishProviderManager notificationPublishProviderManager)
{
+ Clock = clock;
Options = options.Value;
TenantConfigurationCache = tenantConfigurationCache;
CurrentTenant = currentTenant;
@@ -435,20 +442,40 @@ namespace LINGYUN.Abp.MicroService.MessageService.Handlers.Distributed
///
/// 通知发布者
/// 通知信息
- /// 订阅用户列表
+ /// 订阅用户列表
///
protected async Task PublishToSubscriberAsync(
INotificationPublishProvider provider,
NotificationInfo notificationInfo,
IEnumerable subscriptionUsers)
{
+ var sendInfo = OnPublishing(provider, notificationInfo, subscriptionUsers);
+
try
{
Logger.LogDebug($"Sending notification with provider {provider.Name}");
- // 发布
- await provider.PublishAsync(notificationInfo, subscriptionUsers);
- Logger.LogDebug($"Send notification {notificationInfo.Name} with provider {provider.Name} was successful");
+ if (await provider.CanPublishAsync(notificationInfo))
+ {
+ var context = new NotificationPublishContext(notificationInfo, subscriptionUsers);
+ // 发布
+ await provider.PublishAsync(context);
+
+ sendInfo.Sent(context.Exception);
+
+ if (context.Exception == null && !context.Reason.IsNullOrWhiteSpace())
+ {
+ sendInfo.Cancel(context.Reason);
+ }
+
+ Logger.LogDebug($"Send notification {notificationInfo.Name} with provider {provider.Name} was successful");
+ }
+ else
+ {
+ sendInfo.Disbaled();
+ }
+
+ await OnPublished(sendInfo);
}
catch (Exception ex)
{
@@ -457,6 +484,13 @@ namespace LINGYUN.Abp.MicroService.MessageService.Handlers.Distributed
Logger.LogDebug($"Failed to send notification {notificationInfo.Name}. Try to push notification to background job");
// 发送失败的消息进入后台队列
await ProcessingFailedToQueueAsync(provider, notificationInfo, subscriptionUsers);
+
+ try
+ {
+ sendInfo.Sent(ex);
+ await OnPublished(sendInfo);
+ }
+ catch { }
}
}
///
@@ -489,5 +523,22 @@ namespace LINGYUN.Abp.MicroService.MessageService.Handlers.Distributed
Logger.LogWarning("Failed to push to background job, notification will be discarded, error cause: {message}", ex.Message);
}
}
+
+ protected virtual NotificationSendInfo OnPublishing(
+ INotificationPublishProvider provider,
+ NotificationInfo notification,
+ IEnumerable identifiers)
+ {
+ return new NotificationSendInfo(
+ provider.Name,
+ Clock.Now,
+ notification,
+ identifiers);
+ }
+
+ protected async Task OnPublished(NotificationSendInfo sendInfo)
+ {
+ await NotificationStore.InsertSendStateAsync(sendInfo);
+ }
}
}
diff --git a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql/Migrations/20260316031109_Add-AI-Management-Module.Designer.cs b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql/Migrations/20260316031109_Add-AI-Management-Module.Designer.cs
new file mode 100644
index 000000000..1dfa168ec
--- /dev/null
+++ b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql/Migrations/20260316031109_Add-AI-Management-Module.Designer.cs
@@ -0,0 +1,5696 @@
+//
+using System;
+using LY.MicroService.Applications.Single.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using Volo.Abp.EntityFrameworkCore;
+
+#nullable disable
+
+namespace LY.MicroService.Applications.Single.EntityFrameworkCore.PostgreSql.Migrations
+{
+ [DbContext(typeof(SingleMigrationsDbContext))]
+ [Migration("20260316031109_Add-AI-Management-Module")]
+ partial class AddAIManagementModule
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.PostgreSql)
+ .HasAnnotation("ProductVersion", "10.0.0")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("LINGYUN.Abp.AIManagement.Chats.ConversationRecord", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp without time zone");
+
+ b.Property("CreationTime")
+ .HasColumnType("timestamp without time zone")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uuid")
+ .HasColumnName("CreatorId");
+
+ b.Property("ExpiredAt")
+ .HasColumnType("timestamp without time zone");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("timestamp without time zone")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("uuid")
+ .HasColumnName("LastModifierId");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("TenantId")
+ .HasColumnType("uuid")
+ .HasColumnName("TenantId");
+
+ b.Property("UpdateAt")
+ .HasColumnType("timestamp without time zone");
+
+ b.Property("Workspace")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)");
+
+ b.HasKey("Id");
+
+ b.ToTable("AbpAIConversations", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.AIManagement.Chats.TextChatMessageRecord", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uuid");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("character varying(40)")
+ .HasColumnName("ConcurrencyStamp");
+
+ b.Property("Content")
+ .IsRequired()
+ .HasMaxLength(1024)
+ .HasColumnType("character varying(1024)");
+
+ b.Property("ConversationId")
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp without time zone");
+
+ b.Property("CreationTime")
+ .HasColumnType("timestamp without time zone")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uuid")
+ .HasColumnName("CreatorId");
+
+ b.Property("ExtraProperties")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("timestamp without time zone")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("uuid")
+ .HasColumnName("LastModifierId");
+
+ b.Property("ReplyAt")
+ .HasColumnType("timestamp without time zone");
+
+ b.Property("ReplyMessage")
+ .HasColumnType("text");
+
+ b.Property("Role")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("character varying(20)");
+
+ b.Property("TenantId")
+ .HasColumnType("uuid")
+ .HasColumnName("TenantId");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.Property("Workspace")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TenantId", "ConversationId");
+
+ b.ToTable("AbpAITextChatMessages", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.AIManagement.Tokens.TokenUsageRecord", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uuid");
+
+ b.Property("CachedInputTokenCount")
+ .HasColumnType("bigint");
+
+ b.Property("ConversationId")
+ .HasColumnType("uuid");
+
+ b.Property("CreationTime")
+ .HasColumnType("timestamp without time zone")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uuid")
+ .HasColumnName("CreatorId");
+
+ b.Property("InputTokenCount")
+ .HasColumnType("bigint");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("timestamp without time zone")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("uuid")
+ .HasColumnName("LastModifierId");
+
+ b.Property("MessageId")
+ .HasColumnType("uuid");
+
+ b.Property("OutputTokenCount")
+ .HasColumnType("bigint");
+
+ b.Property("ReasoningTokenCount")
+ .HasColumnType("bigint");
+
+ b.Property("TenantId")
+ .HasColumnType("uuid")
+ .HasColumnName("TenantId");
+
+ b.Property("TotalTokenCount")
+ .HasColumnType("bigint");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TenantId", "ConversationId");
+
+ b.ToTable("AbpAITokenUsages", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.AIManagement.Workspaces.WorkspaceDefinitionRecord", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uuid");
+
+ b.Property("ApiBaseUrl")
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)");
+
+ b.Property("ApiKey")
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("character varying(40)")
+ .HasColumnName("ConcurrencyStamp");
+
+ b.Property("CreationTime")
+ .HasColumnType("timestamp without time zone")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("uuid")
+ .HasColumnName("CreatorId");
+
+ b.Property("Description")
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)");
+
+ b.Property("DisplayName")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)");
+
+ b.Property("ExtraProperties")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("FrequencyPenalty")
+ .HasColumnType("real");
+
+ b.Property("Instructions")
+ .HasMaxLength(512)
+ .HasColumnType("character varying(512)");
+
+ b.Property("IsEnabled")
+ .HasColumnType("boolean");
+
+ b.Property("IsSystem")
+ .HasColumnType("boolean");
+
+ b.Property