using Model.Entity.System; using ORM; namespace Service.Implement { /// /// RBAC 数据种子:预定义 4 个系统角色 + 6 个权限 + 默认管理员账号(admin/admin123) /// 幂等:按 Code 查存在性,存在则跳过;可重复执行 /// public static class DataSeeder { /// 数据范围:1=全部, 2=本实验室 public const byte DataScopeAll = 1; public const byte DataScopeLab = 2; /// 7 个系统权限编码 public static readonly (string Code, string Name, string Group)[] Permissions = { ("device:view", "查看设备", "device"), ("device:edit", "编辑设备", "device"), ("device:control", "控制设备", "device"), ("alert:confirm", "确认告警", "alert"), ("inspection:manage", "巡检管理", "inspection"), ("user:manage", "用户管理", "user"), ("system:manage", "系统配置管理", "system") }; /// /// 4 个预定义角色:超级管理员(全部) / 实验室管理员(本实验室) / 设备操作员(本实验室) / 维修工程师(本实验室) /// 权限矩阵严格按需求文档 /// public static readonly (string Code, string Name, byte DataScope, string[] Permissions)[] Roles = { ("superadmin", "超级管理员", DataScopeAll, new[] { "device:view", "device:edit", "device:control", "alert:confirm", "inspection:manage", "user:manage", "system:manage" }), ("labadmin", "实验室管理员", DataScopeLab, new[] { "device:view", "device:edit", "device:control", "alert:confirm", "inspection:manage", "system:manage" }), ("operator", "设备操作员", DataScopeLab, new[] { "device:view", "inspection:manage" }), ("maintengineer", "维修工程师", DataScopeLab, new[] { "device:view", "device:edit", "device:control", "alert:confirm" }) }; public static void Seed() { try { var db = SqlSugarContext.DbContext; var now = DateTime.Now; // 1. 权限种子 var permIdByCode = new Dictionary(); foreach (var (code, name, group) in Permissions) { var existing = db.Queryable().Where(x => x.Code == code).First(); if (existing != null) { permIdByCode[code] = existing.Id; continue; } var perm = new PermissionEntity { Code = code, Name = name, Group = group, IsSystem = 1, Sort = Array.FindIndex(Permissions, p => p.Code == code), CreateTime = now }; var id = db.Insertable(perm).ExecuteReturnSnowflakeId(); permIdByCode[code] = id; } // 2. 角色种子 + 角色-权限关联 foreach (var (code, name, scope, perms) in Roles) { var role = db.Queryable().Where(x => x.Code == code).First(); long roleId; if (role == null) { role = new RoleEntity { Code = code, Name = name, DataScope = scope, IsSystem = 1, Sort = Array.FindIndex(Roles, r => r.Code == code), Remark = "系统预定义角色", CreateTime = now }; roleId = db.Insertable(role).ExecuteReturnSnowflakeId(); } else { roleId = role.Id; } // 补齐角色-权限关联(只加不删,避免覆盖管理员自定义调整) foreach (var permCode in perms) { if (!permIdByCode.TryGetValue(permCode, out var permId)) continue; var linkExists = db.Queryable() .Where(x => x.RoleId == roleId && x.PermissionId == permId).Any(); if (!linkExists) { db.Insertable(new RolePermissionEntity { RoleId = roleId, PermissionId = permId, CreateTime = now }).ExecuteCommand(); } } } // 3. 默认管理员账号(admin/admin123,挂在超级管理员角色) var adminExists = db.Queryable().Where(x => x.UserName == "admin" && x.IsDel == 0).Any(); if (!adminExists) { var superAdmin = db.Queryable().Where(x => x.Code == "superadmin").First(); var admin = new UserEntity { UserName = "admin", PasswordHash = PasswordHelper.Hash("admin123"), RealName = "系统管理员", IsEnabled = 1, Remark = "系统默认管理员(首次登录后请修改密码)", CreateTime = now }; var adminId = db.Insertable(admin).ExecuteReturnSnowflakeId(); if (superAdmin != null) { db.Insertable(new UserRoleEntity { UserId = adminId, RoleId = superAdmin.Id, CreateTime = now }).ExecuteCommand(); } } // 4. 系统参数种子(一期 4 个内置参数,幂等:按 ParamKey 跳过已存在) SeedSystemParams(db, now); // 5. 默认本地文件存储配置(幂等:仅当无任何配置时插入一条默认 Local 通道) SeedDefaultFileStorage(db, now); } catch (Exception) { // 种子失败不阻断启动(例如表刚建好并发场景),下次启动会重试 throw; } } private static void SeedDefaultFileStorage(SqlSugar.ISqlSugarClient db, DateTime now) { var hasAny = db.Queryable().Where(x => x.IsDel == 0).Any(); if (hasAny) return; var entity = new FileStorageConfigEntity { Provider = "local", Name = "本地存储", Endpoint = "/uploads", AccessKey = null, SecretKey = null, Bucket = null, Region = null, BasePath = "wwwroot/uploads", MaxSizeMB = 10, AllowedExts = null, // 不限制扩展名;如需限制填 [".jpg",".png",".pdf",".xlsx"] IsDefault = 1, Status = 1, Remark = "系统默认本地存储通道(文件落 wwwroot/uploads,通过 /uploads 静态访问)", CreateTime = now }; db.Insertable(entity).ExecuteReturnSnowflakeId(); } /// 一期 4 个内置系统参数(IsSystem=1,禁止删除,仅允许改 Value/Remark) /// Group 与 ParamType 约定:0=int,1=text,2=enum,3=json private static readonly (string Key, string Name, string? Value, byte Type, string? Options, string? Unit, string Group, int Sort, string? Remark)[] SystemParams = { ("data_collect_default_frequency", "数据采集默认频率", "5", 0, null, "秒", "数据采集", 1, "设备数据采集的默认间隔(秒),新建设备时作为默认值"), ("alert_notify_method", "告警通知方式", "feishu", 2, "[{\"value\":\"feishu\",\"label\":\"飞书\"},{\"value\":\"dingtalk\",\"label\":\"钉钉\"},{\"value\":\"wecom\",\"label\":\"企业微信\"},{\"value\":\"email\",\"label\":\"邮件\"}]", null, "告警", 2, "默认告警通知渠道(多选需在告警规则内单独配置)"), ("work_order_code_rule", "工单编号规则", "WO{yyyyMMddHHmmss}", 1, null, null, "工单", 3, "工单编号生成模板,支持占位符:{yyyy}年 {MM}月 {dd}日 {HH}时 {mm}分 {ss}秒,序列号用 {seq4} 表示 4 位顺序号"), ("file_upload_limit", "文件上传限制", "10", 2, "[{\"value\":\"5\",\"label\":\"5MB\"},{\"value\":\"10\",\"label\":\"10MB\"},{\"value\":\"20\",\"label\":\"20MB\"},{\"value\":\"50\",\"label\":\"50MB\"}]", "MB", "文件", 4, "单个文件上传大小上限(MB)") }; private static void SeedSystemParams(SqlSugar.ISqlSugarClient db, DateTime now) { foreach (var (key, name, value, type, options, unit, group, sort, remark) in SystemParams) { var exists = db.Queryable().Where(x => x.ParamKey == key).Any(); if (exists) continue; var entity = new SystemParamEntity { ParamKey = key, ParamName = name, ParamValue = value, ParamType = type, ParamOptions = options, Unit = unit, Group = group, Sort = sort, Remark = remark, IsSystem = 1, LastUpdateUser = "system", LastUpdateTime = now, CreateTime = now }; db.Insertable(entity).ExecuteReturnSnowflakeId(); } } } }