forked from xiongyuxing/tiku-backend.net
feat: add learning reports and practice access persistence
This commit is contained in:
@@ -58,6 +58,7 @@ public sealed class ContentNode : AuditableTenantEntity
|
||||
public bool IsActive { get; set; } = true;
|
||||
public bool IsSelectable { get; set; } = true;
|
||||
public bool IsLeaf { get; set; }
|
||||
public JsonElement AccessRules { get; set; } = JsonDefaults.Object();
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
public Guid? CreatedBy { get; set; }
|
||||
public Guid? UpdatedBy { get; set; }
|
||||
@@ -100,6 +101,7 @@ public sealed class QuestionCollection : AuditableTenantEntity
|
||||
public QuestionCollectionType CollectionType { get; set; } = QuestionCollectionType.Dynamic;
|
||||
public QuestionCollectionSourceType SourceType { get; set; } = QuestionCollectionSourceType.Filters;
|
||||
public JsonElement Filters { get; set; } = JsonDefaults.Object();
|
||||
public JsonElement AccessRules { get; set; } = JsonDefaults.Object();
|
||||
public int QuestionCount { get; set; }
|
||||
public decimal? TotalScore { get; set; }
|
||||
public int? DurationMinutes { get; set; }
|
||||
@@ -163,6 +165,7 @@ public sealed class PracticeBlueprint : AuditableTenantEntity
|
||||
public decimal? PassScore { get; set; }
|
||||
public JsonElement Sections { get; set; } = JsonDefaults.Array();
|
||||
public JsonElement Rules { get; set; } = JsonDefaults.Object();
|
||||
public JsonElement AccessRules { get; set; } = JsonDefaults.Object();
|
||||
public ContentStatus Status { get; set; } = ContentStatus.Active;
|
||||
public int SortOrder { get; set; }
|
||||
public Guid? CreatedBy { get; set; }
|
||||
|
||||
@@ -20,9 +20,20 @@ public sealed class PracticeSession : TenantEntity
|
||||
public int? DurationMinutes { get; set; }
|
||||
public decimal? TotalScore { get; set; }
|
||||
public DateTimeOffset? ExpiresAt { get; set; }
|
||||
public PracticeAccessMode AccessMode { get; set; } = PracticeAccessMode.Free;
|
||||
public Guid? AccessEntitlementId { get; set; }
|
||||
public int ConsumedFreeQuota { get; set; }
|
||||
public JsonElement AccessSnapshot { get; set; } = JsonDefaults.Object();
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
}
|
||||
|
||||
public enum PracticeAccessMode
|
||||
{
|
||||
Free,
|
||||
Svip,
|
||||
Staff
|
||||
}
|
||||
|
||||
public sealed class AnswerRecord : TenantEntity
|
||||
{
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
229
Tiku.Domain/Learning/LearningReportEntities.cs
Normal file
229
Tiku.Domain/Learning/LearningReportEntities.cs
Normal file
@@ -0,0 +1,229 @@
|
||||
using System.Text.Json;
|
||||
using Tiku.Domain.Common;
|
||||
|
||||
namespace Tiku.Domain.Learning;
|
||||
|
||||
public sealed class ExamDate : AuditableTenantEntity
|
||||
{
|
||||
public Guid? RegionId { get; set; }
|
||||
public Guid? SchoolId { get; set; }
|
||||
public string? LegacyId { get; set; }
|
||||
public string ExamName { get; set; } = string.Empty;
|
||||
public DateTimeOffset? ExamAt { get; set; }
|
||||
public string? ExamType { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public int SortOrder { get; set; }
|
||||
public bool IsActive { get; set; } = true;
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
}
|
||||
|
||||
public sealed class Report : AuditableTenantEntity
|
||||
{
|
||||
public Guid? QuestionId { get; set; }
|
||||
public Guid? UserId { get; set; }
|
||||
public Guid? HandledBy { get; set; }
|
||||
public string? LegacyId { get; set; }
|
||||
public ReportType? Type { get; set; }
|
||||
public string? Title { get; set; }
|
||||
public string? Category { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public ReportStatus Status { get; set; } = ReportStatus.Pending;
|
||||
public ReportPriority Priority { get; set; } = ReportPriority.Normal;
|
||||
public DateTimeOffset? HandledAt { get; set; }
|
||||
public string? Resolution { get; set; }
|
||||
public string? Contact { get; set; }
|
||||
public JsonElement Attachments { get; set; } = JsonDefaults.Array();
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
}
|
||||
|
||||
public sealed class ReportStatusEvent : Entity
|
||||
{
|
||||
public Guid TenantId { get; set; }
|
||||
public Guid ReportId { get; set; }
|
||||
public ReportStatus? FromStatus { get; set; }
|
||||
public ReportStatus ToStatus { get; set; } = ReportStatus.Pending;
|
||||
public string? Note { get; set; }
|
||||
public Guid? ActorUserId { get; set; }
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
public sealed class UserScoreEvent : Entity
|
||||
{
|
||||
public Guid TenantId { get; set; }
|
||||
public Guid UserId { get; set; }
|
||||
public UserScoreEventType EventType { get; set; } = UserScoreEventType.ManualAdjust;
|
||||
public int Points { get; set; }
|
||||
public int BalanceAfter { get; set; }
|
||||
public string? SourceType { get; set; }
|
||||
public Guid? SourceId { get; set; }
|
||||
public string? IdempotencyKey { get; set; }
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
public sealed class PracticeDailyUsage : AuditableTenantEntity
|
||||
{
|
||||
public Guid UserId { get; set; }
|
||||
public DateOnly UsageDate { get; set; } = DateOnly.FromDateTime(DateTime.UtcNow);
|
||||
public PracticeUsageScopeType ScopeType { get; set; } = PracticeUsageScopeType.Tenant;
|
||||
public Guid? ScopeId { get; set; }
|
||||
public int FreeLimit { get; set; } = 25;
|
||||
public int UsedCount { get; set; }
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
}
|
||||
|
||||
public sealed class PracticeAccessEvent : Entity
|
||||
{
|
||||
public Guid TenantId { get; set; }
|
||||
public Guid? UserId { get; set; }
|
||||
public Guid? PracticeSessionId { get; set; }
|
||||
public PracticeAccessEventType EventType { get; set; } = PracticeAccessEventType.SessionCreated;
|
||||
public PracticeAccessEventMode AccessMode { get; set; } = PracticeAccessEventMode.Free;
|
||||
public int RequestedCount { get; set; }
|
||||
public int GrantedCount { get; set; }
|
||||
public int ConsumedFreeQuota { get; set; }
|
||||
public string? Reason { get; set; }
|
||||
public PracticeUsageScopeType? ScopeType { get; set; }
|
||||
public Guid? ScopeId { get; set; }
|
||||
public Guid? EntitlementId { get; set; }
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
public sealed class PracticeSessionReport : AuditableTenantEntity
|
||||
{
|
||||
public Guid UserId { get; set; }
|
||||
public Guid PracticeSessionId { get; set; }
|
||||
public Guid? BlueprintId { get; set; }
|
||||
public Guid? CollectionId { get; set; }
|
||||
public string Mode { get; set; } = "mock_exam";
|
||||
public int TotalQuestions { get; set; }
|
||||
public int AnsweredCount { get; set; }
|
||||
public int CorrectCount { get; set; }
|
||||
public int WrongCount { get; set; }
|
||||
public int UnansweredCount { get; set; }
|
||||
public decimal Score { get; set; }
|
||||
public decimal TotalScore { get; set; }
|
||||
public decimal Accuracy { get; set; }
|
||||
public int DurationSeconds { get; set; }
|
||||
public DateTimeOffset? StartedAt { get; set; }
|
||||
public DateTimeOffset SubmittedAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
public JsonElement SectionStats { get; set; } = JsonDefaults.Array();
|
||||
public JsonElement QuestionResults { get; set; } = JsonDefaults.Array();
|
||||
public JsonElement WrongQuestionIds { get; set; } = JsonDefaults.Array();
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
}
|
||||
|
||||
public sealed class PracticeSessionReportSection : AuditableTenantEntity
|
||||
{
|
||||
public Guid ReportId { get; set; }
|
||||
public Guid PracticeSessionId { get; set; }
|
||||
public string SectionKey { get; set; } = string.Empty;
|
||||
public string? SectionName { get; set; }
|
||||
public string? QuestionType { get; set; }
|
||||
public int QuestionCount { get; set; }
|
||||
public int AnsweredCount { get; set; }
|
||||
public int CorrectCount { get; set; }
|
||||
public int WrongCount { get; set; }
|
||||
public int UnansweredCount { get; set; }
|
||||
public decimal Score { get; set; }
|
||||
public decimal TotalScore { get; set; }
|
||||
public decimal Accuracy { get; set; }
|
||||
public int SortOrder { get; set; }
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
}
|
||||
|
||||
public sealed class DashboardDailyStat : AuditableTenantEntity
|
||||
{
|
||||
public Guid? RegionId { get; set; }
|
||||
public string? LegacyId { get; set; }
|
||||
public string? LegacyRegionId { get; set; }
|
||||
public DateOnly StatDate { get; set; }
|
||||
public int NewUsers { get; set; }
|
||||
public int NewQuestions { get; set; }
|
||||
public int NewOrders { get; set; }
|
||||
public int NewRevenueCents { get; set; }
|
||||
public int ActiveUsers { get; set; }
|
||||
public DateTimeOffset? RebuiltAt { get; set; }
|
||||
}
|
||||
|
||||
public sealed class RevenueDailyStat : AuditableTenantEntity
|
||||
{
|
||||
public Guid? RegionId { get; set; }
|
||||
public string? LegacyId { get; set; }
|
||||
public string? LegacyRegionId { get; set; }
|
||||
public DateOnly StatDate { get; set; }
|
||||
public string? SaleType { get; set; }
|
||||
public int RealRevenueCents { get; set; }
|
||||
public int OrderCount { get; set; }
|
||||
public int CodeCount { get; set; }
|
||||
public int CodeUsed { get; set; }
|
||||
public int CodeEstimated { get; set; }
|
||||
public int EstimatedRevenueCents { get; set; }
|
||||
public DateTimeOffset? RebuiltAt { get; set; }
|
||||
}
|
||||
|
||||
public enum ReportType
|
||||
{
|
||||
QuestionError,
|
||||
ContentError,
|
||||
VideoError,
|
||||
AssetError,
|
||||
SystemBug,
|
||||
Suggestion,
|
||||
Other
|
||||
}
|
||||
|
||||
public enum ReportStatus
|
||||
{
|
||||
Pending,
|
||||
Accepted,
|
||||
Rejected,
|
||||
Resolved,
|
||||
Closed
|
||||
}
|
||||
|
||||
public enum ReportPriority
|
||||
{
|
||||
Low,
|
||||
Normal,
|
||||
High,
|
||||
Urgent
|
||||
}
|
||||
|
||||
public enum UserScoreEventType
|
||||
{
|
||||
CheckIn,
|
||||
ManualAdjust,
|
||||
FeedbackReward,
|
||||
ActivityReward,
|
||||
RedeemCost
|
||||
}
|
||||
|
||||
public enum PracticeUsageScopeType
|
||||
{
|
||||
Tenant,
|
||||
Region,
|
||||
Subject,
|
||||
QuestionBank,
|
||||
ContentEntry,
|
||||
ContentNode,
|
||||
Collection,
|
||||
Blueprint
|
||||
}
|
||||
|
||||
public enum PracticeAccessEventType
|
||||
{
|
||||
SessionCreated,
|
||||
SessionDenied,
|
||||
QuotaConsumed
|
||||
}
|
||||
|
||||
public enum PracticeAccessEventMode
|
||||
{
|
||||
Free,
|
||||
Svip,
|
||||
Staff,
|
||||
Denied
|
||||
}
|
||||
Reference in New Issue
Block a user