feat(member): add message reach backend module and docs seeds

This commit is contained in:
2026-03-04 13:35:22 +08:00
parent bd418c5927
commit b5aa060faf
33 changed files with 4282 additions and 2 deletions

View File

@@ -422,6 +422,18 @@ public sealed class TakeoutAppDbContext(
/// </summary>
public DbSet<MemberStoredCardRechargeRecord> MemberStoredCardRechargeRecords => Set<MemberStoredCardRechargeRecord>();
/// <summary>
/// 会员消息触达记录。
/// </summary>
public DbSet<MemberReachMessage> MemberReachMessages => Set<MemberReachMessage>();
/// <summary>
/// 会员消息模板。
/// </summary>
public DbSet<MemberMessageTemplate> MemberMessageTemplates => Set<MemberMessageTemplate>();
/// <summary>
/// 会员消息触达收件明细。
/// </summary>
public DbSet<MemberReachRecipient> MemberReachRecipients => Set<MemberReachRecipient>();
/// <summary>
/// 会话记录。
/// </summary>
public DbSet<ChatSession> ChatSessions => Set<ChatSession>();
@@ -593,6 +605,9 @@ public sealed class TakeoutAppDbContext(
ConfigureMemberPointMallRecord(modelBuilder.Entity<MemberPointMallRecord>());
ConfigureMemberStoredCardPlan(modelBuilder.Entity<MemberStoredCardPlan>());
ConfigureMemberStoredCardRechargeRecord(modelBuilder.Entity<MemberStoredCardRechargeRecord>());
ConfigureMemberReachMessage(modelBuilder.Entity<MemberReachMessage>());
ConfigureMemberMessageTemplate(modelBuilder.Entity<MemberMessageTemplate>());
ConfigureMemberReachRecipient(modelBuilder.Entity<MemberReachRecipient>());
ConfigureChatSession(modelBuilder.Entity<ChatSession>());
ConfigureChatMessage(modelBuilder.Entity<ChatMessage>());
ConfigureSupportTicket(modelBuilder.Entity<SupportTicket>());
@@ -1981,6 +1996,62 @@ public sealed class TakeoutAppDbContext(
builder.HasIndex(x => new { x.TenantId, x.StoreId, x.RechargedAt });
}
private static void ConfigureMemberReachMessage(EntityTypeBuilder<MemberReachMessage> builder)
{
builder.ToTable("member_reach_messages");
builder.HasKey(x => x.Id);
builder.Property(x => x.StoreId);
builder.Property(x => x.TemplateId);
builder.Property(x => x.Title).HasMaxLength(128).IsRequired();
builder.Property(x => x.Content).HasColumnType("text").IsRequired();
builder.Property(x => x.ChannelsJson).HasColumnType("text").IsRequired();
builder.Property(x => x.AudienceType).HasConversion<int>();
builder.Property(x => x.AudienceTagsJson).HasColumnType("text").IsRequired();
builder.Property(x => x.EstimatedReachCount).IsRequired();
builder.Property(x => x.ScheduleType).HasConversion<int>();
builder.Property(x => x.ScheduledAt);
builder.Property(x => x.Status).HasConversion<int>();
builder.Property(x => x.SentAt);
builder.Property(x => x.SentCount).IsRequired();
builder.Property(x => x.ReadCount).IsRequired();
builder.Property(x => x.ConvertedCount).IsRequired();
builder.Property(x => x.HangfireJobId).HasMaxLength(64);
builder.Property(x => x.LastError).HasMaxLength(1024);
builder.HasIndex(x => new { x.TenantId, x.Status, x.ScheduledAt });
builder.HasIndex(x => new { x.TenantId, x.CreatedAt });
}
private static void ConfigureMemberMessageTemplate(EntityTypeBuilder<MemberMessageTemplate> builder)
{
builder.ToTable("member_message_templates");
builder.HasKey(x => x.Id);
builder.Property(x => x.Name).HasMaxLength(64).IsRequired();
builder.Property(x => x.Category).HasConversion<int>();
builder.Property(x => x.Content).HasColumnType("text").IsRequired();
builder.Property(x => x.UsageCount).IsRequired();
builder.Property(x => x.LastUsedAt);
builder.HasIndex(x => new { x.TenantId, x.Name }).IsUnique();
builder.HasIndex(x => new { x.TenantId, x.Category, x.UsageCount });
}
private static void ConfigureMemberReachRecipient(EntityTypeBuilder<MemberReachRecipient> builder)
{
builder.ToTable("member_reach_recipients");
builder.HasKey(x => x.Id);
builder.Property(x => x.MessageId).IsRequired();
builder.Property(x => x.MemberId).IsRequired();
builder.Property(x => x.Channel).HasConversion<int>();
builder.Property(x => x.Mobile).HasMaxLength(32);
builder.Property(x => x.OpenId).HasMaxLength(128);
builder.Property(x => x.Status).HasConversion<int>();
builder.Property(x => x.SentAt);
builder.Property(x => x.ReadAt);
builder.Property(x => x.ConvertedAt);
builder.Property(x => x.ErrorMessage).HasMaxLength(512);
builder.HasIndex(x => new { x.TenantId, x.MessageId, x.MemberId, x.Channel }).IsUnique();
builder.HasIndex(x => new { x.TenantId, x.MessageId, x.Status });
}
private static void ConfigureChatSession(EntityTypeBuilder<ChatSession> builder)
{
builder.ToTable("chat_sessions");
@@ -2191,4 +2262,3 @@ public sealed class TakeoutAppDbContext(
builder.HasIndex(x => new { x.TenantId, x.QuotaPackageId, x.PurchasedAt });
}
}