学生可在“学籍管理 → 电子成绩单与证明”申请成绩单或学籍证明。
服务端根据登录账号绑定本人档案,不接受学生 ID,无法代他人申请。 成绩单仅包含正式发布成绩;无已发布成绩时明确提示。 同类型、同用途 5 分钟内重复申请复用已有有效凭证。 申请后即时生成 PDF,可在本人凭证列表下载、二维码验真。 管理员的下载记录、失效、重签能力保持不变。
This commit is contained in:
@@ -91,6 +91,9 @@ public sealed class AppDbContext(DbContextOptions<AppDbContext> options)
|
||||
Set<GraduationClearanceItem>();
|
||||
public DbSet<GraduationClearanceRecord> GraduationClearanceRecords =>
|
||||
Set<GraduationClearanceRecord>();
|
||||
public DbSet<OfficialDocument> OfficialDocuments => Set<OfficialDocument>();
|
||||
public DbSet<OfficialDocumentDownload> OfficialDocumentDownloads =>
|
||||
Set<OfficialDocumentDownload>();
|
||||
public DbSet<AuditLog> AuditLogs => Set<AuditLog>();
|
||||
|
||||
protected override void ConfigureConventions(
|
||||
@@ -927,6 +930,54 @@ public sealed class AppDbContext(DbContextOptions<AppDbContext> options)
|
||||
entity.Property(x => x.IpAddress).HasMaxLength(64);
|
||||
entity.HasIndex(x => x.CreatedAt);
|
||||
});
|
||||
|
||||
builder.Entity<OfficialDocument>(entity =>
|
||||
{
|
||||
entity.Property(x => x.DocumentNumber).HasMaxLength(50);
|
||||
entity.Property(x => x.VerificationCodeHash).HasMaxLength(64);
|
||||
entity.Property(x => x.Purpose).HasMaxLength(200);
|
||||
entity.Property(x => x.SnapshotJson).HasColumnType("longtext");
|
||||
entity.Property(x => x.PdfContent).HasColumnType("longblob");
|
||||
entity.Property(x => x.PdfSha256).HasMaxLength(64);
|
||||
entity.Property(x => x.InvalidationReason).HasMaxLength(500);
|
||||
entity.HasIndex(x => x.DocumentNumber).IsUnique();
|
||||
entity.HasIndex(x => x.VerificationCodeHash).IsUnique();
|
||||
entity.HasIndex(x => new { x.StudentId, x.IssuedAt });
|
||||
entity.HasIndex(x => new { x.Status, x.IssuedAt });
|
||||
entity.HasOne(x => x.Student)
|
||||
.WithMany()
|
||||
.HasForeignKey(x => x.StudentId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
entity.HasOne(x => x.IssuedByUser)
|
||||
.WithMany()
|
||||
.HasForeignKey(x => x.IssuedByUserId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
entity.HasOne(x => x.InvalidatedByUser)
|
||||
.WithMany()
|
||||
.HasForeignKey(x => x.InvalidatedByUserId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
entity.HasIndex(x => x.ReissuedFromDocumentId).IsUnique();
|
||||
entity.HasOne(x => x.ReissuedFromDocument)
|
||||
.WithMany()
|
||||
.HasForeignKey(x => x.ReissuedFromDocumentId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
});
|
||||
|
||||
builder.Entity<OfficialDocumentDownload>(entity =>
|
||||
{
|
||||
entity.Property(x => x.IpAddress).HasMaxLength(64);
|
||||
entity.Property(x => x.UserAgent).HasMaxLength(500);
|
||||
entity.HasIndex(x => new { x.OfficialDocumentId, x.CreatedAt });
|
||||
entity.HasIndex(x => new { x.DownloadedByUserId, x.CreatedAt });
|
||||
entity.HasOne(x => x.OfficialDocument)
|
||||
.WithMany(x => x.Downloads)
|
||||
.HasForeignKey(x => x.OfficialDocumentId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
entity.HasOne(x => x.DownloadedByUser)
|
||||
.WithMany()
|
||||
.HasForeignKey(x => x.DownloadedByUserId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
});
|
||||
}
|
||||
|
||||
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
|
||||
|
||||
Reference in New Issue
Block a user