480 lines
12 KiB
C#
480 lines
12 KiB
C#
using System.ComponentModel.DataAnnotations;
|
||
using System.ComponentModel.DataAnnotations.Schema;
|
||
using MilliSim.Common.Models;
|
||
|
||
namespace MilliSim.Common.Entities;
|
||
|
||
/// <summary>
|
||
/// 实体基类
|
||
/// </summary>
|
||
public abstract class BaseEntity
|
||
{
|
||
[Key]
|
||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||
public long Id { get; set; }
|
||
|
||
public DateTime CreatedAt { get; set; } = DateTime.Now;
|
||
|
||
public DateTime UpdatedAt { get; set; } = DateTime.Now;
|
||
|
||
public bool IsDeleted { get; set; } = false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 用户表(员工 + 客户)
|
||
/// </summary>
|
||
public class User : BaseEntity
|
||
{
|
||
[Required, StringLength(50)]
|
||
public string Username { get; set; } = string.Empty;
|
||
|
||
[Required, StringLength(255)]
|
||
public string Password { get; set; } = string.Empty;
|
||
|
||
[StringLength(50)]
|
||
public string Nickname { get; set; } = string.Empty;
|
||
|
||
[StringLength(500)]
|
||
public string Avatar { get; set; } = string.Empty;
|
||
|
||
[StringLength(20)]
|
||
public string Phone { get; set; } = string.Empty;
|
||
|
||
[StringLength(100)]
|
||
public string Email { get; set; } = string.Empty;
|
||
|
||
public UserRole Role { get; set; } = UserRole.Customer;
|
||
|
||
public UserStatus Status { get; set; } = UserStatus.Active;
|
||
|
||
/// <summary>
|
||
/// 创建人 ID(销售创建客户时记录)
|
||
/// </summary>
|
||
public long? CreatedBy { get; set; }
|
||
|
||
[NotMapped]
|
||
public string RoleName => Role.ToString();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 项目表
|
||
/// </summary>
|
||
public class Project : BaseEntity
|
||
{
|
||
[Required, StringLength(100)]
|
||
public string Name { get; set; } = string.Empty;
|
||
|
||
public long CategoryId { get; set; }
|
||
|
||
[StringLength(500)]
|
||
public string CoverImage { get; set; } = string.Empty;
|
||
|
||
[StringLength(500)]
|
||
public string VideoUrl { get; set; } = string.Empty;
|
||
|
||
/// <summary>
|
||
/// 视频封面(已废弃,保留字段避免数据库迁移问题)
|
||
/// </summary>
|
||
[StringLength(500)]
|
||
public string VideoCover { get; set; } = string.Empty;
|
||
|
||
[StringLength(1000)]
|
||
public string Description { get; set; } = string.Empty;
|
||
|
||
public string Content { get; set; } = string.Empty;
|
||
|
||
/// <summary>
|
||
/// 平台标签(逗号分隔)
|
||
/// </summary>
|
||
[StringLength(200)]
|
||
public string Platforms { get; set; } = string.Empty;
|
||
|
||
public ProjectStatus Status { get; set; } = ProjectStatus.Offline;
|
||
|
||
/// <summary>
|
||
/// 是否推荐(已废弃,保留字段避免数据库迁移问题)
|
||
/// </summary>
|
||
public bool IsFeatured { get; set; } = false;
|
||
|
||
/// <summary>
|
||
/// 排序值(已废弃,保留字段避免数据库迁移问题)
|
||
/// </summary>
|
||
public int SortOrder { get; set; } = 0;
|
||
|
||
public int ViewCount { get; set; } = 0;
|
||
|
||
public int ExperienceCount { get; set; } = 0;
|
||
|
||
public int FavoriteCount { get; set; } = 0;
|
||
|
||
public DateTime? PublishedAt { get; set; }
|
||
|
||
[ForeignKey(nameof(CategoryId))]
|
||
public ProjectCategory? Category { get; set; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 项目分类表
|
||
/// </summary>
|
||
public class ProjectCategory : BaseEntity
|
||
{
|
||
[Required, StringLength(50)]
|
||
public string Name { get; set; } = string.Empty;
|
||
|
||
[StringLength(500)]
|
||
public string Icon { get; set; } = string.Empty;
|
||
|
||
public int SortOrder { get; set; } = 0;
|
||
|
||
public UserStatus Status { get; set; } = UserStatus.Active;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 平台类型表
|
||
/// </summary>
|
||
public class PlatformType : BaseEntity
|
||
{
|
||
[Required, StringLength(50)]
|
||
public string Name { get; set; } = string.Empty;
|
||
|
||
[StringLength(500)]
|
||
public string Icon { get; set; } = string.Empty;
|
||
|
||
public int SortOrder { get; set; } = 0;
|
||
|
||
public UserStatus Status { get; set; } = UserStatus.Active;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 特性标签表
|
||
/// </summary>
|
||
public class FeatureTag : BaseEntity
|
||
{
|
||
[Required, StringLength(50)]
|
||
public string Name { get; set; } = string.Empty;
|
||
|
||
[StringLength(500)]
|
||
public string Icon { get; set; } = string.Empty;
|
||
|
||
public int SortOrder { get; set; } = 0;
|
||
|
||
public UserStatus Status { get; set; } = UserStatus.Active;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 项目标签关联表
|
||
/// </summary>
|
||
public class ProjectTagRelation : BaseEntity
|
||
{
|
||
public long ProjectId { get; set; }
|
||
|
||
public long TagId { get; set; }
|
||
|
||
[ForeignKey(nameof(ProjectId))]
|
||
public Project? Project { get; set; }
|
||
|
||
[ForeignKey(nameof(TagId))]
|
||
public FeatureTag? Tag { get; set; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 项目截图表(已废弃,保留表避免数据库迁移问题,不再使用)
|
||
/// </summary>
|
||
public class ProjectScreenshot : BaseEntity
|
||
{
|
||
public long ProjectId { get; set; }
|
||
|
||
[StringLength(500)]
|
||
public string Url { get; set; } = string.Empty;
|
||
|
||
public int SortOrder { get; set; } = 0;
|
||
|
||
[ForeignKey(nameof(ProjectId))]
|
||
public Project? Project { get; set; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 项目资源包表
|
||
/// </summary>
|
||
public class ProjectPackage : BaseEntity
|
||
{
|
||
public long ProjectId { get; set; }
|
||
|
||
public PackageType Type { get; set; }
|
||
|
||
/// <summary>
|
||
/// 原始文件名(上传时的文件名,非重命名后的对象键)
|
||
/// </summary>
|
||
[StringLength(255)]
|
||
public string FileName { get; set; } = string.Empty;
|
||
|
||
[StringLength(500)]
|
||
public string Url { get; set; } = string.Empty;
|
||
|
||
public long FileSize { get; set; }
|
||
|
||
/// <summary>
|
||
/// 唤醒协议前缀(固定为 millisim,Android/PC 平台使用)
|
||
/// </summary>
|
||
[StringLength(50)]
|
||
public string WakeProtocolPrefix { get; set; } = string.Empty;
|
||
|
||
/// <summary>
|
||
/// 唤醒协议参数(Android/PC 平台使用,用户输入)
|
||
/// </summary>
|
||
[StringLength(500)]
|
||
public string WakeProtocolParam { get; set; } = string.Empty;
|
||
|
||
/// <summary>
|
||
/// WebGL 解压后的根路径对象键(仅 WebGL 类型使用,用于在线运行)
|
||
/// </summary>
|
||
[StringLength(500)]
|
||
public string ExtractedPath { get; set; } = string.Empty;
|
||
|
||
[ForeignKey(nameof(ProjectId))]
|
||
public Project? Project { get; set; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 收藏表
|
||
/// </summary>
|
||
public class Favorite : BaseEntity
|
||
{
|
||
public long UserId { get; set; }
|
||
|
||
public long ProjectId { get; set; }
|
||
|
||
[ForeignKey(nameof(UserId))]
|
||
public User? User { get; set; }
|
||
|
||
[ForeignKey(nameof(ProjectId))]
|
||
public Project? Project { get; set; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 体验记录表
|
||
/// </summary>
|
||
public class ExperienceLog : BaseEntity
|
||
{
|
||
public long UserId { get; set; }
|
||
|
||
public long ProjectId { get; set; }
|
||
|
||
public int DurationSeconds { get; set; }
|
||
|
||
[ForeignKey(nameof(UserId))]
|
||
public User? User { get; set; }
|
||
|
||
[ForeignKey(nameof(ProjectId))]
|
||
public Project? Project { get; set; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 授权记录表(客户级授权,授权后可运行所有项目)
|
||
/// </summary>
|
||
public class Authorization : BaseEntity
|
||
{
|
||
public long UserId { get; set; }
|
||
|
||
/// <summary>
|
||
/// 项目 ID(已废弃,改为客户级授权,保留字段避免数据库迁移问题)
|
||
/// </summary>
|
||
public long? ProjectId { get; set; }
|
||
|
||
public long AuthorizedBy { get; set; }
|
||
|
||
public DateTime StartTime { get; set; } = DateTime.Now;
|
||
|
||
public DateTime EndTime { get; set; }
|
||
|
||
public AuthorizationStatus Status { get; set; } = AuthorizationStatus.Active;
|
||
|
||
[ForeignKey(nameof(UserId))]
|
||
public User? User { get; set; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 轮播图表
|
||
/// </summary>
|
||
public class Banner : BaseEntity
|
||
{
|
||
[StringLength(100)]
|
||
public string Title { get; set; } = string.Empty;
|
||
|
||
[Required, StringLength(500)]
|
||
public string Image { get; set; } = string.Empty;
|
||
|
||
[StringLength(500)]
|
||
public string Link { get; set; } = string.Empty;
|
||
|
||
public int SortOrder { get; set; } = 0;
|
||
|
||
public UserStatus Status { get; set; } = UserStatus.Active;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 合作伙伴表
|
||
/// </summary>
|
||
public class Partner : BaseEntity
|
||
{
|
||
[Required, StringLength(100)]
|
||
public string Name { get; set; } = string.Empty;
|
||
|
||
[Required, StringLength(500)]
|
||
public string Logo { get; set; } = string.Empty;
|
||
|
||
[StringLength(500)]
|
||
public string Link { get; set; } = string.Empty;
|
||
|
||
public int SortOrder { get; set; } = 0;
|
||
|
||
public bool IsVisible { get; set; } = true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 咨询消息表
|
||
/// </summary>
|
||
public class Consultation : BaseEntity
|
||
{
|
||
[Required, StringLength(50)]
|
||
public string Name { get; set; } = string.Empty;
|
||
|
||
[Required, StringLength(20)]
|
||
public string Contact { get; set; } = string.Empty;
|
||
|
||
[StringLength(1000)]
|
||
public string Content { get; set; } = string.Empty;
|
||
|
||
public bool IsRead { get; set; } = false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通知表
|
||
/// </summary>
|
||
public class Notification : BaseEntity
|
||
{
|
||
public NotificationType Type { get; set; }
|
||
|
||
[Required, StringLength(200)]
|
||
public string Title { get; set; } = string.Empty;
|
||
|
||
[StringLength(1000)]
|
||
public string Content { get; set; } = string.Empty;
|
||
|
||
public long? UserId { get; set; }
|
||
|
||
/// <summary>
|
||
/// 业务事件 ID(防重复)
|
||
/// </summary>
|
||
[StringLength(100)]
|
||
public string? EventId { get; set; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通知已读记录表
|
||
/// </summary>
|
||
public class NotificationRead : BaseEntity
|
||
{
|
||
public long UserId { get; set; }
|
||
|
||
public long NotificationId { get; set; }
|
||
|
||
[ForeignKey(nameof(NotificationId))]
|
||
public Notification? Notification { get; set; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 操作日志表
|
||
/// </summary>
|
||
public class OperationLog : BaseEntity
|
||
{
|
||
public long UserId { get; set; }
|
||
|
||
[StringLength(50)]
|
||
public string Username { get; set; } = string.Empty;
|
||
|
||
[StringLength(50)]
|
||
public string Module { get; set; } = string.Empty;
|
||
|
||
[StringLength(50)]
|
||
public string Operation { get; set; } = string.Empty;
|
||
|
||
[StringLength(1000)]
|
||
public string Detail { get; set; } = string.Empty;
|
||
|
||
[StringLength(50)]
|
||
public string Ip { get; set; } = string.Empty;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 系统设置表
|
||
/// </summary>
|
||
public class SystemSetting : BaseEntity
|
||
{
|
||
[Required, StringLength(100)]
|
||
public string Key { get; set; } = string.Empty;
|
||
|
||
[Column(TypeName = "longtext")]
|
||
public string Value { get; set; } = string.Empty;
|
||
|
||
[StringLength(200)]
|
||
public string Description { get; set; } = string.Empty;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 备份记录表
|
||
/// </summary>
|
||
public class Backup : BaseEntity
|
||
{
|
||
[Required, StringLength(200)]
|
||
public string FileName { get; set; } = string.Empty;
|
||
|
||
public long FileSize { get; set; }
|
||
|
||
[StringLength(20)]
|
||
public string Type { get; set; } = "Manual";
|
||
|
||
[StringLength(500)]
|
||
public string Url { get; set; } = string.Empty;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 唤醒协议配置表
|
||
/// </summary>
|
||
public class WakeProtocol : BaseEntity
|
||
{
|
||
[Required, StringLength(50)]
|
||
public string TerminalType { get; set; } = string.Empty;
|
||
|
||
[Required, StringLength(200)]
|
||
public string ProtocolPrefix { get; set; } = string.Empty;
|
||
|
||
[Column(TypeName = "text")]
|
||
public string ParamTemplate { get; set; } = string.Empty;
|
||
|
||
public UserStatus Status { get; set; } = UserStatus.Active;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 待消费上传文件记录(用于垃圾资源清理跟踪)
|
||
/// </summary>
|
||
public class PendingUpload : BaseEntity
|
||
{
|
||
/// <summary>COS 对象键或本地访问 URL</summary>
|
||
[Required, StringLength(500)]
|
||
public string ObjectKey { get; set; } = string.Empty;
|
||
|
||
/// <summary>上传目录(icons/videos/logos/packages 等)</summary>
|
||
[StringLength(50)]
|
||
public string Folder { get; set; } = string.Empty;
|
||
|
||
/// <summary>上传者用户 ID</summary>
|
||
public long? UploadedBy { get; set; }
|
||
|
||
/// <summary>上传时间</summary>
|
||
public DateTime UploadedAt { get; set; } = DateTime.Now;
|
||
|
||
/// <summary>消费时间(null=待消费,非null=已保存到实体)</summary>
|
||
public DateTime? ConsumedAt { get; set; }
|
||
}
|