Add transfer tracking and secure admin access
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
namespace MiaoJiZhang.Domain.Entities;
|
||||
|
||||
public static class AdminRoles
|
||||
{
|
||||
public const string SuperAdmin = "super_admin";
|
||||
public const string Operator = "operator";
|
||||
public const string Viewer = "viewer";
|
||||
|
||||
public static readonly string[] All = [SuperAdmin, Operator, Viewer];
|
||||
}
|
||||
|
||||
public class AdminUser
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public string Username { get; set; } = null!;
|
||||
public string PasswordHash { get; set; } = null!;
|
||||
public string Role { get; set; } = AdminRoles.Viewer;
|
||||
public bool IsActive { get; set; } = true;
|
||||
public bool MustChangePassword { get; set; }
|
||||
public int AuthVersion { get; set; }
|
||||
public int FailedLoginCount { get; set; }
|
||||
public DateTime? LockedUntil { get; set; }
|
||||
public DateTime? LastLoginAt { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
public DateTime UpdatedAt { get; set; }
|
||||
public ICollection<AdminSession> Sessions { get; set; } = [];
|
||||
}
|
||||
|
||||
public class AdminSession
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long AdminUserId { get; set; }
|
||||
public AdminUser AdminUser { get; set; } = null!;
|
||||
public string TokenHash { get; set; } = null!;
|
||||
public string CsrfTokenHash { get; set; } = null!;
|
||||
public int AuthVersion { get; set; }
|
||||
public DateTime ExpiresAt { get; set; }
|
||||
public DateTime AbsoluteExpiresAt { get; set; }
|
||||
public DateTime? RevokedAt { get; set; }
|
||||
public DateTime LastSeenAt { get; set; }
|
||||
public string? IpAddress { get; set; }
|
||||
public string? UserAgent { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
}
|
||||
|
||||
public class AdminAuditLog
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long? AdminUserId { get; set; }
|
||||
public string? Username { get; set; }
|
||||
public string Action { get; set; } = null!;
|
||||
public string Resource { get; set; } = null!;
|
||||
public string HttpMethod { get; set; } = null!;
|
||||
public string Path { get; set; } = null!;
|
||||
public int StatusCode { get; set; }
|
||||
public bool Success { get; set; }
|
||||
public string? Detail { get; set; }
|
||||
public string? IpAddress { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
}
|
||||
@@ -44,8 +44,10 @@ public class Transaction
|
||||
public TransactionType Type { get; set; }
|
||||
public decimal Amount { get; set; }
|
||||
public string? Note { get; set; }
|
||||
public string? PaymentMethod { get; set; }
|
||||
public DateTime OccurredAt { get; set; }
|
||||
public string? PaymentMethod { get; set; }
|
||||
public TransferDirection? TransferDirection { get; set; }
|
||||
public string? Counterparty { get; set; }
|
||||
public DateTime OccurredAt { get; set; }
|
||||
|
||||
// ---- AI 来源追溯(决策:可核对、可撤销) ----
|
||||
public TransactionSource Source { get; set; } = TransactionSource.Manual;
|
||||
@@ -53,7 +55,12 @@ public class Transaction
|
||||
public string? SourceText { get; set; }
|
||||
/// <summary>关联的聊天消息 Id(追溯用)</summary>
|
||||
public long? SourceChatMessageId { get; set; }
|
||||
public string? ClientRequestId { get; set; }
|
||||
public string? ClientRequestId { get; set; }
|
||||
public string? Provider { get; set; }
|
||||
public string? ProviderTransactionId { get; set; }
|
||||
public string? RecognitionOccurrenceId { get; set; }
|
||||
public string? EvidenceFingerprint { get; set; }
|
||||
public string? RecognitionConfidence { get; set; }
|
||||
|
||||
// ---- 软删除(决策:直接入账 + 可撤销) ----
|
||||
public bool IsDeleted { get; set; }
|
||||
|
||||
@@ -17,12 +17,49 @@ public enum AppMode
|
||||
}
|
||||
|
||||
/// <summary>账单类型</summary>
|
||||
public enum TransactionType
|
||||
public enum TransactionType
|
||||
{
|
||||
Expense = 0,
|
||||
Income = 1,
|
||||
Transfer = 2,
|
||||
}
|
||||
}
|
||||
|
||||
public enum TransferDirection
|
||||
{
|
||||
In = 0,
|
||||
Out = 1,
|
||||
}
|
||||
|
||||
public static class TransactionTypeRules
|
||||
{
|
||||
public static bool IsExpense(this TransactionType type, TransferDirection? direction = null) =>
|
||||
type == TransactionType.Expense ||
|
||||
type == TransactionType.Transfer && direction == TransferDirection.Out;
|
||||
|
||||
public static bool IsIncome(this TransactionType type, TransferDirection? direction = null) =>
|
||||
type == TransactionType.Income ||
|
||||
type == TransactionType.Transfer && direction == TransferDirection.In;
|
||||
|
||||
public static TransactionType CategoryType(
|
||||
this TransactionType type,
|
||||
TransferDirection? direction = null) => type == TransactionType.Transfer
|
||||
? direction == TransferDirection.In ? TransactionType.Income : TransactionType.Expense
|
||||
: type;
|
||||
|
||||
public static string ToWire(this TransactionType type) => type switch
|
||||
{
|
||||
TransactionType.Income => "income",
|
||||
TransactionType.Transfer => "transfer",
|
||||
_ => "expense",
|
||||
};
|
||||
|
||||
public static string? ToWire(this TransferDirection? direction) => direction switch
|
||||
{
|
||||
TransferDirection.In => "in",
|
||||
TransferDirection.Out => "out",
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>账单来源(决策:AI 记账可追溯)</summary>
|
||||
public enum TransactionSource
|
||||
|
||||
Reference in New Issue
Block a user