first commit
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
namespace F9WebAiTest.Domain.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// DDD 聚合根基类:BusinessEntity + 领域事件。
|
||||
/// 聚合根是聚合的入口与唯一代表,外部只能通过聚合根访问聚合内部对象,通过仓储持久化。
|
||||
/// 参考 BBIT.F9.Domain.Entities.AggregateRoot
|
||||
/// </summary>
|
||||
public abstract class AggregateRoot : BusinessEntity, IAggregateRoot
|
||||
{
|
||||
private readonly List<IDomainEvent> _domainEvents = new();
|
||||
public IReadOnlyCollection<IDomainEvent> DomainEvents => _domainEvents.AsReadOnly();
|
||||
|
||||
protected void AddDomainEvent(IDomainEvent domainEvent) => _domainEvents.Add(domainEvent);
|
||||
|
||||
public void ClearDomainEvents() => _domainEvents.Clear();
|
||||
}
|
||||
|
||||
/// <summary>聚合根标记接口</summary>
|
||||
public interface IAggregateRoot
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Common;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities.Attendance;
|
||||
|
||||
/// <summary>考勤打卡记录</summary>
|
||||
[Table(Name = "AttendanceRecords")]
|
||||
[Index("IX_AttendanceRecords_EmployeeId_WorkDate", "EmployeeId, WorkDate", IsUnique = true)]
|
||||
public class AttendanceRecord : BaseEntity
|
||||
{
|
||||
public long EmployeeId { get; set; }
|
||||
public DateTime WorkDate { get; set; } // 考勤日期
|
||||
public DateTime? SignInTime { get; set; } // 签到时间
|
||||
public DateTime? SignOutTime { get; set; } // 签退时间
|
||||
public string SignInStatus { get; set; } = ""; // 正常/迟到/缺卡
|
||||
public string SignOutStatus { get; set; } = ""; // 正常/早退/缺卡
|
||||
public string Remark { get; set; } = "";
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Common;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities.Attendance;
|
||||
|
||||
/// <summary>请假审批节点(多级审批流程,OrderNo 表示审批顺序)</summary>
|
||||
[Table(Name = "LeaveApprovers")]
|
||||
[Index("IX_LeaveApprovers_LeaveId_OrderNo", "LeaveId, OrderNo", IsUnique = true)]
|
||||
public class LeaveApprover : BaseEntity
|
||||
{
|
||||
public long LeaveId { get; set; }
|
||||
public long ApproverId { get; set; } // 审批人ID
|
||||
public string ApproverName { get; set; } = ""; // 审批人姓名(冗余)
|
||||
public int OrderNo { get; set; } // 序号(从1开始,表示审批顺序)
|
||||
public string Status { get; set; } = "待审批"; // 待审批/已批准/已驳回
|
||||
public string ApproveRemark { get; set; } = "";
|
||||
public DateTime? ApprovedAt { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Common;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities.Attendance;
|
||||
|
||||
/// <summary>请假申请</summary>
|
||||
[Table(Name = "LeaveRequests")]
|
||||
public class LeaveRequest : BaseEntity
|
||||
{
|
||||
public long EmployeeId { get; set; }
|
||||
public string Type { get; set; } = "事假"; // 事假/病假/年假/调休/婚假/产假
|
||||
public DateTime StartTime { get; set; }
|
||||
public DateTime EndTime { get; set; }
|
||||
public string Reason { get; set; } = "";
|
||||
public string Status { get; set; } = "待审批"; // 待审批/已批准/已驳回
|
||||
public int CurrentOrderNo { get; set; } = 1; // 当前审批到第几步(多级审批)
|
||||
public long? ApproverId { get; set; }
|
||||
public string ApproverName { get; set; } = "";
|
||||
public string ApproveRemark { get; set; } = "";
|
||||
public DateTime? ApprovedAt { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Common;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities.Base;
|
||||
|
||||
/// <summary>工艺庄口</summary>
|
||||
[Table(Name = "CraftZhuangKous")]
|
||||
public class CraftZhuangKou : BaseEntity
|
||||
{
|
||||
public int BelongingYear { get; set; } // 年度
|
||||
public int BendiWaidi { get; set; } // 本地外地:1=本地 2=外地
|
||||
public string JidiWaigou { get; set; } = ""; // 基地外购
|
||||
public string ZhuangKouCode { get; set; } = ""; // 庄口编号
|
||||
public string ZhuangKouName { get; set; } = ""; // 庄口名称
|
||||
public string ProductionDisplayName { get; set; } = ""; // 生产显示名称
|
||||
public string Chandi { get; set; } = ""; // 产地
|
||||
public int Sort { get; set; } // 排序
|
||||
public string Memo { get; set; } = ""; // 备注
|
||||
public string IsJiezhuang { get; set; } = "0"; // 是否结庄
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Common;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities.Base;
|
||||
|
||||
/// <summary>机组车台</summary>
|
||||
[Table(Name = "JizuChetais")]
|
||||
public class JizuChetai : BaseEntity
|
||||
{
|
||||
public long DepartmentId { get; set; } // 车间(部门)
|
||||
public int Jizu { get; set; } // 机组号
|
||||
public int ChetaiStart { get; set; } // 开始车台号
|
||||
public int ChetaiEnd { get; set; } // 结束车台号
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Common;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities.Base;
|
||||
|
||||
/// <summary>生丝定级指标</summary>
|
||||
[Table(Name = "ShengsiDingjizhibiaos")]
|
||||
public class ShengsiDingjizhibiao : BaseEntity
|
||||
{
|
||||
public int Standard { get; set; } // 标准:0=厂标 1=国标 2=个人
|
||||
public string Guige { get; set; } = ""; // 规格
|
||||
public string Grade { get; set; } = ""; // 等级
|
||||
public double GradeScore { get; set; } // 等级分值
|
||||
public double Piancha { get; set; } // 偏差
|
||||
public double Dacha { get; set; } // 大差
|
||||
public double Erdu { get; set; } // 二度变化
|
||||
public double Sandu { get; set; } // 三度变化
|
||||
public double Qingjie { get; set; } // 清洁
|
||||
public double Jiejing { get; set; } // 洁净
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Common;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities.Base;
|
||||
|
||||
/// <summary>生丝规格</summary>
|
||||
[Table(Name = "ShengsiGuiges")]
|
||||
public class ShengsiGuige : BaseEntity
|
||||
{
|
||||
public string Guige { get; set; } = ""; // 规格
|
||||
public double CenterrangeLolimit { get; set; } // 中心范围下限
|
||||
public double CenterrangeUplimit { get; set; } // 中心范围上限
|
||||
public double CenterXiandu { get; set; } // 中心纤度
|
||||
public double ValidLolimit { get; set; } // 有效下限
|
||||
public double ValidUplimit { get; set; } // 有效上限
|
||||
public double XiaoyeLolimit { get; set; } // 小野下限
|
||||
public double XiaoyeUplimit { get; set; } // 小野上限
|
||||
public double DayeLolimit { get; set; } // 大野下限
|
||||
public double DayeUplimit { get; set; } // 大野上限
|
||||
public double TeyeLolimit { get; set; } // 特野下限
|
||||
public double TeyeUplimit { get; set; } // 特野上限
|
||||
public double YexianNkLolimitLeft { get; set; } // 内控左下
|
||||
public double YexianNkLolimitRight { get; set; } // 内控左上
|
||||
public double YexianNkUplimitLeft { get; set; } // 内控右下
|
||||
public double YexianNkUplimitRight { get; set; } // 内控右上
|
||||
public double LaodongJingsaiYexianLolimit { get; set; } // 野纤下限
|
||||
public double LaodongJingsaiYexianUplimit { get; set; } // 野纤上限
|
||||
public int Sort { get; set; } // 顺序号
|
||||
public string Memo { get; set; } = ""; // 备注
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// DDD 业务实体基类:Entity + 审计字段(CreatedBy/UpdateBy/DeletedAt)。
|
||||
/// 参考 BBIT.F9.Domain.Entities.BusinessEntity
|
||||
/// </summary>
|
||||
public abstract class BusinessEntity : Entity
|
||||
{
|
||||
/// <summary>创建人</summary>
|
||||
[Column(Name = "created_by")]
|
||||
public string CreatedBy { get; set; }
|
||||
|
||||
/// <summary>修改人</summary>
|
||||
[Column(Name = "update_by")]
|
||||
public string UpdateBy { get; set; }
|
||||
|
||||
/// <summary>逻辑删除时间(null=未删除)</summary>
|
||||
[Column(Name = "deleted_at")]
|
||||
public DateTime? DeletedAt { get; protected set; }
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Common;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities;
|
||||
|
||||
/// <summary>部门(树形结构)</summary>
|
||||
[Table(Name = "Departments")]
|
||||
public class Department : BaseEntity
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Code { get; set; } = ""; // 部门编码
|
||||
public long? ParentId { get; set; }
|
||||
public long? LeaderId { get; set; }
|
||||
public string Phone { get; set; } = "";
|
||||
public int Sort { get; set; }
|
||||
public int Status { get; set; } = 1; // 1 启用 0 禁用
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Common;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities;
|
||||
|
||||
/// <summary>职工/用户</summary>
|
||||
[Table(Name = "Employees")]
|
||||
[Index("IX_Employees_Username", "Username", IsUnique = true)]
|
||||
public class Employee : BaseEntity
|
||||
{
|
||||
public string Username { get; set; } // 登录账号
|
||||
public string Password { get; set; } // 密码哈希
|
||||
public string RealName { get; set; } // 真实姓名
|
||||
public string Nickname { get; set; } = "";
|
||||
public string Avatar { get; set; } = "";
|
||||
public string Gender { get; set; } = "男";
|
||||
public string Phone { get; set; } = "";
|
||||
public string Email { get; set; } = "";
|
||||
public long DepartmentId { get; set; }
|
||||
public int Status { get; set; } = 1; // 1 在职 0 离职/禁用
|
||||
public string Remark { get; set; } = "";
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Common;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities;
|
||||
|
||||
/// <summary>职工-角色 关联</summary>
|
||||
[Table(Name = "EmployeeRoles")]
|
||||
[Index("IX_EmployeeRoles_EmployeeId_RoleId", "EmployeeId, RoleId", IsUnique = true)]
|
||||
public class EmployeeRole : BaseEntity
|
||||
{
|
||||
public long EmployeeId { get; set; }
|
||||
public long RoleId { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Common;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// DDD 实体基类:具有唯一标识与生命周期。
|
||||
/// 实现 IEntity 以兼容通用仓储(IRepository<T>)。
|
||||
/// 主键由应用层通过雪花 ID 生成器赋值(非数据库自增)。
|
||||
/// 参考 BBIT.F9.Domain.Entities.Entity
|
||||
/// </summary>
|
||||
public abstract class Entity : IEntity
|
||||
{
|
||||
[Column(IsPrimary = true)]
|
||||
public long Id { get; set; }
|
||||
|
||||
[Column(Name = "created_at")]
|
||||
public DateTime CreatedAt { get; set; }
|
||||
|
||||
[Column(Name = "updated_at")]
|
||||
public DateTime? UpdatedAt { get; set; }
|
||||
|
||||
[Column(Name = "is_deleted")]
|
||||
public bool IsDeleted { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using MediatR;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities;
|
||||
|
||||
/// <summary>领域事件接口(继承 MediatR 的 INotification,便于事件总线发布)</summary>
|
||||
public interface IDomainEvent : INotification
|
||||
{
|
||||
DateTime OccurredOn { get; }
|
||||
}
|
||||
|
||||
/// <summary>领域事件基类</summary>
|
||||
public abstract record DomainEvent : IDomainEvent
|
||||
{
|
||||
public DateTime OccurredOn => DateTime.Now;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Common;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities;
|
||||
|
||||
/// <summary>菜单/权限(支持目录、菜单、按钮三种类型)</summary>
|
||||
[Table(Name = "Menus")]
|
||||
public class Menu : BaseEntity
|
||||
{
|
||||
public long? ParentId { get; set; }
|
||||
public string Name { get; set; } // 菜单名称
|
||||
public string Type { get; set; } = "menu"; // directory 目录 / menu 菜单 / button 按钮
|
||||
public string Path { get; set; } = ""; // 路由路径
|
||||
public string Component { get; set; } = "";// 组件路径
|
||||
public string Icon { get; set; } = ""; // 图标
|
||||
public string Permission { get; set; } = "";// 权限标识,如 system:user:list
|
||||
public int Sort { get; set; }
|
||||
public int Status { get; set; } = 1; // 1 显示 0 隐藏
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
namespace F9WebAiTest.Domain.Entities.Notice;
|
||||
|
||||
/// <summary>消息优先级</summary>
|
||||
public enum NotificationPriority
|
||||
{
|
||||
Normal = 0, // 普通
|
||||
Important = 1, // 重要
|
||||
Urgent = 2 // 紧急
|
||||
}
|
||||
|
||||
/// <summary>消息状态</summary>
|
||||
public enum NotificationStatus
|
||||
{
|
||||
Ready = 0, // 准备(待投递)
|
||||
Sent = 1, // 已发送
|
||||
Failed = 2, // 失败
|
||||
PartialSuccess = 3, // 部分成功
|
||||
Revoked = 4 // 已撤销
|
||||
}
|
||||
|
||||
/// <summary>阅读状态</summary>
|
||||
public enum NotificationReadStatus
|
||||
{
|
||||
Unread = 0, // 未读
|
||||
Read = 1 // 已读
|
||||
}
|
||||
|
||||
/// <summary>推送状态</summary>
|
||||
public enum NotificationSendStatus
|
||||
{
|
||||
NotSent = 0, // 未发送
|
||||
Success = 1, // 成功
|
||||
Failed = 2 // 失败
|
||||
}
|
||||
|
||||
/// <summary>待办状态</summary>
|
||||
public enum TodoItemStatus
|
||||
{
|
||||
Pending = 0, // 待处理
|
||||
Processing = 1, // 处理中
|
||||
Completed = 2, // 已完成
|
||||
Cancelled = 3 // 已取消
|
||||
}
|
||||
|
||||
/// <summary>消息分类(决定消息中心展示形态与处理方式)</summary>
|
||||
public enum NotificationCategory
|
||||
{
|
||||
Notification = 0, // 通知:纯提醒,点开查看/标记已读
|
||||
Todo = 1, // 待办:需用户处理(审批/任务),关联待办事项
|
||||
Announcement = 2 // 公告:广播给全体,重点展示
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 消息类型枚举(枚举名与 NotificationType.Code 一一对应)。
|
||||
/// 业务侧通过「该枚举 + MediatR 命令」发送消息,无需关心底层实现。
|
||||
/// 新增消息类型时:1) 在此加枚举值 2) 在数据库/种子中配置同名 Code 的消息类型(标题、路由模板、接收规则等)。
|
||||
/// </summary>
|
||||
public enum NotificationTypeEnum
|
||||
{
|
||||
TeyeFound = 1, // 发现特野
|
||||
TdcFound = 2, // 发现特大糙
|
||||
LeaveApproval = 3, // 请假审批(待办)
|
||||
LeaveResult = 4 // 请假结果通知(通知)
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Common;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities.Notice;
|
||||
|
||||
/// <summary>消息主表(业务系统触发创建,创建时即时投递并实时推送)</summary>
|
||||
[Table(Name = "NotificationMessages")]
|
||||
[Index("IX_NotificationMessages_MessageTypeCode", "MessageTypeCode")]
|
||||
public class NotificationMessage : BaseEntity
|
||||
{
|
||||
public long NotificationTypeId { get; set; } // 消息类型ID
|
||||
public string MessageTypeCode { get; set; } = ""; // 消息类型编码(冗余,路由查询免联表)
|
||||
public string BusinessType { get; set; } = ""; // 业务类型标识
|
||||
public string BusinessId { get; set; } = ""; // 业务单据ID
|
||||
public string Title { get; set; } = ""; // 标题
|
||||
public string Content { get; set; } = ""; // 内容
|
||||
public NotificationPriority Priority { get; set; } = NotificationPriority.Normal; // 优先级
|
||||
public NotificationStatus Status { get; set; } = NotificationStatus.Ready; // 状态
|
||||
public int RetryCount { get; set; } // 重试次数
|
||||
public int MaxRetryCount { get; set; } = 3; // 最大重试次数
|
||||
public string BizContext { get; set; } = ""; // 业务上下文(JSON)
|
||||
public string ForceReceivers { get; set; } = ""; // 强制接收人(JSON 数组,如 "[1001,1002]"),空=仅按订阅
|
||||
public long CreatorId { get; set; } // 创建人ID
|
||||
public string CreatorName { get; set; } = ""; // 创建人姓名
|
||||
public NotificationCategory Category { get; set; } = NotificationCategory.Notification; // 消息分类(冗余,前端免联表)
|
||||
public string RoutePath { get; set; } = ""; // Web 端跳转路由(最终值,由模板+业务ID生成)
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Common;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities.Notice;
|
||||
|
||||
/// <summary>消息接收人(投递时生成,记录阅读状态与推送结果:在线推送成功 / 离线待拉取)</summary>
|
||||
[Table(Name = "NotificationReceivers")]
|
||||
[Index("IX_NotificationReceivers_MessageId_UserId", "MessageId, UserId", IsUnique = true)]
|
||||
[Index("IX_NotificationReceivers_UserId_ReadStatus", "UserId, ReadStatus")]
|
||||
public class NotificationReceiver : BaseEntity
|
||||
{
|
||||
public long MessageId { get; set; } // 消息ID
|
||||
public long UserId { get; set; } // 接收人用户ID
|
||||
public NotificationReadStatus ReadStatus { get; set; } = NotificationReadStatus.Unread; // 阅读状态
|
||||
public DateTime? ReadTime { get; set; } // 阅读时间
|
||||
public bool IsOffline { get; set; } // 推送时是否离线
|
||||
public NotificationSendStatus SendStatus { get; set; } = NotificationSendStatus.NotSent; // 推送状态
|
||||
public DateTime? SendTime { get; set; } // 推送时间
|
||||
public string ErrorMsg { get; set; } = ""; // 错误信息
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Common;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities.Notice;
|
||||
|
||||
/// <summary>消息类型(管理员维护,定义订阅所需权限)</summary>
|
||||
[Table(Name = "NotificationTypes")]
|
||||
[Index("IX_NotificationTypes_Code", "Code", IsUnique = true)]
|
||||
public class NotificationType : BaseEntity
|
||||
{
|
||||
public string Code { get; set; } = ""; // 消息类型编码,唯一,如 "TeyeFound"
|
||||
public string Name { get; set; } = ""; // 消息类型名称,如 "发现特野"
|
||||
public string Description { get; set; } = ""; // 类型描述,展示在订阅页
|
||||
public string RequiredPermission { get; set; } = ""; // 订阅该类型所需权限码,空=所有用户可订阅
|
||||
public bool IsActive { get; set; } = true; // 是否开放订阅
|
||||
public long CreatedBy { get; set; } // 创建人ID
|
||||
public int Sort { get; set; } // 排序号
|
||||
public NotificationCategory Category { get; set; } = NotificationCategory.Notification; // 消息分类
|
||||
public string Icon { get; set; } = ""; // 图标(Element Plus 图标名,如 "Bell")
|
||||
public string RouteTemplate { get; set; } = ""; // Web 端跳转路由模板,支持 {businessId} 占位符
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Common;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities.Notice;
|
||||
|
||||
/// <summary>待办事项(消息可携带待办)</summary>
|
||||
[Table(Name = "TodoItems")]
|
||||
[Index("IX_TodoItems_AssigneeId_TodoStatus", "AssigneeId, TodoStatus")]
|
||||
public class TodoItem : BaseEntity
|
||||
{
|
||||
public long MessageId { get; set; } // 关联消息ID
|
||||
public long AssigneeId { get; set; } // 处理人用户ID
|
||||
public TodoItemStatus TodoStatus { get; set; } = TodoItemStatus.Pending; // 待办状态
|
||||
public DateTime? DueTime { get; set; } // 截止时间
|
||||
public DateTime? CompletedTime { get; set; } // 完成时间
|
||||
public string HandleResult { get; set; } = ""; // 处理结果
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Common;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities.Notice;
|
||||
|
||||
/// <summary>用户订阅(用户主动订阅/取消,保留历史)</summary>
|
||||
[Table(Name = "UserNotificationSubscriptions")]
|
||||
[Index("IX_UserNotificationSubscriptions_UserId_NotificationTypeId", "UserId, NotificationTypeId", IsUnique = true)]
|
||||
public class UserNotificationSubscription : BaseEntity
|
||||
{
|
||||
public long UserId { get; set; } // 订阅用户ID
|
||||
public long NotificationTypeId { get; set; } // 消息类型ID
|
||||
public bool IsActive { get; set; } = true; // 订阅状态:true=已订阅 false=已取消
|
||||
public DateTime SubscribedTime { get; set; } = DateTime.Now; // 订阅时间
|
||||
public DateTime? CancelTime { get; set; } // 取消订阅时间
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Common;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities;
|
||||
|
||||
/// <summary>操作日志</summary>
|
||||
[Table(Name = "OperationLogs")]
|
||||
public class OperationLog : BaseEntity
|
||||
{
|
||||
public long? EmployeeId { get; set; }
|
||||
public string EmployeeName { get; set; } = "";
|
||||
public string Module { get; set; } = "";
|
||||
public string Action { get; set; } = "";
|
||||
public string Description { get; set; } = "";
|
||||
public string Ip { get; set; } = "";
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Common;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities.Prod;
|
||||
|
||||
/// <summary>黑板检验-落丝汇总(每个落丝记录一条)</summary>
|
||||
[Table(Name = "HbjyLsjls")]
|
||||
[Index("IX_HbjyLsjls_LsjlId", "LsjlId", IsUnique = true)]
|
||||
public class HbjyLsjl : BaseEntity
|
||||
{
|
||||
public long LsjlId { get; set; } // 落丝记录
|
||||
public int Pianshu { get; set; } // 片数
|
||||
public double Qingjie { get; set; } // 清洁分
|
||||
public double Jiejing { get; set; } // 洁净分
|
||||
public int YdErdu { get; set; } // 二度变化片数
|
||||
public int YdSandu { get; set; } // 三度变化片数
|
||||
public string Dengji { get; set; } = ""; // 等级
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Common;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities.Prod;
|
||||
|
||||
/// <summary>黑板检验-车台明细(每车台一行)</summary>
|
||||
[Table(Name = "HbjyRecords")]
|
||||
[Index("IX_HbjyRecords_LsjlId_Chetaihao", "LsjlId, Chetaihao", IsUnique = true)]
|
||||
public class HbjyRecord : BaseEntity
|
||||
{
|
||||
public long LsjlId { get; set; } // 落丝记录
|
||||
public int Chetaihao { get; set; } // 车台号
|
||||
public int YdYidu { get; set; } // 一度变化片数
|
||||
public int YdErdu { get; set; } // 二度变化片数
|
||||
public int YdSandu { get; set; } // 三度变化片数
|
||||
// 洁净等级片数(100~60)
|
||||
public int Jj100 { get; set; }
|
||||
public int Jj95 { get; set; }
|
||||
public int Jj90 { get; set; }
|
||||
public int Jj85 { get; set; }
|
||||
public int Jj80 { get; set; }
|
||||
public int Jj75 { get; set; }
|
||||
public int Jj70 { get; set; }
|
||||
public int Jj65 { get; set; }
|
||||
public int Jj60 { get; set; }
|
||||
// 清洁疵点-特大类
|
||||
public int QjZycdTdc { get; set; } // 特大糙
|
||||
// 清洁疵点-大类
|
||||
public int QjCycdFs { get; set; } // 废丝
|
||||
public int QjCycdDc { get; set; } // 大糙
|
||||
public int QjCycdNfc { get; set; } // 粘付糙
|
||||
public int QjCycdDcj { get; set; } // 大长结
|
||||
public int QjCycdZlx { get; set; } // 重螺旋
|
||||
// 清洁疵点-小类
|
||||
public int QjPtcdXc { get; set; } // 小糙
|
||||
public int QjPtcdCj { get; set; } // 长结
|
||||
public int QjPtcdLx { get; set; } // 螺旋
|
||||
public int QjPtcdHjls { get; set; } // 环结及裂丝
|
||||
public int Pianshu { get; set; } // 本车台片数
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Common;
|
||||
using F9WebAiTest.Domain.Entities.Base;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities.Prod;
|
||||
|
||||
/// <summary>落丝记录(前缫生产)</summary>
|
||||
[Table(Name = "LsjlRecords")]
|
||||
public class LsjlRecord : BaseEntity
|
||||
{
|
||||
public DateTime WorkDate { get; set; } // 日期
|
||||
public long DeptId { get; set; } // 车间
|
||||
public long GyzkId { get; set; } // 工艺庄口
|
||||
public int Jizu { get; set; } // 机组
|
||||
public string LuosiTime { get; set; } = ""; // 落丝时间
|
||||
public string Yanse { get; set; } = ""; // 颜色
|
||||
public int Huishu { get; set; } // 回数
|
||||
public int ChetaiStart { get; set; } // 开始车台号
|
||||
public int ChetaiEnd { get; set; } // 结束车台号
|
||||
public int Chetaishu { get; set; } // 车台数
|
||||
public bool Isbanche { get; set; } // 是否半车
|
||||
public double Hours { get; set; } // 缫丝时长
|
||||
public string Guige { get; set; } = ""; // 规格
|
||||
public double Chesu { get; set; } // 车速
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Common;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities.Prod;
|
||||
|
||||
/// <summary>纤度检验-落丝汇总(每个落丝记录一条)</summary>
|
||||
[Table(Name = "XdjyLsjls")]
|
||||
[Index("IX_XdjyLsjls_LsjlId", "LsjlId", IsUnique = true)]
|
||||
public class XdjyLsjl : BaseEntity
|
||||
{
|
||||
public long LsjlId { get; set; } // 落丝记录
|
||||
public int Jiaoshu { get; set; } // 已称绞数
|
||||
public double Avgxiandu { get; set; } // 平均纤度
|
||||
public double Junfangcha { get; set; } // 均方差
|
||||
public double Zongcha { get; set; } // 总差
|
||||
public double FanxianLv { get; set; } // 范纤率(%)
|
||||
public int FanweiNum { get; set; } // 范围数
|
||||
public int XiaoyeNum { get; set; } // 小野数
|
||||
public int DayeNum { get; set; } // 大野数
|
||||
public int TeyeNum { get; set; } // 特野数
|
||||
public int CenterNum { get; set; } // 中心数
|
||||
public string Dengji { get; set; } = ""; // 等级
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Common;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities.Prod;
|
||||
|
||||
/// <summary>纤度检验-车台明细(每车台一行,4 个纤度值)</summary>
|
||||
[Table(Name = "XdjyRecords")]
|
||||
[Index("IX_XdjyRecords_LsjlId_Chetaihao", "LsjlId, Chetaihao", IsUnique = true)]
|
||||
public class XdjyRecord : BaseEntity
|
||||
{
|
||||
public long LsjlId { get; set; } // 落丝记录
|
||||
public int Chetaihao { get; set; } // 车台号
|
||||
public double Xd1 { get; set; } // 纤度1
|
||||
public double Xd2 { get; set; } // 纤度2
|
||||
public double Xd3 { get; set; } // 纤度3
|
||||
public double Xd4 { get; set; } // 纤度4
|
||||
public int XdNum { get; set; } // 已称绞数
|
||||
public double XdAvg { get; set; } // 平均纤度
|
||||
public int FanweiNum { get; set; } // 范围
|
||||
public int XiaoyeNum { get; set; } // 小野
|
||||
public int DayeNum { get; set; } // 大野
|
||||
public int TeyeNum { get; set; } // 特野
|
||||
public int CenterNum { get; set; } // 中心
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Common;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities;
|
||||
|
||||
/// <summary>刷新令牌</summary>
|
||||
[Table(Name = "RefreshTokens")]
|
||||
public class RefreshToken : BaseEntity
|
||||
{
|
||||
public long EmployeeId { get; set; }
|
||||
public string Token { get; set; }
|
||||
public DateTime ExpiresAt { get; set; }
|
||||
public bool IsRevoked { get; set; }
|
||||
public string CreatedByIp { get; set; } = "";
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Common;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities;
|
||||
|
||||
/// <summary>角色</summary>
|
||||
[Table(Name = "Roles")]
|
||||
[Index("IX_Roles_Code", "Code", IsUnique = true)]
|
||||
public class Role : BaseEntity
|
||||
{
|
||||
public string Name { get; set; } // 角色名称
|
||||
public string Code { get; set; } // 角色编码(唯一)
|
||||
public string Description { get; set; } = "";
|
||||
public int Sort { get; set; }
|
||||
public int Status { get; set; } = 1;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Common;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities;
|
||||
|
||||
/// <summary>角色-菜单 关联</summary>
|
||||
[Table(Name = "RoleMenus")]
|
||||
[Index("IX_RoleMenus_RoleId_MenuId", "RoleId, MenuId", IsUnique = true)]
|
||||
public class RoleMenu : BaseEntity
|
||||
{
|
||||
public long RoleId { get; set; }
|
||||
public long MenuId { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Enums.SYS.Departments;
|
||||
using F9WebAiTest.Domain.Events.SYS.Departments;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities.SYS.Departments;
|
||||
|
||||
/// <summary>
|
||||
/// 部门:用户与部门是独立聚合,仅保存 DepartmentId 关联(避免双向强耦合)。
|
||||
/// 部门用户列表仅用于查询展示,通过读模型实现。
|
||||
/// </summary>
|
||||
[Table(Name = "sys_departments")]
|
||||
public class Department : AggregateRoot
|
||||
{
|
||||
[Column(Name = "code")]
|
||||
public string Code { get; private set; }
|
||||
|
||||
[Column(Name = "name")]
|
||||
public string Name { get; private set; }
|
||||
|
||||
[Column(Name = "parent_id")]
|
||||
public long ParentId { get; private set; }
|
||||
|
||||
[Column(Name = "manage_type")]
|
||||
public Department_ManageType_Enum ManageType { get; private set; }
|
||||
|
||||
[Column(Name = "duty_type")]
|
||||
public Department_DutyType_Enum DutyType { get; private set; }
|
||||
|
||||
[Column(Name = "description")]
|
||||
public string? Description { get; private set; }
|
||||
|
||||
[Column(Name = "is_active")]
|
||||
public bool IsActive { get; private set; }
|
||||
|
||||
[Column(Name = "sort_order")]
|
||||
public int SortOrder { get; private set; }
|
||||
|
||||
private readonly List<long> _userIds = [];
|
||||
public IReadOnlyCollection<long> UserIds => _userIds.AsReadOnly();
|
||||
|
||||
public Department() { }
|
||||
|
||||
public Department(long id, string code, string name, long parentId,
|
||||
Department_ManageType_Enum manageType, Department_DutyType_Enum dutyType, int sortOrder, string? description = null)
|
||||
{
|
||||
Id = id;
|
||||
Code = code;
|
||||
Name = name;
|
||||
ParentId = parentId;
|
||||
ManageType = manageType;
|
||||
DutyType = dutyType;
|
||||
SortOrder = sortOrder;
|
||||
Description = description;
|
||||
IsActive = true;
|
||||
AddDomainEvent(new Department_ChangedDomainEvent(Id));
|
||||
}
|
||||
|
||||
public void AddUser(long userId)
|
||||
{
|
||||
if (!_userIds.Contains(userId))
|
||||
_userIds.Add(userId);
|
||||
}
|
||||
|
||||
public void RemoveUser(long userId) => _userIds.Remove(userId);
|
||||
|
||||
public void Activate()
|
||||
{
|
||||
IsActive = true;
|
||||
AddDomainEvent(new Department_ChangedDomainEvent(Id));
|
||||
}
|
||||
|
||||
public void Deactivate()
|
||||
{
|
||||
IsActive = false;
|
||||
AddDomainEvent(new Department_ChangedDomainEvent(Id));
|
||||
}
|
||||
|
||||
public void Deleted() => AddDomainEvent(new Department_ChangedDomainEvent(Id));
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities.SYS.Departments;
|
||||
|
||||
/// <summary>部门用户关联:部门与用户的关联记录。</summary>
|
||||
[Table(Name = "sys_department_users")]
|
||||
public class DepartmentUser : BusinessEntity
|
||||
{
|
||||
[Column(Name = "department_id")]
|
||||
public long DepartmentId { get; private set; }
|
||||
|
||||
[Column(Name = "user_id")]
|
||||
public long UserId { get; private set; }
|
||||
|
||||
[Column(Name = "assigned_at")]
|
||||
public DateTime AssignedAt { get; private set; }
|
||||
|
||||
public DepartmentUser() { }
|
||||
|
||||
public DepartmentUser(long id, long departmentId, long userId)
|
||||
{
|
||||
Id = id;
|
||||
DepartmentId = departmentId;
|
||||
UserId = userId;
|
||||
AssignedAt = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Enums.SYS.RBAC;
|
||||
using F9WebAiTest.Domain.Events.SYS.RBAC;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities.SYS.RBAC;
|
||||
|
||||
/// <summary>资源:权限作用的对象,如菜单项、按钮、报表等。</summary>
|
||||
[Table(Name = "sys_rbac_menus")]
|
||||
public class Menu : AggregateRoot
|
||||
{
|
||||
[Column(Name = "icon_svg")]
|
||||
public string IconSvg { get; private set; } // 图标
|
||||
|
||||
[Column(Name = "code")]
|
||||
public string Code { get; private set; } // 唯一标识
|
||||
|
||||
[Column(Name = "name")]
|
||||
public string Name { get; private set; } // 显示名称
|
||||
|
||||
[Column(Name = "menu_type")]
|
||||
public MenuType_Enum MenuType { get; private set; } // 菜单类型:分组/页面
|
||||
|
||||
[Column(Name = "assembly_name")]
|
||||
public string? AssemblyName { get; private set; }
|
||||
|
||||
[Column(Name = "type_full_name")]
|
||||
public string? TypeFullName { get; private set; }
|
||||
|
||||
[Column(Name = "parent_id")]
|
||||
public long ParentId { get; private set; } // 支持菜单层级
|
||||
|
||||
[Column(Name = "level")]
|
||||
public int Level { get; private set; } // 层级
|
||||
|
||||
[Column(Name = "is_active")]
|
||||
public bool IsActive { get; private set; }
|
||||
|
||||
[Column(Name = "sort_order")]
|
||||
public int SortOrder { get; private set; }
|
||||
|
||||
[Column(Name = "path")]
|
||||
public string Path { get; private set; } = ""; // Web 路由路径
|
||||
|
||||
[Column(Name = "component")]
|
||||
public string Component { get; private set; } = ""; // 前端组件路径
|
||||
|
||||
[Column(Name = "permission")]
|
||||
public string Permission { get; private set; } = ""; // 权限标识,如 sys:user:list
|
||||
|
||||
public Menu() { }
|
||||
|
||||
public Menu(long id, string name, string iconSvg, MenuType_Enum menuType = MenuType_Enum.默认,
|
||||
string? assemblyName = null, string? typeFullName = null, long parentId = 0, int sortOrder = 0, int parentLevel = 0)
|
||||
{
|
||||
Id = id;
|
||||
Name = name;
|
||||
IconSvg = iconSvg;
|
||||
MenuType = menuType;
|
||||
AssemblyName = assemblyName;
|
||||
TypeFullName = typeFullName;
|
||||
ParentId = parentId;
|
||||
Level = parentId == 0 ? 1 : parentLevel + 1;
|
||||
IsActive = true;
|
||||
CreatedAt = DateTime.Now;
|
||||
SortOrder = sortOrder;
|
||||
AddDomainEvent(new Menu_ChangedDomainEvent(Id));
|
||||
}
|
||||
|
||||
public void GenerateNewCode() => Code = $"menu.{DateTime.Now.Ticks}";
|
||||
|
||||
/// <summary>设置 Web 路由信息(路径/组件/权限码)</summary>
|
||||
public void SetWebInfo(string path, string component, string permission)
|
||||
{
|
||||
Path = path ?? "";
|
||||
Component = component ?? "";
|
||||
Permission = permission ?? "";
|
||||
}
|
||||
|
||||
public IReadOnlySet<Permission_Type_Enum> SupportedPermissionType =>
|
||||
new HashSet<Permission_Type_Enum> { Permission_Type_Enum.Visble };
|
||||
|
||||
public void SoftDelete() => AddDomainEvent(new Menu_ChangedDomainEvent(Id));
|
||||
|
||||
public void Activate()
|
||||
{
|
||||
IsActive = true;
|
||||
AddDomainEvent(new Menu_ChangedDomainEvent(Id));
|
||||
}
|
||||
|
||||
public void Deactivate()
|
||||
{
|
||||
IsActive = false;
|
||||
AddDomainEvent(new Menu_ChangedDomainEvent(Id));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Enums.SYS.RBAC;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities.SYS.RBAC;
|
||||
|
||||
/// <summary>权限:最小的权限单元,如“查看用户列表”、“导出报表”。</summary>
|
||||
[Table(Name = "sys_rbac_permissions")]
|
||||
public class Permission : AggregateRoot
|
||||
{
|
||||
/// <summary>编号,格式:资源:操作,例如 user:add, report:sales:view</summary>
|
||||
[Column(Name = "code")]
|
||||
public string Code { get; private set; }
|
||||
|
||||
[Column(Name = "permission_type")]
|
||||
public Permission_Type_Enum PermissionType { get; private set; }
|
||||
|
||||
[Column(Name = "resource_type")]
|
||||
public Resource_Type_Enum ResourceType { get; private set; }
|
||||
|
||||
[Column(Name = "resource_id")]
|
||||
public long ResourceId { get; private set; } // 关联资源(菜单、报表等)
|
||||
|
||||
public Permission() { }
|
||||
|
||||
public Permission(long id, Permission_Type_Enum permissionType, Resource_Type_Enum resourceType, string resourceIdentity, long resourceId)
|
||||
{
|
||||
Id = id;
|
||||
PermissionType = permissionType;
|
||||
ResourceType = resourceType;
|
||||
ResourceId = resourceId;
|
||||
CreatedAt = DateTime.Now;
|
||||
Code = $"{GetResorceTypeIdentity}:{resourceIdentity}:{permissionType.ToString().ToLower()}";
|
||||
}
|
||||
|
||||
public string GetResorceTypeIdentity => ResourceType switch
|
||||
{
|
||||
Resource_Type_Enum.菜单 => "menu",
|
||||
Resource_Type_Enum.报表 => "report",
|
||||
Resource_Type_Enum.操作 => "operation",
|
||||
Resource_Type_Enum.部门 => "department",
|
||||
Resource_Type_Enum.消息订阅 => "subscribe",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
|
||||
/// <summary>自定义权限码(用于消息订阅等业务权限码与 RBAC 权限码保持一致)</summary>
|
||||
public void SetCode(string code) => Code = code;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Enums.SYS.RBAC;
|
||||
using F9WebAiTest.Domain.Events.SYS.RBAC;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities.SYS.RBAC;
|
||||
|
||||
/// <summary>角色:一组权限的集合。</summary>
|
||||
[Table(Name = "sys_rbac_roles")]
|
||||
public class Role : AggregateRoot
|
||||
{
|
||||
[Column(Name = "name")]
|
||||
public string Name { get; private set; } // 如 "财务专员", "系统管理员"
|
||||
|
||||
[Column(Name = "code")]
|
||||
public string Code { get; private set; } // 如:role:xxxx
|
||||
|
||||
[Column(Name = "sort_order")]
|
||||
public int SortOrder { get; private set; }
|
||||
|
||||
[Column(Name = "description")]
|
||||
public string Description { get; private set; }
|
||||
|
||||
[Column(Name = "is_active")]
|
||||
public bool IsActive { get; private set; }
|
||||
|
||||
private readonly List<long> _permissionIds = [];
|
||||
public IReadOnlyCollection<long> PermissionIds => _permissionIds.AsReadOnly();
|
||||
|
||||
public Role() { }
|
||||
|
||||
public Role(long id, string name, string code, int sortOrder, string description)
|
||||
{
|
||||
Id = id;
|
||||
Name = name;
|
||||
Code = code;
|
||||
SortOrder = sortOrder;
|
||||
IsActive = true;
|
||||
Description = description;
|
||||
CreatedAt = DateTime.Now;
|
||||
}
|
||||
|
||||
public void Activate() => IsActive = true;
|
||||
public void Deactivate() => IsActive = false;
|
||||
|
||||
public void AddPermission(long permissionId, Resource_Type_Enum type)
|
||||
{
|
||||
if (!_permissionIds.Contains(permissionId))
|
||||
_permissionIds.Add(permissionId);
|
||||
|
||||
if (type == Resource_Type_Enum.菜单)
|
||||
AddDomainEvent(new RoleMenu_ChangedDomainEvent(Id));
|
||||
else if (type == Resource_Type_Enum.部门)
|
||||
AddDomainEvent(new RoleDepartment_ChangedDomainEvent(Id));
|
||||
}
|
||||
|
||||
public void RemovePermission(long permissionId, Resource_Type_Enum type)
|
||||
{
|
||||
_permissionIds.Remove(permissionId);
|
||||
|
||||
if (type == Resource_Type_Enum.菜单)
|
||||
AddDomainEvent(new RoleMenu_ChangedDomainEvent(Id));
|
||||
else if (type == Resource_Type_Enum.部门)
|
||||
AddDomainEvent(new RoleDepartment_ChangedDomainEvent(Id));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities.SYS.RBAC;
|
||||
|
||||
/// <summary>角色权限关联:角色与权限的多对多关系。</summary>
|
||||
[Table(Name = "sys_rbac_role_permissions")]
|
||||
public class RolePermission : BusinessEntity
|
||||
{
|
||||
[Column(Name = "role_id")]
|
||||
public long RoleId { get; private set; }
|
||||
|
||||
[Column(Name = "permission_id")]
|
||||
public long PermissionId { get; private set; }
|
||||
|
||||
public RolePermission() { }
|
||||
|
||||
public RolePermission(long id, long roleId, long permissionId)
|
||||
{
|
||||
Id = id;
|
||||
RoleId = roleId;
|
||||
PermissionId = permissionId;
|
||||
CreatedAt = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using F9WebAiTest.Domain.Events.SYS.RBAC;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities.SYS.RBAC;
|
||||
|
||||
/// <summary>用户:可以拥有多个角色。</summary>
|
||||
[Table(Name = "sys_rbac_users")]
|
||||
public class User : AggregateRoot
|
||||
{
|
||||
[Column(Name = "department_id")]
|
||||
public long DepartmentId { get; private set; }
|
||||
|
||||
[Column(Name = "user_name")]
|
||||
public string UserName { get; private set; }
|
||||
|
||||
[Column(Name = "phone_number")]
|
||||
public string PhoneNumber { get; private set; }
|
||||
|
||||
[Column(Name = "login_name")]
|
||||
public string LoginName { get; private set; }
|
||||
|
||||
[Column(Name = "password_hash")]
|
||||
public string PasswordHash { get; private set; }
|
||||
|
||||
[Column(Name = "is_active")]
|
||||
public bool IsActive { get; private set; }
|
||||
|
||||
[Column(Name = "sort_order")]
|
||||
public int SortOrder { get; private set; }
|
||||
|
||||
[Column(Name = "lastlogin_at")]
|
||||
public DateTime? LastLoginAt { get; private set; }
|
||||
|
||||
[Column(Name = "nickname")]
|
||||
public string Nickname { get; private set; } = "";
|
||||
|
||||
[Column(Name = "avatar")]
|
||||
public string Avatar { get; private set; } = "";
|
||||
|
||||
[Column(Name = "email")]
|
||||
public string Email { get; private set; } = "";
|
||||
|
||||
[Column(Name = "gender")]
|
||||
public string Gender { get; private set; } = "男";
|
||||
|
||||
public User() { }
|
||||
|
||||
public User(long id, string userName, string phoneNumber, string loginName, long departmentId, int sortOrder)
|
||||
{
|
||||
Id = id;
|
||||
UserName = userName;
|
||||
PhoneNumber = phoneNumber;
|
||||
LoginName = loginName;
|
||||
DepartmentId = departmentId;
|
||||
IsActive = true;
|
||||
SortOrder = sortOrder;
|
||||
}
|
||||
|
||||
public void Update(string userName, string phoneNumber, string loginName, long departmentId, int sortOrder)
|
||||
{
|
||||
UserName = userName;
|
||||
PhoneNumber = phoneNumber;
|
||||
LoginName = loginName;
|
||||
DepartmentId = departmentId;
|
||||
IsActive = true;
|
||||
SortOrder = sortOrder;
|
||||
}
|
||||
|
||||
public void Activate() => IsActive = true;
|
||||
public void Deactivate() => IsActive = false;
|
||||
|
||||
/// <summary>获取默认密码明文</summary>
|
||||
public string GetDefaultPasswordText() => "123456";
|
||||
|
||||
/// <summary>设置密码(哈希后的密文)</summary>
|
||||
public void SetPassword(string password) => PasswordHash = password;
|
||||
|
||||
/// <summary>更新个人资料(昵称/头像/邮箱/手机号/性别)</summary>
|
||||
public void UpdateProfile(string nickname, string avatar, string email, string phoneNumber, string gender)
|
||||
{
|
||||
Nickname = nickname ?? Nickname;
|
||||
Avatar = avatar ?? Avatar;
|
||||
Email = email ?? Email;
|
||||
PhoneNumber = phoneNumber ?? PhoneNumber;
|
||||
Gender = gender ?? Gender;
|
||||
}
|
||||
|
||||
/// <summary>登录成功,记录登录时间并发布登录事件</summary>
|
||||
public void LoginSuccess(string deviceId, string account, bool success, long userId, string userName)
|
||||
{
|
||||
LastLoginAt = DateTime.Now;
|
||||
AddDomainEvent(new UserLoginDomainEvent(deviceId, account, success, userId, userName));
|
||||
}
|
||||
|
||||
public void AddRole(long roleId) => AddDomainEvent(new UserRole_ChangedDomainEvent(Id));
|
||||
|
||||
public void RemoveRole(long roleId) => AddDomainEvent(new UserRole_ChangedDomainEvent(Id));
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
|
||||
namespace F9WebAiTest.Domain.Entities.SYS.RBAC;
|
||||
|
||||
/// <summary>
|
||||
/// 用户角色关联:用户与角色的多对多关系。
|
||||
/// DDD 中作为独立关联实体,应用层直接操作其仓储(不通过 User 聚合)。
|
||||
/// </summary>
|
||||
[Table(Name = "sys_rbac_user_roles")]
|
||||
public class UserRole : BusinessEntity
|
||||
{
|
||||
[Column(Name = "user_id")]
|
||||
public long UserId { get; private set; }
|
||||
|
||||
[Column(Name = "role_id")]
|
||||
public long RoleId { get; private set; }
|
||||
|
||||
public UserRole() { }
|
||||
|
||||
public UserRole(long id, long userId, long roleId)
|
||||
{
|
||||
Id = id;
|
||||
UserId = userId;
|
||||
RoleId = roleId;
|
||||
CreatedAt = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user