diff --git a/Magic.Application/Entity/JobhuntMessage.cs b/Magic.Application/Entity/JobhuntMessage.cs new file mode 100644 index 0000000..f5a65ea --- /dev/null +++ b/Magic.Application/Entity/JobhuntMessage.cs @@ -0,0 +1,47 @@ +using System; +using SqlSugar; +using System.ComponentModel; +using Magic.Core.Entity; +namespace Magic.Application.Entity +{ + /// + /// 求职信息 + /// + [SugarTable("jobhunt_message")] + [Description("求职信息")] + public class JobhuntMessage : DEntityBase + { + /// + /// 租户Id + /// + public long TenantId { get; set; } + /// + /// 求职详情 + /// + public string PositionInfo { get; set; } + /// + /// 求职标题 + /// + public string Title { get; set; } + /// + /// 求职状态 + /// + public int Status { get; set; } + /// + /// 经验 + /// + public int Experience { get; set; } + /// + /// 标签 + /// + public string Tag { get; set; } + /// + /// 省份 + /// + public int ProvinceId { get; set; } + /// + /// 城市 + /// + public int CityId { get; set; } + } +} \ No newline at end of file diff --git a/Magic.Application/Entity/RecruitMessage.cs b/Magic.Application/Entity/RecruitMessage.cs new file mode 100644 index 0000000..55eddd9 --- /dev/null +++ b/Magic.Application/Entity/RecruitMessage.cs @@ -0,0 +1,63 @@ +using System; +using SqlSugar; +using System.ComponentModel; +using Magic.Core.Entity; +namespace Magic.Application.Entity +{ + /// + /// 招聘消息 + /// + [SugarTable("recruit_message")] + [Description("招聘消息")] + public class RecruitMessage : DEntityBase + { + /// + /// 租户Id + /// + public long TenantId { get; set; } + /// + /// 职位详情 + /// + public string PositionInfo { get; set; } + /// + /// 标题 + /// + public string Title { get; set; } + /// + /// 状态 + /// + public int Status { get; set; } + /// + /// 省份 + /// + public int ProvinceId { get; set; } + /// + /// 城市 + /// + public int CityId { get; set; } + /// + /// 区 + /// + public int AreaId { get; set; } + /// + /// 详细地址 + /// + public int Address { get; set; } + /// + /// 联系电话 + /// + public string Phone { get; set; } + /// + /// 标签 + /// + public string Tag { get; set; } + /// + /// 学历 + /// + public int Education { get; set; } + /// + /// 经验 + /// + public int Experience { get; set; } + } +} \ No newline at end of file diff --git a/Magic.Application/Entity/SysArea.cs b/Magic.Application/Entity/SysArea.cs new file mode 100644 index 0000000..8da7543 --- /dev/null +++ b/Magic.Application/Entity/SysArea.cs @@ -0,0 +1,24 @@ +using System; +using SqlSugar; +using System.ComponentModel; +using Magic.Core.Entity; +namespace Magic.Application.Entity +{ + /// + /// 系统地区数据 + /// + [SugarTable("sys_area")] + [Description("系统地区数据")] + public class SysArea : AutoIncrementEntity + { + + /// + /// 父级ID + /// + public Int16 parent_id { get; set; } + /// + /// 地区名 + /// + public string name { get; set; } + } +} \ No newline at end of file diff --git a/Magic.Application/Magic.Application.csproj b/Magic.Application/Magic.Application.csproj new file mode 100644 index 0000000..91a5fc4 --- /dev/null +++ b/Magic.Application/Magic.Application.csproj @@ -0,0 +1,29 @@ + + + + net7.0 + 1701;1702;1591 + Magic.Application.xml + + + + + + + + + + PreserveNewest + + + + + + + + + + + + + diff --git a/Magic.Application/Magic.Application.xml b/Magic.Application/Magic.Application.xml new file mode 100644 index 0000000..3f6f27c --- /dev/null +++ b/Magic.Application/Magic.Application.xml @@ -0,0 +1,133 @@ + + + + Magic.Application + + + + + 求职信息 + + + + + 租户Id + + + + + 求职详情 + + + + + 求职标题 + + + + + 求职状态 + + + + + 经验 + + + + + 标签 + + + + + 省份 + + + + + 城市 + + + + + 招聘消息 + + + + + 租户Id + + + + + 职位详情 + + + + + 标题 + + + + + 状态 + + + + + 省份 + + + + + 城市 + + + + + 区 + + + + + 详细地址 + + + + + 联系电话 + + + + + 标签 + + + + + 学历 + + + + + 经验 + + + + + 系统地区数据 + + + + + 父级ID + + + + + 地区名 + + + + diff --git a/Magic.Application/README.md b/Magic.Application/README.md new file mode 100644 index 0000000..11a79cd --- /dev/null +++ b/Magic.Application/README.md @@ -0,0 +1,3 @@ +1、原则上服务应该放在Application层次,考虑将咱自己的业务层直接写在Application里面好些,后续升级后,咱大家直接升级就行了,减少冲突! +2、系统默认ORM为EF Core,如果觉得不趁手,可以自行更换 +3、在此应用层默认集成了SqlSugar,其他ORM类同,可以多个ORM并行开发,熟悉哪个用哪个 diff --git a/Magic.Application/Service/Test/ITestService.cs b/Magic.Application/Service/Test/ITestService.cs new file mode 100644 index 0000000..d842f76 --- /dev/null +++ b/Magic.Application/Service/Test/ITestService.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Magic.Application.Service; + +public interface ITestService +{ + Task TestChangeDatabase(); +} diff --git a/Magic.Application/Service/Test/TestService.cs b/Magic.Application/Service/Test/TestService.cs new file mode 100644 index 0000000..ba57fa6 --- /dev/null +++ b/Magic.Application/Service/Test/TestService.cs @@ -0,0 +1,80 @@ +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Furion.FriendlyException; +using Furion.JsonSerialization; +using Furion.Logging.Extensions; +using Magic.Core; +using Magic.Core.Entity; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Text.Json; +using System.Threading.Tasks; + +namespace Magic.Application.Service; + +[ApiDescriptionSettings("Application",Name = "Test", Order = 1)] +public class TestService : ITestService, IDynamicApiController, ITransient +{ + private readonly SqlSugarRepository _userRep; + + public TestService(SqlSugarRepository userRep) + { + _userRep=userRep; + } + + [AllowAnonymous] + public void TestDatabaseChange() { + Type[] types = new Type[] { typeof(SysUser) }; + var diffString = _userRep.Context.CodeFirst.GetDifferenceTables(types).ToDiffList(); + Console.Write(diffString); + } + + + [HttpGet("/test/TestChangeDatabase")] + [AllowAnonymous] + public async Task TestChangeDatabase() + { + var user = await _userRep.ToListAsync(); + + _userRep.CurrentBeginTran(); + _userRep.CurrentCommitTran(); + + } + + [AllowAnonymous] + public async Task JsonSerializerTest(string json) { + string us = UserManager.Account; + var sq = JsonSerializer.Deserialize(json); + var ss= Newtonsoft.Json.JsonConvert.DeserializeObject(json); + var s = JSON.Deserialize(json); + return s; + } + + [LoggingMonitor] + public void TestLog() + { + throw Oops.Bah($"业务异常{DateTime.Now}"); + + } + [AllowAnonymous] + public void TestLog2() + { + Student student = null; + student.FirstName = "hahah"; + + } + + [NonUnify] + public void TestLogInfo() + { + $"info日志{DateTime.Now}".LogInformation(); + } + +} + +public class Student { + public string FirstName { get; set; } + + public int RealAge { get; set; } +} \ No newline at end of file diff --git a/Magic.Application/Startup.cs b/Magic.Application/Startup.cs new file mode 100644 index 0000000..e32791e --- /dev/null +++ b/Magic.Application/Startup.cs @@ -0,0 +1,12 @@ +using Furion; +using Microsoft.Extensions.DependencyInjection; + +namespace Magic.Application; + +public class Startup : AppStartup +{ + public void ConfigureServices(IServiceCollection services) + { + + } +} diff --git a/Magic.Application/applicationsettings.json b/Magic.Application/applicationsettings.json new file mode 100644 index 0000000..19682d9 --- /dev/null +++ b/Magic.Application/applicationsettings.json @@ -0,0 +1,3 @@ +{ + +} \ No newline at end of file diff --git a/Magic.CodeFirst/Magic.CodeFirst.csproj b/Magic.CodeFirst/Magic.CodeFirst.csproj new file mode 100644 index 0000000..6bb0c8e --- /dev/null +++ b/Magic.CodeFirst/Magic.CodeFirst.csproj @@ -0,0 +1,14 @@ + + + + Exe + net7.0 + enable + enable + + + + + + + diff --git a/Magic.CodeFirst/Program.cs b/Magic.CodeFirst/Program.cs new file mode 100644 index 0000000..59eba81 --- /dev/null +++ b/Magic.CodeFirst/Program.cs @@ -0,0 +1,223 @@ +// See https://aka.ms/new-console-template for more information + + + + +using Magic.CodeFirst; +using Magic.Core; +using Magic.Core.Entity; +using Microsoft.Extensions.Configuration; +using SqlSugar; +using System.Collections; +using System.Data; +using System.Reflection; +using System.Text; + + + + +var assembles = new string[] { "Magic.FlowCenter.dll", "Magic.Core.dll" }; +//首先创建数据库 +CreateDatabase(); +//初始化表结构 +InitDatabase(assembles); +//插入种子数据 +InsertData(); +Console.WriteLine("数据库迁移成功"); +Console.ReadLine(); + + +static void CreateDatabase() { + var conn = SqlSugarHelper.GetSetting(); + SqlSugarHelper.Db().GetConnectionScope(conn.DefaultDbNumber).DbMaintenance.CreateDatabase(); + foreach (var item in conn.DbConfigs) + { + if (item.DbType != SqlSugar.DbType.Oracle.ToString()) + SqlSugarHelper.Db().GetConnectionScope(item.DbNumber).DbMaintenance.CreateDatabase(); + } +} + + +static void InitDatabase(string[] assembles) { + var conn = SqlSugarHelper.GetSetting(); + var configIds = new List(); + configIds.Add(conn.DefaultDbNumber); + foreach (var item in conn.DbConfigs) + { + configIds.Add(item.DbNumber); + } + + foreach (var item in assembles) + { + Type[] types = Assembly + .LoadFrom(item)//如果 .dll报错,可以换成 xxx.exe 有些生成的是exe + .GetTypes() + .Where(m => m.GetCustomAttribute() != null && m.Name != "FlcFlowinstanceOutput") + .ToArray(); + + foreach (Type type in types) { + if (type.GetCustomAttribute() == null) + { + SqlSugarHelper.Db().CodeFirst.InitTables(type); + } + else { + SqlSugarHelper.Db().GetConnectionScope(type.GetCustomAttribute().configId).CodeFirst.InitTables(type); + } + } + + //SqlSugarHelper.Db().CodeFirst.InitTables(types); + + Console.WriteLine($"数据库{item}创建成功"); + } + + + +} + + +static void CreateSeedData(string[] assembles) +{ + foreach (var item in assembles) + { + Type[] types = Assembly + .LoadFrom(item)//如果 .dll报错,可以换成 xxx.exe 有些生成的是exe + .GetTypes() + .Where(m => m.GetCustomAttribute() != null && m.Name != "FlcFlowinstanceOutput") + .ToArray(); + + //Get type of Worker + SelectTable worker = new SelectTable(); + + //Get type of Worker + Type workerType = typeof(SelectTable); + + //Get Generic Method + MethodInfo staticDoWorkMethod = workerType.GetMethod("GetAll"); + + //Invoke StaticDoWork + foreach (Type curType in types) + { + if (curType.IsClass && !curType.IsAbstract) + { + MethodInfo curMethod = staticDoWorkMethod.MakeGenericMethod(curType); + var list = curMethod.Invoke(null, null); + if (list == null) continue; + var path = Path.Combine(@"D:\Workspace\admin-net-sqlsugar\backend\Magic.CodeFirst\SeedData", $"{curType.Name}SeedData.cs"); + + + if (File.Exists(path)) + File.Delete(path); + + FileStream fs = new FileStream(path, FileMode.CreateNew, FileAccess.ReadWrite); + StreamWriter sw = new StreamWriter(fs); + StringBuilder sb = new StringBuilder($@"using Magic.Core; +using Magic.Core.Entity; + +namespace Magic.CodeFirst; + +public class {curType.Name}SeedData : ISeedData , ISqlSugarEntitySeedData<{curType.Name}> +{{ public IEnumerable<{curType.Name}> HasData() + {{ string json = @"""); + sb.AppendLine(JsonUtil.ToJsonString(list).Replace(@"""", @"""""")); + sb.AppendLine(@""";"); + + sb.AppendLine($@" List<{curType.Name}> list = JsonUtil.ToObject>(json); + + return list;"); + sb.AppendLine(@"}}"); + sw.Write(sb.ToString()); + sw.Flush(); + sw.Close(); + + }; + } + } + + +} + + + + + +static void InsertData() +{ + var baseType = typeof(ISeedData); + var path = AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory; + var referencedAssemblies = System.IO.Directory.GetFiles(path, "Magic.CodeFirst.dll").Select(Assembly.LoadFrom).ToArray(); + var seedDataTypes = referencedAssemblies + .SelectMany(a => a.DefinedTypes) + .Select(type => type.AsType()) + .Where(x => x != baseType && baseType.IsAssignableFrom(x)).ToArray(); + + foreach (var seedType in seedDataTypes) + { + var instance = Activator.CreateInstance(seedType); + + var hasDataMethod = seedType.GetMethod("HasData"); + var seedData = ((IEnumerable)hasDataMethod?.Invoke(instance, null))?.Cast(); + if (seedData == null) continue; + + var entityType = seedType.GetInterfaces().First().GetGenericArguments().First(); + + var seedDataTable = seedData.ToList().ToDataTable(); + seedDataTable.TableName = SqlSugarHelper.Db().EntityMaintenance.GetEntityInfo(entityType).DbTableName; + + var storage = SqlSugarHelper.Db().Storageable(seedDataTable).ToStorage(); + storage.AsInsertable.ExecuteCommand(); + } +} + + +public static class ObjectExtension +{ + public static DataTable ToDataTable(this List list) + { + DataTable result = new(); + if (list.Count > 0) + { + // result.TableName = list[0].GetType().Name; // 表名赋值 + PropertyInfo[] propertys = list[0].GetType().GetProperties(); + foreach (PropertyInfo pi in propertys) + { + Type colType = pi.PropertyType; + if (colType.IsGenericType && colType.GetGenericTypeDefinition() == typeof(Nullable<>)) + { + colType = colType.GetGenericArguments()[0]; + } + if (IsIgnoreColumn(pi)) + continue; + result.Columns.Add(pi.Name, colType); + } + for (int i = 0; i < list.Count; i++) + { + ArrayList tempList = new(); + foreach (PropertyInfo pi in propertys) + { + if (IsIgnoreColumn(pi)) + continue; + object obj = pi.GetValue(list[i], null); + tempList.Add(obj); + } + object[] array = tempList.ToArray(); + result.LoadDataRow(array, true); + } + } + return result; + } + + private static bool IsIgnoreColumn(PropertyInfo pi) + { + var sc = pi.GetCustomAttributes(false).FirstOrDefault(u => u.IsIgnore == true); + return sc != null; + } +} + +public class SelectTable +{ + public static List GetAll() + { + var list = SqlSugarHelper.Db().Queryable().ToList(); + return list.Any() ? list : null; + } +} \ No newline at end of file diff --git a/Magic.CodeFirst/SeedData/DocumentationSeedData.cs b/Magic.CodeFirst/SeedData/DocumentationSeedData.cs new file mode 100644 index 0000000..1e67a2d --- /dev/null +++ b/Magic.CodeFirst/SeedData/DocumentationSeedData.cs @@ -0,0 +1,13 @@ +using Magic.Core; +using Magic.Core.Entity; + +namespace Magic.CodeFirst; + +public class DocumentationSeedData : ISeedData , ISqlSugarEntitySeedData +{ public IEnumerable HasData() + { string json = @"[{""PId"":0,""PIds"":null,""Name"":""新建文件夹"",""DocumentType"":1,""FileSuffix"":null,""FileSizeKb"":null,""FilePath"":null,""FileObjectName"":null,""Label"":3,""Remark"":null,""Visible"":true,""Children"":null,""CreatedTime"":""2022-04-27T11:15:12.403"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":282067396128837},{""PId"":282067396128837,""PIds"":null,""Name"":""logo.png"",""DocumentType"":2,""FileSuffix"":"".png"",""FileSizeKb"":25,""FilePath"":""Upload/Document/2022/4/27"",""FileObjectName"":""282067842687045.png"",""Label"":null,""Remark"":null,""Visible"":true,""Children"":null,""CreatedTime"":""2022-04-27T11:17:01.427"",""UpdatedTime"":""2022-04-27T11:20:46.45"",""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":282067842687046},{""PId"":282067396128837,""PIds"":null,""Name"":""呃呃呃"",""DocumentType"":1,""FileSuffix"":null,""FileSizeKb"":null,""FilePath"":null,""FileObjectName"":null,""Label"":3,""Remark"":null,""Visible"":true,""Children"":null,""CreatedTime"":""2022-04-27T11:21:14.207"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":282068878082117}] +"; + List list = JsonUtil.ToObject>(json); + + return list; +}} diff --git a/Magic.CodeFirst/SeedData/ISqlSugarEntitySeedData.cs b/Magic.CodeFirst/SeedData/ISqlSugarEntitySeedData.cs new file mode 100644 index 0000000..a936b06 --- /dev/null +++ b/Magic.CodeFirst/SeedData/ISqlSugarEntitySeedData.cs @@ -0,0 +1,17 @@ +namespace Magic.CodeFirst; + +/// +/// 实体种子数据接口 +/// +/// +public interface ISqlSugarEntitySeedData + where TEntity : class, new() +{ + /// + /// 种子数据 + /// + /// + IEnumerable HasData(); +} + +public class ISeedData { } \ No newline at end of file diff --git a/Magic.CodeFirst/SeedData/SysAppSeedData.cs b/Magic.CodeFirst/SeedData/SysAppSeedData.cs new file mode 100644 index 0000000..7e64dfb --- /dev/null +++ b/Magic.CodeFirst/SeedData/SysAppSeedData.cs @@ -0,0 +1,13 @@ +using Magic.Core; +using Magic.Core.Entity; + +namespace Magic.CodeFirst; + +public class SysAppSeedData : ISeedData , ISqlSugarEntitySeedData +{ public IEnumerable HasData() + { string json = @"[{""Name"":""平台管理"",""Code"":""system"",""Active"":""Y"",""Status"":0,""Sort"":100,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070898245},{""Name"":""系统管理"",""Code"":""manage"",""Active"":""N"",""Status"":0,""Sort"":300,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902341},{""Name"":""运营管理"",""Code"":""platform"",""Active"":""N"",""Status"":0,""Sort"":200,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922826},{""Name"":""业务应用"",""Code"":""busiapp"",""Active"":""N"",""Status"":0,""Sort"":400,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922869},{""Name"":""流程中心"",""Code"":""flowcenter"",""Active"":""N"",""Status"":0,""Sort"":500,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":246681684324421}] +"; + List list = JsonUtil.ToObject>(json); + + return list; +}} diff --git a/Magic.CodeFirst/SeedData/SysCodeGenConfigSeedData.cs b/Magic.CodeFirst/SeedData/SysCodeGenConfigSeedData.cs new file mode 100644 index 0000000..77dbf5b --- /dev/null +++ b/Magic.CodeFirst/SeedData/SysCodeGenConfigSeedData.cs @@ -0,0 +1,13 @@ +using Magic.Core; +using Magic.Core.Entity; + +namespace Magic.CodeFirst; + +public class SysCodeGenConfigSeedData : ISeedData , ISqlSugarEntitySeedData +{ public IEnumerable HasData() + { string json = @"[{""CodeGenId"":291946907033669,""ColumnName"":""Id"",""ColumnComment"":""主键Id"",""NetType"":""long"",""EffectType"":""input"",""FkEntityName"":null,""FkColumnName"":null,""FkColumnNetType"":null,""DictTypeCode"":null,""WhetherRetract"":""N"",""WhetherRequired"":""N"",""QueryWhether"":""N"",""QueryType"":""=="",""WhetherTable"":""N"",""WhetherAddUpdate"":""N"",""ColumnKey"":""True"",""DataType"":""bigint"",""WhetherCommon"":""N"",""CreatedTime"":""2022-05-25T09:15:02.403"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""超级管理员"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":291946907168837},{""CodeGenId"":291946907033669,""ColumnName"":""Name"",""ColumnComment"":""姓名"",""NetType"":""string"",""EffectType"":""input"",""FkEntityName"":null,""FkColumnName"":null,""FkColumnNetType"":null,""DictTypeCode"":null,""WhetherRetract"":""N"",""WhetherRequired"":""N"",""QueryWhether"":""Y"",""QueryType"":""=="",""WhetherTable"":""Y"",""WhetherAddUpdate"":""Y"",""ColumnKey"":""False"",""DataType"":""nvarchar"",""WhetherCommon"":""N"",""CreatedTime"":""2022-05-25T09:15:02.403"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""超级管理员"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":291946907168838},{""CodeGenId"":291946907033669,""ColumnName"":""CreatedTime"",""ColumnComment"":""创建时间"",""NetType"":""DateTime"",""EffectType"":""datepicker"",""FkEntityName"":null,""FkColumnName"":null,""FkColumnNetType"":null,""DictTypeCode"":null,""WhetherRetract"":""N"",""WhetherRequired"":""N"",""QueryWhether"":""N"",""QueryType"":""=="",""WhetherTable"":""N"",""WhetherAddUpdate"":""N"",""ColumnKey"":""False"",""DataType"":""datetime"",""WhetherCommon"":""Y"",""CreatedTime"":""2022-05-25T09:15:02.403"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""超级管理员"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":291946907168839},{""CodeGenId"":291946907033669,""ColumnName"":""UpdatedTime"",""ColumnComment"":""更新时间"",""NetType"":""DateTime"",""EffectType"":""datepicker"",""FkEntityName"":null,""FkColumnName"":null,""FkColumnNetType"":null,""DictTypeCode"":null,""WhetherRetract"":""N"",""WhetherRequired"":""N"",""QueryWhether"":""N"",""QueryType"":""=="",""WhetherTable"":""N"",""WhetherAddUpdate"":""N"",""ColumnKey"":""False"",""DataType"":""datetime"",""WhetherCommon"":""Y"",""CreatedTime"":""2022-05-25T09:15:02.403"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""超级管理员"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":291946907168840},{""CodeGenId"":291946907033669,""ColumnName"":""CreatedUserId"",""ColumnComment"":""创建者Id"",""NetType"":""long"",""EffectType"":""input"",""FkEntityName"":null,""FkColumnName"":null,""FkColumnNetType"":null,""DictTypeCode"":null,""WhetherRetract"":""N"",""WhetherRequired"":""N"",""QueryWhether"":""N"",""QueryType"":""=="",""WhetherTable"":""N"",""WhetherAddUpdate"":""N"",""ColumnKey"":""False"",""DataType"":""bigint"",""WhetherCommon"":""Y"",""CreatedTime"":""2022-05-25T09:15:02.403"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""超级管理员"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":291946907172933},{""CodeGenId"":291946907033669,""ColumnName"":""CreatedUserName"",""ColumnComment"":""创建者名称"",""NetType"":""string"",""EffectType"":""input"",""FkEntityName"":null,""FkColumnName"":null,""FkColumnNetType"":null,""DictTypeCode"":null,""WhetherRetract"":""N"",""WhetherRequired"":""N"",""QueryWhether"":""N"",""QueryType"":""=="",""WhetherTable"":""N"",""WhetherAddUpdate"":""N"",""ColumnKey"":""False"",""DataType"":""nvarchar"",""WhetherCommon"":""Y"",""CreatedTime"":""2022-05-25T09:15:02.403"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""超级管理员"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":291946907172934},{""CodeGenId"":291946907033669,""ColumnName"":""UpdatedUserId"",""ColumnComment"":""修改者Id"",""NetType"":""long"",""EffectType"":""input"",""FkEntityName"":null,""FkColumnName"":null,""FkColumnNetType"":null,""DictTypeCode"":null,""WhetherRetract"":""N"",""WhetherRequired"":""N"",""QueryWhether"":""N"",""QueryType"":""=="",""WhetherTable"":""N"",""WhetherAddUpdate"":""N"",""ColumnKey"":""False"",""DataType"":""bigint"",""WhetherCommon"":""Y"",""CreatedTime"":""2022-05-25T09:15:02.403"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""超级管理员"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":291946907172935},{""CodeGenId"":291946907033669,""ColumnName"":""UpdatedUserName"",""ColumnComment"":""修改者名称"",""NetType"":""string"",""EffectType"":""input"",""FkEntityName"":null,""FkColumnName"":null,""FkColumnNetType"":null,""DictTypeCode"":null,""WhetherRetract"":""N"",""WhetherRequired"":""N"",""QueryWhether"":""N"",""QueryType"":""=="",""WhetherTable"":""N"",""WhetherAddUpdate"":""N"",""ColumnKey"":""False"",""DataType"":""nvarchar"",""WhetherCommon"":""Y"",""CreatedTime"":""2022-05-25T09:15:02.403"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""超级管理员"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":291946907172936},{""CodeGenId"":291946907033669,""ColumnName"":""IsDeleted"",""ColumnComment"":""软删除"",""NetType"":""bool"",""EffectType"":""switch"",""FkEntityName"":null,""FkColumnName"":null,""FkColumnNetType"":null,""DictTypeCode"":null,""WhetherRetract"":""N"",""WhetherRequired"":""N"",""QueryWhether"":""N"",""QueryType"":""=="",""WhetherTable"":""N"",""WhetherAddUpdate"":""N"",""ColumnKey"":""False"",""DataType"":""bit"",""WhetherCommon"":""Y"",""CreatedTime"":""2022-05-25T09:15:02.403"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""超级管理员"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":291946907172937},{""CodeGenId"":291946907033669,""ColumnName"":""TenantId"",""ColumnComment"":""租户Id"",""NetType"":""long"",""EffectType"":""input"",""FkEntityName"":null,""FkColumnName"":null,""FkColumnNetType"":null,""DictTypeCode"":null,""WhetherRetract"":""N"",""WhetherRequired"":""N"",""QueryWhether"":""Y"",""QueryType"":""=="",""WhetherTable"":""Y"",""WhetherAddUpdate"":""Y"",""ColumnKey"":""False"",""DataType"":""bigint"",""WhetherCommon"":""N"",""CreatedTime"":""2022-05-25T09:15:02.403"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""超级管理员"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":291946907172938}] +"; + List list = JsonUtil.ToObject>(json); + + return list; +}} diff --git a/Magic.CodeFirst/SeedData/SysCodeGenSeedData.cs b/Magic.CodeFirst/SeedData/SysCodeGenSeedData.cs new file mode 100644 index 0000000..15e8112 --- /dev/null +++ b/Magic.CodeFirst/SeedData/SysCodeGenSeedData.cs @@ -0,0 +1,13 @@ +using Magic.Core; +using Magic.Core.Entity; + +namespace Magic.CodeFirst; + +public class SysCodeGenSeedData : ISeedData , ISqlSugarEntitySeedData +{ public IEnumerable HasData() + { string json = @"[{""AuthorName"":""Magic"",""TablePrefix"":null,""GenerateType"":""2"",""TableName"":""Test"",""NameSpace"":""Magic.Application"",""BusName"":""测试"",""MenuApplication"":""busiapp"",""MenuPid"":0,""CreatedTime"":""2022-05-25T09:15:02.367"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""超级管理员"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":291946907033669}] +"; + List list = JsonUtil.ToObject>(json); + + return list; +}} diff --git a/Magic.CodeFirst/SeedData/SysConfigSeedData.cs b/Magic.CodeFirst/SeedData/SysConfigSeedData.cs new file mode 100644 index 0000000..b19666d --- /dev/null +++ b/Magic.CodeFirst/SeedData/SysConfigSeedData.cs @@ -0,0 +1,13 @@ +using Magic.Core; +using Magic.Core.Entity; + +namespace Magic.CodeFirst; + +public class SysConfigSeedData : ISeedData , ISqlSugarEntitySeedData +{ public IEnumerable HasData() + { string json = @"[{""Name"":""jwt密钥"",""Code"":""JWT_SECRET"",""Value"":""xiaonuo"",""SysFlag"":""Y"",""Remark"":""(重要)jwt密钥,默认为空,自行设置"",""Status"":0,""GroupCode"":""DEFAULT"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902342},{""Name"":""默认密码"",""Code"":""DEFAULT_PASSWORD"",""Value"":""123456"",""SysFlag"":""Y"",""Remark"":""默认密码"",""Status"":0,""GroupCode"":""DEFAULT"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902343},{""Name"":""token过期时间"",""Code"":""TOKEN_EXPIRE"",""Value"":""86400"",""SysFlag"":""Y"",""Remark"":""token过期时间(单位:秒)"",""Status"":0,""GroupCode"":""DEFAULT"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902344},{""Name"":""session会话过期时间"",""Code"":""SESSION_EXPIRE"",""Value"":""7200"",""SysFlag"":""Y"",""Remark"":""session会话过期时间(单位:秒)"",""Status"":0,""GroupCode"":""DEFAULT"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902345},{""Name"":""阿里云短信keyId"",""Code"":""ALIYUN_SMS_ACCESSKEY_ID"",""Value"":""你的keyId"",""SysFlag"":""Y"",""Remark"":""阿里云短信keyId"",""Status"":0,""GroupCode"":""ALIYUN_SMS"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902346},{""Name"":""阿里云短信secret"",""Code"":""ALIYUN_SMS_ACCESSKEY_SECRET"",""Value"":""你的secret"",""SysFlag"":""Y"",""Remark"":""阿里云短信secret"",""Status"":0,""GroupCode"":""ALIYUN_SMS"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902347},{""Name"":""阿里云短信签名"",""Code"":""ALIYUN_SMS_SIGN_NAME"",""Value"":""你的签名"",""SysFlag"":""Y"",""Remark"":""阿里云短信签名"",""Status"":0,""GroupCode"":""ALIYUN_SMS"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902348},{""Name"":""阿里云短信-登录模板号"",""Code"":""ALIYUN_SMS_LOGIN_TEMPLATE_CODE"",""Value"":""SMS_1877123456"",""SysFlag"":""Y"",""Remark"":""阿里云短信-登录模板号"",""Status"":0,""GroupCode"":""ALIYUN_SMS"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902349},{""Name"":""阿里云短信默认失效时间"",""Code"":""ALIYUN_SMS_INVALIDATE_MINUTES"",""Value"":""5"",""SysFlag"":""Y"",""Remark"":""阿里云短信默认失效时间(单位:分钟)"",""Status"":0,""GroupCode"":""ALIYUN_SMS"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902350},{""Name"":""腾讯云短信secretId"",""Code"":""TENCENT_SMS_SECRET_ID"",""Value"":""你的secretId"",""SysFlag"":""Y"",""Remark"":""腾讯云短信secretId"",""Status"":0,""GroupCode"":""TENCENT_SMS"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902351},{""Name"":""腾讯云短信secretKey"",""Code"":""TENCENT_SMS_SECRET_KEY"",""Value"":""你的secretkey"",""SysFlag"":""Y"",""Remark"":""腾讯云短信secretKey"",""Status"":0,""GroupCode"":""TENCENT_SMS"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902352},{""Name"":""腾讯云短信sdkAppId"",""Code"":""TENCENT_SMS_SDK_APP_ID"",""Value"":""1400375123"",""SysFlag"":""Y"",""Remark"":""腾讯云短信sdkAppId"",""Status"":0,""GroupCode"":""TENCENT_SMS"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902353},{""Name"":""腾讯云短信签名"",""Code"":""TENCENT_SMS_SIGN"",""Value"":""你的签名"",""SysFlag"":""Y"",""Remark"":""腾讯云短信签名"",""Status"":0,""GroupCode"":""TENCENT_SMS"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902354},{""Name"":""邮箱host"",""Code"":""EMAIL_HOST"",""Value"":""smtp.126.com"",""SysFlag"":""Y"",""Remark"":""邮箱host"",""Status"":0,""GroupCode"":""EMAIL"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902355},{""Name"":""邮箱用户名"",""Code"":""EMAIL_USERNAME"",""Value"":""test@126.com"",""SysFlag"":""Y"",""Remark"":""邮箱用户名"",""Status"":0,""GroupCode"":""EMAIL"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902356},{""Name"":""邮箱密码"",""Code"":""EMAIL_PASSWORD"",""Value"":""你的邮箱密码"",""SysFlag"":""Y"",""Remark"":""邮箱密码"",""Status"":0,""GroupCode"":""EMAIL"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902357},{""Name"":""邮箱端口"",""Code"":""EMAIL_PORT"",""Value"":""465"",""SysFlag"":""Y"",""Remark"":""邮箱端口"",""Status"":0,""GroupCode"":""EMAIL"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902358},{""Name"":""邮箱是否开启ssl"",""Code"":""EMAIL_SSL"",""Value"":""true"",""SysFlag"":""Y"",""Remark"":""邮箱是否开启ssl"",""Status"":0,""GroupCode"":""EMAIL"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902359},{""Name"":""邮箱发件人"",""Code"":""EMAIL_FROM"",""Value"":""test@126.com"",""SysFlag"":""Y"",""Remark"":""邮箱发件人"",""Status"":0,""GroupCode"":""EMAIL"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902360},{""Name"":""Win本地上传文件路径"",""Code"":""FILE_UPLOAD_PATH_FOR_WINDOWS"",""Value"":""D:/tmp"",""SysFlag"":""Y"",""Remark"":""Win本地上传文件路径"",""Status"":0,""GroupCode"":""FILE_PATH"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902361},{""Name"":""Linux/Mac本地上传文件路径"",""Code"":""FILE_UPLOAD_PATH_FOR_LINUX"",""Value"":""/tmp"",""SysFlag"":""Y"",""Remark"":""Linux/Mac本地上传文件路径"",""Status"":0,""GroupCode"":""FILE_PATH"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902362},{""Name"":""放开XSS过滤的接口"",""Code"":""UN_XSS_FILTER_URL"",""Value"":""/demo/xssfilter,/demo/unxss"",""SysFlag"":""Y"",""Remark"":""多个url可以用英文逗号隔开"",""Status"":0,""GroupCode"":""DEFAULT"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902363},{""Name"":""单用户登陆的开关"",""Code"":""ENABLE_SINGLE_LOGIN"",""Value"":""false"",""SysFlag"":""Y"",""Remark"":""true-打开,false-关闭,如果一个人登录两次,就会将上一次登陆挤下去"",""Status"":0,""GroupCode"":""DEFAULT"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902364},{""Name"":""登录验证码的开关"",""Code"":""CAPTCHA_OPEN"",""Value"":""false"",""SysFlag"":""Y"",""Remark"":""true-打开,false-关闭"",""Status"":0,""GroupCode"":""DEFAULT"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902365},{""Name"":""Druid监控登录账号"",""Code"":""DRUID_USERNAME"",""Value"":""superAdmin"",""SysFlag"":""Y"",""Remark"":""Druid监控登录账号"",""Status"":0,""GroupCode"":""DEFAULT"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902366},{""Name"":""Druid监控界面登录密码"",""Code"":""DRUID_PASSWORD"",""Value"":""123456"",""SysFlag"":""Y"",""Remark"":""Druid监控界面登录密码"",""Status"":0,""GroupCode"":""DEFAULT"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902367},{""Name"":""阿里云定位api接口地址"",""Code"":""IP_GEO_API"",""Value"":""http://api01.aliyun.venuscn.com/ip?ip=%s"",""SysFlag"":""Y"",""Remark"":""阿里云定位api接口地址"",""Status"":0,""GroupCode"":""DEFAULT"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902368},{""Name"":""阿里云定位appCode"",""Code"":""IP_GEO_APP_CODE"",""Value"":""461535aabeae4f34861884d392f5d452"",""SysFlag"":""Y"",""Remark"":""阿里云定位appCode"",""Status"":0,""GroupCode"":""DEFAULT"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902369},{""Name"":""Oauth用户登录的开关"",""Code"":""ENABLE_OAUTH_LOGIN"",""Value"":""true"",""SysFlag"":""Y"",""Remark"":""Oauth用户登录的开关"",""Status"":0,""GroupCode"":""OAUTH"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902370},{""Name"":""Oauth码云登录ClientId"",""Code"":""OAUTH_GITEE_CLIENT_ID"",""Value"":""你的clientId"",""SysFlag"":""Y"",""Remark"":""Oauth码云登录ClientId"",""Status"":0,""GroupCode"":""OAUTH"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902371},{""Name"":""Oauth码云登录ClientSecret"",""Code"":""OAUTH_GITEE_CLIENT_SECRET"",""Value"":""你的clientSecret"",""SysFlag"":""Y"",""Remark"":""Oauth码云登录ClientSecret"",""Status"":0,""GroupCode"":""OAUTH"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902372},{""Name"":""Oauth码云登录回调地址"",""Code"":""OAUTH_GITEE_REDIRECT_URI"",""Value"":""http://127.0.0.1:5566/oauth/callback/gitee"",""SysFlag"":""Y"",""Remark"":""Oauth码云登录回调地址"",""Status"":0,""GroupCode"":""OAUTH"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902373},{""Name"":""演示环境"",""Code"":""DEMO_ENV_FLAG"",""Value"":""false"",""SysFlag"":""Y"",""Remark"":""演示环境的开关,true-打开,false-关闭,如果演示环境开启,则只能读数据不能写数据"",""Status"":0,""GroupCode"":""DEFAULT"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902374}] +"; + List list = JsonUtil.ToObject>(json); + + return list; +}} diff --git a/Magic.CodeFirst/SeedData/SysDictDataSeedData.cs b/Magic.CodeFirst/SeedData/SysDictDataSeedData.cs new file mode 100644 index 0000000..151eecd --- /dev/null +++ b/Magic.CodeFirst/SeedData/SysDictDataSeedData.cs @@ -0,0 +1,13 @@ +using Magic.Core; +using Magic.Core.Entity; + +namespace Magic.CodeFirst; + +public class SysDictDataSeedData : ISeedData , ISqlSugarEntitySeedData +{ public IEnumerable HasData() + { string json = @"[{""TypeId"":142307070906484,""Value"":""男"",""Code"":""1"",""Sort"":100,""Remark"":""男性"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902375},{""TypeId"":142307070906484,""Value"":""女"",""Code"":""2"",""Sort"":100,""Remark"":""女性"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902376},{""TypeId"":142307070906484,""Value"":""未知"",""Code"":""3"",""Sort"":100,""Remark"":""未知性别"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902377},{""TypeId"":142307070906485,""Value"":""默认常量"",""Code"":""DEFAULT"",""Sort"":100,""Remark"":""默认常量,都以XIAONUO_开头的"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902378},{""TypeId"":142307070906485,""Value"":""阿里云短信"",""Code"":""ALIYUN_SMS"",""Sort"":100,""Remark"":""阿里云短信配置"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902379},{""TypeId"":142307070906485,""Value"":""腾讯云短信"",""Code"":""TENCENT_SMS"",""Sort"":100,""Remark"":""腾讯云短信"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902380},{""TypeId"":142307070906485,""Value"":""邮件配置"",""Code"":""EMAIL"",""Sort"":100,""Remark"":""邮件配置"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902381},{""TypeId"":142307070906485,""Value"":""文件上传路径"",""Code"":""FILE_PATH"",""Sort"":100,""Remark"":""文件上传路径"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902382},{""TypeId"":142307070906485,""Value"":""Oauth配置"",""Code"":""OAUTH"",""Sort"":100,""Remark"":""Oauth配置"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902383},{""TypeId"":142307070906483,""Value"":""正常"",""Code"":""0"",""Sort"":100,""Remark"":""正常"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902384},{""TypeId"":142307070906483,""Value"":""停用"",""Code"":""1"",""Sort"":100,""Remark"":""停用"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902385},{""TypeId"":142307070906483,""Value"":""删除"",""Code"":""2"",""Sort"":100,""Remark"":""删除"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902386},{""TypeId"":142307070906486,""Value"":""否"",""Code"":""N"",""Sort"":100,""Remark"":""否"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902387},{""TypeId"":142307070906486,""Value"":""是"",""Code"":""Y"",""Sort"":100,""Remark"":""是"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902388},{""TypeId"":142307070906487,""Value"":""登录"",""Code"":""1"",""Sort"":100,""Remark"":""登录"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902389},{""TypeId"":142307070906487,""Value"":""登出"",""Code"":""2"",""Sort"":100,""Remark"":""登出"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902390},{""TypeId"":142307070906488,""Value"":""目录"",""Code"":""0"",""Sort"":100,""Remark"":""目录"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902391},{""TypeId"":142307070906488,""Value"":""菜单"",""Code"":""1"",""Sort"":100,""Remark"":""菜单"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902392},{""TypeId"":142307070906488,""Value"":""按钮"",""Code"":""2"",""Sort"":100,""Remark"":""按钮"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902393},{""TypeId"":142307070906489,""Value"":""未发送"",""Code"":""0"",""Sort"":100,""Remark"":""未发送"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902394},{""TypeId"":142307070906489,""Value"":""发送成功"",""Code"":""1"",""Sort"":100,""Remark"":""发送成功"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902395},{""TypeId"":142307070906489,""Value"":""发送失败"",""Code"":""2"",""Sort"":100,""Remark"":""发送失败"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902396},{""TypeId"":142307070906489,""Value"":""失效"",""Code"":""3"",""Sort"":100,""Remark"":""失效"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902397},{""TypeId"":142307070906490,""Value"":""无"",""Code"":""0"",""Sort"":100,""Remark"":""无"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902398},{""TypeId"":142307070906490,""Value"":""组件"",""Code"":""1"",""Sort"":100,""Remark"":""组件"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070902399},{""TypeId"":142307070906490,""Value"":""内链"",""Code"":""2"",""Sort"":100,""Remark"":""内链"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906437},{""TypeId"":142307070906490,""Value"":""外链"",""Code"":""3"",""Sort"":100,""Remark"":""外链"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906438},{""TypeId"":142307070906491,""Value"":""系统权重"",""Code"":""1"",""Sort"":100,""Remark"":""系统权重"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906439},{""TypeId"":142307070906491,""Value"":""业务权重"",""Code"":""2"",""Sort"":100,""Remark"":""业务权重"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906440},{""TypeId"":142307070906492,""Value"":""全部数据"",""Code"":""1"",""Sort"":100,""Remark"":""全部数据"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906441},{""TypeId"":142307070906492,""Value"":""本部门及以下数据"",""Code"":""2"",""Sort"":100,""Remark"":""本部门及以下数据"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906442},{""TypeId"":142307070906492,""Value"":""本部门数据"",""Code"":""3"",""Sort"":100,""Remark"":""本部门数据"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906443},{""TypeId"":142307070906492,""Value"":""仅本人数据"",""Code"":""4"",""Sort"":100,""Remark"":""仅本人数据"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906444},{""TypeId"":142307070906492,""Value"":""自定义数据"",""Code"":""5"",""Sort"":100,""Remark"":""自定义数据"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906445},{""TypeId"":142307070906493,""Value"":""app"",""Code"":""1"",""Sort"":100,""Remark"":""app"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906446},{""TypeId"":142307070906493,""Value"":""pc"",""Code"":""2"",""Sort"":100,""Remark"":""pc"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906447},{""TypeId"":142307070906493,""Value"":""其他"",""Code"":""3"",""Sort"":100,""Remark"":""其他"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906448},{""TypeId"":142307070906494,""Value"":""其它"",""Code"":""0"",""Sort"":100,""Remark"":""其它"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906449},{""TypeId"":142307070906494,""Value"":""增加"",""Code"":""1"",""Sort"":100,""Remark"":""增加"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906450},{""TypeId"":142307070906494,""Value"":""删除"",""Code"":""2"",""Sort"":100,""Remark"":""删除"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906451},{""TypeId"":142307070906494,""Value"":""编辑"",""Code"":""3"",""Sort"":100,""Remark"":""编辑"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906452},{""TypeId"":142307070906494,""Value"":""更新"",""Code"":""4"",""Sort"":100,""Remark"":""更新"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906453},{""TypeId"":142307070906494,""Value"":""查询"",""Code"":""5"",""Sort"":100,""Remark"":""查询"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906454},{""TypeId"":142307070906494,""Value"":""详情"",""Code"":""6"",""Sort"":100,""Remark"":""详情"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906455},{""TypeId"":142307070906494,""Value"":""树"",""Code"":""7"",""Sort"":100,""Remark"":""树"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906456},{""TypeId"":142307070906494,""Value"":""导入"",""Code"":""8"",""Sort"":100,""Remark"":""导入"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906457},{""TypeId"":142307070906494,""Value"":""导出"",""Code"":""9"",""Sort"":100,""Remark"":""导出"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906458},{""TypeId"":142307070906494,""Value"":""授权"",""Code"":""10"",""Sort"":100,""Remark"":""授权"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906459},{""TypeId"":142307070906494,""Value"":""强退"",""Code"":""11"",""Sort"":100,""Remark"":""强退"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906460},{""TypeId"":142307070906494,""Value"":""清空"",""Code"":""12"",""Sort"":100,""Remark"":""清空"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906461},{""TypeId"":142307070906494,""Value"":""修改状态"",""Code"":""13"",""Sort"":100,""Remark"":""修改状态"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906462},{""TypeId"":142307070906495,""Value"":""阿里云"",""Code"":""1"",""Sort"":100,""Remark"":""阿里云"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906463},{""TypeId"":142307070906495,""Value"":""腾讯云"",""Code"":""2"",""Sort"":100,""Remark"":""腾讯云"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906464},{""TypeId"":142307070906495,""Value"":""minio"",""Code"":""3"",""Sort"":100,""Remark"":""minio"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906465},{""TypeId"":142307070906495,""Value"":""本地"",""Code"":""4"",""Sort"":100,""Remark"":""本地"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906466},{""TypeId"":142307070910533,""Value"":""运行"",""Code"":""1"",""Sort"":100,""Remark"":""运行"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906467},{""TypeId"":142307070910533,""Value"":""停止"",""Code"":""2"",""Sort"":100,""Remark"":""停止"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906468},{""TypeId"":142307070910534,""Value"":""通知"",""Code"":""1"",""Sort"":100,""Remark"":""通知"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906469},{""TypeId"":142307070910534,""Value"":""公告"",""Code"":""2"",""Sort"":100,""Remark"":""公告"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906470},{""TypeId"":142307070910535,""Value"":""草稿"",""Code"":""0"",""Sort"":100,""Remark"":""草稿"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906471},{""TypeId"":142307070910535,""Value"":""发布"",""Code"":""1"",""Sort"":100,""Remark"":""发布"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906472},{""TypeId"":142307070910535,""Value"":""撤回"",""Code"":""2"",""Sort"":100,""Remark"":""撤回"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906473},{""TypeId"":142307070910535,""Value"":""删除"",""Code"":""3"",""Sort"":100,""Remark"":""删除"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906474},{""TypeId"":142307070910536,""Value"":""是"",""Code"":""true"",""Sort"":100,""Remark"":""是"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906475},{""TypeId"":142307070910536,""Value"":""否"",""Code"":""false"",""Sort"":100,""Remark"":""否"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906476},{""TypeId"":142307070910537,""Value"":""下载压缩包"",""Code"":""1"",""Sort"":100,""Remark"":""下载压缩包"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906477},{""TypeId"":142307070910537,""Value"":""生成到本项目"",""Code"":""2"",""Sort"":100,""Remark"":""生成到本项目"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906478},{""TypeId"":142307070910538,""Value"":""GET"",""Code"":""1"",""Sort"":100,""Remark"":""GET"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906479},{""TypeId"":142307070910538,""Value"":""POST"",""Code"":""2"",""Sort"":100,""Remark"":""POST"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906480},{""TypeId"":142307070910538,""Value"":""PUT"",""Code"":""3"",""Sort"":100,""Remark"":""PUT"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906481},{""TypeId"":142307070910538,""Value"":""DELETE"",""Code"":""4"",""Sort"":100,""Remark"":""DELETE"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906482},{""TypeId"":142307070922827,""Value"":""外键"",""Code"":""fk"",""Sort"":100,""Remark"":""外键"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922829},{""TypeId"":142307070922827,""Value"":""输入框"",""Code"":""input"",""Sort"":100,""Remark"":""输入框"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922830},{""TypeId"":142307070922827,""Value"":""时间选择"",""Code"":""datepicker"",""Sort"":100,""Remark"":""时间选择"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922831},{""TypeId"":142307070922827,""Value"":""下拉框"",""Code"":""select"",""Sort"":100,""Remark"":""下拉框"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922832},{""TypeId"":142307070922827,""Value"":""单选框"",""Code"":""radio"",""Sort"":100,""Remark"":""单选框"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922833},{""TypeId"":142307070922827,""Value"":""开关"",""Code"":""switch"",""Sort"":100,""Remark"":""开关"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922834},{""TypeId"":142307070922827,""Value"":""多选框"",""Code"":""checkbox"",""Sort"":100,""Remark"":""多选框"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922835},{""TypeId"":142307070922827,""Value"":""数字输入框"",""Code"":""inputnumber"",""Sort"":100,""Remark"":""数字输入框"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922836},{""TypeId"":142307070922827,""Value"":""文本域"",""Code"":""textarea"",""Sort"":100,""Remark"":""文本域"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922837},{""TypeId"":142307070922828,""Value"":""等于"",""Code"":""=="",""Sort"":1,""Remark"":""等于"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922838},{""TypeId"":142307070922828,""Value"":""模糊"",""Code"":""like"",""Sort"":2,""Remark"":""模糊"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922839},{""TypeId"":142307070922828,""Value"":""大于"",""Code"":"">"",""Sort"":3,""Remark"":""大于"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922840},{""TypeId"":142307070922828,""Value"":""小于"",""Code"":""<"",""Sort"":4,""Remark"":""小于"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922841},{""TypeId"":142307070922828,""Value"":""不等于"",""Code"":""!="",""Sort"":5,""Remark"":""不等于"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922842},{""TypeId"":142307070922828,""Value"":""大于等于"",""Code"":"">="",""Sort"":6,""Remark"":""大于等于"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922843},{""TypeId"":142307070922828,""Value"":""小于等于"",""Code"":""<="",""Sort"":7,""Remark"":""小于等于"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922844},{""TypeId"":142307070922828,""Value"":""不为空"",""Code"":""isNotNull"",""Sort"":8,""Remark"":""不为空"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922845},{""TypeId"":142307070922829,""Value"":""long"",""Code"":""long"",""Sort"":100,""Remark"":""long"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922846},{""TypeId"":142307070922829,""Value"":""string"",""Code"":""string"",""Sort"":100,""Remark"":""string"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922847},{""TypeId"":142307070922829,""Value"":""DateTime"",""Code"":""DateTime"",""Sort"":100,""Remark"":""DateTime"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922848},{""TypeId"":142307070922829,""Value"":""bool"",""Code"":""bool"",""Sort"":100,""Remark"":""bool"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922850},{""TypeId"":142307070922829,""Value"":""int"",""Code"":""int"",""Sort"":100,""Remark"":""int"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922851},{""TypeId"":142307070922829,""Value"":""double"",""Code"":""double"",""Sort"":100,""Remark"":""double"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922852},{""TypeId"":142307070922829,""Value"":""float"",""Code"":""float"",""Sort"":100,""Remark"":""float"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922861},{""TypeId"":142307070922829,""Value"":""decimal"",""Code"":""decimal"",""Sort"":100,""Remark"":""decimal"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922862},{""TypeId"":142307070922829,""Value"":""Guid"",""Code"":""Guid"",""Sort"":100,""Remark"":""Guid"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922863},{""TypeId"":142307070922829,""Value"":""DateTimeOffset"",""Code"":""DateTimeOffset"",""Sort"":100,""Remark"":""DateTimeOffset"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922864},{""TypeId"":250931744608325,""Value"":""正在运行"",""Code"":""0"",""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-01-29T11:45:20"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":250932094988357},{""TypeId"":250931744608325,""Value"":""审批通过"",""Code"":""1"",""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-01-29T11:45:39"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":250932172402757},{""TypeId"":250931744608325,""Value"":""被撤回"",""Code"":""2"",""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-01-29T11:45:50"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":250932217757765},{""TypeId"":250931744608325,""Value"":""不同意"",""Code"":""3"",""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-01-29T11:45:58"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":250932249595973},{""TypeId"":250931744608325,""Value"":""被驳回"",""Code"":""4"",""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-01-29T11:46:08"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":250932291698757},{""TypeId"":277112635904069,""Value"":""文件夹"",""Code"":""1"",""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-04-13T11:14:32.053"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":277112709247045},{""TypeId"":277112635904069,""Value"":""文件"",""Code"":""2"",""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-04-13T11:14:37.463"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":277112731418693},{""TypeId"":277534340079685,""Value"":""文档"",""Code"":""doc,docx,txt,xls,ppt,xlsx,pptx,tmd,tmdx,prd,prdx,pmd,pmdx,pdf"",""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-04-14T15:53:35.023"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":277535182864453},{""TypeId"":277534340079685,""Value"":""图片"",""Code"":""png,jpg,jpeg,gif,tiff,swf"",""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-04-14T15:59:56.08"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":277536743669829},{""TypeId"":277534340079685,""Value"":""文件夹"",""Code"":""文件夹"",""Sort"":98,""Remark"":null,""Status"":0,""CreatedTime"":""2022-04-14T16:06:49.17"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":277538435686469},{""TypeId"":277109712883781,""Value"":""流程图"",""Code"":""3"",""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-04-15T08:38:15.013"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":277782089695301},{""TypeId"":277109712883781,""Value"":""月小结"",""Code"":""4"",""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-04-15T08:38:42.61"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":277782202732613},{""TypeId"":277534340079685,""Value"":""应用程序"",""Code"":""exe,msi"",""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-04-15T09:12:33.293"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":277790520414277},{""TypeId"":277534340079685,""Value"":""压缩包"",""Code"":""zip,rar,7z,tar,tar.gz,ace,zipx,iso,rz"",""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-04-15T09:57:55.887"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":277801672163397}] +"; + List list = JsonUtil.ToObject>(json); + + return list; +}} diff --git a/Magic.CodeFirst/SeedData/SysDictTypeSeedData.cs b/Magic.CodeFirst/SeedData/SysDictTypeSeedData.cs new file mode 100644 index 0000000..1c15e32 --- /dev/null +++ b/Magic.CodeFirst/SeedData/SysDictTypeSeedData.cs @@ -0,0 +1,13 @@ +using Magic.Core; +using Magic.Core.Entity; + +namespace Magic.CodeFirst; + +public class SysDictTypeSeedData : ISeedData , ISqlSugarEntitySeedData +{ public IEnumerable HasData() + { string json = @"[{""Name"":""通用状态"",""Code"":""common_status"",""Sort"":100,""Remark"":""通用状态"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906483},{""Name"":""性别"",""Code"":""sex"",""Sort"":100,""Remark"":""性别字典"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906484},{""Name"":""常量的分类"",""Code"":""consts_type"",""Sort"":100,""Remark"":""常量的分类,用于区别一组配置"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906485},{""Name"":""是否"",""Code"":""yes_or_no"",""Sort"":100,""Remark"":""是否"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906486},{""Name"":""访问类型"",""Code"":""vis_type"",""Sort"":100,""Remark"":""访问类型"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906487},{""Name"":""菜单类型"",""Code"":""menu_type"",""Sort"":100,""Remark"":""菜单类型"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906488},{""Name"":""发送类型"",""Code"":""send_type"",""Sort"":100,""Remark"":""发送类型"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906489},{""Name"":""打开方式"",""Code"":""open_type"",""Sort"":100,""Remark"":""打开方式"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906490},{""Name"":""菜单权重"",""Code"":""menu_weight"",""Sort"":100,""Remark"":""菜单权重"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906491},{""Name"":""数据范围类型"",""Code"":""data_scope_type"",""Sort"":100,""Remark"":""数据范围类型"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906492},{""Name"":""短信发送来源"",""Code"":""sms_send_source"",""Sort"":100,""Remark"":""短信发送来源"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906493},{""Name"":""操作类型"",""Code"":""op_type"",""Sort"":100,""Remark"":""操作类型"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906494},{""Name"":""文件存储位置"",""Code"":""file_storage_location"",""Sort"":100,""Remark"":""文件存储位置"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070906495},{""Name"":""运行状态"",""Code"":""run_status"",""Sort"":100,""Remark"":""定时任务运行状态"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910533},{""Name"":""通知公告类型"",""Code"":""notice_type"",""Sort"":100,""Remark"":""通知公告类型"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910534},{""Name"":""通知公告状态"",""Code"":""notice_status"",""Sort"":100,""Remark"":""通知公告状态"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910535},{""Name"":""是否boolean"",""Code"":""yes_true_false"",""Sort"":100,""Remark"":""是否boolean"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910536},{""Name"":""代码生成方式"",""Code"":""code_gen_create_type"",""Sort"":100,""Remark"":""代码生成方式"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910537},{""Name"":""请求方式"",""Code"":""request_type"",""Sort"":100,""Remark"":""请求方式"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910538},{""Name"":""代码生成作用类型"",""Code"":""code_gen_effect_type"",""Sort"":100,""Remark"":""代码生成作用类型"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922827},{""Name"":""代码生成查询类型"",""Code"":""code_gen_query_type"",""Sort"":100,""Remark"":""代码生成查询类型"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922828},{""Name"":""代码生成.NET类型"",""Code"":""code_gen_net_type"",""Sort"":100,""Remark"":""代码生成.NET类型"",""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922829},{""Name"":""流程状态"",""Code"":""flow_status"",""Sort"":100,""Remark"":""流程申请状态显示"",""Status"":0,""CreatedTime"":""2022-01-29T11:43:54"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":250931744608325},{""Name"":""文档标签"",""Code"":""doc_label"",""Sort"":99,""Remark"":null,""Status"":0,""CreatedTime"":""2022-04-13T11:02:20.517"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":277109712883781},{""Name"":""文档类型"",""Code"":""doc_type"",""Sort"":99,""Remark"":null,""Status"":0,""CreatedTime"":""2022-04-13T11:14:14.147"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":277112635904069},{""Name"":""文件类型"",""Code"":""file_type"",""Sort"":99,""Remark"":null,""Status"":0,""CreatedTime"":""2022-04-14T15:50:09.267"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":277534340079685}] +"; + List list = JsonUtil.ToObject>(json); + + return list; +}} diff --git a/Magic.CodeFirst/SeedData/SysEmpPosSeedData.cs b/Magic.CodeFirst/SeedData/SysEmpPosSeedData.cs new file mode 100644 index 0000000..ef0b584 --- /dev/null +++ b/Magic.CodeFirst/SeedData/SysEmpPosSeedData.cs @@ -0,0 +1,13 @@ +using Magic.Core; +using Magic.Core.Entity; + +namespace Magic.CodeFirst; + +public class SysEmpPosSeedData : ISeedData , ISqlSugarEntitySeedData +{ public IEnumerable HasData() + { string json = @"[{""SysEmpId"":177325484421189,""SysPosId"":177325394366533},{""SysEmpId"":182314279026757,""SysPosId"":177325394366533}] +"; + List list = JsonUtil.ToObject>(json); + + return list; +}} diff --git a/Magic.CodeFirst/SeedData/SysEmpSeedData.cs b/Magic.CodeFirst/SeedData/SysEmpSeedData.cs new file mode 100644 index 0000000..d62649d --- /dev/null +++ b/Magic.CodeFirst/SeedData/SysEmpSeedData.cs @@ -0,0 +1,13 @@ +using Magic.Core; +using Magic.Core.Entity; + +namespace Magic.CodeFirst; + +public class SysEmpSeedData : ISeedData , ISqlSugarEntitySeedData +{ public IEnumerable HasData() + { string json = @"[{""JobNum"":null,""OrgId"":177325089079365,""OrgName"":""系统机构"",""Id"":142307070910551},{""JobNum"":""1"",""OrgId"":175624015089733,""OrgName"":""土豆新车"",""Id"":175624015269957},{""JobNum"":null,""OrgId"":177325089079365,""OrgName"":""系统机构"",""Id"":177325484421189},{""JobNum"":null,""OrgId"":182313953165381,""OrgName"":""机构1"",""Id"":182314279026757},{""JobNum"":""1"",""OrgId"":278024843092037,""OrgName"":""租户1"",""Id"":278024843153477}] +"; + List list = JsonUtil.ToObject>(json); + + return list; +}} diff --git a/Magic.CodeFirst/SeedData/SysFileSeedData.cs b/Magic.CodeFirst/SeedData/SysFileSeedData.cs new file mode 100644 index 0000000..ae853a0 --- /dev/null +++ b/Magic.CodeFirst/SeedData/SysFileSeedData.cs @@ -0,0 +1,13 @@ +using Magic.Core; +using Magic.Core.Entity; + +namespace Magic.CodeFirst; + +public class SysFileSeedData : ISeedData , ISqlSugarEntitySeedData +{ public IEnumerable HasData() + { string json = @"[{""FileLocation"":4,""FileBucket"":""LOCAL"",""FileOriginName"":""icon_avatar.png"",""FileSuffix"":""png"",""FileSizeKb"":""4"",""FileSizeInfo"":null,""FileObjectName"":""178111296725062.png"",""FilePath"":""Upload/Default"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":178111296725061},{""FileLocation"":4,""FileBucket"":""LOCAL"",""FileOriginName"":""icon_alipay.png"",""FileSuffix"":""png"",""FileSizeKb"":""22"",""FileSizeInfo"":null,""FileObjectName"":""188632919339077.png"",""FilePath"":""Upload/Avatar"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":188632919339077}] +"; + List list = JsonUtil.ToObject>(json); + + return list; +}} diff --git a/Magic.CodeFirst/SeedData/SysMenuSeedData.cs b/Magic.CodeFirst/SeedData/SysMenuSeedData.cs new file mode 100644 index 0000000..1d0eb46 --- /dev/null +++ b/Magic.CodeFirst/SeedData/SysMenuSeedData.cs @@ -0,0 +1,13 @@ +using Magic.Core; +using Magic.Core.Entity; + +namespace Magic.CodeFirst; + +public class SysMenuSeedData : ISeedData , ISqlSugarEntitySeedData +{ public IEnumerable HasData() + { string json = @"[{""Pid"":0,""Pids"":""[0],"",""Name"":""组织架构"",""Code"":""sys_mgr"",""Type"":0,""Icon"":""team"",""Router"":""/sys"",""Component"":""PageView"",""Permission"":null,""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307000914633},{""Pid"":0,""Pids"":""[0],"",""Name"":""主控面板"",""Code"":""system_index"",""Type"":0,""Icon"":""home"",""Router"":""/"",""Component"":""RouteView"",""Permission"":null,""Application"":""busiapp"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":""/analysis"",""Weight"":1,""Sort"":1,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910560},{""Pid"":142307070910560,""Pids"":""[0],[142307070910560],"",""Name"":""分析页"",""Code"":""system_index_dashboard"",""Type"":1,""Icon"":null,""Router"":""analysis"",""Component"":""system/dashboard/Analysis"",""Permission"":null,""Application"":""busiapp"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910561},{""Pid"":142307070910560,""Pids"":""[0],[142307070910560],"",""Name"":""工作台"",""Code"":""system_index_workplace"",""Type"":1,""Icon"":null,""Router"":""workplace"",""Component"":""system/dashboard/Workplace"",""Permission"":null,""Application"":""busiapp"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910562},{""Pid"":0,""Pids"":""[0],"",""Name"":""权限管理"",""Code"":""auth_manager"",""Type"":0,""Icon"":""safety-certificate"",""Router"":""/auth"",""Component"":""PageView"",""Permission"":null,""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910563},{""Pid"":142307070910563,""Pids"":""[0],[142307070910563],"",""Name"":""用户管理"",""Code"":""sys_user_mgr"",""Type"":1,""Icon"":null,""Router"":""/mgr_user"",""Component"":""system/user/index"",""Permission"":null,""Application"":""manage"",""OpenType"":1,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910564},{""Pid"":142307070910564,""Pids"":""[0],[142307070910563],[142307070910564],"",""Name"":""用户查询"",""Code"":""sys_user_mgr_page"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysUser:page"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910565},{""Pid"":142307070910564,""Pids"":""[0],[142307070910563],[142307070910564],"",""Name"":""用户编辑"",""Code"":""sys_user_mgr_edit"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysUser:edit"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910566},{""Pid"":142307070910564,""Pids"":""[0],[142307070910563],[142307070910564],"",""Name"":""用户增加"",""Code"":""sys_user_mgr_add"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysUser:add"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910567},{""Pid"":142307070910564,""Pids"":""[0],[142307070910563],[142307070910564],"",""Name"":""用户删除"",""Code"":""sys_user_mgr_delete"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysUser:delete"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910568},{""Pid"":142307070910564,""Pids"":""[0],[142307070910563],[142307070910564],"",""Name"":""用户详情"",""Code"":""sys_user_mgr_detail"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysUser:detail"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910569},{""Pid"":142307070910564,""Pids"":""[0],[142307070910563],[142307070910564],"",""Name"":""用户导出"",""Code"":""sys_user_mgr_export"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysUser:export"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910570},{""Pid"":142307070910564,""Pids"":""[0],[142307070910563],[142307070910564],"",""Name"":""用户选择器"",""Code"":""sys_user_mgr_selector"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysUser:selector"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910571},{""Pid"":142307070910564,""Pids"":""[0],[142307070910563],[142307070910564],"",""Name"":""用户授权角色"",""Code"":""sys_user_mgr_grant_role"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysUser:grantRole"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910572},{""Pid"":142307070910564,""Pids"":""[0],[142307070910563],[142307070910564],"",""Name"":""用户拥有角色"",""Code"":""sys_user_mgr_own_role"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysUser:ownRole"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910573},{""Pid"":142307070910564,""Pids"":""[0],[142307070910563],[142307070910564],"",""Name"":""用户授权数据"",""Code"":""sys_user_mgr_grant_data"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysUser:grantData"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910574},{""Pid"":142307070910564,""Pids"":""[0],[142307070910563],[142307070910564],"",""Name"":""用户拥有数据"",""Code"":""sys_user_mgr_own_data"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysUser:ownData"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910575},{""Pid"":142307070910564,""Pids"":""[0],[142307070910563],[142307070910564],"",""Name"":""用户更新信息"",""Code"":""sys_user_mgr_update_info"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysUser:updateInfo"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910576},{""Pid"":142307070910564,""Pids"":""[0],[142307070910563],[142307070910564],"",""Name"":""用户修改密码"",""Code"":""sys_user_mgr_update_pwd"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysUser:updatePwd"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910577},{""Pid"":142307070910564,""Pids"":""[0],[142307070910563],[142307070910564],"",""Name"":""用户修改状态"",""Code"":""sys_user_mgr_change_status"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysUser:changeStatus"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910578},{""Pid"":142307070910564,""Pids"":""[0],[142307070910563],[142307070910564],"",""Name"":""用户修改头像"",""Code"":""sys_user_mgr_update_avatar"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysUser:updateAvatar"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910579},{""Pid"":142307070910564,""Pids"":""[0],[142307070910563],[142307070910564],"",""Name"":""用户重置密码"",""Code"":""sys_user_mgr_reset_pwd"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysUser:resetPwd"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910580},{""Pid"":142307000914633,""Pids"":""[0],[142307000914633],"",""Name"":""机构管理"",""Code"":""sys_org_mgr"",""Type"":1,""Icon"":null,""Router"":""/org"",""Component"":""system/org/index"",""Permission"":null,""Application"":""manage"",""OpenType"":1,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910581},{""Pid"":142307070910581,""Pids"":""[0],[142307000914633],[142307070910581],"",""Name"":""机构查询"",""Code"":""sys_org_mgr_page"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysOrg:page"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910582},{""Pid"":142307070910581,""Pids"":""[0],[142307000914633],[142307070910581],"",""Name"":""机构列表"",""Code"":""sys_org_mgr_list"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysOrg:list"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910583},{""Pid"":142307070910581,""Pids"":""[0],[142307000914633],[142307070910581],"",""Name"":""机构增加"",""Code"":""sys_org_mgr_add"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysOrg:add"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910584},{""Pid"":142307070910581,""Pids"":""[0],[142307000914633],[142307070910581],"",""Name"":""机构编辑"",""Code"":""sys_org_mgr_edit"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysOrg:edit"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910585},{""Pid"":142307070910581,""Pids"":""[0],[142307000914633],[142307070910581],"",""Name"":""机构删除"",""Code"":""sys_org_mgr_delete"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysOrg:delete"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910586},{""Pid"":142307070910581,""Pids"":""[0],[142307000914633],[142307070910581],"",""Name"":""机构详情"",""Code"":""sys_org_mgr_detail"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysOrg:detail"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910587},{""Pid"":142307070910581,""Pids"":""[0],[142307000914633],[142307070910581],"",""Name"":""机构树"",""Code"":""sys_org_mgr_tree"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysOrg:tree"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910588},{""Pid"":142307000914633,""Pids"":""[0],[142307000914633],"",""Name"":""职位管理"",""Code"":""sys_pos_mgr"",""Type"":1,""Icon"":null,""Router"":""/pos"",""Component"":""system/pos/index"",""Permission"":null,""Application"":""manage"",""OpenType"":1,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2021-04-26T17:01:18.123"",""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910589},{""Pid"":142307070910589,""Pids"":""[0],[142307000914633],[142307070910589],"",""Name"":""职位查询"",""Code"":""sys_pos_mgr_page"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysPos:page"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910590},{""Pid"":142307070910589,""Pids"":""[0],[142307000914633],[142307070910589],"",""Name"":""职位列表"",""Code"":""sys_pos_mgr_list"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysPos:list"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910591},{""Pid"":142307070918732,""Pids"":""[0],[142307070918732],"",""Name"":""异常日志"",""Code"":""sys_log_mgr_ex_log"",""Type"":1,""Icon"":null,""Router"":""/exlog"",""Component"":""system/log/exlog/index"",""Permission"":null,""Application"":""manage"",""OpenType"":1,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070911739},{""Pid"":142307070911739,""Pids"":""[0],[142307070918732],[142307070911739],"",""Name"":""异常日志查询"",""Code"":""sys_log_mgr_ex_log_page"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysExLog:page"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070911740},{""Pid"":142307070911739,""Pids"":""[0],[142307070918732],[142307070911739],"",""Name"":""异常日志清空"",""Code"":""sys_log_mgr_ex_log_delete"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysExLog:delete"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070911741},{""Pid"":142307070910589,""Pids"":""[0],[142307000914633],[142307070910589],"",""Name"":""职位增加"",""Code"":""sys_pos_mgr_add"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysPos:add"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914629},{""Pid"":142307070910589,""Pids"":""[0],[142307000914633],[142307070910589],"",""Name"":""职位编辑"",""Code"":""sys_pos_mgr_edit"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysPos:edit"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914630},{""Pid"":142307070910589,""Pids"":""[0],[142307000914633],[142307070910589],"",""Name"":""职位删除"",""Code"":""sys_pos_mgr_delete"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysPos:delete"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914631},{""Pid"":142307070910589,""Pids"":""[0],[142307000914633],[142307070910589],"",""Name"":""职位详情"",""Code"":""sys_pos_mgr_detail"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysPos:detail"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914632},{""Pid"":0,""Pids"":""[0],"",""Name"":""平台管理"",""Code"":""auth_manager"",""Type"":0,""Icon"":""safety-certificate"",""Router"":""/auth"",""Component"":""PageView"",""Permission"":null,""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914633},{""Pid"":142307070914633,""Pids"":""[0],[142307070914633],"",""Name"":""应用管理"",""Code"":""sys_app_mgr"",""Type"":1,""Icon"":null,""Router"":""/app"",""Component"":""system/app/index"",""Permission"":null,""Application"":""system"",""OpenType"":1,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914634},{""Pid"":142307070914634,""Pids"":""[0],[142307070914633],[142307070914634],"",""Name"":""应用查询"",""Code"":""sys_app_mgr_page"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysApp:page"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914635},{""Pid"":142307070914634,""Pids"":""[0],[142307070914633],[142307070914634],"",""Name"":""应用列表"",""Code"":""sys_app_mgr_list"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysApp:list"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914636},{""Pid"":142307070914634,""Pids"":""[0],[142307070914633],[142307070914634],"",""Name"":""应用增加"",""Code"":""sys_app_mgr_add"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysApp:add"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914637},{""Pid"":142307070914634,""Pids"":""[0],[142307070914633],[142307070914634],"",""Name"":""应用编辑"",""Code"":""sys_app_mgr_edit"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysApp:edit"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914638},{""Pid"":142307070914634,""Pids"":""[0],[142307070914633],[142307070914634],"",""Name"":""应用删除"",""Code"":""sys_app_mgr_delete"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysApp:delete"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914639},{""Pid"":142307070914634,""Pids"":""[0],[142307070914633],[142307070914634],"",""Name"":""应用详情"",""Code"":""sys_app_mgr_detail"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysApp:detail"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914640},{""Pid"":142307070914634,""Pids"":""[0],[142307070914633],[142307070914634],"",""Name"":""设为默认应用"",""Code"":""sys_app_mgr_set_as_default"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysApp:setAsDefault"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914641},{""Pid"":142307070914633,""Pids"":""[0],[142307070914633],"",""Name"":""菜单管理"",""Code"":""sys_menu_mgr"",""Type"":1,""Icon"":null,""Router"":""/menu"",""Component"":""system/menu/index"",""Permission"":null,""Application"":""system"",""OpenType"":1,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914642},{""Pid"":142307070914642,""Pids"":""[0],[142307070914633],[142307070914642],"",""Name"":""菜单列表"",""Code"":""sys_menu_mgr_list"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysMenu:list"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914643},{""Pid"":142307070914642,""Pids"":""[0],[142307070914633],[142307070914642],"",""Name"":""菜单增加"",""Code"":""sys_menu_mgr_add"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysMenu:add"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914644},{""Pid"":142307070914642,""Pids"":""[0],[142307070914633],[142307070914642],"",""Name"":""菜单编辑"",""Code"":""sys_menu_mgr_edit"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysMenu:edit"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914645},{""Pid"":142307070914642,""Pids"":""[0],[142307070914633],[142307070914642],"",""Name"":""菜单删除"",""Code"":""sys_menu_mgr_delete"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysMenu:delete"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914646},{""Pid"":142307070914642,""Pids"":""[0],[142307070914633],[142307070914642],"",""Name"":""菜单详情"",""Code"":""sys_menu_mgr_detail"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysMenu:detail"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914647},{""Pid"":142307070914651,""Pids"":""[0],[142307070914633],[142307070914651],"",""Name"":""菜单授权树"",""Code"":""sys_menu_mgr_grant_tree"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysMenu:treeForGrant"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914648},{""Pid"":142307070914651,""Pids"":""[0],[142307070914633],[142307070914651],"",""Name"":""菜单树"",""Code"":""sys_menu_mgr_tree"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysMenu:tree"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914649},{""Pid"":142307070914642,""Pids"":""[0],[142307070914633],[142307070914642],"",""Name"":""菜单切换"",""Code"":""sys_menu_mgr_change"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysMenu:change"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914650},{""Pid"":142307070910563,""Pids"":""[0],[142307070910563],"",""Name"":""角色管理"",""Code"":""sys_role_mgr"",""Type"":1,""Icon"":null,""Router"":""/role"",""Component"":""system/role/index"",""Permission"":null,""Application"":""manage"",""OpenType"":1,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914651},{""Pid"":142307070914651,""Pids"":""[0],[142307070910563],[142307070914651],"",""Name"":""角色查询"",""Code"":""sys_role_mgr_page"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysRole:page"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914652},{""Pid"":142307070914651,""Pids"":""[0],[142307070910563],[142307070914651],"",""Name"":""角色增加"",""Code"":""sys_role_mgr_add"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysRole:add"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914653},{""Pid"":142307070914651,""Pids"":""[0],[142307070910563],[142307070914651],"",""Name"":""角色编辑"",""Code"":""sys_role_mgr_edit"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysRole:edit"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914654},{""Pid"":142307070914651,""Pids"":""[0],[142307070910563],[142307070914651],"",""Name"":""角色删除"",""Code"":""sys_role_mgr_delete"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysRole:delete"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914655},{""Pid"":142307070914651,""Pids"":""[0],[142307070910563],[142307070914651],"",""Name"":""角色详情"",""Code"":""sys_role_mgr_detail"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysRole:detail"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914656},{""Pid"":142307070914651,""Pids"":""[0],[142307070910563],[142307070914651],"",""Name"":""角色下拉"",""Code"":""sys_role_mgr_drop_down"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysRole:dropDown"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914657},{""Pid"":142307070914651,""Pids"":""[0],[142307070910563],[142307070914651],"",""Name"":""角色授权菜单"",""Code"":""sys_role_mgr_grant_menu"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysRole:grantMenu"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914658},{""Pid"":142307070914651,""Pids"":""[0],[142307070910563],[142307070914651],"",""Name"":""角色拥有菜单"",""Code"":""sys_role_mgr_own_menu"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysRole:ownMenu"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914659},{""Pid"":142307070914651,""Pids"":""[0],[142307070910563],[142307070914651],"",""Name"":""角色授权数据"",""Code"":""sys_role_mgr_grant_data"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysRole:grantData"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914660},{""Pid"":142307070914651,""Pids"":""[0],[142307070910563],[142307070914651],"",""Name"":""角色拥有数据"",""Code"":""sys_role_mgr_own_data"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysRole:ownData"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914661},{""Pid"":0,""Pids"":""[0],"",""Name"":""开发管理"",""Code"":""system_tools"",""Type"":0,""Icon"":""euro"",""Router"":""/tools"",""Component"":""PageView"",""Permission"":null,""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914662},{""Pid"":142307070914662,""Pids"":""[0],[142307070914662],"",""Name"":""系统配置"",""Code"":""system_tools_config"",""Type"":1,""Icon"":null,""Router"":""/config"",""Component"":""system/config/index"",""Permission"":null,""Application"":""system"",""OpenType"":1,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914663},{""Pid"":142307070914663,""Pids"":""[0],[142307070914662],[142307070914663],"",""Name"":""配置查询"",""Code"":""system_tools_config_page"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysConfig:page"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914664},{""Pid"":142307070914663,""Pids"":""[0],[142307070914662],[142307070914663],"",""Name"":""配置列表"",""Code"":""system_tools_config_list"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysConfig:list"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914665},{""Pid"":142307070914663,""Pids"":""[0],[142307070914662],[142307070914663],"",""Name"":""配置增加"",""Code"":""system_tools_config_add"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysConfig:add"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914666},{""Pid"":142307070914663,""Pids"":""[0],[142307070914662],[142307070914663],"",""Name"":""配置编辑"",""Code"":""system_tools_config_edit"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysConfig:edit"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914667},{""Pid"":142307070914663,""Pids"":""[0],[142307070914662],[142307070914663],"",""Name"":""配置删除"",""Code"":""system_tools_config_delete"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysConfig:delete"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914668},{""Pid"":142307070914663,""Pids"":""[0],[142307070914662],[142307070914663],"",""Name"":""配置详情"",""Code"":""system_tools_config_detail"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysConfig:detail"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914669},{""Pid"":142307070914663,""Pids"":""[0],[142307070914662],[142307070914663],"",""Name"":""设为默认应用"",""Code"":""sys_app_mgr_set_as_default"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysApp:setAsDefault"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914670},{""Pid"":142307070914662,""Pids"":""[0],[142307070914662],"",""Name"":""邮件发送"",""Code"":""sys_email_mgr"",""Type"":1,""Icon"":null,""Router"":""/email"",""Component"":""system/email/index"",""Permission"":null,""Application"":""system"",""OpenType"":1,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914671},{""Pid"":142307070914671,""Pids"":""[0],[142307070914662],[142307070914671],"",""Name"":""发送文本邮件"",""Code"":""sys_email_mgr_send_email"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""email:sendEmail"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914672},{""Pid"":142307070914671,""Pids"":""[0],[142307070914662],[142307070914671],"",""Name"":""发送html邮件"",""Code"":""sys_email_mgr_send_email_html"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""email:sendEmailHtml"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914673},{""Pid"":142307070914662,""Pids"":""[0],[142307070914662],"",""Name"":""短信管理"",""Code"":""sys_sms_mgr"",""Type"":1,""Icon"":null,""Router"":""/sms"",""Component"":""system/sms/index"",""Permission"":null,""Application"":""system"",""OpenType"":1,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914674},{""Pid"":142307070914674,""Pids"":""[0],[142307070914662],[142307070914674],"",""Name"":""短信发送查询"",""Code"":""sys_sms_mgr_page"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sms:page"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914675},{""Pid"":142307070914674,""Pids"":""[0],[142307070914662],[142307070914674],"",""Name"":""发送验证码短信"",""Code"":""sys_sms_mgr_send_login_message"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sms:sendLoginMessage"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914676},{""Pid"":142307070914674,""Pids"":""[0],[142307070914662],[142307070914674],"",""Name"":""验证短信验证码"",""Code"":""sys_sms_mgr_validate_message"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sms:validateMessage"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914677},{""Pid"":142307070914662,""Pids"":""[0],[142307070914662],"",""Name"":""字典管理"",""Code"":""sys_dict_mgr"",""Type"":1,""Icon"":null,""Router"":""/dict"",""Component"":""system/dict/index"",""Permission"":null,""Application"":""system"",""OpenType"":1,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914678},{""Pid"":142307070914678,""Pids"":""[0],[142307070914662],[142307070914678],"",""Name"":""字典类型查询"",""Code"":""sys_dict_mgr_dict_type_page"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysDictType:page"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914679},{""Pid"":142307070914678,""Pids"":""[0],[142307070914662],[142307070914678],"",""Name"":""字典类型列表"",""Code"":""sys_dict_mgr_dict_type_list"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysDictType:list"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914680},{""Pid"":142307070914678,""Pids"":""[0],[142307070914662],[142307070914678],"",""Name"":""字典类型增加"",""Code"":""sys_dict_mgr_dict_type_add"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysDictType:add"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914681},{""Pid"":142307070914678,""Pids"":""[0],[142307070914662],[142307070914678],"",""Name"":""字典类型删除"",""Code"":""sys_dict_mgr_dict_type_delete"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysDictType:delete"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914682},{""Pid"":142307070914678,""Pids"":""[0],[142307070914662],[142307070914678],"",""Name"":""字典类型编辑"",""Code"":""sys_dict_mgr_dict_type_edit"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysDictType:edit"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914683},{""Pid"":142307070914678,""Pids"":""[0],[142307070914662],[142307070914678],"",""Name"":""字典类型详情"",""Code"":""sys_dict_mgr_dict_type_detail"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysDictType:detail"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914684},{""Pid"":142307070914678,""Pids"":""[0],[142307070914662],[142307070914678],"",""Name"":""字典类型下拉"",""Code"":""sys_dict_mgr_dict_type_drop_down"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysDictType:dropDown"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914685},{""Pid"":142307070914678,""Pids"":""[0],[142307070914662],[142307070914678],"",""Name"":""字典类型修改状态"",""Code"":""sys_dict_mgr_dict_type_change_status"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysDictType:changeStatus"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914686},{""Pid"":142307070914678,""Pids"":""[0],[142307070914662],[142307070914678],"",""Name"":""字典值查询"",""Code"":""sys_dict_mgr_dict_page"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysDictData:page"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070914687},{""Pid"":142307070914678,""Pids"":""[0],[142307070914662],[142307070914678],"",""Name"":""字典值列表"",""Code"":""sys_dict_mgr_dict_list"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysDictData:list"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918725},{""Pid"":142307070914678,""Pids"":""[0],[142307070914662],[142307070914678],"",""Name"":""字典值增加"",""Code"":""sys_dict_mgr_dict_add"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysDictData:add"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918726},{""Pid"":142307070914678,""Pids"":""[0],[142307070914662],[142307070914678],"",""Name"":""字典值删除"",""Code"":""sys_dict_mgr_dict_delete"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysDictData:delete"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918727},{""Pid"":142307070914678,""Pids"":""[0],[142307070914662],[142307070914678],"",""Name"":""字典值编辑"",""Code"":""sys_dict_mgr_dict_edit"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysDictData:edit"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918728},{""Pid"":142307070914678,""Pids"":""[0],[142307070914662],[142307070914678],"",""Name"":""字典值详情"",""Code"":""sys_role_mgr_grant_data"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysDictData:detail"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918729},{""Pid"":142307070914678,""Pids"":""[0],[142307070914662],[142307070914678],"",""Name"":""字典值修改状态"",""Code"":""sys_dict_mgr_dict_change_status"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysDictData:changeStatus"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918730},{""Pid"":142307070914662,""Pids"":""[0],[142307070914662],"",""Name"":""接口文档"",""Code"":""sys_swagger_mgr"",""Type"":1,""Icon"":null,""Router"":""/swagger"",""Component"":""Iframe"",""Permission"":null,""Application"":""system"",""OpenType"":2,""Visible"":""Y"",""Link"":""http://localhost:5566/"",""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918731},{""Pid"":0,""Pids"":""[0],"",""Name"":""日志管理"",""Code"":""sys_log_mgr"",""Type"":0,""Icon"":""read"",""Router"":""/log"",""Component"":""PageView"",""Permission"":null,""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918732},{""Pid"":142307070918732,""Pids"":""[0],[142307070918732],"",""Name"":""访问日志"",""Code"":""sys_log_mgr_vis_log"",""Type"":1,""Icon"":null,""Router"":""/vislog"",""Component"":""system/log/vislog/index"",""Permission"":null,""Application"":""manage"",""OpenType"":1,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918733},{""Pid"":142307070918733,""Pids"":""[0],[142307070918732],[142307070918733],"",""Name"":""访问日志查询"",""Code"":""sys_log_mgr_vis_log_page"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysVisLog:page"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918734},{""Pid"":142307070918733,""Pids"":""[0],[142307070918732],[142307070918733],"",""Name"":""访问日志清空"",""Code"":""sys_log_mgr_vis_log_delete"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysVisLog:delete"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918735},{""Pid"":142307070918732,""Pids"":""[0],[142307070918732],"",""Name"":""操作日志"",""Code"":""sys_log_mgr_op_log"",""Type"":1,""Icon"":null,""Router"":""/oplog"",""Component"":""system/log/oplog/index"",""Permission"":null,""Application"":""manage"",""OpenType"":1,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918736},{""Pid"":142307070918736,""Pids"":""[0],[142307070918732],[142307070918736],"",""Name"":""操作日志查询"",""Code"":""sys_log_mgr_op_log_page"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysOpLog:page"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918737},{""Pid"":142307070918736,""Pids"":""[0],[142307070918732],[142307070918736],"",""Name"":""操作日志清空"",""Code"":""sys_log_mgr_op_log_delete"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysOpLog:delete"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918738},{""Pid"":0,""Pids"":""[0],"",""Name"":""系统监控"",""Code"":""sys_monitor_mgr"",""Type"":0,""Icon"":""deployment-unit"",""Router"":""/monitor"",""Component"":""PageView"",""Permission"":null,""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918739},{""Pid"":142307070918739,""Pids"":""[0],[142307070918739],"",""Name"":""服务监控"",""Code"":""sys_monitor_mgr_machine_monitor"",""Type"":1,""Icon"":null,""Router"":""/machine"",""Component"":""system/machine/index"",""Permission"":null,""Application"":""system"",""OpenType"":1,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918740},{""Pid"":142307070918740,""Pids"":""[0],[142307070918739],[142307070918740],"",""Name"":""服务监控查询"",""Code"":""sys_monitor_mgr_machine_monitor_query"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysMachine:query"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918741},{""Pid"":142307070918739,""Pids"":""[0],[142307070918739],"",""Name"":""在线用户"",""Code"":""sys_monitor_mgr_online_user"",""Type"":1,""Icon"":null,""Router"":""/onlineUser"",""Component"":""system/onlineUser/index"",""Permission"":null,""Application"":""system"",""OpenType"":1,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918742},{""Pid"":142307070918742,""Pids"":""[0],[142307070918739],[142307070918742],"",""Name"":""在线用户列表"",""Code"":""sys_monitor_mgr_online_user_list"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysOnlineUser:list"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918743},{""Pid"":142307070918742,""Pids"":""[0],[142307070918739],[142307070918742],"",""Name"":""在线用户强退"",""Code"":""sys_monitor_mgr_online_user_force_exist"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysOnlineUser:forceExist"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918744},{""Pid"":142307070918739,""Pids"":""[0],[142307070918739],"",""Name"":""数据监控"",""Code"":""sys_monitor_mgr_druid"",""Type"":1,""Icon"":null,""Router"":""/druid"",""Component"":""Iframe"",""Permission"":null,""Application"":""system"",""OpenType"":2,""Visible"":""N"",""Link"":""http://localhost:82/druid/login.html"",""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918745},{""Pid"":0,""Pids"":""[0],"",""Name"":""通知公告"",""Code"":""sys_notice"",""Type"":0,""Icon"":""sound"",""Router"":""/notice"",""Component"":""PageView"",""Permission"":null,""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918746},{""Pid"":142307070918746,""Pids"":""[0],[142307070918746],"",""Name"":""公告管理"",""Code"":""sys_notice_mgr"",""Type"":1,""Icon"":null,""Router"":""/notice"",""Component"":""system/notice/index"",""Permission"":null,""Application"":""manage"",""OpenType"":1,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918747},{""Pid"":142307070918747,""Pids"":""[0],[142307070918746],[142307070918747],"",""Name"":""公告查询"",""Code"":""sys_notice_mgr_page"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysNotice:page"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918748},{""Pid"":142307070918747,""Pids"":""[0],[142307070918746],[142307070918747],"",""Name"":""公告增加"",""Code"":""sys_notice_mgr_add"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysNotice:add"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918749},{""Pid"":142307070918747,""Pids"":""[0],[142307070918746],[142307070918747],"",""Name"":""公告编辑"",""Code"":""sys_notice_mgr_edit"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysNotice:edit"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918750},{""Pid"":142307070918747,""Pids"":""[0],[142307070918746],[142307070918747],"",""Name"":""公告删除"",""Code"":""sys_notice_mgr_delete"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysNotice:delete"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918751},{""Pid"":142307070918747,""Pids"":""[0],[142307070918746],[142307070918747],"",""Name"":""公告查看"",""Code"":""sys_notice_mgr_detail"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysNotice:detail"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918752},{""Pid"":142307070918747,""Pids"":""[0],[142307070918746],[142307070918747],"",""Name"":""公告修改状态"",""Code"":""sys_notice_mgr_changeStatus"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysNotice:changeStatus"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918753},{""Pid"":142307070918746,""Pids"":""[0],[142307070918746],"",""Name"":""已收公告"",""Code"":""sys_notice_mgr_received"",""Type"":1,""Icon"":null,""Router"":""/noticeReceived"",""Component"":""system/noticeReceived/index"",""Permission"":null,""Application"":""manage"",""OpenType"":1,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918754},{""Pid"":142307070918754,""Pids"":""[0],[142307070918746],[142307070918754],"",""Name"":""已收公告查询"",""Code"":""sys_notice_mgr_received_page"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysNotice:received"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918755},{""Pid"":0,""Pids"":""[0],"",""Name"":""文件管理"",""Code"":""sys_file_mgr"",""Type"":0,""Icon"":""file"",""Router"":""/file"",""Component"":""PageView"",""Permission"":null,""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918756},{""Pid"":142307070918756,""Pids"":""[0],[142307070918756],"",""Name"":""系统文件"",""Code"":""sys_file_mgr_sys_file"",""Type"":1,""Icon"":null,""Router"":""/file"",""Component"":""system/file/index"",""Permission"":null,""Application"":""manage"",""OpenType"":1,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918757},{""Pid"":142307070918757,""Pids"":""[0],[142307070918756],[142307070918757],"",""Name"":""文件查询"",""Code"":""sys_file_mgr_sys_file_page"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysFileInfo:page"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918758},{""Pid"":142307070918757,""Pids"":""[0],[142307070918756],[142307070918757],"",""Name"":""文件列表"",""Code"":""sys_file_mgr_sys_file_list"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysFileInfo:list"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918759},{""Pid"":142307070918757,""Pids"":""[0],[142307070918756],[142307070918757],"",""Name"":""文件删除"",""Code"":""sys_file_mgr_sys_file_delete"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysFileInfo:delete"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918760},{""Pid"":142307070918757,""Pids"":""[0],[142307070918756],[142307070918757],"",""Name"":""文件详情"",""Code"":""sys_file_mgr_sys_file_detail"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysFileInfo:detail"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918761},{""Pid"":142307070918757,""Pids"":""[0],[142307070918756],[142307070918757],"",""Name"":""文件上传"",""Code"":""sys_file_mgr_sys_file_upload"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysFileInfo:upload"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918762},{""Pid"":142307070918757,""Pids"":""[0],[142307070918756],[142307070918757],"",""Name"":""文件下载"",""Code"":""sys_file_mgr_sys_file_download"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysFileInfo:download"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918763},{""Pid"":142307070918757,""Pids"":""[0],[142307070918756],[142307070918757],"",""Name"":""图片预览"",""Code"":""sys_file_mgr_sys_file_preview"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysFileInfo:preview"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918764},{""Pid"":0,""Pids"":""[0],"",""Name"":""定时任务"",""Code"":""sys_timers"",""Type"":0,""Icon"":""dashboard"",""Router"":""/timers"",""Component"":""PageView"",""Permission"":null,""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918765},{""Pid"":142307070918765,""Pids"":""[0],[142307070918765],"",""Name"":""任务管理"",""Code"":""sys_timers_mgr"",""Type"":1,""Icon"":null,""Router"":""/timers"",""Component"":""system/timers/index"",""Permission"":null,""Application"":""system"",""OpenType"":1,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918766},{""Pid"":142307070918766,""Pids"":""[0],[142307070918765],[142307070918766],"",""Name"":""定时任务查询"",""Code"":""sys_timers_mgr_page"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysTimers:page"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918767},{""Pid"":142307070918766,""Pids"":""[0],[142307070918765],[142307070918766],"",""Name"":""定时任务列表"",""Code"":""sys_timers_mgr_list"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysTimers:list"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918768},{""Pid"":142307070918766,""Pids"":""[0],[142307070918765],[142307070918766],"",""Name"":""定时任务详情"",""Code"":""sys_timers_mgr_detail"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysTimers:detail"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918769},{""Pid"":142307070918766,""Pids"":""[0],[142307070918765],[142307070918766],"",""Name"":""定时任务增加"",""Code"":""sys_timers_mgr_add"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysTimers:add"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918770},{""Pid"":142307070918766,""Pids"":""[0],[142307070918765],[142307070918766],"",""Name"":""定时任务删除"",""Code"":""sys_timers_mgr_delete"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysTimers:delete"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918771},{""Pid"":142307070918766,""Pids"":""[0],[142307070918765],[142307070918766],"",""Name"":""定时任务编辑"",""Code"":""sys_timers_mgr_edit"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysTimers:edit"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918772},{""Pid"":142307070918766,""Pids"":""[0],[142307070918765],[142307070918766],"",""Name"":""定时任务可执行列表"",""Code"":""sys_timers_mgr_get_action_classes"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysTimers:getActionClasses"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918773},{""Pid"":142307070918766,""Pids"":""[0],[142307070918765],[142307070918766],"",""Name"":""定时任务启动"",""Code"":""sys_timers_mgr_start"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysTimers:start"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918774},{""Pid"":142307070918766,""Pids"":""[0],[142307070918765],[142307070918766],"",""Name"":""定时任务关闭"",""Code"":""sys_timers_mgr_stop"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysTimers:stop"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918775},{""Pid"":0,""Pids"":""[0],"",""Name"":""代码生成"",""Code"":""code_gen"",""Type"":1,""Icon"":""thunderbolt"",""Router"":""/codeGenerate/index"",""Component"":""gen/codeGenerate/index"",""Permission"":null,""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918776},{""Pid"":142307070910564,""Pids"":""[0],[142307070910563],[142307070910564],"",""Name"":""用户登录信息"",""Code"":""sys_user_mgr_login"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""getLoginUser"",""Application"":""manage"",""OpenType"":0,""Visible"":""N"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":1,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918777},{""Pid"":0,""Pids"":""[0],"",""Name"":""SaaS租户"",""Code"":""sys_tenant"",""Type"":1,""Icon"":""switcher"",""Router"":""/tenant"",""Component"":""PageView"",""Permission"":null,""Application"":""platform"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918782},{""Pid"":142307070918782,""Pids"":""[0],[142307070918782],"",""Name"":""租户管理"",""Code"":""sys_tenant_mgr"",""Type"":1,""Icon"":null,""Router"":""/tenant"",""Component"":""system/tenant/index"",""Permission"":null,""Application"":""platform"",""OpenType"":1,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918783},{""Pid"":142307070918783,""Pids"":""[0],[142307070918782],[142307070918783],"",""Name"":""租户查询"",""Code"":""sys_tenant_mgr_page"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysTenant:page"",""Application"":""platform"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922821},{""Pid"":142307070918783,""Pids"":""[0],[142307070918782],[142307070918783],"",""Name"":""租户详情"",""Code"":""sys_tenant_mgr_detail"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysTenant:detail"",""Application"":""platform"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922822},{""Pid"":142307070918783,""Pids"":""[0],[142307070918782],[142307070918783],"",""Name"":""租户增加"",""Code"":""sys_tenant_mgr_add"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysTenant:add"",""Application"":""platform"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922823},{""Pid"":142307070918783,""Pids"":""[0],[142307070918782],[142307070918783],"",""Name"":""租户删除"",""Code"":""sys_tenant_mgr_delete"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysTenant:delete"",""Application"":""platform"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922824},{""Pid"":142307070918783,""Pids"":""[0],[142307070918782],[142307070918783],"",""Name"":""租户编辑"",""Code"":""sys_tenant_mgr_edit"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysTenant:edit"",""Application"":""platform"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922825},{""Pid"":142307070918783,""Pids"":""[0],[142307070918782],[142307070918783],"",""Name"":""授权租户菜单"",""Code"":""sys_tenant_mgr_grant_menu"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysTenant:grantMenu"",""Application"":""platform"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922826},{""Pid"":142307070918783,""Pids"":""[0],[142307070918782],[142307070918783],"",""Name"":""重置租户密码"",""Code"":""sys_tenant_mgr_reset_pwd"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysTenant:resetPwd"",""Application"":""platform"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922827},{""Pid"":0,""Pids"":""[0],"",""Name"":""表单设计"",""Code"":""form_design"",""Type"":1,""Icon"":""robot"",""Router"":""/formDesign/index"",""Component"":""system/formDesign/index"",""Permission"":null,""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922870},{""Pid"":142307070918757,""Pids"":""[0],[142307070918756],[142307070918757],"",""Name"":""头像上传"",""Code"":""sys_file_mgr_sys_file_upload_avatar"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysFileInfo:uploadAvatar"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922874},{""Pid"":142307070918757,""Pids"":""[0],[142307070918756],[142307070918757],"",""Name"":""文档上传"",""Code"":""sys_file_mgr_sys_file_upload_document"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysFileInfo:uploadDocument"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922875},{""Pid"":142307070918757,""Pids"":""[0],[142307070918756],[142307070918757],"",""Name"":""商城上传"",""Code"":""sys_file_mgr_sys_file_upload_shop"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""sysFileInfo:uploadShop"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070922876},{""Pid"":0,""Pids"":""[0],"",""Name"":""大屏监控"",""Code"":""main_screen_monitor"",""Type"":1,""Icon"":""pie-chart"",""Router"":""/monitor"",""Component"":""main/screenMonitor/index"",""Permission"":"""",""Application"":""busiapp"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":"""",""Weight"":2,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2021-07-07T14:50:13.943"",""UpdatedTime"":""2021-07-07T14:54:25.19"",""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":178075287240773},{""Pid"":0,""Pids"":""[0],"",""Name"":""地理信息"",""Code"":""main_map"",""Type"":1,""Icon"":""environment"",""Router"":""/map"",""Component"":""main/map/index"",""Permission"":"""",""Application"":""busiapp"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":"""",""Weight"":2,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2021-07-07T15:07:38.88"",""UpdatedTime"":""2021-07-08T15:21:28.267"",""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":178079567294533},{""Pid"":0,""Pids"":""[0],"",""Name"":""数据库管理"",""Code"":""database_manager"",""Type"":1,""Icon"":""radar-chart"",""Router"":""/database/index"",""Component"":""gen/database/index"",""Permission"":"""",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2021-07-20T10:30:56.68"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":182612191891525},{""Pid"":182612191891525,""Pids"":""[0],[182612191891525],"",""Name"":""新增数据表"",""Code"":""table_add"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""table:add"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2021-07-20T16:21:16.13"",""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":182692422213701},{""Pid"":182612191891525,""Pids"":""[0],[182612191891525],"",""Name"":""编辑数据表"",""Code"":""table_edit"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""table:edit"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2021-07-20T15:58:19.803"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":182692650123333},{""Pid"":182612191891525,""Pids"":""[0],[182612191891525],"",""Name"":""删除数据表"",""Code"":""table_delete"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""table:delete"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2021-07-20T15:59:00.237"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":182692815732805},{""Pid"":182612191891525,""Pids"":""[0],[182612191891525],"",""Name"":""新增数据列"",""Code"":""column_add"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""column:add"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2021-07-20T16:00:20.08"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":182693142773829},{""Pid"":182612191891525,""Pids"":""[0],[182612191891525],"",""Name"":""编辑数据列"",""Code"":""column_edit"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""column:edit"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2021-07-20T16:00:50.293"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":182693266526277},{""Pid"":182612191891525,""Pids"":""[0],[182612191891525],"",""Name"":""删除数据列"",""Code"":""column_delete"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""column:delete"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2021-07-20T16:01:16.163"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":182693372485701},{""Pid"":142307070918776,""Pids"":""[0],[142307070918776],"",""Name"":""新增代码生成"",""Code"":""codeGenerate_add"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""codeGenerate:add"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2021-07-20T16:27:01.137"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":182699700703301},{""Pid"":142307070918776,""Pids"":""[0],[142307070918776],"",""Name"":""编辑代码生成"",""Code"":""codeGenerate_edit"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""codeGenerate:edit"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2021-07-20T16:29:27.36"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":182700299632709},{""Pid"":142307070918776,""Pids"":""[0],[142307070918776],"",""Name"":""删除代码生成"",""Code"":""codeGenerate:delete"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""codeGenerate:delete"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2021-07-20T16:29:55.023"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":182700412936261},{""Pid"":142307070918776,""Pids"":""[0],[142307070918776],"",""Name"":""开始生成"",""Code"":""codeGenerate_runDown"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""codeGenerate:runDown"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2021-07-20T16:30:37.063"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":182700585140293},{""Pid"":142307070918776,""Pids"":""[0],[142307070918776],"",""Name"":""生成到本地"",""Code"":""codeGenerate_runLocal"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""codeGenerate:runLocal"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2021-07-20T16:31:45.223"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":182700864315461},{""Pid"":142307070918776,""Pids"":""[0],[142307070918776],"",""Name"":""生成代码配置"",""Code"":""codeGenerate_config"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""codeGenerate:config"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2021-07-20T16:32:19.377"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":182701004218437},{""Pid"":182612191891525,""Pids"":""[0],[182612191891525],"",""Name"":""数据库表查询"",""Code"":""dataBase_tableInfoList"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""dataBase:tableInfoList"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":98,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2021-07-22T17:41:23.773"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":183425655615557},{""Pid"":182612191891525,""Pids"":""[0],[182612191891525],"",""Name"":""数据表列查询"",""Code"":""dataBase_columnInfoList"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""dataBase:columnInfoList"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":99,""Remark"":null,""Status"":0,""CreatedTime"":""2021-07-22T17:42:07.527"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":183425947672645},{""Pid"":142307070918776,""Pids"":""[0],[142307070918776],"",""Name"":""代码生成查询"",""Code"":""codeGenerate_page"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""codeGenerate:page"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":98,""Remark"":null,""Status"":0,""CreatedTime"":""2021-07-22T17:43:29.207"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":183426282242117},{""Pid"":142307070918776,""Pids"":""[0],[142307070918776],"",""Name"":""代码生成配置查询"",""Code"":""sysCodeGenerateConfig_list"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""sysCodeGenerateConfig:list"",""Application"":""system"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":99,""Remark"":null,""Status"":0,""CreatedTime"":""2021-07-22T17:44:27.167"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":183426519642181},{""Pid"":249828267671621,""Pids"":""[0],[249828267671621],"",""Name"":""表单管理"",""Code"":""flc_form_mgr"",""Type"":1,""Icon"":"""",""Router"":""/flcForm"",""Component"":""flowCenter/form/index"",""Permission"":"""",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-26T08:57:36.147"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":246828204404805},{""Pid"":246828204404805,""Pids"":""[0],[249828267671621],[246828204404805],"",""Name"":""表单查询"",""Code"":""flc_form_mgr_page"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""flcForm:page"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-26T08:55:15.723"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":246829143507013},{""Pid"":246828204404805,""Pids"":""[0],[249828267671621],[246828204404805],"",""Name"":""表单新增"",""Code"":""flc_form_mgr_add"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""flcForm:add"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-26T08:55:15.723"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":246829667049541},{""Pid"":246828204404805,""Pids"":""[0],[249828267671621],[246828204404805],"",""Name"":""表单编辑"",""Code"":""flc_form_mgr_edit"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""flcForm:edit"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-26T08:55:15.723"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":246829802606661},{""Pid"":246828204404805,""Pids"":""[0],[249828267671621],[246828204404805],"",""Name"":""表单删除"",""Code"":""flc_form_mgr_delete"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""flcForm:delete"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-26T08:55:15.723"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":246829942235205},{""Pid"":246828204404805,""Pids"":""[0],[249828267671621],[246828204404805],"",""Name"":""表单详情"",""Code"":""flc_form_mgr_detail"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""flcForm:detail"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-26T08:55:15.723"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":246830165426245},{""Pid"":246828204404805,""Pids"":""[0],[249828267671621],[246828204404805],"",""Name"":""表单列表"",""Code"":""flc_form_mgr_list"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""flcForm:list"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-26T08:55:15.723"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":246841718005829},{""Pid"":246828204404805,""Pids"":""[0],[249828267671621],[246828204404805],"",""Name"":""表单设计"",""Code"":""flc_form_mgr_design"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""flcForm:design"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-01-18T15:12:03.047"",""UpdatedTime"":""2022-01-26T08:55:15.723"",""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":247090057326661},{""Pid"":249828267671621,""Pids"":""[0],[249828267671621],"",""Name"":""流程管理"",""Code"":""flc_flow_mgr"",""Type"":1,""Icon"":"""",""Router"":""/flcFlow"",""Component"":""flowCenter/flow/index"",""Permission"":null,""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-26T08:57:47.367"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":248420412096581},{""Pid"":248420412096581,""Pids"":""[0],[249828267671621],[248420412096581],"",""Name"":""流程查询"",""Code"":""flc_flow_mgr_page"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""flcFlowscheme:page"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-26T08:55:07.453"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":248420412231749},{""Pid"":248420412096581,""Pids"":""[0],[249828267671621],[248420412096581],"",""Name"":""流程详情"",""Code"":""flc_flow_mgr_detail"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""flcFlowscheme:detail"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-26T08:55:07.453"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":248420412231750},{""Pid"":248420412096581,""Pids"":""[0],[249828267671621],[248420412096581],"",""Name"":""流程增加"",""Code"":""flc_flow_mgr_add"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""flcFlowscheme:add"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-26T08:55:07.453"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":248420412231751},{""Pid"":248420412096581,""Pids"":""[0],[249828267671621],[248420412096581],"",""Name"":""流程删除"",""Code"":""flc_flow_mgr_delete"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""flcFlowscheme:delete"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-26T08:55:07.453"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":248420412231752},{""Pid"":248420412096581,""Pids"":""[0],[249828267671621],[248420412096581],"",""Name"":""流程编辑"",""Code"":""flc_flow_mgr_edit"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""flcFlowscheme:edit"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-26T08:55:07.453"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":248420412231753},{""Pid"":248420412096581,""Pids"":""[0],[249828267671621],[248420412096581],"",""Name"":""流程列表"",""Code"":""flc_flow_mgr_list"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""flcFlowscheme:list"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-26T08:55:07.453"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":248433799409733},{""Pid"":248420412096581,""Pids"":""[0],[249828267671621],[248420412096581],"",""Name"":""流程设计"",""Code"":""flc_flow_mgr_design"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""flcFlowscheme:design"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-26T08:55:07.453"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":248433972678725},{""Pid"":248420412096581,""Pids"":""[0],[249828267671621],[248420412096581],"",""Name"":""流程预览"",""Code"":""flc_flow_mgr_preview"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""flcFlowscheme:preview"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-01-25T23:10:33.82"",""UpdatedTime"":""2022-01-26T08:55:07.453"",""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":249684917448773},{""Pid"":246828204404805,""Pids"":""[0],[249828267671621],[246828204404805],"",""Name"":""表单预览"",""Code"":""flc_form_mgr_preview"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""flcForm:preview"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-01-25T23:11:23.05"",""UpdatedTime"":""2022-01-26T08:55:15.723"",""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":249685119098949},{""Pid"":0,""Pids"":""[0],"",""Name"":""工作流设置"",""Code"":""flc_mgr"",""Type"":0,""Icon"":""retweet"",""Router"":""/flc"",""Component"":""PageView"",""Permission"":"""",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-26T08:54:53.35"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":249828267671621},{""Pid"":0,""Pids"":""[0],"",""Name"":""工作流"",""Code"":""flc_center"",""Type"":0,""Icon"":""qrcode"",""Router"":""/flcCenter"",""Component"":""PageView"",""Permission"":"""",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-01-26T09:39:58"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":249839600734277},{""Pid"":249839600734277,""Pids"":""[0],[249839600734277],"",""Name"":""我的申请"",""Code"":""flc_center_my"",""Type"":1,""Icon"":null,""Router"":""/workflow/my"",""Component"":""flowCenter/workflow/my"",""Permission"":"""",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":"""",""Weight"":1,""Sort"":2,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-27T15:23:07.82"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":249840339677253},{""Pid"":249839600734277,""Pids"":""[0],[249839600734277],"",""Name"":""待处理申请"",""Code"":""flc_center_undone"",""Type"":1,""Icon"":null,""Router"":""/workflow/undone"",""Component"":""flowCenter/workflow/undone"",""Permission"":"""",""Application"":""flowcenter"",""OpenType"":1,""Visible"":""Y"",""Link"":null,""Redirect"":"""",""Weight"":1,""Sort"":3,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-27T15:23:12.537"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":249840961151045},{""Pid"":249839600734277,""Pids"":""[0],[249839600734277],"",""Name"":""已处理申请"",""Code"":""flc_center_done"",""Type"":1,""Icon"":null,""Router"":""/workflow/done"",""Component"":""flowCenter/workflow/done"",""Permission"":"""",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-27T15:23:16.227"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":249841253343301},{""Pid"":249839600734277,""Pids"":""[0],[249839600734277],"",""Name"":""创建申请"",""Code"":""flc_center_create"",""Type"":1,""Icon"":null,""Router"":""/workflow/create"",""Component"":""flowCenter/workflow/create"",""Permission"":"""",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":"""",""Weight"":1,""Sort"":1,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-27T15:23:02.753"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":249845560930373},{""Pid"":249845560930373,""Pids"":""[0],[249839600734277],[249845560930373],"",""Name"":""创建申请"",""Code"":""flc_center_create_add"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""flcFlowinstance:add"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-27T13:55:52.017"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":250246088646725},{""Pid"":249845560930373,""Pids"":""[0],[249839600734277],[249845560930373],"",""Name"":""流程列表"",""Code"":""flc_center_create_page"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""flcFlowscheme:page"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-01-27T13:16:16"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":250246654218309},{""Pid"":249840339677253,""Pids"":""[0],[249839600734277],[249840339677253],"",""Name"":""申请查询"",""Code"":""flc_center_my_page"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""flcFlowinstance:page"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-27T13:56:03.513"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":250248590839877},{""Pid"":249840961151045,""Pids"":""[0],[249839600734277],[249840961151045],"",""Name"":""申请查询"",""Code"":""flc_center_undone_page"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""flcFlowinstance:page"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-27T13:56:20.9"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":250249084047429},{""Pid"":249841253343301,""Pids"":""[0],[249839600734277],[249841253343301],"",""Name"":""申请查询"",""Code"":""flc_center_done_page"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""flcFlowinstance:page"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-27T13:56:27.31"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":250249277808709},{""Pid"":249840339677253,""Pids"":""[0],[249839600734277],[249840339677253],"",""Name"":""申请详情"",""Code"":""flc_center_my_detail"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""flcFlowinstance:detail"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-27T13:56:11.56"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":250255905538117},{""Pid"":249841253343301,""Pids"":""[0],[249839600734277],[249841253343301],"",""Name"":""申请详情"",""Code"":""flc_center_done_detail"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""flcFlowinstance:detail"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-01-27T13:59:28"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":250257271820357},{""Pid"":249840961151045,""Pids"":""[0],[249839600734277],[249840961151045],"",""Name"":""申请处理"",""Code"":""flc_center_undone_verification"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""flcFlowinstance:verification"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-27T14:06:08.94"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":250258434728005},{""Pid"":249840339677253,""Pids"":""[0],[249839600734277],[249840339677253],"",""Name"":""申请编辑"",""Code"":""flc_center_my_edit"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""flcFlowinstance:edit"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-27T14:05:58.917"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":250258651136069},{""Pid"":249840339677253,""Pids"":""[0],[249839600734277],[249840339677253],"",""Name"":""申请删除"",""Code"":""flc_center_my_delete"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""flcFlowinstance:delete"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-27T14:06:04.077"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":250258822766661},{""Pid"":249840339677253,""Pids"":""[0],[249839600734277],[249840339677253],"",""Name"":""申请撤回"",""Code"":""flc_center_my_cancle"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""flcFlowinstance:cancle"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-01-27T14:07:16.057"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":250259140735045},{""Pid"":248420412096581,""Pids"":""[0],[249828267671621],[248420412096581],"",""Name"":""流程变更状态"",""Code"":""flc_flow_mgr_changestatus"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""flcFlowscheme:changeStatus"",""Application"":""flowcenter"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-01-28T13:51:21"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":250609169530949},{""Pid"":0,""Pids"":""[0],"",""Name"":""文档管理"",""Code"":""doc_manager"",""Type"":0,""Icon"":""folder"",""Router"":""/doc"",""Component"":""PageView"",""Permission"":"""",""Application"":""manage"",""OpenType"":1,""Visible"":""Y"",""Link"":null,""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-04-13T11:11:14.9"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":277111901716549},{""Pid"":277111901716549,""Pids"":""[0],[277111901716549],"",""Name"":""文档管理"",""Code"":""zxzyadmin_document_mgr"",""Type"":1,""Icon"":null,""Router"":""/document"",""Component"":""system/fileManage/document/index"",""Permission"":null,""Application"":""manage"",""OpenType"":1,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":2,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-04-13T11:31:49.327"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":277116957925445},{""Pid"":277116957925445,""Pids"":""[0],[277111901716549],[277116957925445],"",""Name"":""文档查询"",""Code"":""zxzyadmin_document_mgr_page"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""Document:page"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":2,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-04-13T11:31:49.343"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":277116957995077},{""Pid"":277116957925445,""Pids"":""[0],[277111901716549],[277116957925445],"",""Name"":""文档详情"",""Code"":""zxzyadmin_document_mgr_detail"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""Document:detail"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":2,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-04-13T11:31:49.343"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":277116957995078},{""Pid"":277116957925445,""Pids"":""[0],[277111901716549],[277116957925445],"",""Name"":""文档增加"",""Code"":""zxzyadmin_document_mgr_add"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""Document:add"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":2,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-04-13T11:31:49.343"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":277116957995079},{""Pid"":277116957925445,""Pids"":""[0],[277111901716549],[277116957925445],"",""Name"":""文档删除"",""Code"":""zxzyadmin_document_mgr_delete"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""Document:delete"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":2,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-04-13T11:31:49.343"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":277116957995080},{""Pid"":277116957925445,""Pids"":""[0],[277111901716549],[277116957925445],"",""Name"":""文档编辑"",""Code"":""zxzyadmin_document_mgr_edit"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""Document:edit"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":2,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-04-13T11:31:49.343"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":277116957995081},{""Pid"":142307070918783,""Pids"":""[0],[142307070918782],[142307070918783],"",""Name"":""模拟登录"",""Code"":""sysTenant_simulation_login"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""simulationTenantLogin"",""Application"":""platform"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":2,""Sort"":100,""Remark"":""模拟租户登录"",""Status"":0,""CreatedTime"":""2022-04-16T23:14:16"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":277289592221765},{""Pid"":277111901716549,""Pids"":""[0],[277111901716549],"",""Name"":""回收站"",""Code"":""zxzyadmin_trash_mgr"",""Type"":1,""Icon"":null,""Router"":""/trash"",""Component"":""system/fileManage/trash/index"",""Permission"":null,""Application"":""manage"",""OpenType"":1,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":2,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":null,""UpdatedTime"":""2022-04-18T16:37:17.91"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":278944617066565},{""Pid"":278944617066565,""Pids"":""[0],[277111901716549],[278944617066565],"",""Name"":""回收站查询"",""Code"":""zxzyadmin_trash_mgr_page"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""Trash:page"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":2,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-04-18T15:28:35.183"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":278944617115717},{""Pid"":278944617066565,""Pids"":""[0],[277111901716549],[278944617066565],"",""Name"":""回收站详情"",""Code"":""zxzyadmin_trash_mgr_detail"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""Trash:detail"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":2,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-04-18T15:28:35.183"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":278944617115718},{""Pid"":278944617066565,""Pids"":""[0],[277111901716549],[278944617066565],"",""Name"":""回收站增加"",""Code"":""zxzyadmin_trash_mgr_add"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""Trash:add"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":2,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-04-18T15:28:35.183"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":278944617115719},{""Pid"":278944617066565,""Pids"":""[0],[277111901716549],[278944617066565],"",""Name"":""回收站删除"",""Code"":""zxzyadmin_trash_mgr_delete"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""Trash:delete"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":2,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-04-18T15:28:35.183"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":278944617115720},{""Pid"":278944617066565,""Pids"":""[0],[277111901716549],[278944617066565],"",""Name"":""回收站编辑"",""Code"":""zxzyadmin_trash_mgr_edit"",""Type"":2,""Icon"":null,""Router"":null,""Component"":null,""Permission"":""Trash:edit"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":null,""Redirect"":null,""Weight"":2,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-04-18T15:28:35.183"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":278944617115721},{""Pid"":277116957925445,""Pids"":""[0],[277111901716549],[277116957925445],"",""Name"":""文档下载"",""Code"":""document_download"",""Type"":2,""Icon"":"""",""Router"":"""",""Component"":"""",""Permission"":""Document:download"",""Application"":""manage"",""OpenType"":0,""Visible"":""Y"",""Link"":"""",""Redirect"":"""",""Weight"":1,""Sort"":100,""Remark"":null,""Status"":0,""CreatedTime"":""2022-04-19T16:30:49.807"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":279313808535621}] +"; + List list = JsonUtil.ToObject>(json); + + return list; +}} diff --git a/Magic.CodeFirst/SeedData/SysNoticeSeedData.cs b/Magic.CodeFirst/SeedData/SysNoticeSeedData.cs new file mode 100644 index 0000000..43f70b0 --- /dev/null +++ b/Magic.CodeFirst/SeedData/SysNoticeSeedData.cs @@ -0,0 +1,13 @@ +using Magic.Core; +using Magic.Core.Entity; + +namespace Magic.CodeFirst; + +public class SysNoticeSeedData : ISeedData , ISqlSugarEntitySeedData +{ public IEnumerable HasData() + { string json = @"[{""Title"":""1"",""Content"":""1111

"",""Type"":1,""PublicUserId"":177325484421189,""PublicUserName"":""郑国静"",""PublicOrgId"":177325089079365,""PublicOrgName"":""系统机构"",""PublicTime"":""2021-07-12T11:25:31.123"",""CancelTime"":""1753-01-01T00:00:00"",""Status"":1,""CreatedTime"":""2021-07-12T11:25:25.69"",""UpdatedTime"":null,""CreatedUserId"":177325484421189,""CreatedUserName"":""admin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":179794426552389},{""Title"":""2"",""Content"":""

333

"",""Type"":2,""PublicUserId"":177325484421189,""PublicUserName"":""郑国静"",""PublicOrgId"":177325089079365,""PublicOrgName"":""系统机构"",""PublicTime"":""2021-07-12T11:25:56.11"",""CancelTime"":""1753-01-01T00:00:00"",""Status"":1,""CreatedTime"":""2021-07-12T11:25:56.11"",""UpdatedTime"":null,""CreatedUserId"":177325484421189,""CreatedUserName"":""admin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":179794551148613},{""Title"":""4"",""Content"":""444

"",""Type"":2,""PublicUserId"":177325484421189,""PublicUserName"":""郑国静"",""PublicOrgId"":177325089079365,""PublicOrgName"":""系统机构"",""PublicTime"":""2021-07-12T11:40:29.21"",""CancelTime"":""1753-01-01T00:00:00"",""Status"":1,""CreatedTime"":""2021-07-12T11:40:29.213"",""UpdatedTime"":null,""CreatedUserId"":177325484421189,""CreatedUserName"":""admin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":179798127382597},{""Title"":""6"",""Content"":""6666

"",""Type"":2,""PublicUserId"":177325484421189,""PublicUserName"":""郑国静"",""PublicOrgId"":177325089079365,""PublicOrgName"":""系统机构"",""PublicTime"":""2021-07-12T11:41:28.417"",""CancelTime"":""1753-01-01T00:00:00"",""Status"":1,""CreatedTime"":""2021-07-12T11:41:28.417"",""UpdatedTime"":null,""CreatedUserId"":177325484421189,""CreatedUserName"":""admin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":179798369882181},{""Title"":""777"",""Content"":""玉婷

"",""Type"":1,""PublicUserId"":177325484421189,""PublicUserName"":""郑国静"",""PublicOrgId"":177325089079365,""PublicOrgName"":""系统机构"",""PublicTime"":""2021-07-12T11:45:14.92"",""CancelTime"":""1753-01-01T00:00:00"",""Status"":1,""CreatedTime"":""2021-07-12T11:45:14.92"",""UpdatedTime"":null,""CreatedUserId"":177325484421189,""CreatedUserName"":""admin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":179799297638469},{""Title"":""Ang"",""Content"":""frgf

"",""Type"":1,""PublicUserId"":177325484421189,""PublicUserName"":""郑国静"",""PublicOrgId"":177325089079365,""PublicOrgName"":""系统机构"",""PublicTime"":""2021-07-12T11:47:15.83"",""CancelTime"":""1753-01-01T00:00:00"",""Status"":1,""CreatedTime"":""2021-07-12T11:47:15.83"",""UpdatedTime"":null,""CreatedUserId"":177325484421189,""CreatedUserName"":""admin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":179799792885829},{""Title"":""fgfg"",""Content"":""fgfg

"",""Type"":1,""PublicUserId"":177325484421189,""PublicUserName"":""郑国静"",""PublicOrgId"":177325089079365,""PublicOrgName"":""系统机构"",""PublicTime"":""2021-07-12T11:47:58.19"",""CancelTime"":""1753-01-01T00:00:00"",""Status"":1,""CreatedTime"":""2021-07-12T11:47:58.19"",""UpdatedTime"":null,""CreatedUserId"":177325484421189,""CreatedUserName"":""admin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":179799966392389},{""Title"":""878"",""Content"":""8888

"",""Type"":1,""PublicUserId"":177325484421189,""PublicUserName"":""郑国静"",""PublicOrgId"":177325089079365,""PublicOrgName"":""系统机构"",""PublicTime"":""2021-07-12T11:49:15.067"",""CancelTime"":""1753-01-01T00:00:00"",""Status"":1,""CreatedTime"":""2021-07-12T11:49:15.067"",""UpdatedTime"":null,""CreatedUserId"":177325484421189,""CreatedUserName"":""admin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":179800281276485},{""Title"":""hgfhh"",""Content"":""gfhgf

"",""Type"":1,""PublicUserId"":177325484421189,""PublicUserName"":""郑国静"",""PublicOrgId"":177325089079365,""PublicOrgName"":""系统机构"",""PublicTime"":""2021-07-12T11:53:49.537"",""CancelTime"":""1753-01-01T00:00:00"",""Status"":1,""CreatedTime"":""2021-07-12T11:53:46.487"",""UpdatedTime"":null,""CreatedUserId"":177325484421189,""CreatedUserName"":""admin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":179801393012805},{""Title"":""jlkjllj"",""Content"":""

hjkhjkjh

"",""Type"":2,""PublicUserId"":177325484421189,""PublicUserName"":""郑国静"",""PublicOrgId"":177325089079365,""PublicOrgName"":""系统机构"",""PublicTime"":""2021-07-12T11:54:12.417"",""CancelTime"":""1753-01-01T00:00:00"",""Status"":1,""CreatedTime"":""2021-07-12T11:54:12.417"",""UpdatedTime"":null,""CreatedUserId"":177325484421189,""CreatedUserName"":""admin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":179801499226181},{""Title"":""jhkhkhj"",""Content"":""

hkhjkh

"",""Type"":1,""PublicUserId"":177325484421189,""PublicUserName"":""郑国静"",""PublicOrgId"":177325089079365,""PublicOrgName"":""系统机构"",""PublicTime"":""2021-07-12T11:54:25.243"",""CancelTime"":""1753-01-01T00:00:00"",""Status"":1,""CreatedTime"":""2021-07-12T11:54:25.243"",""UpdatedTime"":null,""CreatedUserId"":177325484421189,""CreatedUserName"":""admin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":179801551765573},{""Title"":""FGHGF"",""Content"":""GFHGF

"",""Type"":2,""PublicUserId"":177325484421189,""PublicUserName"":""郑国静"",""PublicOrgId"":177325089079365,""PublicOrgName"":""系统机构"",""PublicTime"":""2021-07-12T12:00:47.973"",""CancelTime"":""1753-01-01T00:00:00"",""Status"":1,""CreatedTime"":""2021-07-12T12:00:47.973"",""UpdatedTime"":null,""CreatedUserId"":177325484421189,""CreatedUserName"":""admin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":179803119427653},{""Title"":""HAHAH"",""Content"":""

FDGFDGFD

"",""Type"":2,""PublicUserId"":177325484421189,""PublicUserName"":""郑国静"",""PublicOrgId"":177325089079365,""PublicOrgName"":""系统机构"",""PublicTime"":""2021-07-12T12:01:06.76"",""CancelTime"":""1753-01-01T00:00:00"",""Status"":1,""CreatedTime"":""2021-07-12T12:01:06.76"",""UpdatedTime"":null,""CreatedUserId"":177325484421189,""CreatedUserName"":""admin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":179803196371013},{""Title"":""HAHAHA"",""Content"":""GFHGF

"",""Type"":1,""PublicUserId"":177325484421189,""PublicUserName"":""郑国静"",""PublicOrgId"":177325089079365,""PublicOrgName"":""系统机构"",""PublicTime"":""2021-07-12T12:02:00.293"",""CancelTime"":""1753-01-01T00:00:00"",""Status"":1,""CreatedTime"":""2021-07-12T12:02:00.293"",""UpdatedTime"":null,""CreatedUserId"":177325484421189,""CreatedUserName"":""admin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":179803415650373},{""Title"":""呵呵呵"",""Content"":""第三方大幅度

"",""Type"":1,""PublicUserId"":177325484421189,""PublicUserName"":""郑国静"",""PublicOrgId"":177325089079365,""PublicOrgName"":""系统机构"",""PublicTime"":""2021-07-12T13:35:19.073"",""CancelTime"":""1753-01-01T00:00:00"",""Status"":1,""CreatedTime"":""2021-07-12T13:35:19.077"",""UpdatedTime"":null,""CreatedUserId"":177325484421189,""CreatedUserName"":""admin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":179826348257349},{""Title"":""风格和规范"",""Content"":""风格化规范化

"",""Type"":1,""PublicUserId"":142307070910551,""PublicUserName"":""超级管理员"",""PublicOrgId"":177325089079365,""PublicOrgName"":""系统机构"",""PublicTime"":""2021-08-19T23:14:28.403"",""CancelTime"":""1753-01-01T00:00:00"",""Status"":1,""CreatedTime"":""2021-08-19T23:14:28.407"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":193416668713029}] +"; + List list = JsonUtil.ToObject>(json); + + return list; +}} diff --git a/Magic.CodeFirst/SeedData/SysNoticeUserSeedData.cs b/Magic.CodeFirst/SeedData/SysNoticeUserSeedData.cs new file mode 100644 index 0000000..7ad6194 --- /dev/null +++ b/Magic.CodeFirst/SeedData/SysNoticeUserSeedData.cs @@ -0,0 +1,13 @@ +using Magic.Core; +using Magic.Core.Entity; + +namespace Magic.CodeFirst; + +public class SysNoticeUserSeedData : ISeedData , ISqlSugarEntitySeedData +{ public IEnumerable HasData() + { string json = @"[{""NoticeId"":179794426552389,""UserId"":177325484421189,""ReadTime"":""2021-07-12T11:40:09.753"",""ReadStatus"":1},{""NoticeId"":179794551148613,""UserId"":177325484421189,""ReadTime"":""2021-07-12T11:40:13.633"",""ReadStatus"":1},{""NoticeId"":179798127382597,""UserId"":177325484421189,""ReadTime"":""1753-01-01T00:00:00"",""ReadStatus"":0},{""NoticeId"":179798369882181,""UserId"":177325484421189,""ReadTime"":""1753-01-01T00:00:00"",""ReadStatus"":0},{""NoticeId"":179799297638469,""UserId"":177325484421189,""ReadTime"":""1753-01-01T00:00:00"",""ReadStatus"":0},{""NoticeId"":179799792885829,""UserId"":177325484421189,""ReadTime"":""1753-01-01T00:00:00"",""ReadStatus"":0},{""NoticeId"":179799966392389,""UserId"":177325484421189,""ReadTime"":""1753-01-01T00:00:00"",""ReadStatus"":0},{""NoticeId"":179800281276485,""UserId"":177325484421189,""ReadTime"":""1753-01-01T00:00:00"",""ReadStatus"":0},{""NoticeId"":179803119427653,""UserId"":177325484421189,""ReadTime"":""1753-01-01T00:00:00"",""ReadStatus"":0},{""NoticeId"":179803196371013,""UserId"":177325484421189,""ReadTime"":""1753-01-01T00:00:00"",""ReadStatus"":0},{""NoticeId"":179803415650373,""UserId"":177325484421189,""ReadTime"":""1753-01-01T00:00:00"",""ReadStatus"":0},{""NoticeId"":179826348257349,""UserId"":177325484421189,""ReadTime"":""1753-01-01T00:00:00"",""ReadStatus"":0},{""NoticeId"":179801393012805,""UserId"":177325484421189,""ReadTime"":""1753-01-01T00:00:00"",""ReadStatus"":0},{""NoticeId"":179801499226181,""UserId"":177325484421189,""ReadTime"":""1753-01-01T00:00:00"",""ReadStatus"":0},{""NoticeId"":179801551765573,""UserId"":177325484421189,""ReadTime"":""1753-01-01T00:00:00"",""ReadStatus"":0},{""NoticeId"":193416668713029,""UserId"":177325484421189,""ReadTime"":""1753-01-01T00:00:00"",""ReadStatus"":0}] +"; + List list = JsonUtil.ToObject>(json); + + return list; +}} diff --git a/Magic.CodeFirst/SeedData/SysOrgSeedData.cs b/Magic.CodeFirst/SeedData/SysOrgSeedData.cs new file mode 100644 index 0000000..27ca7ca --- /dev/null +++ b/Magic.CodeFirst/SeedData/SysOrgSeedData.cs @@ -0,0 +1,13 @@ +using Magic.Core; +using Magic.Core.Entity; + +namespace Magic.CodeFirst; + +public class SysOrgSeedData : ISeedData , ISqlSugarEntitySeedData +{ public IEnumerable HasData() + { string json = @"[{""Pid"":0,""Pids"":""[0],"",""Name"":""土豆新车"",""Code"":""1"",""Contacts"":""tdadmin"",""Tel"":null,""Sort"":0,""Remark"":null,""Status"":0,""TenantId"":175624014975045,""CreatedTime"":""2021-06-30T16:35:58.83"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":175624015089733},{""Pid"":0,""Pids"":""[0],"",""Name"":""系统机构"",""Code"":""SystemOrg"",""Contacts"":null,""Tel"":null,""Sort"":1,""Remark"":null,""Status"":0,""TenantId"":142307070918780,""CreatedTime"":""2021-07-05T11:57:40.097"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":177325089079365},{""Pid"":177325089079365,""Pids"":""[0],[177325089079365],"",""Name"":""机构1"",""Code"":""1"",""Contacts"":null,""Tel"":null,""Sort"":100,""Remark"":null,""Status"":0,""TenantId"":142307070918780,""CreatedTime"":""2021-07-19T14:17:24.493"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":182313953165381},{""Pid"":182313953165381,""Pids"":""[0],[177325089079365],[182313953165381],"",""Name"":""机构2"",""Code"":""2"",""Contacts"":null,""Tel"":null,""Sort"":100,""Remark"":null,""Status"":0,""TenantId"":142307070918780,""CreatedTime"":""2021-07-19T14:17:38.037"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":182314008641605},{""Pid"":0,""Pids"":""[0],"",""Name"":""租户1"",""Code"":""1"",""Contacts"":""租户1管理员"",""Tel"":null,""Sort"":0,""Remark"":null,""Status"":0,""TenantId"":278024843046981,""CreatedTime"":""2022-04-16T01:06:00.98"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":278024843092037}] +"; + List list = JsonUtil.ToObject>(json); + + return list; +}} diff --git a/Magic.CodeFirst/SeedData/SysPosSeedData.cs b/Magic.CodeFirst/SeedData/SysPosSeedData.cs new file mode 100644 index 0000000..d4fb43f --- /dev/null +++ b/Magic.CodeFirst/SeedData/SysPosSeedData.cs @@ -0,0 +1,13 @@ +using Magic.Core; +using Magic.Core.Entity; + +namespace Magic.CodeFirst; + +public class SysPosSeedData : ISeedData , ISqlSugarEntitySeedData +{ public IEnumerable HasData() + { string json = @"[{""Name"":""系统职位"",""Code"":""SystemPos"",""Sort"":1,""Remark"":null,""Status"":0,""TenantId"":142307070918780,""CreatedTime"":""2021-07-05T11:58:54.63"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":177325394366533}] +"; + List list = JsonUtil.ToObject>(json); + + return list; +}} diff --git a/Magic.CodeFirst/SeedData/SysRoleDataScopeSeedData.cs b/Magic.CodeFirst/SeedData/SysRoleDataScopeSeedData.cs new file mode 100644 index 0000000..687d016 --- /dev/null +++ b/Magic.CodeFirst/SeedData/SysRoleDataScopeSeedData.cs @@ -0,0 +1,13 @@ +using Magic.Core; +using Magic.Core.Entity; + +namespace Magic.CodeFirst; + +public class SysRoleDataScopeSeedData : ISeedData , ISqlSugarEntitySeedData +{ public IEnumerable HasData() + { string json = @"[{""SysRoleId"":278024843124805,""SysOrgId"":278024843092037}] +"; + List list = JsonUtil.ToObject>(json); + + return list; +}} diff --git a/Magic.CodeFirst/SeedData/SysRoleMenuSeedData.cs b/Magic.CodeFirst/SeedData/SysRoleMenuSeedData.cs new file mode 100644 index 0000000..0d03e7f --- /dev/null +++ b/Magic.CodeFirst/SeedData/SysRoleMenuSeedData.cs @@ -0,0 +1,13 @@ +using Magic.Core; +using Magic.Core.Entity; + +namespace Magic.CodeFirst; + +public class SysRoleMenuSeedData : ISeedData , ISqlSugarEntitySeedData +{ public IEnumerable HasData() + { string json = @"[{""SysRoleId"":175624015192133,""SysMenuId"":142307000914633},{""SysRoleId"":175633246363717,""SysMenuId"":142307000914633},{""SysRoleId"":278024843124805,""SysMenuId"":142307000914633},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910560},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910560},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910561},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910561},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910562},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910562},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910563},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910563},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910563},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910564},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910564},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910564},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910565},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910565},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910565},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910566},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910566},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910566},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910567},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910567},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910567},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910568},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910568},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910568},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910569},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910569},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910569},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910570},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910570},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910570},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910571},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910571},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910571},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910572},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910572},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910572},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910573},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910573},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910573},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910574},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910574},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910574},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910575},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910575},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910575},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910576},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910576},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910576},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910577},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910577},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910577},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910578},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910578},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910578},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910579},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910579},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910579},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910580},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910580},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910580},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910581},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910581},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910581},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910582},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910582},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910582},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910583},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910583},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910583},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910584},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910584},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910584},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910585},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910585},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910585},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910586},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910586},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910586},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910587},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910587},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910587},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910588},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910588},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910588},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910589},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910589},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910589},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910590},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910590},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910590},{""SysRoleId"":175624015192133,""SysMenuId"":142307070910591},{""SysRoleId"":175633246363717,""SysMenuId"":142307070910591},{""SysRoleId"":278024843124805,""SysMenuId"":142307070910591},{""SysRoleId"":175633246363717,""SysMenuId"":142307070911739},{""SysRoleId"":278024843124805,""SysMenuId"":142307070911739},{""SysRoleId"":175633246363717,""SysMenuId"":142307070911740},{""SysRoleId"":278024843124805,""SysMenuId"":142307070911740},{""SysRoleId"":175633246363717,""SysMenuId"":142307070911741},{""SysRoleId"":278024843124805,""SysMenuId"":142307070911741},{""SysRoleId"":175624015192133,""SysMenuId"":142307070914629},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914629},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914629},{""SysRoleId"":175624015192133,""SysMenuId"":142307070914630},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914630},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914630},{""SysRoleId"":175624015192133,""SysMenuId"":142307070914631},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914631},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914631},{""SysRoleId"":175624015192133,""SysMenuId"":142307070914632},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914632},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914632},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914633},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914633},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914634},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914634},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914635},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914635},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914636},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914636},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914637},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914637},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914638},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914638},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914639},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914639},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914640},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914640},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914641},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914641},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914642},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914642},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914643},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914643},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914644},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914644},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914645},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914645},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914646},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914646},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914647},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914647},{""SysRoleId"":175624015192133,""SysMenuId"":142307070914648},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914648},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914648},{""SysRoleId"":175624015192133,""SysMenuId"":142307070914649},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914649},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914649},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914650},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914650},{""SysRoleId"":175624015192133,""SysMenuId"":142307070914651},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914651},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914651},{""SysRoleId"":175624015192133,""SysMenuId"":142307070914652},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914652},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914652},{""SysRoleId"":175624015192133,""SysMenuId"":142307070914653},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914653},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914653},{""SysRoleId"":175624015192133,""SysMenuId"":142307070914654},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914654},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914654},{""SysRoleId"":175624015192133,""SysMenuId"":142307070914655},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914655},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914655},{""SysRoleId"":175624015192133,""SysMenuId"":142307070914656},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914656},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914656},{""SysRoleId"":175624015192133,""SysMenuId"":142307070914657},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914657},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914657},{""SysRoleId"":175624015192133,""SysMenuId"":142307070914658},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914658},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914658},{""SysRoleId"":175624015192133,""SysMenuId"":142307070914659},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914659},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914659},{""SysRoleId"":175624015192133,""SysMenuId"":142307070914660},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914660},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914660},{""SysRoleId"":175624015192133,""SysMenuId"":142307070914661},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914661},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914661},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914662},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914662},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914663},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914663},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914664},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914664},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914665},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914665},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914666},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914666},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914667},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914667},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914668},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914668},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914669},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914669},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914670},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914670},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914671},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914671},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914672},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914672},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914673},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914673},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914674},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914674},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914675},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914675},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914676},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914676},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914677},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914677},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914678},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914678},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914679},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914679},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914680},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914680},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914681},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914681},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914682},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914682},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914683},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914683},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914684},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914684},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914685},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914685},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914686},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914686},{""SysRoleId"":175633246363717,""SysMenuId"":142307070914687},{""SysRoleId"":278024843124805,""SysMenuId"":142307070914687},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918725},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918725},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918726},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918726},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918727},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918727},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918728},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918728},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918729},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918729},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918730},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918730},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918731},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918731},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918732},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918732},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918733},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918733},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918734},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918734},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918735},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918735},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918736},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918736},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918737},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918737},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918738},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918738},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918739},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918739},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918740},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918740},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918741},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918741},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918742},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918742},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918743},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918743},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918744},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918744},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918745},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918745},{""SysRoleId"":175624015192133,""SysMenuId"":142307070918746},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918746},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918746},{""SysRoleId"":175624015192133,""SysMenuId"":142307070918747},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918747},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918747},{""SysRoleId"":175624015192133,""SysMenuId"":142307070918748},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918748},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918748},{""SysRoleId"":175624015192133,""SysMenuId"":142307070918749},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918749},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918749},{""SysRoleId"":175624015192133,""SysMenuId"":142307070918750},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918750},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918750},{""SysRoleId"":175624015192133,""SysMenuId"":142307070918751},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918751},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918751},{""SysRoleId"":175624015192133,""SysMenuId"":142307070918752},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918752},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918752},{""SysRoleId"":175624015192133,""SysMenuId"":142307070918753},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918753},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918753},{""SysRoleId"":175624015192133,""SysMenuId"":142307070918754},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918754},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918754},{""SysRoleId"":175624015192133,""SysMenuId"":142307070918755},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918755},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918755},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918756},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918756},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918757},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918757},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918758},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918758},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918759},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918759},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918760},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918760},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918761},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918761},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918762},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918762},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918763},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918763},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918764},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918764},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918765},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918765},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918766},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918766},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918767},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918767},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918768},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918768},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918769},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918769},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918770},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918770},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918771},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918771},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918772},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918772},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918773},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918773},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918774},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918774},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918775},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918775},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918776},{""SysRoleId"":278024843124805,""SysMenuId"":142307070918776},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918782},{""SysRoleId"":175633246363717,""SysMenuId"":142307070918783},{""SysRoleId"":175633246363717,""SysMenuId"":142307070922821},{""SysRoleId"":175633246363717,""SysMenuId"":142307070922822},{""SysRoleId"":175633246363717,""SysMenuId"":142307070922823},{""SysRoleId"":175633246363717,""SysMenuId"":142307070922824},{""SysRoleId"":175633246363717,""SysMenuId"":142307070922825},{""SysRoleId"":175633246363717,""SysMenuId"":142307070922826},{""SysRoleId"":175633246363717,""SysMenuId"":142307070922827},{""SysRoleId"":175633246363717,""SysMenuId"":142307070922870},{""SysRoleId"":175633246363717,""SysMenuId"":142307070922874},{""SysRoleId"":278024843124805,""SysMenuId"":142307070922874},{""SysRoleId"":175633246363717,""SysMenuId"":142307070922875},{""SysRoleId"":278024843124805,""SysMenuId"":142307070922875},{""SysRoleId"":175633246363717,""SysMenuId"":142307070922876},{""SysRoleId"":278024843124805,""SysMenuId"":142307070922876},{""SysRoleId"":175633246363717,""SysMenuId"":178075287240773},{""SysRoleId"":175633246363717,""SysMenuId"":178079567294533},{""SysRoleId"":175633246363717,""SysMenuId"":182612191891525},{""SysRoleId"":175633246363717,""SysMenuId"":182692422213701},{""SysRoleId"":175633246363717,""SysMenuId"":182692650123333},{""SysRoleId"":175633246363717,""SysMenuId"":182692815732805},{""SysRoleId"":175633246363717,""SysMenuId"":182693142773829},{""SysRoleId"":175633246363717,""SysMenuId"":182693266526277},{""SysRoleId"":175633246363717,""SysMenuId"":182693372485701},{""SysRoleId"":175633246363717,""SysMenuId"":182699700703301},{""SysRoleId"":278024843124805,""SysMenuId"":182699700703301},{""SysRoleId"":175633246363717,""SysMenuId"":182700299632709},{""SysRoleId"":278024843124805,""SysMenuId"":182700299632709},{""SysRoleId"":175633246363717,""SysMenuId"":182700412936261},{""SysRoleId"":278024843124805,""SysMenuId"":182700412936261},{""SysRoleId"":175633246363717,""SysMenuId"":182700585140293},{""SysRoleId"":278024843124805,""SysMenuId"":182700585140293},{""SysRoleId"":175633246363717,""SysMenuId"":182700864315461},{""SysRoleId"":278024843124805,""SysMenuId"":182700864315461},{""SysRoleId"":175633246363717,""SysMenuId"":182701004218437},{""SysRoleId"":278024843124805,""SysMenuId"":182701004218437},{""SysRoleId"":175633246363717,""SysMenuId"":183425655615557},{""SysRoleId"":175633246363717,""SysMenuId"":183425947672645},{""SysRoleId"":175633246363717,""SysMenuId"":183426282242117},{""SysRoleId"":278024843124805,""SysMenuId"":183426282242117},{""SysRoleId"":175633246363717,""SysMenuId"":183426519642181},{""SysRoleId"":278024843124805,""SysMenuId"":183426519642181}] +"; + List list = JsonUtil.ToObject>(json); + + return list; +}} diff --git a/Magic.CodeFirst/SeedData/SysRoleSeedData.cs b/Magic.CodeFirst/SeedData/SysRoleSeedData.cs new file mode 100644 index 0000000..d4c5b50 --- /dev/null +++ b/Magic.CodeFirst/SeedData/SysRoleSeedData.cs @@ -0,0 +1,13 @@ +using Magic.Core; +using Magic.Core.Entity; + +namespace Magic.CodeFirst; + +public class SysRoleSeedData : ISeedData , ISqlSugarEntitySeedData +{ public IEnumerable HasData() + { string json = @"[{""Name"":""系统管理员"",""Code"":""1"",""Sort"":0,""DataScopeType"":1,""Remark"":null,""Status"":0,""RoleType"":1,""TenantId"":175624014975045,""CreatedTime"":""2021-06-30T16:35:58.853"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":175624015192133},{""Name"":""财务"",""Code"":""cw"",""Sort"":100,""DataScopeType"":1,""Remark"":null,""Status"":0,""RoleType"":0,""TenantId"":175624014975045,""CreatedTime"":""2021-06-30T17:06:59.447"",""UpdatedTime"":null,""CreatedUserId"":175624015269957,""CreatedUserName"":""toudou@qq.com"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":175631636172869},{""Name"":""普通用户"",""Code"":""pt"",""Sort"":100,""DataScopeType"":1,""Remark"":null,""Status"":0,""RoleType"":0,""TenantId"":142307070918780,""CreatedTime"":""2021-06-30T17:13:32.56"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":175633246363717},{""Name"":""系统管理员"",""Code"":""1"",""Sort"":0,""DataScopeType"":1,""Remark"":null,""Status"":0,""RoleType"":1,""TenantId"":278024843046981,""CreatedTime"":""2022-04-16T01:06:00.987"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":278024843124805}] +"; + List list = JsonUtil.ToObject>(json); + + return list; +}} diff --git a/Magic.CodeFirst/SeedData/SysTenantSeedData.cs b/Magic.CodeFirst/SeedData/SysTenantSeedData.cs new file mode 100644 index 0000000..eaeade2 --- /dev/null +++ b/Magic.CodeFirst/SeedData/SysTenantSeedData.cs @@ -0,0 +1,13 @@ +using Magic.Core; +using Magic.Core.Entity; + +namespace Magic.CodeFirst; + +public class SysTenantSeedData : ISeedData , ISqlSugarEntitySeedData +{ public IEnumerable HasData() + { string json = @"[{""Name"":""系统租户"",""AdminName"":""SystemAdmin"",""Host"":null,""Email"":""SystemAdmin"",""Phone"":null,""Connection"":null,""Schema"":null,""Remark"":null,""TenantType"":1,""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070918780},{""Name"":""土豆新车"",""AdminName"":""tdadmin"",""Host"":null,""Email"":""toudou@qq.com"",""Phone"":null,""Connection"":null,""Schema"":null,""Remark"":null,""TenantType"":0,""CreatedTime"":""2021-06-30T16:35:58.803"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":175624014975045},{""Name"":""租户1"",""AdminName"":""租户1管理员"",""Host"":null,""Email"":""zuhutest"",""Phone"":null,""Connection"":null,""Schema"":null,""Remark"":null,""TenantType"":0,""CreatedTime"":""2022-04-16T01:06:00.967"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":278024843046981}] +"; + List list = JsonUtil.ToObject>(json); + + return list; +}} diff --git a/Magic.CodeFirst/SeedData/SysTestSeedData.cs b/Magic.CodeFirst/SeedData/SysTestSeedData.cs new file mode 100644 index 0000000..b29f73e --- /dev/null +++ b/Magic.CodeFirst/SeedData/SysTestSeedData.cs @@ -0,0 +1,13 @@ +using Magic.Core; +using Magic.Core.Entity; + +namespace Magic.CodeFirst; + +public class SysTestSeedData : ISeedData , ISqlSugarEntitySeedData +{ public IEnumerable HasData() + { string json = @"[{""Account"":""superAdmin"",""Password"":""e10adc3949ba59abbe56e057f20f883e"",""NickName"":""superAdmin"",""Name"":""超级管理员"",""Avatar"":""188632919339077"",""Birthday"":""1753-01-01T00:00:00"",""Sex"":1,""Email"":null,""Phone"":""18020030720"",""Tel"":null,""LastLoginIp"":""127.0.0.1"",""LastLoginTime"":""2022-05-25T09:12:40.45"",""AdminType"":1,""Status"":0,""TenantId"":142307070918780,""CreatedTime"":null,""UpdatedTime"":""2021-08-06T10:49:21.047"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":142307070910551},{""Account"":""toudou@qq.com"",""Password"":""e10adc3949ba59abbe56e057f20f883e"",""NickName"":""tdadmin"",""Name"":""tdadmin"",""Avatar"":null,""Birthday"":""1753-01-01T00:00:00"",""Sex"":0,""Email"":""toudou@qq.com"",""Phone"":null,""Tel"":null,""LastLoginIp"":""127.0.0.1"",""LastLoginTime"":""2022-04-16T00:42:43.103"",""AdminType"":2,""Status"":0,""TenantId"":175624014975045,""CreatedTime"":""2021-06-30T16:35:58.873"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":175624015269957},{""Account"":""admin"",""Password"":""e10adc3949ba59abbe56e057f20f883e"",""NickName"":""admin"",""Name"":""管理员"",""Avatar"":null,""Birthday"":""1753-01-01T00:00:00"",""Sex"":1,""Email"":null,""Phone"":""15959110752"",""Tel"":null,""LastLoginIp"":""0.0.0.1"",""LastLoginTime"":""2021-08-19T23:55:06.2"",""AdminType"":0,""Status"":0,""TenantId"":142307070918780,""CreatedTime"":""2021-07-05T11:59:16.617"",""UpdatedTime"":""2021-08-19T23:10:52.907"",""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":177325484421189},{""Account"":""zhangsan"",""Password"":""e10adc3949ba59abbe56e057f20f883e"",""NickName"":""张三"",""Name"":""张三"",""Avatar"":null,""Birthday"":""1753-01-01T00:00:00"",""Sex"":1,""Email"":null,""Phone"":""15959110751"",""Tel"":null,""LastLoginIp"":""127.0.0.1"",""LastLoginTime"":""2021-07-19T15:13:27.183"",""AdminType"":0,""Status"":0,""TenantId"":142307070918780,""CreatedTime"":""2021-07-19T14:18:44.05"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":182314279026757},{""Account"":""zuhutest"",""Password"":""e10adc3949ba59abbe56e057f20f883e"",""NickName"":""租户1管理员"",""Name"":""租户1管理员"",""Avatar"":null,""Birthday"":""1753-01-01T00:00:00"",""Sex"":0,""Email"":""zuhutest"",""Phone"":null,""Tel"":null,""LastLoginIp"":""127.0.0.1"",""LastLoginTime"":""2022-04-16T01:06:31.343"",""AdminType"":2,""Status"":0,""TenantId"":278024843046981,""CreatedTime"":""2022-04-16T01:06:00.993"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":278024843153477}] +"; + List list = JsonUtil.ToObject>(json); + + return list; +}} diff --git a/Magic.CodeFirst/SeedData/SysTimerSeedData.cs b/Magic.CodeFirst/SeedData/SysTimerSeedData.cs new file mode 100644 index 0000000..c80de1c --- /dev/null +++ b/Magic.CodeFirst/SeedData/SysTimerSeedData.cs @@ -0,0 +1,13 @@ +using Magic.Core; +using Magic.Core.Entity; + +namespace Magic.CodeFirst; + +public class SysTimerSeedData : ISeedData , ISqlSugarEntitySeedData +{ public IEnumerable HasData() + { string json = @"[{""JobName"":""百度api"",""DoOnce"":false,""StartNow"":false,""ExecuteType"":1,""Interval"":5,""Cron"":null,""TimerType"":0,""RequestUrl"":""https://www.baidu.com"",""RequestParameters"":null,""Headers"":null,""RequestType"":2,""Remark"":""接口API"",""CreatedTime"":null,""UpdatedTime"":null,""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":142307070910556},{""JobName"":""异常日志"",""DoOnce"":false,""StartNow"":false,""ExecuteType"":1,""Interval"":1,""Cron"":null,""TimerType"":0,""RequestUrl"":""LogJobWorker/DoLogEx"",""RequestParameters"":null,""Headers"":null,""RequestType"":0,""Remark"":"""",""CreatedTime"":null,""UpdatedTime"":""2021-07-22T17:49:29.37"",""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":142307070910557},{""JobName"":""操作日志"",""DoOnce"":false,""StartNow"":false,""ExecuteType"":1,""Interval"":1,""Cron"":null,""TimerType"":0,""RequestUrl"":""LogJobWorker/DoLogOp"",""RequestParameters"":null,""Headers"":null,""RequestType"":0,""Remark"":"""",""CreatedTime"":null,""UpdatedTime"":""2021-07-22T17:49:31.363"",""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":142307070910558},{""JobName"":""访问日志"",""DoOnce"":false,""StartNow"":false,""ExecuteType"":1,""Interval"":1,""Cron"":null,""TimerType"":0,""RequestUrl"":""LogJobWorker/DoLogVis"",""RequestParameters"":null,""Headers"":null,""RequestType"":0,""Remark"":"""",""CreatedTime"":null,""UpdatedTime"":""2021-07-22T17:49:33.267"",""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":142307070910559}] +"; + List list = JsonUtil.ToObject>(json); + + return list; +}} diff --git a/Magic.CodeFirst/SeedData/SysUserDataScopeSeedData.cs b/Magic.CodeFirst/SeedData/SysUserDataScopeSeedData.cs new file mode 100644 index 0000000..3631bc5 --- /dev/null +++ b/Magic.CodeFirst/SeedData/SysUserDataScopeSeedData.cs @@ -0,0 +1,13 @@ +using Magic.Core; +using Magic.Core.Entity; + +namespace Magic.CodeFirst; + +public class SysUserDataScopeSeedData : ISeedData , ISqlSugarEntitySeedData +{ public IEnumerable HasData() + { string json = @"[{""SysUserId"":175624015269957,""SysOrgId"":175624015089733},{""SysUserId"":278024843153477,""SysOrgId"":278024843092037}] +"; + List list = JsonUtil.ToObject>(json); + + return list; +}} diff --git a/Magic.CodeFirst/SeedData/SysUserRoleSeedData.cs b/Magic.CodeFirst/SeedData/SysUserRoleSeedData.cs new file mode 100644 index 0000000..c417436 --- /dev/null +++ b/Magic.CodeFirst/SeedData/SysUserRoleSeedData.cs @@ -0,0 +1,13 @@ +using Magic.Core; +using Magic.Core.Entity; + +namespace Magic.CodeFirst; + +public class SysUserRoleSeedData : ISeedData , ISqlSugarEntitySeedData +{ public IEnumerable HasData() + { string json = @"[{""SysUserId"":175624015269957,""SysRoleId"":175624015192133},{""SysUserId"":177325484421189,""SysRoleId"":175633246363717},{""SysUserId"":182314279026757,""SysRoleId"":175633246363717},{""SysUserId"":278024843153477,""SysRoleId"":278024843124805}] +"; + List list = JsonUtil.ToObject>(json); + + return list; +}} diff --git a/Magic.CodeFirst/SeedData/SysUserSeedData.cs b/Magic.CodeFirst/SeedData/SysUserSeedData.cs new file mode 100644 index 0000000..e96b02d --- /dev/null +++ b/Magic.CodeFirst/SeedData/SysUserSeedData.cs @@ -0,0 +1,13 @@ +using Magic.Core; +using Magic.Core.Entity; + +namespace Magic.CodeFirst; + +public class SysUserSeedData : ISeedData , ISqlSugarEntitySeedData +{ public IEnumerable HasData() + { string json = @"[{""Account"":""superAdmin"",""Password"":""e10adc3949ba59abbe56e057f20f883e"",""NickName"":""superAdmin"",""Name"":""超级管理员"",""Avatar"":""188632919339077"",""Birthday"":""1753-01-01T00:00:00"",""Sex"":1,""Email"":null,""Phone"":""18020030720"",""Tel"":null,""LastLoginIp"":""127.0.0.1"",""LastLoginTime"":""2022-05-25T09:12:40.45"",""AdminType"":1,""Status"":0,""TenantId"":142307070918780,""CreatedTime"":null,""UpdatedTime"":""2021-08-06T10:49:21.047"",""CreatedUserId"":null,""CreatedUserName"":null,""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":142307070910551},{""Account"":""toudou@qq.com"",""Password"":""e10adc3949ba59abbe56e057f20f883e"",""NickName"":""tdadmin"",""Name"":""tdadmin"",""Avatar"":null,""Birthday"":""1753-01-01T00:00:00"",""Sex"":0,""Email"":""toudou@qq.com"",""Phone"":null,""Tel"":null,""LastLoginIp"":""127.0.0.1"",""LastLoginTime"":""2022-04-16T00:42:43.103"",""AdminType"":2,""Status"":0,""TenantId"":175624014975045,""CreatedTime"":""2021-06-30T16:35:58.873"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":175624015269957},{""Account"":""admin"",""Password"":""e10adc3949ba59abbe56e057f20f883e"",""NickName"":""admin"",""Name"":""管理员"",""Avatar"":null,""Birthday"":""1753-01-01T00:00:00"",""Sex"":1,""Email"":null,""Phone"":""15959110752"",""Tel"":null,""LastLoginIp"":""0.0.0.1"",""LastLoginTime"":""2021-08-19T23:55:06.2"",""AdminType"":0,""Status"":0,""TenantId"":142307070918780,""CreatedTime"":""2021-07-05T11:59:16.617"",""UpdatedTime"":""2021-08-19T23:10:52.907"",""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":142307070910551,""UpdatedUserName"":""superAdmin"",""IsDeleted"":false,""Id"":177325484421189},{""Account"":""zhangsan"",""Password"":""e10adc3949ba59abbe56e057f20f883e"",""NickName"":""张三"",""Name"":""张三"",""Avatar"":null,""Birthday"":""1753-01-01T00:00:00"",""Sex"":1,""Email"":null,""Phone"":""15959110751"",""Tel"":null,""LastLoginIp"":""127.0.0.1"",""LastLoginTime"":""2021-07-19T15:13:27.183"",""AdminType"":0,""Status"":0,""TenantId"":142307070918780,""CreatedTime"":""2021-07-19T14:18:44.05"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":182314279026757},{""Account"":""zuhutest"",""Password"":""e10adc3949ba59abbe56e057f20f883e"",""NickName"":""租户1管理员"",""Name"":""租户1管理员"",""Avatar"":null,""Birthday"":""1753-01-01T00:00:00"",""Sex"":0,""Email"":""zuhutest"",""Phone"":null,""Tel"":null,""LastLoginIp"":""127.0.0.1"",""LastLoginTime"":""2022-04-16T01:06:31.343"",""AdminType"":2,""Status"":0,""TenantId"":278024843046981,""CreatedTime"":""2022-04-16T01:06:00.993"",""UpdatedTime"":null,""CreatedUserId"":142307070910551,""CreatedUserName"":""superAdmin"",""UpdatedUserId"":null,""UpdatedUserName"":null,""IsDeleted"":false,""Id"":278024843153477}] +"; + List list = JsonUtil.ToObject>(json); + + return list; +}} diff --git a/Magic.CodeFirst/SqlSugarHelper.cs b/Magic.CodeFirst/SqlSugarHelper.cs new file mode 100644 index 0000000..d92870c --- /dev/null +++ b/Magic.CodeFirst/SqlSugarHelper.cs @@ -0,0 +1,114 @@ +using Magic.Core; +using Microsoft.Extensions.Configuration; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Magic.CodeFirst; + +public class SqlSugarHelper +{ + //用单例模式 + // public static SqlSugarScope Db = new SqlSugarScope(new ConnectionConfig() + // { + // ConnectionString = "Server=.;Database=MagicCodeFirst;User=sa;Password=123456;MultipleActiveResultSets=True;",//连接符字串 + // DbType = DbType.SqlServer,//数据库类型 + // IsAutoCloseConnection = true //不设成true要手动close + // }, + //db => { + // //(A)全局生效配置点,一般AOP和程序启动的配置扔这里面 ,所有上下文生效 + // //调试SQL事件,可以删掉 + // db.Aop.OnLogExecuting = (sql, pars) => + // { + // Console.WriteLine(sql);//输出sql,查看执行sql 性能无影响 + + + // //5.0.8.2 获取无参数化 SQL 对性能有影响,特别大的SQL参数多的,调试使用 + // //UtilMethods.GetSqlString(DbType.SqlServer,sql,pars) + // }; + + // //多个配置就写下面 + // //db.Ado.IsDisableMasterSlaveSeparation=true; + // }); + + + public static ConnectionStringsOptions GetSetting() + { + var builder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("dbsettings.json", optional: false, reloadOnChange: true); + + + IConfigurationRoot config = builder.Build(); + var conn = config.GetSection("ConnectionStrings").Get(); + return conn; + } + + + public static SqlSugarScope Db() + { + //数据库序号从0开始,默认数据库为0 + var config = GetSetting(); + + //默认数据库 + List dbList = new List(); + DbConfig defaultdb = new DbConfig() + { + DbNumber = config.DefaultDbNumber, + DbString = config.DefaultDbString, + DbType = config.DefaultDbType + }; + dbList.Add(defaultdb); + //业务数据库集合 + foreach (var item in config.DbConfigs) + { + dbList.Add(item); + } + + List connectConfigList = new List(); + + foreach (var item in dbList) + { + //防止数据库重复,导致的事务异常 + if (connectConfigList.Any(a => a.ConfigId == (dynamic)item.DbNumber || a.ConnectionString == item.DbString)) + { + continue; + } + connectConfigList.Add(new ConnectionConfig() + { + ConnectionString = item.DbString, + DbType = (DbType)Convert.ToInt32(Enum.Parse(typeof(DbType), item.DbType)), + IsAutoCloseConnection = true, + ConfigId = item.DbNumber, + InitKeyType = InitKeyType.Attribute, + MoreSettings = new ConnMoreSettings() + { + IsAutoRemoveDataCache = true//自动清理缓存 + + } + }); + } + + return new SqlSugarScope(connectConfigList, + //全局上下文生效 + db => + { + /* + * 默认只会配置到第一个数据库,这里按照官方文档进行多数据库/多租户文档的说明进行循环配置 + */ + foreach (var c in connectConfigList) + { + var dbProvider = db.GetConnectionScope((string)c.ConfigId); + //执行超时时间 + dbProvider.Ado.CommandTimeOut = 30; + + dbProvider.Aop.OnLogExecuting = (sql, pars) => + { + Console.WriteLine(sql);//输出sql,查看执行sql 性能无影响 + }; + } + }); + } +} diff --git a/Magic.Core/Attributes/OpLogAttribute.cs b/Magic.Core/Attributes/OpLogAttribute.cs new file mode 100644 index 0000000..9faeefc --- /dev/null +++ b/Magic.Core/Attributes/OpLogAttribute.cs @@ -0,0 +1,12 @@ +using System; + +namespace Magic.Core; + +/// +/// 启用用操作日志 +/// +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property)] + public class OpLogAttribute : Attribute + { + + } diff --git a/Magic.Core/Attributes/SqlSugarUnitOfWorkAttribute.cs b/Magic.Core/Attributes/SqlSugarUnitOfWorkAttribute.cs new file mode 100644 index 0000000..b14829e --- /dev/null +++ b/Magic.Core/Attributes/SqlSugarUnitOfWorkAttribute.cs @@ -0,0 +1,39 @@ +using System; +using System.Data; + +namespace Magic.Core; + +/// +/// SqlSugar 工作单元配置特性 +/// +[AttributeUsage(AttributeTargets.Method, Inherited = true)] +public class SqlSugarUnitOfWorkAttribute : Attribute +{ + /// + /// 构造函数 + /// + public SqlSugarUnitOfWorkAttribute() + { + } + + /// + /// 构造函数 + /// + /// + /// 支持传入事务隔离级别 参数值 + /// + /// 事务隔离级别 + public SqlSugarUnitOfWorkAttribute(IsolationLevel isolationLevel) + { + IsolationLevel = isolationLevel; + } + + /// + /// 事务隔离级别 + /// + /// + /// 默认:,参见: + /// 说明:当事务A更新某条数据的时候,不容许其他事务来更新该数据,但可以进行读取操作 + /// + public IsolationLevel IsolationLevel { get; set; } = IsolationLevel.ReadCommitted; +} diff --git a/Magic.Core/Cache/ICache.cs b/Magic.Core/Cache/ICache.cs new file mode 100644 index 0000000..fef584e --- /dev/null +++ b/Magic.Core/Cache/ICache.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.Core; + +/// +/// 缓存接口 +/// +public interface ICache +{ + /// + /// 用于在 key 存在时删除 key + /// + /// 键 + long Del(params string[] key); + + /// + /// 用于在 key 存在时删除 key + /// + /// 键 + /// + Task DelAsync(params string[] key); + + /// + /// 用于在 key 模板存在时删除 + /// + /// key模板 + /// + Task DelByPatternAsync(string pattern); + + /// + /// 检查给定 key 是否存在 + /// + /// 键 + /// + bool Exists(string key); + + /// + /// 检查给定 key 是否存在 + /// + /// 键 + /// + Task ExistsAsync(string key); + + /// + /// 获取指定 key 的值 + /// + /// 键 + /// + string Get(string key); + + /// + /// 获取指定 key 的值 + /// + /// byte[] 或其他类型 + /// 键 + /// + T Get(string key); + + /// + /// 获取指定 key 的值 + /// + /// 键 + /// + Task GetAsync(string key); + + /// + /// 获取指定 key 的值 + /// + /// byte[] 或其他类型 + /// 键 + /// + Task GetAsync(string key); + + /// + /// 设置指定 key 的值,所有写入参数object都支持string | byte[] | 数值 | 对象 + /// + /// 键 + /// 值 + bool Set(string key, object value); + + /// + /// 设置指定 key 的值,所有写入参数object都支持string | byte[] | 数值 | 对象 + /// + /// 键 + /// 值 + /// 有效期 + bool Set(string key, object value, TimeSpan expire); + + /// + /// 设置指定 key 的值,所有写入参数object都支持string | byte[] | 数值 | 对象 + /// + /// 键 + /// 值 + /// + Task SetAsync(string key, object value); + + /// + /// 设置指定 key 的值,所有写入参数object都支持string | byte[] | 数值 | 对象 + /// + /// 键 + /// 值 + /// 有效期 + /// + Task SetAsync(string key, object value, TimeSpan expire); + + /// + /// 获取所有缓存 + /// + /// + List GetAllKeys(); +} diff --git a/Magic.Core/Cache/MemoryCache.cs b/Magic.Core/Cache/MemoryCache.cs new file mode 100644 index 0000000..baa6565 --- /dev/null +++ b/Magic.Core/Cache/MemoryCache.cs @@ -0,0 +1,141 @@ +using Furion.DependencyInjection; +using Microsoft.Extensions.Caching.Memory; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; + +namespace Magic.Core; + +/// +/// 内存缓存 +/// +public class MemoryCache : ICache, ISingleton +{ + private readonly IMemoryCache _memoryCache; + + public MemoryCache(IMemoryCache memoryCache) + { + _memoryCache = memoryCache; + } + + public long Del(params string[] key) + { + foreach (var k in key) + { + _memoryCache.Remove(k); + } + return key.Length; + } + + public Task DelAsync(params string[] key) + { + foreach (var k in key) + { + _memoryCache.Remove(k); + } + + return Task.FromResult((long)key.Length); + } + + public async Task DelByPatternAsync(string pattern) + { + if (string.IsNullOrEmpty(pattern)) + return default; + + //pattern = Regex.Replace(pattern, @"\{*.\}", "(.*)"); + var keys = GetAllKeys().Where(k => k.StartsWith(pattern)); + if (keys != null && keys.Any()) + return await DelAsync(keys.ToArray()); + + return default; + } + + public bool Exists(string key) + { + return _memoryCache.TryGetValue(key, out _); + } + + public Task ExistsAsync(string key) + { + return Task.FromResult(_memoryCache.TryGetValue(key, out _)); + } + + public string Get(string key) + { + return _memoryCache.Get(key)?.ToString(); + } + + public T Get(string key) + { + return _memoryCache.Get(key); + } + + public Task GetAsync(string key) + { + return Task.FromResult(Get(key)); + } + + public Task GetAsync(string key) + { + return Task.FromResult(Get(key)); + } + + public bool Set(string key, object value) + { + _memoryCache.Set(key, value); + return true; + } + + public bool Set(string key, object value, TimeSpan expire) + { + _memoryCache.Set(key, value, expire); + return true; + } + + public Task SetAsync(string key, object value) + { + Set(key, value); + return Task.FromResult(true); + } + + public Task SetAsync(string key, object value, TimeSpan expire) + { + Set(key, value, expire); + return Task.FromResult(true); + } + + public List GetAllKeys() + { + //const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic; + //var entries = _memoryCache.GetType().GetField("_entries", flags)?.GetValue(_memoryCache); + //var cacheItems = entries?.GetType().GetProperty("Keys").GetValue(entries) as ICollection; //entries as IDictionary; + //var keys = new List(); + //if (cacheItems == null) return keys; + //return cacheItems.Select(u => u.ToString()).ToList(); + + const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic; + var entries = _memoryCache.GetType().GetField("_coherentState", flags)?.GetValue(_memoryCache); + + var cacheItems = entries?.GetType().GetProperty("EntriesCollection", flags).GetValue(entries) as ICollection; //entries as IDictionary; + var keys = new List(); + if (cacheItems == null) return keys; + + foreach (var item in cacheItems) + { + var methodInfo = item.GetType().GetProperty("Key"); + + var val = methodInfo.GetValue(item); + + keys.Add(val.ToString()); + } + + return keys; + + + } + + +} diff --git a/Magic.Core/Cache/RedisCache.cs b/Magic.Core/Cache/RedisCache.cs new file mode 100644 index 0000000..a434a9d --- /dev/null +++ b/Magic.Core/Cache/RedisCache.cs @@ -0,0 +1,100 @@ +using Furion.DependencyInjection; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Magic.Core; + +/// +/// Redis缓存 +/// +public class RedisCache : ICache, ISingleton +{ + public RedisCache(IOptions cacheOptions) + { + var csredis = new CSRedis.CSRedisClient(cacheOptions.Value.RedisConnectionString); + RedisHelper.Initialization(csredis); + } + + public long Del(params string[] key) + { + return RedisHelper.Del(key); + } + + public Task DelAsync(params string[] key) + { + return RedisHelper.DelAsync(key); + } + + public async Task DelByPatternAsync(string pattern) + { + if (string.IsNullOrEmpty(pattern)) + return default; + + //pattern = Regex.Replace(pattern, @"\{.*\}", "*"); + var keys = (await RedisHelper.KeysAsync(pattern + "*")); + if (keys != null && keys.Length > 0) + { + return await RedisHelper.DelAsync(keys); + } + + return default; + } + + public bool Exists(string key) + { + return RedisHelper.Exists(key); + } + + public Task ExistsAsync(string key) + { + return RedisHelper.ExistsAsync(key); + } + + public string Get(string key) + { + return RedisHelper.Get(key); + } + + public T Get(string key) + { + return RedisHelper.Get(key); + } + + public Task GetAsync(string key) + { + return RedisHelper.GetAsync(key); + } + + public Task GetAsync(string key) + { + return RedisHelper.GetAsync(key); + } + + public bool Set(string key, object value) + { + return RedisHelper.Set(key, value); + } + + public bool Set(string key, object value, TimeSpan expire) + { + return RedisHelper.Set(key, value, expire); + } + + public Task SetAsync(string key, object value) + { + return RedisHelper.SetAsync(key, value); + } + + public Task SetAsync(string key, object value, TimeSpan expire) + { + return RedisHelper.SetAsync(key, value, expire); + } + + public List GetAllKeys() + { + return RedisHelper.Keys("*").ToList(); + } +} diff --git a/Magic.Core/Cache/SqlSugarCache.cs b/Magic.Core/Cache/SqlSugarCache.cs new file mode 100644 index 0000000..0347377 --- /dev/null +++ b/Magic.Core/Cache/SqlSugarCache.cs @@ -0,0 +1,58 @@ +using Furion; +using Furion.DependencyInjection; +using SqlSugar; +using System; +using System.Collections.Generic; + +namespace Magic.Core; + +public class SqlSugarCache : ICacheService +{ + private static ICache _cache = App.GetOptions().CacheType == CacheType.MemoryCache? App.RootServices.GetService(typeof(MemoryCache)) as ICache : App.RootServices.GetService(typeof(RedisCache)) as ICache; + + public void Add(string key, TV value) + { + _cache.Set(key, value); + } + + public void Add(string key, TV value, int cacheDurationInSeconds) + { + _cache.Set(key, value, TimeSpan.FromSeconds(cacheDurationInSeconds)); + } + + public bool ContainsKey(string key) + { + return _cache.Exists(key); + } + + public TV Get(string key) + { + return _cache.Get(key); + } + + public IEnumerable GetAllKey() + { + + return _cache.GetAllKeys(); + } + + public TV GetOrCreate(string cacheKey, Func create, int cacheDurationInSeconds = int.MaxValue) + { + if (this.ContainsKey(cacheKey)) + { + return this.Get(cacheKey); + } + else + { + var result = create(); + this.Add(cacheKey, result, cacheDurationInSeconds); + return result; + } + } + + public void Remove(string key) + { + _cache.Del(key); + } +} + diff --git a/Magic.Core/Captcha/ClickWord/ClickWordCaptcha.cs b/Magic.Core/Captcha/ClickWord/ClickWordCaptcha.cs new file mode 100644 index 0000000..ac65b35 --- /dev/null +++ b/Magic.Core/Captcha/ClickWord/ClickWordCaptcha.cs @@ -0,0 +1,223 @@ +using Furion; +using Furion.DependencyInjection; +using Furion.JsonSerialization; +using Microsoft.Extensions.Caching.Memory; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Linq; +using Yitter.IdGenerator; + +namespace Magic.Core; + +/// +/// 点选验证码 +/// +public class ClickWordCaptcha : IClickWordCaptcha, ITransient +{ + private readonly IMemoryCache _memoryCache; + + public ClickWordCaptcha(IMemoryCache memoryCache) + { + _memoryCache = memoryCache; + } + + /// + /// 生成验证码图片 + /// + /// + /// + /// + /// + public ClickWordCaptchaResult CreateCaptchaImage(string code, int width, int height) + { + var rtnResult = new ClickWordCaptchaResult(); + + // 变化点: 3个字 + int rightCodeLength = 3; + + Bitmap bitmap = null; + Graphics g = null; + MemoryStream ms = null; + Random random = new(); + + Color[] colorArray = { Color.Black, Color.DarkBlue, Color.Green, Color.Orange, Color.Brown, Color.DarkCyan, Color.Purple }; + + string bgImagesDir = Path.Combine(App.WebHostEnvironment.WebRootPath, "Captcha/Image"); + string[] bgImagesFiles = Directory.GetFiles(bgImagesDir); + + // 字体来自:https://www.zcool.com.cn/special/zcoolfonts/ + string fontsDir = Path.Combine(App.WebHostEnvironment.WebRootPath, "Captcha/Font"); + string[] fontFiles = new DirectoryInfo(fontsDir)?.GetFiles() + ?.Where(m => m.Extension.ToLower() == ".ttf") + ?.Select(m => m.FullName).ToArray(); + + int imgIndex = random.Next(bgImagesFiles.Length); + string randomImgFile = bgImagesFiles[imgIndex]; + var imageStream = Image.FromFile(randomImgFile); + + bitmap = new Bitmap(imageStream, width, height); + imageStream.Dispose(); + g = Graphics.FromImage(bitmap); + Color[] penColor = { Color.Red, Color.Green, Color.Blue }; + int code_length = code.Length; + var words = new List(); + for (int i = 0; i < code_length; i++) + { + int colorIndex = random.Next(colorArray.Length); + int fontIndex = random.Next(fontFiles.Length); + Font f = LoadFont(fontFiles[fontIndex], 15, FontStyle.Regular); + Brush b = new SolidBrush(colorArray[colorIndex]); + int _y = random.Next(height); + if (_y > (height - 30)) + _y -= 60; + + int _x = width / (i + 1); + if ((width - _x) < 50) + { + _x = width - 60; + } + string word = code.Substring(i, 1); + if (rtnResult.repData.point.Count < rightCodeLength) + { + // (int, int) percentPos = ToPercentPos((width, height), (_x, _y)); + // 添加正确答案 位置数据 + if (random.Next(0, 3).Equals(1) || (code_length - i).Equals(rightCodeLength - rtnResult.repData.point.Count)) + { + rtnResult.repData.point.Add(new PointPosModel() + { + X = _x, //percentPos.Item1, + Y = _y //percentPos.Item2, + }); + words.Add(word); + } + } + g.DrawString(word, f, b, _x, _y); + } + rtnResult.repData.wordList = words; + + ms = new MemoryStream(); + bitmap.Save(ms, ImageFormat.Jpeg); + g.Dispose(); + bitmap.Dispose(); + ms.Dispose(); + rtnResult.repData.originalImageBase64 = Convert.ToBase64String(ms.GetBuffer()); //"data:image/jpg;base64," + + rtnResult.repData.token = YitIdHelper.NextId().ToString(); + + // 缓存验证码正确位置集合 + var cacheOptions = new MemoryCacheEntryOptions().SetSlidingExpiration(TimeSpan.FromSeconds(30)); + _memoryCache.Set(CommonConst.CACHE_KEY_CODE + rtnResult.repData.token, rtnResult.repData.point, cacheOptions); + + rtnResult.repData.point = null; // 清空位置信息 + return rtnResult; + } + + /// + /// 转换为相对于图片的百分比单位 + /// + /// 图片宽高 + /// 相对于图片的绝对尺寸 + /// (int:xPercent, int:yPercent) + private (int, int) ToPercentPos((int, int) widthAndHeight, (int, int) xAndy) + { + (int, int) rtnResult = (0, 0); + // 注意: int / int = int (小数部分会被截断) + rtnResult.Item1 = (int)(((double)xAndy.Item1) / ((double)widthAndHeight.Item1) * 100); + rtnResult.Item2 = (int)(((double)xAndy.Item2) / ((double)widthAndHeight.Item2) * 100); + + return rtnResult; + } + + /// + /// 加载字体 + /// + /// 字体文件路径,包含字体文件名和后缀名 + /// 大小 + /// 字形(常规/粗体/斜体/粗斜体) + private Font LoadFont(string path, int size, FontStyle fontStyle) + { + var pfc = new System.Drawing.Text.PrivateFontCollection(); + pfc.AddFontFile(path);// 字体文件路径 + return new Font(pfc.Families[0], size, fontStyle); + } + + /// + /// 随机绘制字符串 + /// + /// + /// + public string RandomCode(int number) + { + char[] str_char_arrary = new char[] { '赵', '钱', '孙', '李', '周', '吴', '郑', '王', '冯', '陈', '卫', '蒋', '沈', '韩', '杨', '朱', '秦', '尤', '许', '何', '吕', '施', '张', '孔', '曹', '严', '华', '金', '魏', '陶', '姜', '戚', '谢', '喻', '柏', '水', '章', '云', '苏', '潘', '葛', '范', '彭', '郎', '鲁', '昌', '马', '苗', '凤', '花', '方', '任', '袁', '柳', '史', '唐', '费', '薛', '雷', '贺', '汤', '殷', '罗', '毕', '安', '常', '傅', '齐', '元', '顾', '孟', '平', '黄', '穆', '萧', '姚', '汪', '毛', '米', '伏', '成', '戴', '谈', '宋', '茅', '庞', '熊', '纪', '舒', '屈', '项', '祝', '董', '梁', '杜', '蓝', '季', '贾', '路', '娄', '江', '童', '颜', '郭', '梅', '盛', '林', '钟', '徐', '骆', '高', '夏', '田', '樊', '胡', '凌', '霍', '万', '支', '管', '卢', '莫', '房', '解', '应', '宗', '丁', '宣', '邓', '单', '杭', '洪', '包', '诸', '左', '石', '崔', '吉', '程', '邢', '陆', '荣', '翁', '于', '惠', '曲', '封', '储', '仲', '伊', '宁', '仇', '甘', '武', '符', '刘', '景', '龙', '叶', '幸', '司', '黎', '印', '怀', '蒲', '从', '索', '赖', '卓', '屠', '池', '乔', '闻', '党', '谭', '贡', '劳', '申', '扶', '堵', '宰', '桑', '寿', '通', '燕', '浦', '尚', '农', '温', '别', '庄', '柴', '阎', '连', '习', '容', '向', '古', '易', '终', '步', '都', '耿', '满', '国', '文', '寇', '广', '东', '欧', '利', '师', '巩', '聂', '关', '荆', '伟', '刚', '勇', '毅', '俊', '峰', '强', '军', '平', '保', '东', '文', '辉', '力', '明', '永', '健', '世', '广', '志', '义', '兴', '良', '海', '山', '仁', '波', '宁', '贵', '福', '生', '龙', '元', '全', '国', '胜', '学', '祥', '才', '发', '武', '新', '利', '清', '飞', '彬', '富', '顺', '信', '子', '杰', '涛', '昌', '成', '康', '星', '光', '天', '达', '安', '岩', '中', '茂', '进', '林', '有', '坚', '和', '彪', '博', '诚', '先', '敬', '震', '振', '壮', '会', '思', '群', '豪', '心', '邦', '承', '乐', '绍', '功', '松', '善', '厚', '庆', '民', '友', '裕', '河', '哲', '江', '超', '浩', '亮', '政', '谦', '奇', '固', '之', '轮', '翰', '朗', '伯', '宏', '言', '若', '鸣', '朋', '梁', '栋', '维', '启', '克', '伦', '翔', '旭', '鹏', '泽', '晨', '辰', '士', '以', '建', '家', '致', '树', '炎', '德', '行', '时', '泰', '盛', '雄', '钧', '冠', '策', '腾', '榕', '风', '航', '秀', '英', '华', '慧', '巧', '美', '娜', '静', '淑', '惠', '珠', '翠', '雅', '芝', '玉', '萍', '红', '玲', '芬', '芳', '燕', '彩', '春', '菊', '兰', '凤', '洁', '梅', '琳', '素', '云', '莲', '真', '环', '雪', '荣', '爱', '妹', '霞', '香', '月', '莺', '艳', '瑞', '凡', '佳', '嘉', '琼', '勤', '珍', '贞', '莉', '桂', '叶', '璧', '晶', '秋', '珊', '锦', '青', '婉', '颖', '露', '雁', '仪', '荷', '丹', '蓉', '眉', '君', '琴', '蕊', '薇', '梦', '韵', '融', '园', '艺', '咏', '卿', '聪', '澜', '纯', '悦', '昭', '冰', '爽', '羽', '希', '欣', '飘', '育', '柔', '竹', '凝', '晓', '欢', '枫', '菲', '寒', '伊', '亚', '宜', '可', '舒', '影', '荔', '枝', '丽', '阳', '宝', '贝', '初', '程', '恒', '鸿', '桦', '剑', '娇', '纪', '宽', '苛', '灵', '玛', '媚', '晴', '容', '烁', '堂', '唯', '威', '苇', '阅', '宇', '雨', '洋', '忠', '宗', '曼', '紫', '逸', '贤', '蝶', '绿', '蓝', '儿', '翠', '烟' }; + var rand = new Random(); + var hs = new HashSet(); + var randomBool = true; + while (randomBool) + { + if (hs.Count == number) + break; + var rand_number = rand.Next(str_char_arrary.Length); + hs.Add(str_char_arrary[rand_number]); + } + return string.Join("", hs); + } + + /// + /// 验证码验证 + /// + /// + /// + public dynamic CheckCode(ClickWordCaptchaInput input) + { + var res = new ClickWordCaptchaResult(); + + var rightVCodePos = _memoryCache.Get(CommonConst.CACHE_KEY_CODE + input.Token) as List; + if (rightVCodePos == null) + { + res.repCode = "6110"; + res.repMsg = "验证码已失效,请重新获取"; + return res; + } + + var userVCodePos = JSON.Deserialize>(input.PointJson); + if (userVCodePos == null || userVCodePos.Count < rightVCodePos.Count) + { + res.repCode = "6111"; + res.repMsg = "验证码无效"; + return res; + } + + int allowOffset = 25; // 允许的偏移量(点触容错) + for (int i = 0; i < userVCodePos.Count; i++) + { + var xOffset = userVCodePos[i].X - rightVCodePos[i].X; + var yOffset = userVCodePos[i].Y - rightVCodePos[i].Y; + xOffset = Math.Abs(xOffset); // x轴偏移量 + yOffset = Math.Abs(yOffset); // y轴偏移量 + // 只要有一个点的任意一个轴偏移量大于allowOffset,则验证不通过 + if (xOffset > allowOffset || yOffset > allowOffset) + { + res.repCode = "6112"; + res.repMsg = "验证码错误"; + return res; + } + } + + _memoryCache.Remove(CommonConst.CACHE_KEY_CODE + input.Token); + res.repCode = "0000"; + res.repMsg = "验证成功"; + return res; + } +} + +/// +/// 记录正确位置 +/// +public class PointPosModel +{ + public int X { get; set; } + + public int Y { get; set; } +} diff --git a/Magic.Core/Captcha/ClickWord/ClickWordCaptchaInput.cs b/Magic.Core/Captcha/ClickWord/ClickWordCaptchaInput.cs new file mode 100644 index 0000000..0c81e5f --- /dev/null +++ b/Magic.Core/Captcha/ClickWord/ClickWordCaptchaInput.cs @@ -0,0 +1,28 @@ +using Furion.DependencyInjection; +using System.ComponentModel.DataAnnotations; + +namespace Magic.Core; + +/// +/// 点击验证码输入参数 +/// +[SuppressSniffer] +public class ClickWordCaptchaInput +{ + /// + /// 验证码类型 + /// + [Required(ErrorMessage = "验证码类型")] + public string CaptchaType { get; set; } + + /// + /// 坐标点集合 + /// + [Required(ErrorMessage = "坐标点集合不能为空")] + public string PointJson { get; set; } + + /// + /// Token + /// + public string Token { get; set; } +} diff --git a/Magic.Core/Captcha/ClickWord/ClickWordCaptchaResult.cs b/Magic.Core/Captcha/ClickWord/ClickWordCaptchaResult.cs new file mode 100644 index 0000000..1644f19 --- /dev/null +++ b/Magic.Core/Captcha/ClickWord/ClickWordCaptchaResult.cs @@ -0,0 +1,43 @@ +using Furion.DependencyInjection; +using System.Collections.Generic; + +namespace Magic.Core; + +/// +/// 验证码输出参数 +/// +[SuppressSniffer] +public class ClickWordCaptchaResult +{ + public string repCode { get; set; } = "0000"; + public string repMsg { get; set; } + public RepData repData { get; set; } = new RepData(); + public bool error { get; set; } + public bool success { get; set; } = true; +} + +[SuppressSniffer] +public class RepData +{ + public string captchaId { get; set; } + public string projectCode { get; set; } + public string captchaType { get; set; } + public string captchaOriginalPath { get; set; } + public string captchaFontType { get; set; } + public string captchaFontSize { get; set; } + public string secretKey { get; set; } + public string originalImageBase64 { get; set; } + public List point { get; set; } = new List(); + public string jigsawImageBase64 { get; set; } + public List wordList { get; set; } = new List(); + public string pointList { get; set; } + public string pointJson { get; set; } + public string token { get; set; } + public bool result { get; set; } + public string captchaVerification { get; set; } +} + +[SuppressSniffer] +public class WordList +{ +} diff --git a/Magic.Core/Captcha/ClickWord/IClickWordCaptcha.cs b/Magic.Core/Captcha/ClickWord/IClickWordCaptcha.cs new file mode 100644 index 0000000..b596462 --- /dev/null +++ b/Magic.Core/Captcha/ClickWord/IClickWordCaptcha.cs @@ -0,0 +1,8 @@ +namespace Magic.Core; + +public interface IClickWordCaptcha +{ + dynamic CheckCode(ClickWordCaptchaInput input); + ClickWordCaptchaResult CreateCaptchaImage(string code, int width, int height); + string RandomCode(int number); +} diff --git a/Magic.Core/Captcha/General/GeneralCaptcha.cs b/Magic.Core/Captcha/General/GeneralCaptcha.cs new file mode 100644 index 0000000..82e7c19 --- /dev/null +++ b/Magic.Core/Captcha/General/GeneralCaptcha.cs @@ -0,0 +1,129 @@ +using Furion.DependencyInjection; +using Microsoft.Extensions.Caching.Memory; +using System; +using System.ComponentModel.DataAnnotations; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Text; + +namespace Magic.Core; + +/// +/// 常规验证码 +/// +public class GeneralCaptcha : IGeneralCaptcha, ITransient +{ + private readonly IMemoryCache _memoryCache; + + public GeneralCaptcha(IMemoryCache memoryCache) + { + _memoryCache = memoryCache; + } + + /// + /// 生成验证码图片 + /// + /// + /// + public string CreateCaptchaImage(int length = 4) + { + return Convert.ToBase64String(Draw(length)); + } + + private string GenerateRandom(int length) + { + var chars = new StringBuilder(); + // 验证码的字符集,去掉了一些容易混淆的字符 + char[] character = { '2', '3', '4', '5', '6', '8', '9', 'a', 'b', 'd', 'e', 'f', 'h', 'k', 'm', 'n', 'r', 'x', 'y', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W', 'X', 'Y' }; + Random rnd = new Random(); + // 生成验证码字符串 + for (int i = 0; i < length; i++) + { + chars.Append(character[rnd.Next(character.Length)]); + } + return chars.ToString(); + } + + private byte[] Draw(int length = 4) + { + int codeW = 110; + int codeH = 36; + int fontSize = 22; + + // 颜色列表,用于验证码、噪线、噪点 + Color[] color = { Color.Black, Color.Red, Color.Blue, Color.Green, Color.Orange, Color.Brown, Color.Brown, Color.DarkBlue }; + // 字体列表,用于验证码 + string[] fonts = new[] { "Times New Roman", "Verdana", "Arial", "Gungsuh", "Impact" }; + + var code = GenerateRandom(length); // 随机字符串集合 + + using (Bitmap bmp = new Bitmap(codeW, codeH)) + using (Graphics g = Graphics.FromImage(bmp)) + using (MemoryStream ms = new MemoryStream()) + { + g.Clear(Color.White); + Random rnd = new Random(); + // 画噪线 + for (int i = 0; i < 1; i++) + { + int x1 = rnd.Next(codeW); + int y1 = rnd.Next(codeH); + int x2 = rnd.Next(codeW); + int y2 = rnd.Next(codeH); + var clr = color[rnd.Next(color.Length)]; + g.DrawLine(new Pen(clr), x1, y1, x2, y2); + } + + // 画验证码字符串 + string fnt; + Font ft; + for (int i = 0; i < code.Length; i++) + { + fnt = fonts[rnd.Next(fonts.Length)]; + ft = new Font(fnt, fontSize); + var clr = color[rnd.Next(color.Length)]; + g.DrawString(code[i].ToString(), ft, new SolidBrush(clr), (float)i * 24 + 2, (float)0); + } + + // 缓存验证码正确集合 + var cacheOptions = new MemoryCacheEntryOptions().SetSlidingExpiration(TimeSpan.FromSeconds(30)); + _memoryCache.Set(CommonConst.CACHE_KEY_CODE + Guid.NewGuid().ToString("N"), code, cacheOptions); + + // 将验证码图片写入内存流 + bmp.Save(ms, ImageFormat.Png); + return ms.ToArray(); + } + } + + /// + /// 验证码验证 + /// + /// + /// + public dynamic CheckCode(GeneralCaptchaInput input) + { + var res = new ClickWordCaptchaResult(); + + var code = _memoryCache.Get(CommonConst.CACHE_KEY_CODE + input.Token); + if (code == null) + { + res.repCode = "6110"; + res.repMsg = "验证码已失效,请重新获取"; + return res; + } + if (input.CaptchaCode != (string)code) + { + res.repCode = "6112"; + res.repMsg = "验证码错误"; + return res; + } + + _memoryCache.Remove(CommonConst.CACHE_KEY_CODE + input.Token); + res.repCode = "0000"; + res.repMsg = "验证成功"; + return res; + } +} + + diff --git a/Magic.Core/Captcha/General/GeneralCaptchaInput.cs b/Magic.Core/Captcha/General/GeneralCaptchaInput.cs new file mode 100644 index 0000000..a2ccebc --- /dev/null +++ b/Magic.Core/Captcha/General/GeneralCaptchaInput.cs @@ -0,0 +1,28 @@ +using Furion.DependencyInjection; +using System.ComponentModel.DataAnnotations; + +namespace Magic.Core; + +/// +/// 常规验证码输入 +/// +[SuppressSniffer] +public class GeneralCaptchaInput +{ + /// + /// 验证码类型 + /// + [Required(ErrorMessage = "验证码类型")] + public string CaptchaType { get; set; } + + /// + /// 验证码字符 + /// + [Required(ErrorMessage = "验证码字符不能为空")] + public string CaptchaCode { get; set; } + + /// + /// Token + /// + public string Token { get; set; } +} diff --git a/Magic.Core/Captcha/General/IGeneralCaptcha.cs b/Magic.Core/Captcha/General/IGeneralCaptcha.cs new file mode 100644 index 0000000..119a96d --- /dev/null +++ b/Magic.Core/Captcha/General/IGeneralCaptcha.cs @@ -0,0 +1,7 @@ +namespace Magic.Core; + +public interface IGeneralCaptcha +{ + dynamic CheckCode(GeneralCaptchaInput input); + string CreateCaptchaImage(int length = 4); +} diff --git a/Magic.Core/ConfigOption/ConfigOptions.cs b/Magic.Core/ConfigOption/ConfigOptions.cs new file mode 100644 index 0000000..19a8b47 --- /dev/null +++ b/Magic.Core/ConfigOption/ConfigOptions.cs @@ -0,0 +1,210 @@ +using Furion.ConfigurableOptions; +using System.Collections.Generic; + +namespace Magic.Core; + +/// +/// 缓存配置 +/// +public class CacheOptions : IConfigurableOptions +{ + /// + /// 缓存类型 + /// + public CacheType CacheType { get; set; } + + /// + /// Redis配置 + /// + public string RedisConnectionString { get; set; } +} +/// +/// 系统配置 +/// +public class SystemSettingsOptions : IConfigurableOptions +{ + /// + /// 超管是否可以查看所有租户的数据 + /// + public bool SuperAdminViewAllData { get; set; } + + /// + /// 是否开启全局请求日志 + /// + public bool IsGlobalRequestLog { get; set; } +} +/// +/// 雪花Id配置 +/// +public class SnowIdOptions : IConfigurableOptions +{ + /// + /// 取值范围0~63,默认1 + /// + public string WorkerId { get; set; } = "1"; +} +/// +/// 第三方配置 +/// +public class OAuthOptions : IConfigurableOptions +{ + /// + ///微信 + /// + public ThirdParty Wechat { get; set; } +} +/// +/// 上传文件 +/// +public class UploadFileOptions : IConfigurableOptions +{ + /// + /// 阿里云 + /// + public FileDescription Aliyun { get; set; } + /// + /// 头像 + /// + public FileDescription Avatar { get; set; } + /// + /// 文档 + /// + public FileDescription Document { get; set; } + /// + /// 商店 + /// + public FileDescription Shop { get; set; } + /// + /// 编辑器 + /// + public FileDescription Editor { get; set; } + /// + /// 默认 + /// + public FileDescription Default { get; set; } +} +/// +/// 数据库配置 +/// +public class ConnectionStringsOptions : IConfigurableOptions +{ + /// + /// 默认数据库编号 + /// + public string DefaultDbNumber { get; set; } + /// + /// 默认数据库类型 + /// + public string DefaultDbType { get; set; } + /// + /// 默认数据库连接字符串 + /// + + public string DefaultDbString { get; set; } + /// + /// 业务库集合 + /// + public List DbConfigs { get; set; } +} +/// +/// JWT配置 +/// +public class JWTSettingsOptions : IConfigurableOptions +{ + /// + /// 是否验证密钥 + /// + public bool ValidateIssuerSigningKey { get; set; } + /// + /// 密钥 + /// + public string IssuerSigningKey { get; set; } + /// + /// 是否验证签发方 + /// + public bool ValidateIssuer { get; set; } + /// + /// 签发方 + /// + public string ValidIssuer { get; set; } + /// + /// 是否验证签收方 + /// + public bool ValidateAudience { get; set; } + /// + /// 签收方 + /// + public string ValidAudience { get; set; } + /// + /// 是否验证过期时间 + /// + public bool ValidateLifetime { get; set; } + /// + /// 过期时间 + /// + public long ExpiredTime { get; set; } + /// + /// 过期时间容错值 + /// + public long ClockSkew { get; set; } +} +/// +/// 数据库参数 +/// +public class DbConfig +{ + /// + /// 数据库编号 + /// + public string DbNumber { get; set; } + /// + /// 数据库类型 + /// + public string DbType { get; set; } + /// + /// 数据库连接字符串 + /// + + public string DbString { get; set; } +} +/// +/// 文件参数 +/// +public class FileDescription +{ + /// + /// 路径 + /// + public string path { get; set; } + /// + /// 大小 + /// + public long maxSize { get; set; } + /// + /// 类型 + /// + public string[] contentType { get; set; } +} +/// +/// 第三方参数 +/// +public class ThirdParty +{ + /// + /// id + /// + public string app_id { get; set; } + /// + /// key + /// + public string app_key { get; set; } + /// + /// 回调地址 + /// + public string redirect_uri { get; set; } + /// + /// scope + /// + public string scope { get; set; } + +} diff --git a/Magic.Core/Const/ClaimConst.cs b/Magic.Core/Const/ClaimConst.cs new file mode 100644 index 0000000..9bdcc6b --- /dev/null +++ b/Magic.Core/Const/ClaimConst.cs @@ -0,0 +1,38 @@ +namespace Magic.Core; + +public class ClaimConst +{ + /// + /// 用户Id + /// + public const string CLAINM_USERID = "UserId"; + + /// + /// 账号 + /// + public const string CLAINM_ACCOUNT = "Account"; + + /// + /// 名称 + /// + public const string CLAINM_NAME = "Name"; + + /// + /// 是否超级管理 + /// + public const string CLAINM_SUPERADMIN = "SuperAdmin"; + + /// + /// 租户Id + /// + public const string TENANT_ID = "TenantId"; + + /// + /// 租户类型 + /// + public const string CLAINM_TENANT_TYPE = "TenantType"; + /// + /// 租户名称 + /// + public const string CLAINM_TENANT_NAME = "TenantName"; +} diff --git a/Magic.Core/Const/CommonConst.cs b/Magic.Core/Const/CommonConst.cs new file mode 100644 index 0000000..2933a99 --- /dev/null +++ b/Magic.Core/Const/CommonConst.cs @@ -0,0 +1,55 @@ +namespace Magic.Core; + +public class CommonConst +{ + #region 缓存 + /// + /// 用户缓存 + /// + public const string CACHE_KEY_USER = "user_"; + + /// + /// 菜单缓存 + /// + public const string CACHE_KEY_MENU = "menu_"; + + /// + /// 权限缓存 + /// + public const string CACHE_KEY_PERMISSION = "permission_"; + + /// + /// 数据范围缓存 + /// + public const string CACHE_KEY_DATASCOPE = "datascope_"; + public const string CACHE_KEY_USERSDATASCOPE = "usersdatascope_"; + + /// + /// 验证码缓存 + /// + public const string CACHE_KEY_CODE = "vercode_"; + + /// + /// 库表实体信息缓存 + /// + public const string CACHE_KEY_ENTITYINFO = "tableentity"; + + /// + /// 所有权限缓存 + /// + public const string CACHE_KEY_ALLPERMISSION = "allpermission"; + #endregion + + /// + /// 程序集 + /// + public static string[] ENTITY_ASSEMBLY_NAME = new string[] { "Magic.Core", "Magic.Application", "Magic.FlowCenter" }; + /// + /// 删除字段 + /// + public const string DELETE_FIELD = "IsDeleted"; + + #region 数据库编号 + public const string MasterDb = "0"; + #endregion +} diff --git a/Magic.Core/Entity/DBEntityTenant.cs b/Magic.Core/Entity/DBEntityTenant.cs new file mode 100644 index 0000000..44b7f2f --- /dev/null +++ b/Magic.Core/Entity/DBEntityTenant.cs @@ -0,0 +1,17 @@ + +using SqlSugar; + +namespace Magic.Core.Entity; + +/// +/// 自定义租户基类实体 +/// +public abstract class DBEntityTenant : DEntityBase +{ + /// + /// 租户id + /// + [SugarColumn(ColumnDescription = "租户id", IsNullable = true)] + public virtual long? TenantId { get; set; } + +} diff --git a/Magic.Core/Entity/DEntityBase.cs b/Magic.Core/Entity/DEntityBase.cs new file mode 100644 index 0000000..f580024 --- /dev/null +++ b/Magic.Core/Entity/DEntityBase.cs @@ -0,0 +1,107 @@ +using SqlSugar; +using System; +using System.ComponentModel.DataAnnotations; + +namespace Magic.Core.Entity; + +/// +/// 自定义实体基类 +/// +[Tenant(CommonConst.MasterDb)] +public abstract class DEntityBase : PrimaryKeyEntity +{ + /// + /// 创建时间 + /// + [SugarColumn(ColumnDescription = "创建时间", IsNullable = true)] + public virtual DateTime? CreatedTime { get; set; } + + /// + /// 更新时间 + /// + [SugarColumn(ColumnDescription = "更新时间", IsNullable = true)] + public virtual DateTime? UpdatedTime { get; set; } + + /// + /// 创建者Id + /// + [SugarColumn(ColumnDescription = "创建者Id", IsNullable = true)] + public virtual long? CreatedUserId { get; set; } + + /// + /// 创建者名称 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "创建者名称", IsNullable = true)] + public virtual string CreatedUserName { get; set; } + + /// + /// 修改者Id + /// + [SugarColumn(ColumnDescription = "修改者Id", IsNullable = true)] + public virtual long? UpdatedUserId { get; set; } + + /// + /// 修改者名称 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "修改者名称", IsNullable = true)] + public virtual string UpdatedUserName { get; set; } + + /// + /// 软删除 + /// + [SugarColumn(ColumnDescription = "软删除")] + public virtual bool IsDeleted { get; set; } = false; + + + /// + /// 更新信息列 + /// + /// + public virtual string[] UpdateColumn() + { + var result = new[] {nameof(UpdatedUserId), nameof(UpdatedUserName), nameof(UpdatedTime)}; + return result; + } + + /// + /// 假删除的列,包含更新信息 + /// + /// + public virtual string[] FalseDeleteColumn() + { + var updateColumn = UpdateColumn(); + var deleteColumn = new[] {nameof(IsDeleted)}; + var result = new string [updateColumn.Length + deleteColumn.Length]; + deleteColumn.CopyTo(result, 0); + updateColumn.CopyTo(result, deleteColumn.Length); + return result; + } +} + +/// +/// 递增主键实体基类 +/// +public abstract class AutoIncrementEntity +{ + /// + /// 主键Id + /// + [SugarColumn(IsIdentity = true, ColumnDescription = "Id主键", IsPrimaryKey = true)] //通过特性设置主键和自增列 + // 注意是在这里定义你的公共实体 + public virtual int Id { get; set; } +} + +/// +/// 主键实体基类 +/// +public abstract class PrimaryKeyEntity +{ + /// + /// 主键Id + /// + [SugarColumn(ColumnDescription = "Id主键", IsPrimaryKey = true)] + // 注意是在这里定义你的公共实体 + public virtual long Id { get; set; } +} diff --git a/Magic.Core/Entity/Documentation.cs b/Magic.Core/Entity/Documentation.cs new file mode 100644 index 0000000..94d579c --- /dev/null +++ b/Magic.Core/Entity/Documentation.cs @@ -0,0 +1,78 @@ +using SqlSugar; +using System.Collections.Generic; +using System.ComponentModel; +namespace Magic.Core.Entity; + +/// +/// 文档表 +/// +[SugarTable("Documentation")] +[Description("文档表")] +public class Documentation : DEntityBase +{ + /// + /// 父Id + /// + + [SugarColumn(ColumnDescription = "父Id")] + public long PId { get; set; } + + /// + /// 父ID列表 + /// + [SugarColumn(IsNullable = true, ColumnDescription= "父ID列表")] + public string PIds { get; set; } + /// + /// 名称 + /// + [SugarColumn(ColumnDescription= "名称")] + public string Name { get; set; } + /// + /// 文档类型:文件、文件夹 + /// + [SugarColumn(ColumnDescription = "文件类型")] + public DocumentType DocumentType { get; set; } + /// + /// 文件后缀 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "文件后缀")] + public string FileSuffix { get; set; } + /// + /// 文件大小kb + /// + [SugarColumn(IsNullable = true, ColumnDescription = "文件大小kb")] + public int? FileSizeKb { get; set; } + + /// + /// 文件路径 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "文件路径")] + public string FilePath { get; set; } + + + /// + /// 存储后的文件名 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "存储后的文件名")] + public string FileObjectName { get; set; } + /// + /// 标签 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "标签")] + public int? Label { get; set; } + /// + /// 备注 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "备注")] + public string Remark { get; set; } + + /// + /// 是否可见 + /// + [SugarColumn(IsNullable = true)] + public bool Visible { get; set; } = true; + + [SugarColumn(IsIgnore = true)] + public List Children { get; set; } + +} diff --git a/Magic.Core/Entity/SysApp.cs b/Magic.Core/Entity/SysApp.cs new file mode 100644 index 0000000..f88e0d2 --- /dev/null +++ b/Magic.Core/Entity/SysApp.cs @@ -0,0 +1,47 @@ +using SqlSugar; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; + +namespace Magic.Core.Entity; + +/// +/// 系统应用表 +/// +[SugarTable("sys_app", TableDescription = "系统应用表")] +[Description("系统应用表")] +public class SysApp : DEntityBase +{ + /// + /// 名称 + /// + [Required, MaxLength(20)] + [SugarColumn(ColumnDescription = "名称")] + public string Name { get; set; } + + /// + /// 编码 + /// + [Required, MaxLength(50)] + [SugarColumn(ColumnDescription = "编码")] + public string Code { get; set; } + + /// + /// 是否默认激活(Y-是,N-否),只能有一个系统默认激活 + /// 用户登录后默认展示此系统菜单 + /// + [MaxLength(5)] + [SugarColumn(ColumnDescription = "是否默认激活")] + public string Active { get; set; } + + /// + /// 状态(字典 0正常 1停用 2删除) + /// + [SugarColumn(ColumnDescription = "状态")] + public CommonStatus Status { get; set; } = CommonStatus.ENABLE; + + /// + /// 排序 + /// + [SugarColumn(ColumnDescription = "排序")] + public int Sort { get; set; } +} diff --git a/Magic.Core/Entity/SysCodeGen.cs b/Magic.Core/Entity/SysCodeGen.cs new file mode 100644 index 0000000..336b02b --- /dev/null +++ b/Magic.Core/Entity/SysCodeGen.cs @@ -0,0 +1,68 @@ +using SqlSugar; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; + +namespace Magic.Core.Entity; + +/// +/// 代码生成表 +/// +[SugarTable("sys_code_gen",TableDescription="代码生成表")] +[Description("代码生成表")] +public class SysCodeGen : DEntityBase +{ + /// + /// 作者姓名 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "作者姓名",IsNullable =true)] + public string AuthorName { get; set; } + + /// + /// 是否移除表前缀 + /// + [MaxLength(5)] + [SugarColumn(ColumnDescription = "是否移除表前缀",IsNullable = true)] + public string TablePrefix { get; set; } + + /// + /// 生成方式 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "生成方式", IsNullable = true)] + public string GenerateType { get; set; } + + /// + /// 数据库表名 + /// + [MaxLength(64)] + [SugarColumn(ColumnDescription = "数据库表名",IsNullable = true)] + public string TableName { get; set; } + + /// + /// 命名空间 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "命名空间", IsNullable = true)] + public string NameSpace { get; set; } + + /// + /// 业务名 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "业务名", IsNullable = true)] + public string BusName { get; set; } + + /// + /// 菜单应用分类(应用编码) + /// + [MaxLength(50)] + [SugarColumn(ColumnDescription = "菜单应用分类", IsNullable = true)] + public string MenuApplication { get; set; } + + /// + /// 菜单编码 + /// + [SugarColumn(ColumnDescription = "菜单编码")] + public long MenuPid { get; set; } +} diff --git a/Magic.Core/Entity/SysCodeGenConfig.cs b/Magic.Core/Entity/SysCodeGenConfig.cs new file mode 100644 index 0000000..4263dc2 --- /dev/null +++ b/Magic.Core/Entity/SysCodeGenConfig.cs @@ -0,0 +1,138 @@ +using SqlSugar; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; + +namespace Magic.Core.Entity; + +/// +/// 代码生成字段配置表 +/// +[SugarTable("sys_code_gen_config")] +[Description("代码生成字段配置表")] +public class SysCodeGenConfig : DEntityBase +{ + /// + /// 代码生成主表ID + /// + [SugarColumn(ColumnDescription = "代码生成主表ID")] + public long CodeGenId { get; set; } + + /// + /// 数据库字段名 + /// + [Required, MaxLength(100)] + [SugarColumn(ColumnDescription = "数据库字段名")] + public string ColumnName { get; set; } + + /// + /// 字段描述 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "字段描述",IsNullable =true)] + public string ColumnComment { get; set; } + + /// + /// .NET数据类型 + /// + [MaxLength(50)] + [SugarColumn(ColumnDescription = ".NET数据类型", IsNullable = true)] + public string NetType { get; set; } + + /// + /// 作用类型(字典) + /// + [MaxLength(50)] + [SugarColumn(ColumnDescription = "作用类型(字典)", IsNullable = true)] + public string EffectType { get; set; } + + /// + /// 外键实体名称 + /// + [MaxLength(50)] + [SugarColumn(ColumnDescription = "外键实体名称", IsNullable = true)] + public string FkEntityName { get; set; } + + /// + /// 外键显示字段 + /// + [MaxLength(50)] + [SugarColumn(ColumnDescription = "外键显示字段", IsNullable = true)] + public string FkColumnName { get; set; } + + /// + /// 外键显示字段.NET类型 + /// + [MaxLength(50)] + [SugarColumn(ColumnDescription = "外键显示字段.NET类型", IsNullable = true)] + public string FkColumnNetType { get; set; } + + /// + /// 字典code + /// + [MaxLength(50)] + [SugarColumn(ColumnDescription = "字典code", IsNullable = true)] + public string DictTypeCode { get; set; } + + /// + /// 列表是否缩进(字典) + /// + [MaxLength(5)] + [SugarColumn(ColumnDescription = "列表是否缩进(字典)", IsNullable = true)] + public string WhetherRetract { get; set; } + + /// + /// 是否必填(字典) + /// + [MaxLength(5)] + [SugarColumn(ColumnDescription = "是否必填(字典)", IsNullable = true)] + public string WhetherRequired { get; set; } + + /// + /// 是否是查询条件 + /// + [MaxLength(5)] + [SugarColumn(ColumnDescription = "是否是查询条件", IsNullable = true)] + public string QueryWhether { get; set; } + + /// + /// 查询方式 + /// + [MaxLength(10)] + [SugarColumn(ColumnDescription = "查询方式", IsNullable = true)] + public string QueryType { get; set; } + + /// + /// 列表显示 + /// + [MaxLength(5)] + [SugarColumn(ColumnDescription = "列表显示", IsNullable = true)] + public string WhetherTable { get; set; } + + /// + /// 增改 + /// + [MaxLength(5)] + [SugarColumn(ColumnDescription = "增改", IsNullable = true)] + public string WhetherAddUpdate { get; set; } + + /// + /// 主键 + /// + [MaxLength(5)] + [SugarColumn(ColumnDescription = "主键", IsNullable = true)] + public string ColumnKey { get; set; } + + /// + /// 数据库中类型(物理类型) + /// + [MaxLength(50)] + [SugarColumn(ColumnDescription = "数据库中类型(物理类型)", IsNullable = true)] + public string DataType { get; set; } + + /// + /// 是否通用字段 + /// + [MaxLength(5)] + [SugarColumn(ColumnDescription = "是否通用字段", IsNullable = true)] + public string WhetherCommon { get; set; } +} diff --git a/Magic.Core/Entity/SysConfig.cs b/Magic.Core/Entity/SysConfig.cs new file mode 100644 index 0000000..2a33d51 --- /dev/null +++ b/Magic.Core/Entity/SysConfig.cs @@ -0,0 +1,62 @@ +using SqlSugar; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; + +namespace Magic.Core.Entity; + +/// +/// 参数配置表 +/// +[SugarTable("sys_config")] +[Description("参数配置表")] +public class SysConfig : DEntityBase +{ + /// + /// 名称 + /// + [Required, MaxLength(50)] + [SugarColumn(ColumnDescription = "名称")] + public string Name { get; set; } + + /// + /// 编码 + /// + [Required, MaxLength(50)] + [SugarColumn(ColumnDescription = "编码", IsNullable = true)] + public string Code { get; set; } + + /// + /// 属性值 + /// + [MaxLength(50)] + [SugarColumn(ColumnDescription = "属性值", IsNullable = true)] + public string Value { get; set; } + + /// + /// 是否是系统参数(Y-是,N-否) + /// + [MaxLength(5)] + [SugarColumn(ColumnDescription = "是否是系统参数(Y-是,N-否)", IsNullable = true)] + public string SysFlag { get; set; } + + /// + /// 备注 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "备注", IsNullable = true)] + public string Remark { get; set; } + + /// + /// 状态(字典 0正常 1停用 2删除) + /// + [SugarColumn(ColumnDescription = "状态(字典 0正常 1停用 2删除)")] + public CommonStatus Status { get; set; } = CommonStatus.ENABLE; + + /// + /// 常量所属分类的编码,来自于“常量的分类”字典 + /// + [MaxLength(50)] + [SugarColumn(ColumnDescription = "常量所属分类的编码,来自于“常量的分类”字典", IsNullable = true)] + public string GroupCode { get; set; } + +} diff --git a/Magic.Core/Entity/SysDictData.cs b/Magic.Core/Entity/SysDictData.cs new file mode 100644 index 0000000..d86aa94 --- /dev/null +++ b/Magic.Core/Entity/SysDictData.cs @@ -0,0 +1,52 @@ +using SqlSugar; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +namespace Magic.Core.Entity; + +/// +/// 字典值表 +/// +[SugarTable("sys_dict_data")] +[Description("字典值表")] +public class SysDictData : DEntityBase +{ + /// + /// 字典类型Id + /// + [SugarColumn(ColumnDescription = "编码")] + public long TypeId { get; set; } + + /// + /// 值 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "值", IsNullable = true)] + public string Value { get; set; } + + /// + /// 编码 + /// + [MaxLength(50)] + [SugarColumn(ColumnDescription = "编码", IsNullable = true)] + public string Code { get; set; } + + /// + /// 排序 + /// + [SugarColumn(ColumnDescription = "排序")] + public int Sort { get; set; } + + /// + /// 备注 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "备注", IsNullable = true)] + public string Remark { get; set; } + + /// + /// 状态(字典 0正常 1停用 2删除) + /// + [SugarColumn(ColumnDescription = "状态(字典 0正常 1停用 2删除)")] + public CommonStatus Status { get; set; } = CommonStatus.ENABLE; + +} diff --git a/Magic.Core/Entity/SysDictType.cs b/Magic.Core/Entity/SysDictType.cs new file mode 100644 index 0000000..a664ce6 --- /dev/null +++ b/Magic.Core/Entity/SysDictType.cs @@ -0,0 +1,50 @@ + + +using SqlSugar; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +namespace Magic.Core.Entity; + +/// +/// 字典类型表 +/// +[SugarTable("sys_dict_type")] +[Description("字典类型表")] +public class SysDictType : DEntityBase +{ + /// + /// 名称 + /// + [Required, MaxLength(50)] + [SugarColumn(ColumnDescription = "名称")] + public string Name { get; set; } + + /// + /// 编码 + /// + [Required, MaxLength(50)] + [SugarColumn(ColumnDescription = "编码")] + public string Code { get; set; } + + /// + /// 排序 + /// + [SugarColumn(ColumnDescription = "排序", IsNullable = true)] + public int Sort { get; set; } + + /// + /// 备注 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "备注", IsNullable = true)] + public string Remark { get; set; } + + /// + /// 状态(字典 0正常 1停用 2删除) + /// + [SugarColumn(ColumnDescription = "状态(字典 0正常 1停用 2删除)")] + public CommonStatus Status { get; set; } = CommonStatus.ENABLE; + +} diff --git a/Magic.Core/Entity/SysEmp.cs b/Magic.Core/Entity/SysEmp.cs new file mode 100644 index 0000000..67336e0 --- /dev/null +++ b/Magic.Core/Entity/SysEmp.cs @@ -0,0 +1,33 @@ +using SqlSugar; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +namespace Magic.Core.Entity; + +/// +/// 员工表 +/// +[SugarTable("sys_emp")] +[Description("员工表")] +public class SysEmp : PrimaryKeyEntity +{ + /// + /// 工号 + /// + [MaxLength(30)] + [SugarColumn(ColumnDescription = "工号", IsNullable = true)] + public string JobNum { get; set; } + + /// + /// 机构Id + /// + [SugarColumn(ColumnDescription = "机构Id")] + public long OrgId { get; set; } + + /// + /// 机构名称 + /// + [MaxLength(50)] + [SugarColumn(ColumnDescription = "机构名称", IsNullable = true)] + public string OrgName { get; set; } + +} diff --git a/Magic.Core/Entity/SysEmpExtOrgPos.cs b/Magic.Core/Entity/SysEmpExtOrgPos.cs new file mode 100644 index 0000000..baab5f6 --- /dev/null +++ b/Magic.Core/Entity/SysEmpExtOrgPos.cs @@ -0,0 +1,31 @@ +using SqlSugar; +using System.ComponentModel; +namespace Magic.Core.Entity; + +/// +/// 员工附属机构职位表 +/// +[SugarTable("sys_emp_ext_org_pos")] +[Description("员工附属机构职位表")] +public class SysEmpExtOrgPos +{ + /// + /// 员工Id + /// + [SugarColumn(ColumnDescription = "员工Id")] + public long SysEmpId { get; set; } + + + /// + /// 机构Id + /// + [SugarColumn(ColumnDescription = "机构Id")] + public long SysOrgId { get; set; } + + + /// + /// 职位Id + /// + [SugarColumn(ColumnDescription = "职位Id")] + public long SysPosId { get; set; } +} diff --git a/Magic.Core/Entity/SysEmpPos.cs b/Magic.Core/Entity/SysEmpPos.cs new file mode 100644 index 0000000..95f010a --- /dev/null +++ b/Magic.Core/Entity/SysEmpPos.cs @@ -0,0 +1,28 @@ +using SqlSugar; +using System.ComponentModel; + +namespace Magic.Core.Entity; + +/// +/// 员工职位表 +/// +[SugarTable("sys_emp_pos")] +[Description("员工职位表")] +public class SysEmpPos +{ + /// + /// 员工Id + /// + [SugarColumn(ColumnDescription = "员工Id")] + public long SysEmpId { get; set; } + + + + /// + /// 职位Id + /// + [SugarColumn(ColumnDescription = "职位Id")] + public long SysPosId { get; set; } + + +} diff --git a/Magic.Core/Entity/SysFile.cs b/Magic.Core/Entity/SysFile.cs new file mode 100644 index 0000000..34f2a92 --- /dev/null +++ b/Magic.Core/Entity/SysFile.cs @@ -0,0 +1,67 @@ +using SqlSugar; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +namespace Magic.Core.Entity; + +/// +/// 文件信息表 +/// +[SugarTable("sys_file")] +[Description("文件信息表")] +public class SysFile : DEntityBase +{ + /// + /// 文件存储位置(1:阿里云,2:腾讯云,3:minio,4:本地) + /// + [SugarColumn(ColumnDescription = "文件存储位置(1:阿里云,2:腾讯云,3:minio,4:本地")] + public int FileLocation { get; set; } + + /// + /// 文件仓库 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "文件仓库",IsNullable =true)] + public string FileBucket { get; set; } + + /// + /// 文件名称(上传时候的文件名) + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "文件名称(上传时候的文件名)", IsNullable = true)] + public string FileOriginName { get; set; } + + /// + /// 文件后缀 + /// + [MaxLength(50)] + [SugarColumn(ColumnDescription = "文件后缀", IsNullable = true)] + public string FileSuffix { get; set; } + + /// + /// 文件大小kb + /// + [MaxLength(10)] + [SugarColumn(ColumnDescription = "文件大小kb", IsNullable = true)] + public string FileSizeKb { get; set; } + + /// + /// 文件大小信息,计算后的 + /// + [MaxLength(50)] + [SugarColumn(ColumnDescription = "文件大小信息,计算后的", IsNullable = true)] + public string FileSizeInfo { get; set; } + + /// + /// 存储到bucket的名称(文件唯一标识id) + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "存储到bucket的名称(文件唯一标识id)", IsNullable = true)] + public string FileObjectName { get; set; } + + /// + /// 存储路径 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "存储路径", IsNullable = true)] + public string FilePath { get; set; } +} diff --git a/Magic.Core/Entity/SysLogAudit.cs b/Magic.Core/Entity/SysLogAudit.cs new file mode 100644 index 0000000..90bda73 --- /dev/null +++ b/Magic.Core/Entity/SysLogAudit.cs @@ -0,0 +1,66 @@ + +using SqlSugar; +using System; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +namespace Magic.Core.Entity; + +/// +/// 系统操作/审计日志表 +/// +[SugarTable("sys_log_audit")] +[Description("系统操作/审计日志表")] +public class SysLogAudit : AutoIncrementEntity +{ + /// + /// 表名 + /// + [MaxLength(50)] + [SugarColumn(ColumnDescription = "表名", IsNullable = true)] + public string TableName { get; set; } + + /// + /// 列名 + /// + [MaxLength(50)] + [SugarColumn(ColumnDescription = "列名", IsNullable = true)] + public string ColumnName { get; set; } + + /// + /// 新值 + /// + [SugarColumn(ColumnDescription = "新值", IsNullable = true)] + public string NewValue { get; set; } + + /// + /// 旧值 + /// + [SugarColumn(ColumnDescription = "旧值", IsNullable = true)] + public string OldValue { get; set; } + + /// + /// 操作时间 + /// + [SugarColumn(ColumnDescription = "操作时间", IsNullable = true)] + public DateTime CreatedTime { get; set; } + + /// + /// 操作人Id + /// + [SugarColumn(ColumnDescription = "操作人Id")] + public long UserId { get; set; } + + /// + /// 操作人名称 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "操作人名称", IsNullable = true)] + public string UserName { get; set; } + + /// + /// 操作方式:新增、更新、删除 + /// + + [SugarColumn(ColumnDescription = "操作方式:新增、更新、删除")] + public DataOpType Operate { get; set; } +} diff --git a/Magic.Core/Entity/SysLogEx.cs b/Magic.Core/Entity/SysLogEx.cs new file mode 100644 index 0000000..93dce64 --- /dev/null +++ b/Magic.Core/Entity/SysLogEx.cs @@ -0,0 +1,78 @@ + +using SqlSugar; +using System; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +namespace Magic.Core.Entity; + +/// +/// 异常日志 +/// +[SugarTable("sys_log_ex")] +[Description("异常日志")] +public class SysLogEx : AutoIncrementEntity +{ + /// + /// 操作人 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "操作人", IsNullable = true)] + public string Account { get; set; } + + /// + /// 名称 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "名称", IsNullable = true)] + public string Name { get; set; } + + /// + /// 类名 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "类名", IsNullable = true)] + public string ClassName { get; set; } + + /// + /// 方法名 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "方法名", IsNullable = true)] + public string MethodName { get; set; } + + /// + /// 异常名称 + /// + [SugarColumn(ColumnDescription = "异常名称", IsNullable = true)] + public string ExceptionName { get; set; } + + /// + /// 异常信息 + /// + [SugarColumn(ColumnDescription = "异常信息", IsNullable = true)] + public string ExceptionMsg { get; set; } + + /// + /// 异常源 + /// + [SugarColumn(ColumnDescription = "异常源", IsNullable = true)] + public string ExceptionSource { get; set; } + + /// + /// 堆栈信息 + /// + [SugarColumn(ColumnDescription = "堆栈信息", IsNullable = true)] + public string StackTrace { get; set; } + + /// + /// 参数对象 + /// + [SugarColumn(ColumnDescription = "参数对象", IsNullable = true)] + public string ParamsObj { get; set; } + + /// + /// 异常时间 + /// + [SugarColumn(ColumnDescription = "异常时间", IsNullable = true)] + public DateTime ExceptionTime { get; set; } +} diff --git a/Magic.Core/Entity/SysLogOp.cs b/Magic.Core/Entity/SysLogOp.cs new file mode 100644 index 0000000..637f6f5 --- /dev/null +++ b/Magic.Core/Entity/SysLogOp.cs @@ -0,0 +1,119 @@ +using SqlSugar; +using System; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +namespace Magic.Core.Entity; + +/// +/// 操作日志表 +/// +[SugarTable("sys_log_op")] +[Description("操作日志表")] +public class SysLogOp : AutoIncrementEntity +{ + /// + /// 名称 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "名称", IsNullable = true)] + public string Name { get; set; } + + /// + /// 是否执行成功(Y-是,N-否) + /// + [SugarColumn(ColumnDescription = "是否执行成功(Y-是,N-否)", IsNullable = true)] + public YesOrNot Success { get; set; } + + /// + /// 具体消息 + /// + [SugarColumn(ColumnDescription = "具体消息", IsNullable = true)] + public string Message { get; set; } + + /// + /// IP + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "IP", IsNullable = true)] + public string Ip { get; set; } + + /// + /// 地址 + /// + [MaxLength(500)] + [SugarColumn(ColumnDescription = "地址", IsNullable = true)] + public string Location { get; set; } + + /// + /// 浏览器 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "浏览器", IsNullable = true)] + public string Browser { get; set; } + + /// + /// 操作系统 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "操作系统", IsNullable = true)] + public string Os { get; set; } + + /// + /// 请求地址 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "请求地址", IsNullable = true)] + public string Url { get; set; } + + /// + /// 类名称 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "类名称", IsNullable = true)] + public string ClassName { get; set; } + + /// + /// 方法名称 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "方法名称", IsNullable = true)] + public string MethodName { get; set; } + + /// + /// 请求方式(GET POST PUT DELETE) + /// + [MaxLength(10)] + [SugarColumn(ColumnDescription = "请求方式(GET POST PUT DELETE)", IsNullable = true)] + public string ReqMethod { get; set; } + + /// + /// 请求参数 + /// + [SugarColumn(ColumnDescription = "请求参数", IsNullable = true)] + public string Param { get; set; } + + /// + /// 返回结果 + /// + [SugarColumn(ColumnDescription = "返回结果", IsNullable = true)] + public string Result { get; set; } + + /// + /// 耗时(毫秒) + /// + [SugarColumn(ColumnDescription = "耗时(毫秒)", IsNullable = true)] + public long ElapsedTime { get; set; } + + /// + /// 操作时间 + /// + [SugarColumn(ColumnDescription = "操作时间", IsNullable = true)] + public DateTime OpTime { get; set; } + + /// + /// 操作人 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "操作人", IsNullable = true)] + public string Account { get; set; } +} diff --git a/Magic.Core/Entity/SysLogVis.cs b/Magic.Core/Entity/SysLogVis.cs new file mode 100644 index 0000000..43c7fab --- /dev/null +++ b/Magic.Core/Entity/SysLogVis.cs @@ -0,0 +1,79 @@ +using SqlSugar; +using System; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +namespace Magic.Core.Entity; + +/// +/// 访问日志表 +/// +[SugarTable("sys_log_vis")] +[Description("访问日志表")] +public class SysLogVis : AutoIncrementEntity +{ + /// + /// 名称 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "名称", IsNullable = true)] + public string Name { get; set; } + + /// + /// 是否执行成功(Y-是,N-否) + /// + [SugarColumn(ColumnDescription = "是否执行成功(Y-是,N-否)")] + public YesOrNot Success { get; set; } + + /// + /// 具体消息 + /// + [SugarColumn(ColumnDescription = "具体消息", IsNullable = true)] + public string Message { get; set; } + + /// + /// IP + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "IP", IsNullable = true)] + public string Ip { get; set; } + + /// + /// 地址 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "地址", IsNullable = true)] + public string Location { get; set; } + + /// + /// 浏览器 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "浏览器", IsNullable = true)] + public string Browser { get; set; } + + /// + /// 操作系统 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "操作系统", IsNullable = true)] + public string Os { get; set; } + + /// + /// 访问类型 + /// + [SugarColumn(ColumnDescription = "访问类型")] + public LoginType VisType { get; set; } + + /// + /// 访问时间 + /// + [SugarColumn(ColumnDescription = "访问时间", IsNullable = true)] + public DateTime VisTime { get; set; } + + /// + /// 访问人 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "访问人", IsNullable = true)] + public string Account { get; set; } +} diff --git a/Magic.Core/Entity/SysMenu.cs b/Magic.Core/Entity/SysMenu.cs new file mode 100644 index 0000000..dd435c9 --- /dev/null +++ b/Magic.Core/Entity/SysMenu.cs @@ -0,0 +1,133 @@ +using SqlSugar; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +namespace Magic.Core.Entity; + +/// +/// 菜单表 +/// +[SugarTable("sys_menu")] +[Description("菜单表")] +public class SysMenu : DEntityBase +{ + /// + /// 父Id + /// + [SugarColumn(ColumnDescription = "父Id")] + public long Pid { get; set; } + + /// + /// 父Ids + /// + [SugarColumn(ColumnDescription = "父Ids")] + public string Pids { get; set; } + + /// + /// 名称 + /// + [Required, MaxLength(20)] + [SugarColumn(ColumnDescription = "名称")] + public string Name { get; set; } + + /// + /// 编码 + /// + [Required, MaxLength(50)] + [SugarColumn(ColumnDescription = "编码")] + public string Code { get; set; } + + /// + /// 菜单类型(字典 0目录 1菜单 2按钮) + /// + [SugarColumn(ColumnDescription = "菜单类型(字典 0目录 1菜单 2按钮)")] + public int Type { get; set; } + + /// + /// 图标 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "图标", IsNullable = true)] + public string Icon { get; set; } + + /// + /// 路由地址 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "路由地址", IsNullable = true)] + public string Router { get; set; } + + /// + /// 组件地址 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "组件地址", IsNullable = true)] + public string Component { get; set; } + + /// + /// 权限标识 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "权限标识", IsNullable = true)] + public string Permission { get; set; } + + /// + /// 应用分类(应用编码) + /// + [MaxLength(50)] + [SugarColumn(ColumnDescription = "应用分类(应用编码)", IsNullable = true)] + public string Application { get; set; } + + /// + /// 打开方式(字典 0无 1组件 2内链 3外链) + /// + [SugarColumn(ColumnDescription = "打开方式(字典 0无 1组件 2内链 3外链)")] + public int OpenType { get; set; } = 0; + + /// + /// 是否可见(Y-是,N-否) + /// + [MaxLength(5)] + [SugarColumn(ColumnDescription = "是否可见(Y-是,N-否)", IsNullable = true)] + public string Visible { get; set; } = "Y"; + + /// + /// 内链地址 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "内链地址", IsNullable = true)] + public string Link { get; set; } + + /// + /// 重定向地址 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "重定向地址", IsNullable = true)] + public string Redirect { get; set; } + + /// + /// 权重(字典 1系统权重 2业务权重) + /// + [SugarColumn(ColumnDescription = "权重(字典 1系统权重 2业务权重)")] + public int Weight { get; set; } = 2; + + /// + /// 排序 + /// + [SugarColumn(ColumnDescription = "排序")] + public int Sort { get; set; } = 100; + + /// + /// 备注 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "备注", IsNullable = true)] + public string Remark { get; set; } + + /// + /// 状态(字典 0正常 1停用 2删除) + /// + [SugarColumn(ColumnDescription = "状态(字典 0正常 1停用 2删除)")] + public CommonStatus Status { get; set; } = CommonStatus.ENABLE; + +} diff --git a/Magic.Core/Entity/SysNotice.cs b/Magic.Core/Entity/SysNotice.cs new file mode 100644 index 0000000..a6b92b1 --- /dev/null +++ b/Magic.Core/Entity/SysNotice.cs @@ -0,0 +1,77 @@ +using SqlSugar; +using System; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +namespace Magic.Core.Entity; + +/// +/// 通知公告表 +/// +[SugarTable("sys_notice")] +[Description("通知公告表")] +public class SysNotice : DEntityBase +{ + /// + /// 标题 + /// + [Required, MaxLength(20)] + [SugarColumn(ColumnDescription = "标题")] + public string Title { get; set; } + + /// + /// 内容 + /// + [Required] + [SugarColumn(ColumnDescription = "内容")] + public string Content { get; set; } + + /// + /// 类型(字典 1通知 2公告) + /// + [SugarColumn(ColumnDescription = "类型(字典 1通知 2公告)")] + public NoticeType Type { get; set; } + + /// + /// 发布人Id + /// + [SugarColumn(ColumnDescription = "发布人Id")] + public long PublicUserId { get; set; } + + /// + /// 发布人姓名 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "发布人姓名", IsNullable = true)] + public string PublicUserName { get; set; } + + /// + /// 发布机构Id + /// + [SugarColumn(ColumnDescription = "发布机构Id")] + public long PublicOrgId { get; set; } + + /// + /// 发布机构名称 + /// + [MaxLength(50)] + [SugarColumn(ColumnDescription = "发布机构名称", IsNullable = true)] + public string PublicOrgName { get; set; } + + /// + /// 发布时间 + /// + [SugarColumn(ColumnDescription = "发布时间")] + public DateTime PublicTime { get; set; } + + /// + /// 撤回时间 + /// + [SugarColumn(ColumnDescription = "撤回时间", IsNullable = true)] + public DateTime CancelTime { get; set; } + + /// + /// 状态(字典 0草稿 1发布 2撤回 3删除) + /// + [SugarColumn(ColumnDescription = "状态(字典 0草稿 1发布 2撤回 3删除)")] + public NoticeStatus Status { get; set; } +} diff --git a/Magic.Core/Entity/SysNoticeUser.cs b/Magic.Core/Entity/SysNoticeUser.cs new file mode 100644 index 0000000..bd1a620 --- /dev/null +++ b/Magic.Core/Entity/SysNoticeUser.cs @@ -0,0 +1,37 @@ +using SqlSugar; +using System; +using System.ComponentModel; + +namespace Magic.Core.Entity; + +/// +/// 通知公告用户表 +/// +[SugarTable("sys_notice_user")] +[Description("通知公告用户表")] +public class SysNoticeUser +{ + /// + /// 通知公告Id + /// + [SugarColumn(ColumnDescription = "通知公告Id")] + public long NoticeId { get; set; } + + /// + /// 用户Id + /// + [SugarColumn(ColumnDescription = "用户Id")] + public long UserId { get; set; } + + /// + /// 阅读时间 + /// + [SugarColumn(ColumnDescription = "阅读时间", IsNullable = true)] + public DateTime ReadTime { get; set; } + + /// + /// 状态(字典 0未读 1已读) + /// + [SugarColumn(ColumnDescription = "状态(字典 0未读 1已读)")] + public NoticeUserStatus ReadStatus { get; set; } +} diff --git a/Magic.Core/Entity/SysOauthUser.cs b/Magic.Core/Entity/SysOauthUser.cs new file mode 100644 index 0000000..359b395 --- /dev/null +++ b/Magic.Core/Entity/SysOauthUser.cs @@ -0,0 +1,93 @@ +using SqlSugar; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +namespace Magic.Core.Entity; + +/// +/// Oauth登录用户表 +/// +[SugarTable("sys_oauth_user")] +[Description("Oauth登录用户表")] +public class SysOauthUser : DEntityBase +{ + /// + /// 第三方平台的用户唯一Id + /// + [MaxLength(50)] + [SugarColumn(ColumnDescription = "第三方平台的用户唯一Id", IsNullable = true)] + public string Uuid { get; set; } + + /// + /// 用户授权的token + /// + [SugarColumn(ColumnDescription = "用户授权的token", IsNullable = true)] + public string AccessToken { get; set; } + + /// + /// 昵称 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "昵称", IsNullable = true)] + public string NickName { get; set; } + + /// + /// 头像 + /// + [SugarColumn(ColumnDescription = "头像", IsNullable = true)] + public string Avatar { get; set; } + + /// + /// 性别 + /// + [MaxLength(5)] + [SugarColumn(ColumnDescription = "性别", IsNullable = true)] + public string Gender { get; set; } + + /// + /// 电话 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "电话", IsNullable = true)] + public string Phone { get; set; } + + /// + /// 邮箱 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "邮箱", IsNullable = true)] + public string Email { get; set; } + + /// + /// 位置 + /// + [MaxLength(50)] + [SugarColumn(ColumnDescription = "位置", IsNullable = true)] + public string Location { get; set; } + + /// + /// 用户网址 + /// + [SugarColumn(ColumnDescription = "用户网址", IsNullable = true)] + public string Blog { get; set; } + + /// + /// 所在公司 + /// + [MaxLength(50)] + [SugarColumn(ColumnDescription = "所在公司", IsNullable = true)] + public string Company { get; set; } + + /// + /// 用户来源 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "用户来源", IsNullable = true)] + public string Source { get; set; } + + /// + /// 用户备注(各平台中的用户个人介绍) + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "用户备注(各平台中的用户个人介绍)", IsNullable = true)] + public string Remark { get; set; } +} diff --git a/Magic.Core/Entity/SysOnlineUser.cs b/Magic.Core/Entity/SysOnlineUser.cs new file mode 100644 index 0000000..b53e5b9 --- /dev/null +++ b/Magic.Core/Entity/SysOnlineUser.cs @@ -0,0 +1,60 @@ +using SqlSugar; +using System; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; + +namespace Magic.Core.Entity; + +/// +/// 在线用户表 +/// +[SugarTable("sys_online_user")] +[Description("在线用户表")] +public class OnlineUser : AutoIncrementEntity +{ + /// + /// 连接Id + /// + [SugarColumn(ColumnDescription = "连接Id")] + public string ConnectionId { get; set; } + + /// + /// 用户Id + /// + [SugarColumn(ColumnDescription = "用户Id")] + public long UserId { get; set; } + + /// + /// 账号 + /// + [Required, MaxLength(20)] + [SugarColumn(ColumnDescription = "账号", IsNullable = true)] + public string Account { get; set; } + + /// + /// 姓名 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "姓名", IsNullable = true)] + public string Name { get; set; } + + /// + /// 最后连接时间 + /// + [SugarColumn(ColumnDescription = "最后连接时间", IsNullable = true)] + public DateTime LastTime { get; set; } + + /// + /// 最后登录IP + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "最后登录IP", IsNullable = true)] + public string LastLoginIp { get; set; } + + /// + /// 租户id + /// + [SugarColumn(ColumnDescription = "租户id", IsNullable = true)] + public virtual long TenantId { get; set; } + +} diff --git a/Magic.Core/Entity/SysOrg.cs b/Magic.Core/Entity/SysOrg.cs new file mode 100644 index 0000000..0d12e4b --- /dev/null +++ b/Magic.Core/Entity/SysOrg.cs @@ -0,0 +1,72 @@ +using SqlSugar; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +namespace Magic.Core.Entity; + +/// +/// 组织机构表 +/// +[SugarTable("sys_org")] +[Description("组织机构表")] +public class SysOrg : DBEntityTenant +{ + /// + /// 父Id + /// + [SugarColumn(ColumnDescription = "父Id")] + public long Pid { get; set; } + + /// + /// 父Ids + /// + [SugarColumn(ColumnDescription = "父Ids", IsNullable = true)] + public string Pids { get; set; } + + /// + /// 名称 + /// + [Required, MaxLength(30)] + [SugarColumn(ColumnDescription = "名称")] + public string Name { get; set; } + + /// + /// 编码 + /// + [Required, MaxLength(50)] + [SugarColumn(ColumnDescription = "编码")] + public string Code { get; set; } + + /// + /// 联系人 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "联系人", IsNullable = true)] + public string Contacts { get; set; } + + /// + /// 电话 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "电话", IsNullable = true)] + public string Tel { get; set; } + + /// + /// 排序 + /// + [SugarColumn(ColumnDescription = "排序")] + public int Sort { get; set; } + + /// + /// 备注 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "备注", IsNullable = true)] + public string Remark { get; set; } + + /// + /// 状态(字典 0正常 1停用 2删除) + /// + [SugarColumn(ColumnDescription = "状态(字典 0正常 1停用 2删除)")] + public CommonStatus Status { get; set; } = CommonStatus.ENABLE; + +} diff --git a/Magic.Core/Entity/SysPos.cs b/Magic.Core/Entity/SysPos.cs new file mode 100644 index 0000000..34c55c8 --- /dev/null +++ b/Magic.Core/Entity/SysPos.cs @@ -0,0 +1,46 @@ +using SqlSugar; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +namespace Magic.Core.Entity; + +/// +/// 职位表 +/// +[SugarTable("sys_pos")] +[Description("职位表")] +public class SysPos : DBEntityTenant +{ + /// + /// 名称 + /// + [Required, MaxLength(20)] + [SugarColumn(ColumnDescription = "名称")] + public string Name { get; set; } + + /// + /// 编码 + /// + [Required, MaxLength(50)] + [SugarColumn(ColumnDescription = "编码")] + public string Code { get; set; } + + /// + /// 排序 + /// + [SugarColumn(ColumnDescription = "排序")] + public int Sort { get; set; } + + /// + /// 备注 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "备注", IsNullable = true)] + public string Remark { get; set; } + + /// + /// 状态(字典 0正常 1停用 2删除) + /// + [SugarColumn(ColumnDescription = "状态(字典 0正常 1停用 2删除)")] + public CommonStatus Status { get; set; } = CommonStatus.ENABLE; + +} diff --git a/Magic.Core/Entity/SysRole.cs b/Magic.Core/Entity/SysRole.cs new file mode 100644 index 0000000..2a77376 --- /dev/null +++ b/Magic.Core/Entity/SysRole.cs @@ -0,0 +1,58 @@ +using SqlSugar; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +namespace Magic.Core.Entity; + +/// +/// 角色表 +/// +[SugarTable("sys_role")] +[Description("角色表")] +public class SysRole : DBEntityTenant +{ + /// + /// 名称 + /// + [Required, MaxLength(20)] + [SugarColumn(ColumnDescription = "名称")] + public string Name { get; set; } + + /// + /// 编码 + /// + [Required, MaxLength(50)] + [SugarColumn(ColumnDescription = "编码")] + public string Code { get; set; } + + /// + /// 排序 + /// + [SugarColumn(ColumnDescription = "排序")] + public int Sort { get; set; } + + /// + /// 数据范围类型(字典 1全部数据 2本部门及以下数据 3本部门数据 4仅本人数据 5自定义数据) + /// + [SugarColumn(ColumnDescription = "数据范围类型(字典 1全部数据 2本部门及以下数据 3本部门数据 4仅本人数据 5自定义数据)")] + public DataScopeType DataScopeType { get; set; } + + /// + /// 备注 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "备注", IsNullable = true)] + public string Remark { get; set; } + + /// + /// 状态(字典 0正常 1停用 2删除) + /// + [SugarColumn(ColumnDescription = "状态(字典 0正常 1停用 2删除)")] + public CommonStatus Status { get; set; } = CommonStatus.ENABLE; + + /// + /// 管理员类型-超级管理员_1、非管理员_2 + /// + [SugarColumn(ColumnDescription = " 管理员类型-超级管理员_1、非管理员_2", IsNullable = true)] + public RoleType? RoleType { get; set; } + +} diff --git a/Magic.Core/Entity/SysRoleDataScope.cs b/Magic.Core/Entity/SysRoleDataScope.cs new file mode 100644 index 0000000..4b68b4e --- /dev/null +++ b/Magic.Core/Entity/SysRoleDataScope.cs @@ -0,0 +1,27 @@ +using SqlSugar; +using System.ComponentModel; + +namespace Magic.Core.Entity; + +/// +/// 角色数据范围表 +/// +[SugarTable("sys_role_data_scope")] +[Description("角色数据范围表")] +public class SysRoleDataScope +{ + /// + /// 角色Id + /// + [SugarColumn(ColumnDescription = "角色Id")] + public long SysRoleId { get; set; } + + + /// + /// 机构Id + /// + [SugarColumn(ColumnDescription = "机构Id")] + public long SysOrgId { get; set; } + + +} diff --git a/Magic.Core/Entity/SysRoleMenu.cs b/Magic.Core/Entity/SysRoleMenu.cs new file mode 100644 index 0000000..0a25ddd --- /dev/null +++ b/Magic.Core/Entity/SysRoleMenu.cs @@ -0,0 +1,26 @@ +using SqlSugar; +using System.ComponentModel; + +namespace Magic.Core.Entity; + +/// +/// 角色菜单表 +/// +[SugarTable("sys_role_menu")] +[Description("角色菜单表")] +public class SysRoleMenu +{ + /// + /// 角色Id + /// + [SugarColumn(ColumnDescription = "角色Id")] + public long SysRoleId { get; set; } + + + /// + /// 菜单Id + /// + [SugarColumn(ColumnDescription = "菜单Id")] + public long SysMenuId { get; set; } + +} diff --git a/Magic.Core/Entity/SysTenant.cs b/Magic.Core/Entity/SysTenant.cs new file mode 100644 index 0000000..669fdb3 --- /dev/null +++ b/Magic.Core/Entity/SysTenant.cs @@ -0,0 +1,74 @@ +using SqlSugar; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +namespace Magic.Core.Entity; + +/// +/// 租户表 +/// +[SugarTable("sys_tenant")] +[Description("租户表")] +public class SysTenant : DEntityBase +{ + /// + /// 公司名称 + /// + [Required, MaxLength(30)] + [SugarColumn(ColumnDescription = "公司名称")] + public string Name { get; set; } + + /// + /// 管理员名称 + /// + [Required, MaxLength(20)] + [SugarColumn(ColumnDescription = "管理员名称")] + public string AdminName { get; set; } + + /// + /// 主机 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "主机", IsNullable = true)] + public string Host { get; set; } + + /// + /// 电子邮箱 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "电子邮箱", IsNullable = true)] + public string Email { get; set; } + + /// + /// 电话 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "电话", IsNullable = true)] + public string Phone { get; set; } + + /// + /// 数据库连接 + /// + [MaxLength(200)] + [SugarColumn(ColumnDescription = "数据库连接", IsNullable = true)] + public string Connection { get; set; } + + /// + /// 架构 + /// + [MaxLength(50)] + [SugarColumn(ColumnDescription = "架构", IsNullable = true)] + public string Schema { get; set; } + + /// + /// 备注 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "备注", IsNullable = true)] + public string Remark { get; set; } + + /// + /// 租户类型 + /// + [SugarColumn(ColumnDescription = "租户类型")] + public TenantTypeEnum TenantType { get; set; } +} diff --git a/Magic.Core/Entity/SysTimer.cs b/Magic.Core/Entity/SysTimer.cs new file mode 100644 index 0000000..b5e2270 --- /dev/null +++ b/Magic.Core/Entity/SysTimer.cs @@ -0,0 +1,94 @@ +using Furion.TaskScheduler; +using SqlSugar; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +namespace Magic.Core.Entity; + +/// +/// 定时任务 +/// +[SugarTable("sys_timer")] +[Description("定时任务")] +public class SysTimer : DEntityBase +{ + /// + /// 任务名称 + /// + /// magic + [Required, MaxLength(20)] + [SugarColumn(ColumnDescription = "任务名称")] + public string JobName { get; set; } + + /// + /// 只执行一次 + /// + [SugarColumn(ColumnDescription = "只执行一次")] + public bool DoOnce { get; set; } = false; + + /// + /// 立即执行(默认等待启动) + /// + [SugarColumn(ColumnDescription = "立即执行(默认等待启动)")] + public bool StartNow { get; set; } = false; + + /// + /// 执行类型(并行、列队) + /// + [SugarColumn(ColumnDescription = "执行类型(并行、列队)")] + public SpareTimeExecuteTypes ExecuteType { get; set; } = SpareTimeExecuteTypes.Parallel; + + /// + /// 执行间隔时间(单位秒) + /// + /// 5 + [SugarColumn(ColumnDescription = "执行间隔时间(单位秒)", IsNullable = true)] + public int? Interval { get; set; } = 5; + + /// + /// Cron表达式 + /// + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "Cron表达式", IsNullable = true)] + public string Cron { get; set; } + + /// + /// 定时器类型 + /// + [SugarColumn(ColumnDescription = "定时器类型")] + public SpareTimeTypes TimerType { get; set; } = SpareTimeTypes.Interval; + + /// + /// 请求url + /// + [MaxLength(200)] + [SugarColumn(ColumnDescription = "请求url", IsNullable = true)] + public string RequestUrl { get; set; } + + /// + /// 请求参数(Post,Put请求用) + /// + [SugarColumn(ColumnDescription = "请求参数(Post,Put请求用)", IsNullable = true)] + public string RequestParameters { get; set; } + + /// + /// Headers(可以包含如:Authorization授权认证) + /// 格式:{"Authorization":"userpassword.."} + /// + [SugarColumn(ColumnDescription = "Headers", IsNullable = true)] + public string Headers { get; set; } + + /// + /// 请求类型 + /// + /// 2 + [SugarColumn(ColumnDescription = "请求类型", IsNullable = true)] + public RequestTypeEnum RequestType { get; set; } = RequestTypeEnum.Post; + + /// + /// 备注 + /// + [MaxLength(100)] + [SugarColumn(ColumnDescription = "备注", IsNullable = true)] + public string Remark { get; set; } +} diff --git a/Magic.Core/Entity/SysUser.cs b/Magic.Core/Entity/SysUser.cs new file mode 100644 index 0000000..fe4ad84 --- /dev/null +++ b/Magic.Core/Entity/SysUser.cs @@ -0,0 +1,105 @@ +using SqlSugar; +using System; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +namespace Magic.Core.Entity; + +/// +/// 用户表 +/// +[SugarTable("sys_user")] +[Description("用户表")] +public class SysUser : DBEntityTenant +{ + /// + /// 账号 + /// + [Required, MaxLength(20)] + [SugarColumn(ColumnDescription = "账号")] + public string Account { get; set; } + + /// + /// 密码(默认MD5加密) + /// + [Required, MaxLength(50)] + [SugarColumn(ColumnDescription = "密码(默认MD5加密)")] + public string Password { get; set; } + + /// + /// 昵称 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "昵称", IsNullable = true)] + public string NickName { get; set; } + + /// + /// 姓名 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "姓名", IsNullable = true)] + public string Name { get; set; } + + /// + /// 头像 + /// + [SugarColumn(ColumnDescription = "头像", IsNullable = true)] + public string Avatar { get; set; } + + /// + /// 生日 + /// + [SugarColumn(ColumnDescription = "生日", IsNullable = true)] + public DateTime Birthday { get; set; } + + /// + /// 性别-男_1、女_2 + /// + [SugarColumn(ColumnDescription = "性别-男_1、女_2")] + public Gender Sex { get; set; } + + /// + /// 邮箱 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "邮箱", IsNullable = true)] + public string Email { get; set; } + + /// + /// 手机 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "手机", IsNullable = true)] + public string Phone { get; set; } + + /// + /// 电话 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "电话", IsNullable = true)] + public string Tel { get; set; } + + /// + /// 最后登录IP + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "最后登录IP", IsNullable = true)] + public string LastLoginIp { get; set; } + + /// + /// 最后登录时间 + /// + [SugarColumn(ColumnDescription = "最后登录时间", IsNullable = true)] + public DateTime LastLoginTime { get; set; } + + /// + /// 管理员类型-超级管理员_1、非管理员_2 + /// + [SugarColumn(ColumnDescription = "管理员类型-超级管理员_1、非管理员_2")] + public AdminType? AdminType { get; set; } + + /// + /// 状态-正常_0、停用_1、删除_2 + /// + [SugarColumn(ColumnDescription = "状态-正常_0、停用_1、删除_2")] + public CommonStatus Status { get; set; } = CommonStatus.ENABLE; +} diff --git a/Magic.Core/Entity/SysUserDataScope.cs b/Magic.Core/Entity/SysUserDataScope.cs new file mode 100644 index 0000000..65395c0 --- /dev/null +++ b/Magic.Core/Entity/SysUserDataScope.cs @@ -0,0 +1,28 @@ +using SqlSugar; +using System.ComponentModel; + +namespace Magic.Core.Entity; + +/// +/// 用户数据范围表 +/// +[SugarTable("sys_user_data_scope")] +[Description("用户数据范围表")] +public class SysUserDataScope +{ + /// + /// 用户Id + /// + [SugarColumn(ColumnDescription = "用户Id")] + public long SysUserId { get; set; } + + + + /// + /// 机构Id + /// + [SugarColumn(ColumnDescription = "机构Id")] + public long SysOrgId { get; set; } + + +} diff --git a/Magic.Core/Entity/SysUserRole.cs b/Magic.Core/Entity/SysUserRole.cs new file mode 100644 index 0000000..3a6a1c2 --- /dev/null +++ b/Magic.Core/Entity/SysUserRole.cs @@ -0,0 +1,28 @@ +using SqlSugar; +using System.ComponentModel; + +namespace Magic.Core.Entity; + +/// +/// 用户角色表 +/// +[SugarTable("sys_user_role")] +[Description("用户角色表")] +public class SysUserRole +{ + /// + /// 用户Id + /// + [SugarColumn(ColumnDescription = "用户Id")] + public long SysUserId { get; set; } + + + + /// + /// 系统角色Id + /// + [SugarColumn(ColumnDescription = "系统角色Id")] + public long SysRoleId { get; set; } + + +} diff --git a/Magic.Core/Entity/Test.cs b/Magic.Core/Entity/Test.cs new file mode 100644 index 0000000..d45697b --- /dev/null +++ b/Magic.Core/Entity/Test.cs @@ -0,0 +1,105 @@ +using SqlSugar; +using System; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +namespace Magic.Core.Entity; + +/// +/// 用户表 +/// +[SugarTable("sys_test")] +[Description("测试表")] +public class Test : DBEntityTenant +{ + /// + /// 账号 + /// + [Required, MaxLength(20)] + [SugarColumn(ColumnDescription = "账号")] + public string Account { get; set; } + + /// + /// 密码(默认MD5加密) + /// + [Required, MaxLength(50)] + [SugarColumn(ColumnDescription = "密码(默认MD5加密)")] + public string Password { get; set; } + + /// + /// 昵称 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "昵称", IsNullable = true)] + public string NickName { get; set; } + + /// + /// 姓名 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "姓名", IsNullable = true)] + public string Name { get; set; } + + /// + /// 头像 + /// + [SugarColumn(ColumnDescription = "头像", IsNullable = true)] + public string Avatar { get; set; } + + /// + /// 生日 + /// + [SugarColumn(ColumnDescription = "生日", IsNullable = true)] + public DateTime Birthday { get; set; } + + /// + /// 性别-男_1、女_2 + /// + [SugarColumn(ColumnDescription = "性别-男_1、女_2")] + public Gender Sex { get; set; } + + /// + /// 邮箱 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "邮箱", IsNullable = true)] + public string Email { get; set; } + + /// + /// 手机 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "手机", IsNullable = true)] + public string Phone { get; set; } + + /// + /// 电话 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "电话", IsNullable = true)] + public string Tel { get; set; } + + /// + /// 最后登录IP + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "最后登录IP", IsNullable = true)] + public string LastLoginIp { get; set; } + + /// + /// 最后登录时间 + /// + [SugarColumn(ColumnDescription = "最后登录时间", IsNullable = true)] + public DateTime LastLoginTime { get; set; } + + /// + /// 管理员类型-超级管理员_1、非管理员_2 + /// + [SugarColumn(ColumnDescription = "管理员类型-超级管理员_1、非管理员_2")] + public AdminType? AdminType { get; set; } + + /// + /// 状态-正常_0、停用_1、删除_2 + /// + [SugarColumn(ColumnDescription = "状态-正常_0、停用_1、删除_2")] + public CommonStatus Status { get; set; } = CommonStatus.ENABLE; +} diff --git a/Magic.Core/Enum/AdminType.cs b/Magic.Core/Enum/AdminType.cs new file mode 100644 index 0000000..71b0532 --- /dev/null +++ b/Magic.Core/Enum/AdminType.cs @@ -0,0 +1,28 @@ +using System.ComponentModel; + +namespace Magic.Core; + +/// +/// 账号类型 +/// +[Description("账号类型")] +public enum AdminType +{ + /// + /// 超级管理员 + /// + [Description("超级管理员")] + SuperAdmin = 1, + + /// + /// 管理员 + /// + [Description("管理员")] + Admin = 2, + + /// + /// 普通账号 + /// + [Description("普通账号")] + None = 3 +} diff --git a/Magic.Core/Enum/CacheType.cs b/Magic.Core/Enum/CacheType.cs new file mode 100644 index 0000000..b081dae --- /dev/null +++ b/Magic.Core/Enum/CacheType.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Magic.Core; + +/// +/// 缓存类型 +/// +public enum CacheType +{ + /// + /// 内存缓存 + /// + MemoryCache, + + /// + /// Redis缓存 + /// + RedisCache +} diff --git a/Magic.Core/Enum/CommonStatus.cs b/Magic.Core/Enum/CommonStatus.cs new file mode 100644 index 0000000..2eb0b0e --- /dev/null +++ b/Magic.Core/Enum/CommonStatus.cs @@ -0,0 +1,27 @@ +using System.ComponentModel; + +namespace Magic.Core; + +/// +/// 公共状态 +/// +public enum CommonStatus +{ + /// + /// 正常 + /// + [Description("正常")] + ENABLE = 0, + + /// + /// 停用 + /// + [Description("停用")] + DISABLE = 1, + + /// + /// 删除 + /// + [Description("删除")] + DELETED = 2 +} diff --git a/Magic.Core/Enum/DataOpType.cs b/Magic.Core/Enum/DataOpType.cs new file mode 100644 index 0000000..76056d6 --- /dev/null +++ b/Magic.Core/Enum/DataOpType.cs @@ -0,0 +1,77 @@ +namespace Magic.Core; + +/// +/// 数据操作类型 +/// +public enum DataOpType +{ + /// + /// 其它 + /// + OTHER, + + /// + /// 增加 + /// + ADD, + + /// + /// 删除 + /// + DELETE, + + /// + /// 编辑 + /// + EDIT, + + /// + /// 更新 + /// + UPDATE, + + /// + /// 查询 + /// + QUERY, + + /// + /// 详情 + /// + DETAIL, + + /// + /// 树 + /// + TREE, + + /// + /// 导入 + /// + IMPORT, + + /// + /// 导出 + /// + EXPORT, + + /// + /// 授权 + /// + GRANT, + + /// + /// 强退 + /// + FORCE, + + /// + /// 清空 + /// + CLEAN, + + /// + /// 修改状态 + /// + CHANGE_STATUS +} diff --git a/Magic.Core/Enum/DataScopeType.cs b/Magic.Core/Enum/DataScopeType.cs new file mode 100644 index 0000000..0642798 --- /dev/null +++ b/Magic.Core/Enum/DataScopeType.cs @@ -0,0 +1,36 @@ +using System.ComponentModel; + +namespace Magic.Core; + +public enum DataScopeType +{ + /// + /// 全部数据 + /// + [Description("全部数据")] + ALL = 1, + + /// + /// 本部门及以下数据 + /// + [Description("本部门及以下数据")] + DEPT_WITH_CHILD = 2, + + /// + /// 本部门数据 + /// + [Description("本部门数据")] + DEPT = 3, + + /// + /// 仅本人数据 + /// + [Description("仅本人数据")] + SELF = 4, + + /// + /// 自定义数据 + /// + [Description("自定义数据")] + DEFINE = 5 +} diff --git a/Magic.Core/Enum/DocumentType.cs b/Magic.Core/Enum/DocumentType.cs new file mode 100644 index 0000000..7fc7d66 --- /dev/null +++ b/Magic.Core/Enum/DocumentType.cs @@ -0,0 +1,22 @@ +using System.ComponentModel; + +namespace Magic.Core; + +/// +/// 文档类型 +/// +public enum DocumentType +{ + /// + /// 文件夹 + /// + [Description("文件夹")] + Folder = 1, + + /// + /// 文件 + /// + [Description("文件")] + File = 2, + +} diff --git a/Magic.Core/Enum/ErrorCode.cs b/Magic.Core/Enum/ErrorCode.cs new file mode 100644 index 0000000..5127691 --- /dev/null +++ b/Magic.Core/Enum/ErrorCode.cs @@ -0,0 +1,406 @@ +using Furion.FriendlyException; + +namespace Magic.Core; + +/// +/// 系统错误码 +/// +[ErrorCodeType] +public enum ErrorCode +{ + /// + /// 用户名或密码不正确 + /// + [ErrorCodeItemMetadata("用户名或密码不正确")] + D1000, + + /// + /// 非法操作!禁止删除自己 + /// + [ErrorCodeItemMetadata("非法操作,禁止删除自己")] + D1001, + + /// + /// 记录不存在 + /// + [ErrorCodeItemMetadata("记录不存在")] + D1002, + + /// + /// 账号已存在 + /// + [ErrorCodeItemMetadata("账号已存在")] + D1003, + + /// + /// 旧密码不匹配 + /// + [ErrorCodeItemMetadata("旧密码输入错误")] + D1004, + + /// + /// 测试数据禁止更改admin密码 + /// + [ErrorCodeItemMetadata("测试数据禁止更改用户【admin】密码")] + D1005, + + /// + /// 数据已存在 + /// + [ErrorCodeItemMetadata("数据已存在")] + D1006, + + /// + /// 数据不存在或含有关联引用,禁止删除 + /// + [ErrorCodeItemMetadata("数据不存在或含有关联引用,禁止删除")] + D1007, + + /// + /// 禁止为管理员分配角色 + /// + [ErrorCodeItemMetadata("禁止为管理员分配角色")] + D1008, + + /// + /// 重复数据或记录含有不存在数据 + /// + [ErrorCodeItemMetadata("重复数据或记录含有不存在数据")] + D1009, + + /// + /// 禁止为超级管理员角色分配权限 + /// + [ErrorCodeItemMetadata("禁止为超级管理员角色分配权限")] + D1010, + + /// + /// 非法数据 + /// + [ErrorCodeItemMetadata("非法数据")] + D1011, + + /// + /// Id不能为空 + /// + [ErrorCodeItemMetadata("Id不能为空")] + D1012, + + /// + /// 所属机构不在自己的数据范围内 + /// + [ErrorCodeItemMetadata("没有权限操作该数据")] + D1013, + + /// + /// 禁止删除超级管理员 + /// + [ErrorCodeItemMetadata("禁止删除超级管理员")] + D1014, + + /// + /// 禁止修改超级管理员状态 + /// + [ErrorCodeItemMetadata("禁止修改超级管理员状态")] + D1015, + + /// + /// 没有权限 + /// + [ErrorCodeItemMetadata("没有权限")] + D1016, + + /// + /// 账号已冻结 + /// + [ErrorCodeItemMetadata("账号已冻结")] + D1017, + + /// + /// 父机构不存在 + /// + [ErrorCodeItemMetadata("父机构不存在")] + D2000, + + /// + /// 当前机构Id不能与父机构Id相同 + /// + [ErrorCodeItemMetadata("当前机构Id不能与父机构Id相同")] + D2001, + + /// + /// 已有相同组织机构,编码或名称相同 + /// + [ErrorCodeItemMetadata("已有相同组织机构,编码或名称相同")] + D2002, + + /// + /// 没有权限操作机构 + /// + [ErrorCodeItemMetadata("没有权限操作机构")] + D2003, + + /// + /// 该机构下有员工禁止删除 + /// + [ErrorCodeItemMetadata("该机构下有员工禁止删除")] + D2004, + + /// + /// 附属机构下有员工禁止删除 + /// + [ErrorCodeItemMetadata("附属机构下有员工禁止删除")] + D2005, + + /// + /// 只能增加下级机构 + /// + [ErrorCodeItemMetadata("只能增加下级机构")] + D2006, + + /// + /// 字典类型不存在 + /// + [ErrorCodeItemMetadata("字典类型不存在")] + D3000, + + /// + /// 字典类型已存在 + /// + [ErrorCodeItemMetadata("字典类型已存在,名称或编码重复")] + D3001, + + /// + /// 字典类型下面有字典值禁止删除 + /// + [ErrorCodeItemMetadata("字典类型下面有字典值禁止删除")] + D3002, + + /// + /// 字典值已存在 + /// + [ErrorCodeItemMetadata("字典值已存在,名称或编码重复")] + D3003, + + /// + /// 字典值不存在 + /// + [ErrorCodeItemMetadata("字典值不存在")] + D3004, + + /// + /// 字典状态错误 + /// + [ErrorCodeItemMetadata("字典状态错误")] + D3005, + + /// + /// 菜单已存在 + /// + [ErrorCodeItemMetadata("菜单已存在")] + D4000, + + /// + /// 路由地址为空 + /// + [ErrorCodeItemMetadata("路由地址为空")] + D4001, + + /// + /// 打开方式为空 + /// + [ErrorCodeItemMetadata("打开方式为空")] + D4002, + + /// + /// 权限标识格式为空 + /// + [ErrorCodeItemMetadata("权限标识格式为空")] + D4003, + + /// + /// 权限标识格式错误 + /// + [ErrorCodeItemMetadata("权限标识格式错误")] + D4004, + + /// + /// 权限不存在 + /// + [ErrorCodeItemMetadata("权限不存在")] + D4005, + + /// + /// 父级菜单不能为当前节点,请重新选择父级菜单 + /// + [ErrorCodeItemMetadata("父级菜单不能为当前节点,请重新选择父级菜单")] + D4006, + + /// + /// 不能移动根节点 + /// + [ErrorCodeItemMetadata("不能移动根节点")] + D4007, + + /// + /// 已存在同名或同编码应用 + /// + [ErrorCodeItemMetadata("已存在同名或同编码应用")] + D5000, + + /// + /// 默认激活系统只能有一个 + /// + [ErrorCodeItemMetadata("默认激活系统只能有一个")] + D5001, + + /// + /// 该应用下有菜单禁止删除 + /// + [ErrorCodeItemMetadata("该应用下有菜单禁止删除")] + D5002, + + /// + /// 已存在同名或同编码应用 + /// + [ErrorCodeItemMetadata("已存在同名或同编码应用")] + D5003, + + /// + /// 已存在同名或同编码职位 + /// + [ErrorCodeItemMetadata("已存在同名或同编码职位")] + D6000, + + /// + /// 该职位下有员工禁止删除 + /// + [ErrorCodeItemMetadata("该职位下有员工禁止删除")] + D6001, + + /// + /// 通知公告状态错误 + /// + [ErrorCodeItemMetadata("通知公告状态错误")] + D7000, + + /// + /// 通知公告删除失败 + /// + [ErrorCodeItemMetadata("通知公告删除失败")] + D7001, + + /// + /// 通知公告编辑失败 + /// + [ErrorCodeItemMetadata("通知公告编辑失败,类型必须为草稿")] + D7002, + + /// + /// 文件不存在 + /// + [ErrorCodeItemMetadata("文件不存在")] + D8000, + + /// + /// 已存在同名或同编码参数配置 + /// + [ErrorCodeItemMetadata("已存在同名或同编码参数配置")] + D9000, + + /// + /// 禁止删除系统参数 + /// + [ErrorCodeItemMetadata("禁止删除系统参数")] + D9001, + + /// + /// 已存在同名任务调度 + /// + [ErrorCodeItemMetadata("已存在同名任务调度")] + D1100, + + /// + /// 任务调度不存在 + /// + [ErrorCodeItemMetadata("任务调度不存在")] + D1101, + + /// + /// 演示环境禁止修改数据 + /// + [ErrorCodeItemMetadata("演示环境禁止修改数据")] + D1200, + + /// + /// 已存在同名或同主机租户 + /// + [ErrorCodeItemMetadata("已存在同名或同主机租户")] + D1300, + + /// + /// 该表代码模板已经生成过 + /// + [ErrorCodeItemMetadata("该表代码模板已经生成过")] + D1400, + + /// + /// 该类型不存在 + /// + [ErrorCodeItemMetadata("该类型不存在")] + D1501, + + /// + /// 该字段不存在 + /// + [ErrorCodeItemMetadata("该字段不存在")] + D1502, + + /// + /// 该类型不是枚举类型 + /// + [ErrorCodeItemMetadata("该类型不是枚举类型")] + D1503, + + /// + /// 该实体不存在 + /// + [ErrorCodeItemMetadata("该实体不存在")] + D1504, + + /// + /// 父菜单不存在 + /// + [ErrorCodeItemMetadata("父菜单不存在")] + D1505, + + /// + /// 已存在同名或同编码项目 + /// + [ErrorCodeItemMetadata("已存在同名或同编码项目")] + xg1000, + + /// + /// 已存在相同证件号码人员 + /// + [ErrorCodeItemMetadata("已存在相同证件号码人员")] + xg1001, + + /// + /// 检测数据不存在 + /// + [ErrorCodeItemMetadata("检测数据不存在")] + xg1002, + + [ErrorCodeItemMetadata("请添加数据列")] + db1000, + + [ErrorCodeItemMetadata("数据表不存在")] + db1001, + + /// + /// 表单不存在 + /// + [ErrorCodeItemMetadata("表单不存在")] + F1000 +} diff --git a/Magic.Core/Enum/FileExtensionEnum.cs b/Magic.Core/Enum/FileExtensionEnum.cs new file mode 100644 index 0000000..0bec446 --- /dev/null +++ b/Magic.Core/Enum/FileExtensionEnum.cs @@ -0,0 +1,37 @@ +namespace Magic.Core; + +/// +/// 文件扩展枚举 +/// +public enum FileExtensionEnum +{ + JPG = 255216, + GIF = 7173, + BMP = 6677, + PNG = 13780, + COM = 7790, + EXE = 7790, + DLL = 7790, + RAR = 8297, + ZIP = 8075, + XML = 6063, + HTML = 6033, + ASPX = 239187, + CS = 117115, + JS = 119105, + TXT = 210187, + SQL = 255254, + BAT = 64101, + BTSEED = 10056, + RDP = 255254, + PSD = 5666, + PDF = 3780, + CHM = 7384, + LOG = 70105, + REG = 8269, + HLP = 6395, + DOC = 208207, + XLS = 208207, + DOCX = 208207, + XLSX = 208207, +} diff --git a/Magic.Core/Enum/FileLocation.cs b/Magic.Core/Enum/FileLocation.cs new file mode 100644 index 0000000..b3c6181 --- /dev/null +++ b/Magic.Core/Enum/FileLocation.cs @@ -0,0 +1,33 @@ +using System.ComponentModel; + +namespace Magic.Core; + +/// +/// 文件存储位置 +/// +public enum FileLocation +{ + /// + /// 阿里云 + /// + [Description("阿里云")] + ALIYUN = 1, + + /// + /// 腾讯云 + /// + [Description("腾讯云")] + TENCENT = 2, + + /// + /// minio服务器 + /// + [Description("minio服务器")] + MINIO = 3, + + /// + /// 本地 + /// + [Description("本地")] + LOCAL = 4 +} diff --git a/Magic.Core/Enum/FilterType.cs b/Magic.Core/Enum/FilterType.cs new file mode 100644 index 0000000..07a6702 --- /dev/null +++ b/Magic.Core/Enum/FilterType.cs @@ -0,0 +1,18 @@ +using System.ComponentModel; + +namespace Magic.Core; + + public enum FilterType + { + /// + /// 用户 + /// + [Description("用户")] + User = 0, + + /// + /// 组织 + /// + [Description("组织")] + Org = 1, + } diff --git a/Magic.Core/Enum/Gender.cs b/Magic.Core/Enum/Gender.cs new file mode 100644 index 0000000..044ebdd --- /dev/null +++ b/Magic.Core/Enum/Gender.cs @@ -0,0 +1,27 @@ +using System.ComponentModel; + +namespace Magic.Core; + +/// +/// 性别 +/// +public enum Gender +{ + /// + /// 男 + /// + [Description("男")] + MALE = 1, + + /// + /// 女 + /// + [Description("女")] + FEMALE = 2, + + /// + /// 未知 + /// + [Description("未知")] + UNKNOWN = 3 +} diff --git a/Magic.Core/Enum/HttpStatusCode.cs b/Magic.Core/Enum/HttpStatusCode.cs new file mode 100644 index 0000000..4742608 --- /dev/null +++ b/Magic.Core/Enum/HttpStatusCode.cs @@ -0,0 +1,251 @@ +using System.ComponentModel; + +namespace Magic.Core; + +/// +/// HTTP状态码 +/// +public enum HttpStatusCode +{ + /// + /// 客户端可能继续其请求 + /// + [Description("继续")] + Continue = 100, + + /// + /// 正在更改协议版本或协议 + /// + [Description("交换协议")] + SwitchingProtocols = 101, + + /// + /// 请求成功,且请求的信息包含在响应中 + /// + [Description("OK")] + OK = 200, + + /// + /// 请求导致在响应被发送前创建新资源 + /// + [Description("已创建")] + Created = 201, + + /// + /// 请求已被接受做进一步处理 + /// + [Description("接收")] + Accepted = 202, + + /// + /// 返回的元信息来自缓存副本而不是原始服务器,因此可能不正确 + /// + [Description("非认证信息")] + NonAuthoritativeInformation = 203, + + /// + /// 已成功处理请求并且响应已被设定为无内容 + /// + [Description("无内容")] + NoContent = 204, + + /// + /// 客户端应重置(或重新加载)当前资源 + /// + [Description("重置内容")] + ResetContent = 205, + + /// + /// 响应是包括字节范围的 GET请求所请求的部分响应 + /// + [Description("部分内容")] + PartialContent = 206, + + /// + /// 请求的信息有多种表示形式,默认操作是将此状态视为重定向 + /// + [Description("多路选择")] + MultipleChoices = 300, + + /// + /// 请求的信息已移到 Location头中指定的 URI 处 + /// + [Description("永久转移")] + MovedPermanently = 301, + + /// + /// 请求的信息位于 Location 头中指定的 URI 处 + /// + [Description("暂时转移")] + Found = 302, + + /// + /// 将客户端自动重定向到 Location 头中指定的 URI + /// + [Description("参见其它")] + SeeOther = 303, + + /// + /// 客户端的缓存副本是最新的 + /// + [Description("未修改")] + NotModified = 304, + + /// + /// 请求应使用位于 Location 头中指定的 URI 的代理服务器 + /// + [Description("使用代理")] + UseProxy = 305, + + /// + /// 服务器未能识别请求 + /// + [Description("错误请求")] + BadRequest = 400, + + /// + /// 请求的资源要求身份验证 + /// + [Description("未授权")] + Unauthorized = 401, + + /// + /// 需要付费 + /// + [Description("需要付费")] + PaymentRequired = 402, + + /// + /// 服务器拒绝满足请求 + /// + [Description("禁止请求")] + Forbidden = 403, + + /// + /// 请求的资源不在服务器上 + /// + [Description("未找到")] + NotFound = 404, + + /// + /// 请求的资源上不允许请求方法(POST或 GET) + /// + [Description("请求方法不允许")] + MethodNotAllowed = 405, + + /// + /// 客户端已用 Accept 头指示将不接受资源的任何可用表示形式 + /// + [Description("不接受")] + NotAcceptable = 406, + + /// + /// 请求的代理要求身份验证 + /// Proxy-authenticate 头包含如何执行身份验证的详细信息 + /// + [Description("需要代理认证")] + ProxyAuthenticationRequired = 407, + + /// + /// 客户端没有在服务器期望请求的时间内发送请求 + /// + [Description("请求超时")] + RequestTimeout = 408, + + /// + /// 由于服务器上的冲突而未能执行请求 + /// + [Description("冲突")] + Conflict = 409, + + /// + /// 请求的资源不再可用 + /// + [Description("失败")] + Gone = 410, + + /// + /// 缺少必需的 Content-length + /// + [Description("缺少Content-length头")] + LengthRequired = 411, + + /// + /// 为此请求设置的条件失败,且无法执行此请求 + /// 条件是用条件请求标头(如 If-Match、If-None-Match 或 If-Unmodified-Since)设置的。 + /// + [Description("条件失败")] + PreconditionFailed = 412, + + /// + /// 请求太大,服务器无法处理 + /// + [Description("请求实体太大")] + RequestEntityTooLarge = 413, + + /// + /// URI 太长 + /// + [Description("请求URI太长")] + RequestUriTooLong = 414, + + /// + /// 请求是不支持的类型 + /// + [Description("不支持的媒体类型")] + UnsupportedMediaType = 415, + + /// + /// 无法返回从资源请求的数据范围,因为范围的开头在资源的开头之前,或因为范围的结尾在资源的结尾之后 + /// + [Description("数据范围不匹配")] + RequestedRangeNotSatisfiable = 416, + + /// + /// 服务器未能符合Expect头中给定的预期值 + /// + [Description("服务器与Expect头不匹配")] + ExpectationFailed = 417, + + /// + /// 服务器拒绝处理客户端使用当前协议发送的请求,但是可以接受其使用升级后的协议发送的请求 + /// + [Description("当前协议不受支持")] + UpgradeRequired = 426, + + /// + /// 服务器上发生了一般错误 + /// + [Description("服务器内部错误")] + InternalServerError = 500, + + /// + /// 服务器不支持请求的函数 + /// + [Description("未实现")] + NotImplemented = 501, + + /// + /// 中间代理服务器从另一代理或原始服务器接收到错误响应 + /// + [Description("网关失败")] + BadGateway = 502, + + /// + /// 服务器暂时不可用,通常是由于过多加载或维护 + /// + [Description("服务器维护")] + ServiceUnavailable = 503, + + /// + /// 中间代理服务器在等待来自另一个代理或原始服务器的响应时已超时 + /// + [Description("网关超时")] + GatewayTimeout = 504, + + /// + /// 服务器不支持请求的HTTP版本 + /// + [Description("HTTP版本不支持")] + HttpVersionNotSupported = 505 +} diff --git a/Magic.Core/Enum/LoginType.cs b/Magic.Core/Enum/LoginType.cs new file mode 100644 index 0000000..a621ee2 --- /dev/null +++ b/Magic.Core/Enum/LoginType.cs @@ -0,0 +1,39 @@ +using System.ComponentModel; + +namespace Magic.Core; + +/// +/// 登陆类型 +/// +public enum LoginType +{ + /// + /// 登陆 + /// + [Description("登陆")] + LOGIN = 0, + + /// + /// 登出 + /// + [Description("登出")] + LOGOUT = 1, + + /// + /// 注册 + /// + [Description("注册")] + REGISTER = 2, + + /// + /// 改密 + /// + [Description("改密")] + CHANGEPASSWORD = 3, + + /// + /// 三方授权登陆 + /// + [Description("授权登陆")] + AUTHORIZEDLOGIN = 4 +} diff --git a/Magic.Core/Enum/MenuOpenType.cs b/Magic.Core/Enum/MenuOpenType.cs new file mode 100644 index 0000000..847bcd7 --- /dev/null +++ b/Magic.Core/Enum/MenuOpenType.cs @@ -0,0 +1,33 @@ +using System.ComponentModel; + +namespace Magic.Core; + +/// +/// 系统菜单类型 +/// +public enum MenuOpenType +{ + /// + /// 无 + /// + [Description("无")] + NONE = 0, + + /// + /// 组件 + /// + [Description("组件")] + COMPONENT = 1, + + /// + /// 内链 + /// + [Description("内链")] + INNER = 2, + + /// + /// 外链 + /// + [Description("外链")] + OUTER = 3 +} diff --git a/Magic.Core/Enum/MenuType.cs b/Magic.Core/Enum/MenuType.cs new file mode 100644 index 0000000..abc68ed --- /dev/null +++ b/Magic.Core/Enum/MenuType.cs @@ -0,0 +1,27 @@ +using System.ComponentModel; + +namespace Magic.Core; + +/// +/// 系统菜单类型 +/// +public enum MenuType +{ + /// + /// 目录 + /// + [Description("目录")] + DIR = 0, + + /// + /// 菜单 + /// + [Description("菜单")] + MENU = 1, + + /// + /// 按钮 + /// + [Description("按钮")] + BTN = 2 +} diff --git a/Magic.Core/Enum/MenuWeight.cs b/Magic.Core/Enum/MenuWeight.cs new file mode 100644 index 0000000..b05b6d6 --- /dev/null +++ b/Magic.Core/Enum/MenuWeight.cs @@ -0,0 +1,21 @@ +using System.ComponentModel; + +namespace Magic.Core; + +/// +/// 菜单权重 +/// +public enum MenuWeight +{ + /// + /// 系统权重 + /// + [Description("系统权重")] + SUPER_ADMIN_WEIGHT = 1, + + /// + /// 业务权重 + /// + [Description("业务权重")] + DEFAULT_WEIGHT = 2 +} diff --git a/Magic.Core/Enum/NoticeStatus.cs b/Magic.Core/Enum/NoticeStatus.cs new file mode 100644 index 0000000..e4abf2d --- /dev/null +++ b/Magic.Core/Enum/NoticeStatus.cs @@ -0,0 +1,33 @@ +using System.ComponentModel; + +namespace Magic.Core; + +/// +/// 通知公告状态 +/// +public enum NoticeStatus +{ + /// + /// 草稿 + /// + [Description("草稿")] + DRAFT = 0, + + /// + /// 发布 + /// + [Description("发布")] + PUBLIC = 1, + + /// + /// 撤回 + /// + [Description("撤回")] + CANCEL = 2, + + /// + /// 删除 + /// + [Description("删除")] + DELETED = 3 +} diff --git a/Magic.Core/Enum/NoticeType.cs b/Magic.Core/Enum/NoticeType.cs new file mode 100644 index 0000000..a3966f0 --- /dev/null +++ b/Magic.Core/Enum/NoticeType.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Magic.Core; + +public enum NoticeType +{ + /// + /// 通知 + /// + [Description("通知")] + NOTICE = 1, + + /// + /// 公告 + /// + [Description("公告")] + ANNOUNCEMENT = 2, + +} diff --git a/Magic.Core/Enum/NoticeUserStatus.cs b/Magic.Core/Enum/NoticeUserStatus.cs new file mode 100644 index 0000000..39d19b6 --- /dev/null +++ b/Magic.Core/Enum/NoticeUserStatus.cs @@ -0,0 +1,21 @@ +using System.ComponentModel; + +namespace Magic.Core; + +/// +/// 通知公告用户状态 +/// +public enum NoticeUserStatus +{ + /// + /// 未读 + /// + [Description("未读")] + UNREAD = 0, + + /// + /// 已读 + /// + [Description("已读")] + READ = 1 +} diff --git a/Magic.Core/Enum/QueryTypeEnum.cs b/Magic.Core/Enum/QueryTypeEnum.cs new file mode 100644 index 0000000..ee04aed --- /dev/null +++ b/Magic.Core/Enum/QueryTypeEnum.cs @@ -0,0 +1,57 @@ +using System.ComponentModel; + +namespace Magic.Core; + +/// +/// 查询类型的枚举 +/// +public enum QueryTypeEnum +{ + /// + /// 等于 + /// + [Description("等于")] + eq = 0, + + /// + /// 模糊 + /// + [Description("模糊")] + like = 1, + + /// + /// 大于 + /// + [Description("大于")] + gt = 2, + + /// + /// 小于 + /// + [Description("小于")] + lt = 3, + + /// + /// 不等于 + /// + [Description("不等于")] + ne = 4, + + /// + /// 大于等于 + /// + [Description("大于等于")] + ge = 5, + + /// + /// 小于等于 + /// + [Description("小于等于")] + le = 6, + + /// + /// 不为空 + /// + [Description("不为空")] + isNotNull = 7 +} diff --git a/Magic.Core/Enum/RequestTypeEnum.cs b/Magic.Core/Enum/RequestTypeEnum.cs new file mode 100644 index 0000000..275c2ed --- /dev/null +++ b/Magic.Core/Enum/RequestTypeEnum.cs @@ -0,0 +1,32 @@ +namespace Magic.Core; + +/// +/// http请求类型 +/// +public enum RequestTypeEnum +{ + /// + /// 执行内部方法 + /// + Run = 0, + + /// + /// GET请求 + /// + Get = 1, + + /// + /// POST请求 + /// + Post = 2, + + /// + /// PUT请求 + /// + Put = 3, + + /// + /// DELETE请求 + /// + Delete = 4 +} diff --git a/Magic.Core/Enum/RoleType.cs b/Magic.Core/Enum/RoleType.cs new file mode 100644 index 0000000..2f5e606 --- /dev/null +++ b/Magic.Core/Enum/RoleType.cs @@ -0,0 +1,22 @@ +using System.ComponentModel; + +namespace Magic.Core; + +/// +/// 账号类型 +/// +public enum RoleType +{ + /// + /// 租户管理员角色 + /// + [Description("租户管理员角色")] + AdminRole = 1, + + /// + /// 租户普通角色 + /// + [Description("租户普通角色")] + NormalRole = 0, + +} diff --git a/Magic.Core/Enum/TenantTypeEnum.cs b/Magic.Core/Enum/TenantTypeEnum.cs new file mode 100644 index 0000000..9a18ce3 --- /dev/null +++ b/Magic.Core/Enum/TenantTypeEnum.cs @@ -0,0 +1,12 @@ +using System.ComponentModel; + +namespace Magic.Core; + +public enum TenantTypeEnum +{ + [Description("普通租户")] + COMMON = 0, + + [Description("系统租户")] + SYSTEM = 1, +} diff --git a/Magic.Core/Enum/YesOrNot.cs b/Magic.Core/Enum/YesOrNot.cs new file mode 100644 index 0000000..d81a3f1 --- /dev/null +++ b/Magic.Core/Enum/YesOrNot.cs @@ -0,0 +1,21 @@ +using System.ComponentModel; + +namespace Magic.Core; + +/// +/// 菜单激活类型 +/// +public enum YesOrNot +{ + /// + /// 是 + /// + [Description("是")] + Y = 0, + + /// + /// 否 + /// + [Description("否")] + N = 1 +} diff --git a/Magic.Core/EventSubscriber/LogEventSubscriber.cs b/Magic.Core/EventSubscriber/LogEventSubscriber.cs new file mode 100644 index 0000000..492dd90 --- /dev/null +++ b/Magic.Core/EventSubscriber/LogEventSubscriber.cs @@ -0,0 +1,57 @@ +using Furion.EventBus; +using Magic.Core.Entity; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Threading.Tasks; + +namespace Magic.Core; + +public class LogEventSubscriber : IEventSubscriber +{ + public LogEventSubscriber(IServiceProvider services) + { + Services = services; + } + + public IServiceProvider Services { get; } + + [EventSubscribe("Create:OpLog")] + public async Task CreateOpLog(EventHandlerExecutingContext context) + { + using var scope = Services.CreateScope(); + var _repository = scope.ServiceProvider.GetRequiredService>(); + var log = (SysLogOp)context.Source.Payload; + await _repository.InsertAsync(log); + } + + [EventSubscribe("Create:ExLog")] + public async Task CreateExLog(EventHandlerExecutingContext context) + { + using var scope = Services.CreateScope(); + var _repository = scope.ServiceProvider.GetRequiredService>(); + var log = (SysLogEx)context.Source.Payload; + await _repository.InsertAsync(log); + } + + [EventSubscribe("Create:VisLog")] + public async Task CreateVisLog(EventHandlerExecutingContext context) + { + using var scope = Services.CreateScope(); + var _repository = scope.ServiceProvider.GetRequiredService>(); + var log = (SysLogVis)context.Source.Payload; + await _repository.InsertAsync(log); + } + + [EventSubscribe("Update:UserLoginInfo")] + public async Task UpdateUserLoginInfo(EventHandlerExecutingContext context) + { + using var scope = Services.CreateScope(); + var _repository = scope.ServiceProvider.GetRequiredService>(); + var log = (SysUser)context.Source.Payload; + await _repository.UpdateAsync(a => a.Id == log.Id, a => new SysUser + { + LastLoginTime = log.LastLoginTime, + LastLoginIp = log.LastLoginIp + }); + } +} diff --git a/Magic.Core/Extension/BStyleServiceExtension.cs b/Magic.Core/Extension/BStyleServiceExtension.cs new file mode 100644 index 0000000..45a334f --- /dev/null +++ b/Magic.Core/Extension/BStyleServiceExtension.cs @@ -0,0 +1,44 @@ +using Microsoft.Extensions.DependencyInjection; +using System; + +namespace Magic.Core; + +/// +/// B格 +/// +public static class BStyleServiceExtension +{ + public static void AddBStyle(this IServiceCollection services, Action configure) + { + var builder = new BStyleServiceBuilder(); + configure(builder); + } +} +public class BStyleServiceBuilder +{ + public void UseDefault() + { + Console.ForegroundColor = ConsoleColor.Blue; + Console.WriteLine(@" __ __ _ _ _ ______ _______ + | \/ | (_) | \ | | | ____| |__ __| + | \ / | __ _ __ _ _ ___ | \| | | |__ | | + | |\/| | / _` | / _` | | | / __| | . ` | | __| | | + | | | | | (_| | | (_| | | | | (__ _ | |\ | | |____ | | + |_| |_| \__,_| \__, | |_| \___| (_) |_| \_| |______| |_| + __/ | + |___/ "); + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine(@" + +gitee: https://gitee.com/zhengguojing/magic-net"); + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine(@"期待您的PR,让.net更好! + +"); + } + + public void UseOther() + { + System.Console.WriteLine(@"另一个BStyle"); + } +} \ No newline at end of file diff --git a/Magic.Core/Extension/DataFilterExtensions.cs b/Magic.Core/Extension/DataFilterExtensions.cs new file mode 100644 index 0000000..f78cc74 --- /dev/null +++ b/Magic.Core/Extension/DataFilterExtensions.cs @@ -0,0 +1,121 @@ +using Furion; +using Furion.FriendlyException; +using Microsoft.Extensions.DependencyInjection; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq.Dynamic.Core; +using System.Linq.Expressions; +using System.Reflection; +using System.Threading.Tasks; + +namespace Magic.Core; + +public static class DataFilterExtensions + { + /// + /// 数据过滤,默认用户集合 + /// + /// ISugarQueryable + /// 目标表的parameter + /// 默认用户集合 + /// 需要过滤的用户id字段,默认CreatedUserId和OrgId + /// + public static ISugarQueryable ToDataFilter(this ISugarQueryable query,string parameter="a", string field = "", FilterType type = FilterType.User) + { + Expression expression = null; + var param = Expression.Parameter(typeof(TEntity), parameter); + var dataScopes = GetDataScopeIdList(type).GetAwaiter().GetResult(); + switch (type) + { + case FilterType.User: + if (string.IsNullOrEmpty(field)) + field = "CreatedUserId"; + break; + case FilterType.Org: + if (string.IsNullOrEmpty(field)) + field = "OrgId"; + break; + } + if (!UserManager.IsSuperAdmin) + { + PropertyInfo property = typeof(TEntity).GetProperty(field); + if (property != null) + { + if (property.PropertyType == typeof(string)) + { + var temp = dataScopes.ToJsonString().ToObject>(); + expression = DynamicExpressionParser.ParseLambda(new[] { param }, typeof(bool), $"{field} in @0", temp); + } + else if (property.PropertyType == typeof(long?)) + { + var temp = dataScopes.ToJsonString().ToObject>(); + expression = DynamicExpressionParser.ParseLambda(new[] { param }, typeof(bool), $"{field} in @0", temp); + } + else + { + expression = DynamicExpressionParser.ParseLambda(new[] { param }, typeof(bool), $"{field} in @0", dataScopes); + } + } + } + if (expression != null && UserManager.UserId > 0) + { + query = query.Where((Expression>)expression); + } + return query; + } + /// + /// 检查数据权限,默认用户集合 + /// + /// 检测的id + /// 默认用户集合 + public static async void CheckDataScope(this long field, FilterType type = FilterType.User) + { + // 如果当前用户不是超级管理员,则进行数据范围校验 + if (!UserManager.IsSuperAdmin) + { + var _scopeFactory = App.GetService(); + using (var scope = _scopeFactory.CreateScope()) + { + var service = scope.ServiceProvider; + var _sysUserService = App.GetService(service); + var dataScopes = new List(); + switch (type) + { + case FilterType.User: + dataScopes = await _sysUserService.GetDataScopeIdUserList(UserManager.UserId); + break; + case FilterType.Org: + dataScopes = await _sysUserService.GetUserDataScopeIdList(UserManager.UserId); + break; + } + if (dataScopes == null || field <= 0 || !dataScopes.Contains(field)) + throw Oops.Oh(ErrorCode.D1013); + } + } + } + + /// + /// 获取当前数据权限,默认用户集合 + /// + /// 默认用户集合 + /// + public static async Task> GetDataScopeIdList(FilterType type = FilterType.User) + { + var _scopeFactory = App.GetService(); + using (var scope = _scopeFactory.CreateScope()) + { + var service = scope.ServiceProvider; + var _sysUserService = App.GetService(service); + switch (type) + { + case FilterType.User: + return await _sysUserService.GetDataScopeIdUserList(UserManager.UserId); + case FilterType.Org: + return await _sysUserService.GetUserDataScopeIdList(UserManager.UserId); + default: + return await _sysUserService.GetUserDataScopeIdList(UserManager.UserId); + } + } + } +} diff --git a/Magic.Core/Extension/DictionaryExtensions.cs b/Magic.Core/Extension/DictionaryExtensions.cs new file mode 100644 index 0000000..bc6759e --- /dev/null +++ b/Magic.Core/Extension/DictionaryExtensions.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Magic.Core; + +/// +/// 字典扩展 +/// +public static class DictionaryExtensions +{ + /// + /// 将一个字典转化为 QueryString + /// + /// + /// + /// + public static string ToQueryString(this Dictionary dict, bool urlEncode = true) + { + return string.Join("&", dict.Select(p => $"{(urlEncode ? p.Key?.UrlEncode() : "")}={(urlEncode ? p.Value?.UrlEncode() : "")}")); + } + + /// + /// 将一个字符串 URL 编码 + /// + /// + /// + public static string UrlEncode(this string str) + { + if (string.IsNullOrEmpty(str)) + { + return ""; + } + return System.Web.HttpUtility.UrlEncode(str, Encoding.UTF8); + } + + /// + /// 移除空值项 + /// + /// + public static void RemoveEmptyValueItems(this Dictionary dict) + { + dict.Where(item => string.IsNullOrEmpty(item.Value)).Select(item => item.Key).ToList().ForEach(key => + { + dict.Remove(key); + }); + } +} diff --git a/Magic.Core/Extension/EnumExtensions.cs b/Magic.Core/Extension/EnumExtensions.cs new file mode 100644 index 0000000..2ce9493 --- /dev/null +++ b/Magic.Core/Extension/EnumExtensions.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection; +using Furion.FriendlyException; + +namespace Magic.Core; + +/// +/// 枚举扩展 +/// +public static class EnumExtensions +{ + // 枚举显示字典缓存 + private static readonly ConcurrentDictionary> EnumDisplayValueDict = new(); + + // 枚举值字典缓存 + private static readonly ConcurrentDictionary> EnumNameValueDict = new(); + + // 枚举类型缓存 + private static ConcurrentDictionary _enumTypeDict = null; + + + /// + /// 获取枚举对象Key与名称的字典(缓存) + /// + /// + /// + public static Dictionary GetEnumDictionary(Type enumType) + { + if (!enumType.IsEnum) + throw Oops.Oh(ErrorCode.D1503); + + // 查询缓存 + Dictionary enumDic = EnumNameValueDict.ContainsKey(enumType) ? EnumNameValueDict[enumType] : new Dictionary(); + if (enumDic.Count == 0) + { + // 取枚举类型的Key/Value字典集合 + enumDic = GetEnumDictionaryItems(enumType); + + // 缓存 + EnumNameValueDict[enumType] = enumDic; + } + return enumDic; + } + + /// + /// 获取枚举对象Key与名称的字典 + /// + /// + /// + private static Dictionary GetEnumDictionaryItems(Type enumType) + { + // 获取类型的字段,初始化一个有限长度的字典 + FieldInfo[] enumFields = enumType.GetFields(BindingFlags.Public | BindingFlags.Static); + Dictionary enumDic = new(enumFields.Length); + + // 遍历字段数组获取key和name + foreach (FieldInfo enumField in enumFields) + { + int intValue = (int)enumField.GetValue(enumType); + enumDic[intValue] = enumField.Name; + } + return enumDic; + } + + /// + /// 获取枚举类型key与描述的字典(缓存) + /// + /// + /// + /// + public static Dictionary GetEnumDescDictionary(Type enumType) + { + if (!enumType.IsEnum) + throw Oops.Oh(ErrorCode.D1503); + + // 查询缓存 + Dictionary enumDic = EnumDisplayValueDict.ContainsKey(enumType) ? EnumDisplayValueDict[enumType] : new Dictionary(); + if (enumDic.Count == 0) + { + // 取枚举类型的Key/Value字典集合 + enumDic = GetEnumDescDictionaryItems(enumType); + + // 缓存 + EnumDisplayValueDict[enumType] = enumDic; + } + return enumDic; + } + + /// + /// 获取枚举类型key与描述的字典(没有描述则获取name) + /// + /// + /// + /// + private static Dictionary GetEnumDescDictionaryItems(Type enumType) + { + // 获取类型的字段,初始化一个有限长度的字典 + FieldInfo[] enumFields = enumType.GetFields(BindingFlags.Public | BindingFlags.Static); + Dictionary enumDic = new(enumFields.Length); + + // 遍历字段数组获取key和name + foreach (FieldInfo enumField in enumFields) + { + int intValue = (int)enumField.GetValue(enumType); + var desc = enumField.GetDescriptionValue(); + enumDic[intValue] = desc != null && !string.IsNullOrEmpty(desc.Description) ? desc.Description : enumField.Name; + } + return enumDic; + } + + /// + /// 从程序集中查找指定枚举类型 + /// + /// + /// + /// + public static Type TryToGetEnumType(Assembly assembly, string typeName) + { + // 枚举缓存为空则重新加载枚举类型字典 + _enumTypeDict ??= LoadEnumTypeDict(assembly); + + // 按名称查找 + if (_enumTypeDict.ContainsKey(typeName)) + { + return _enumTypeDict[typeName]; + } + return null; + } + + /// + /// 从程序集中加载所有枚举类型 + /// + /// + /// + private static ConcurrentDictionary LoadEnumTypeDict(Assembly assembly) + { + // 取程序集中所有类型 + Type[] typeArray = assembly.GetTypes(); + + // 过滤非枚举类型,转成字典格式并返回 + Dictionary dict = typeArray.Where(o => o.IsEnum).ToDictionary(o => o.Name, o => o); + ConcurrentDictionary enumTypeDict = new(dict); + return enumTypeDict; + } +} diff --git a/Magic.Core/Extension/InputBase.cs b/Magic.Core/Extension/InputBase.cs new file mode 100644 index 0000000..62d9c7e --- /dev/null +++ b/Magic.Core/Extension/InputBase.cs @@ -0,0 +1,70 @@ +using System.Collections.Generic; + +namespace Magic.Core; + +/// +/// 通用输入扩展参数(带权限) +/// +public class InputBase : PageInputBase +{ + /// + /// 授权菜单 + /// + public List GrantMenuIdList { get; set; } = new List(); + + /// + /// 授权角色 + /// + public virtual List GrantRoleIdList { get; set; } = new List(); + + /// + /// 授权数据 + /// + public virtual List GrantOrgIdList { get; set; } = new List(); +} + +/// +/// 通用分页输入参数 +/// +public class PageInputBase +{ + /// + /// 搜索值 + /// + public virtual string SearchValue { get; set; } + + /// + /// 当前页码 + /// + public virtual int PageNo { get; set; } = 1; + + /// + /// 页码容量 + /// + public virtual int PageSize { get; set; } = 20; + + /// + /// 搜索开始时间 + /// + public virtual string SearchBeginTime { get; set; } + + /// + /// 搜索结束时间 + /// + public virtual string SearchEndTime { get; set; } + + /// + /// 排序字段 + /// + public virtual string SortField { get; set; } + + /// + /// 排序方法,默认升序,否则降序(配合antd前端,约定参数为 Ascend,Dscend) + /// + public virtual string SortOrder { get; set; } + + /// + /// 降序排序(不要问我为什么是descend不是desc,前端约定参数就是这样) + /// + public virtual string DescStr { get; set; } = "descend"; +} diff --git a/Magic.Core/Extension/PageInputOrder.cs b/Magic.Core/Extension/PageInputOrder.cs new file mode 100644 index 0000000..89e0d63 --- /dev/null +++ b/Magic.Core/Extension/PageInputOrder.cs @@ -0,0 +1,26 @@ +namespace Magic.Core; + +/// +/// 通用输入帮助类 +/// +public class PageInputOrder +{ + /// + /// 排序方式(默认降序) + /// + /// + /// 是否降序 + /// + public static string OrderBuilder(PageInputBase pageInput, bool descSort = true) + { + // 约定默认每张表都有Id排序 + var orderStr = descSort ? "Id Desc" : "Id Asc"; + + // 排序是否可用-排序字段和排序顺序都为非空才启用排序 + if (!string.IsNullOrEmpty(pageInput.SortField) && !string.IsNullOrEmpty(pageInput.SortOrder)) + { + orderStr = $"{pageInput.SortField} {(pageInput.SortOrder == pageInput.DescStr ? "Desc" : "Asc")}"; + } + return orderStr; + } +} diff --git a/Magic.Core/Extension/PageResult.cs b/Magic.Core/Extension/PageResult.cs new file mode 100644 index 0000000..55c96f8 --- /dev/null +++ b/Magic.Core/Extension/PageResult.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using Mapster; +using SqlSugar; + +namespace Magic.Core; + +public class PageResult +{ + public int PageNo { get; set; } + public int PageSize { get; set; } + public int TotalPage { get; set; } + public int TotalRows { get; set; } + public ICollection Rows { get; set; } +} + +/// +/// 小诺分页列表结果 +/// +public static class PageResult +{ + /// + /// 替换sqlsugar分页 + /// + /// + /// + public static dynamic XnPagedResult(this SqlSugarPagedList page) + { + return new + { + PageNo = page.PageIndex, + PageSize = page.PageSize, + TotalPage = page.TotalPages, + TotalRows = page.TotalCount, + Rows = page.Items + }; + } +} diff --git a/Magic.Core/Extension/PagedQueryableExtensions.cs b/Magic.Core/Extension/PagedQueryableExtensions.cs new file mode 100644 index 0000000..6d450dc --- /dev/null +++ b/Magic.Core/Extension/PagedQueryableExtensions.cs @@ -0,0 +1,35 @@ +using SqlSugar; +using System; +using System.Threading.Tasks; + +namespace Magic.Core; + + /// + /// 分页拓展类 + /// + public static class PagedQueryableExtensions +{ + /// + /// 分页拓展 + /// + /// + /// + /// + /// + public static async Task> ToPagedListAsync(this ISugarQueryable query, int pageIndex, int pageSize) + { + RefAsync totalCount = 0; + var items = await query.ToPageListAsync(pageIndex, pageSize, totalCount); + var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize); + return new SqlSugarPagedList + { + PageIndex = pageIndex, + PageSize = pageSize, + Items = items, + TotalCount = (int)totalCount, + TotalPages = totalPages, + HasNextPages = pageIndex < totalPages, + HasPrevPages = pageIndex - 1 > 0 + }; + } +} diff --git a/Magic.Core/Extension/RestfulResultProvider.cs b/Magic.Core/Extension/RestfulResultProvider.cs new file mode 100644 index 0000000..0e8c4f7 --- /dev/null +++ b/Magic.Core/Extension/RestfulResultProvider.cs @@ -0,0 +1,134 @@ +using Furion.DataValidation; +using Furion.DependencyInjection; +using Furion.FriendlyException; +using Furion.UnifyResult; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using System; +using System.Threading.Tasks; + +namespace Magic.Core; + +/// +/// 规范化RESTful风格返回值 +/// +[SuppressSniffer, UnifyModel(typeof(XnRestfulResult<>))] +public class RestfulResultProvider : IUnifyResultProvider +{ + public IActionResult OnException(ExceptionContext context, ExceptionMetadata metadata) + { + // 解析异常信息 + var exceptionMetadata = UnifyContext.GetExceptionMetadata(context); + + return new JsonResult(new XnRestfulResult + { + Code = exceptionMetadata.StatusCode, + Success = false, + Data = null, + Message = exceptionMetadata.Errors, + Extras = UnifyContext.Take(), + Timestamp = DateTime.Now.Millisecond + }); + } + + public IActionResult OnSucceeded(ActionExecutedContext context, object data) + { + switch (context.Result) + { + // 处理内容结果 + case ContentResult contentResult: + data = contentResult.Content; + break; + // 处理对象结果 + case ObjectResult objectResult: + data = objectResult.Value; + break; + case EmptyResult: + data = null; + break; + default: + return null; + } + + return new JsonResult(new XnRestfulResult + { + Code = context.Result is EmptyResult ? StatusCodes.Status204NoContent : StatusCodes.Status200OK, // 处理没有返回值情况 204 + Success = true, + Data = data, + Message = "请求成功", + Extras = UnifyContext.Take(), + Timestamp = DateTime.Now.Millisecond + }); + } + + public IActionResult OnValidateFailed(ActionExecutingContext context, ValidationMetadata metadata) + { + return new JsonResult(new XnRestfulResult + { + Code = StatusCodes.Status400BadRequest, + Success = false, + Data = null, + Message = metadata.ValidationResult, + Extras = UnifyContext.Take(), + Timestamp = DateTime.Now.Millisecond + }); + } + + public async Task OnResponseStatusCodes(HttpContext context, int statusCode, UnifyResultSettingsOptions unifyResultSettings = null) + { + Console.WriteLine("OnResponseStatusCodes"); + // 设置响应状态码 + UnifyContext.SetResponseStatusCodes(context, statusCode, unifyResultSettings); + + if (Enum.IsDefined(typeof(HttpStatusCode), (HttpStatusCode)statusCode)){ + await context.Response.WriteAsJsonAsync(new XnRestfulResult + { + Code = statusCode, + Success = false, + Data = null, + Message = EnumUtil.GetDescription((HttpStatusCode)statusCode), + Extras = UnifyContext.Take(), + Timestamp = DateTime.Now.Millisecond + }); + } + } +} + +/// +/// RESTful风格---XIAONUO返回格式 +/// +/// +[SuppressSniffer] +public class XnRestfulResult +{ + /// + /// 执行成功 + /// + public bool Success { get; set; } + + /// + /// 状态码 + /// + public int? Code { get; set; } + + /// + /// 错误信息 + /// + public object Message { get; set; } + + /// + /// 数据 + /// + public T Data { get; set; } + + /// + /// 附加数据 + /// + public object Extras { get; set; } + + /// + /// 时间戳 + /// + public long Timestamp { get; set; } +} diff --git a/Magic.Core/Filter/LogExceptionHandler.cs b/Magic.Core/Filter/LogExceptionHandler.cs new file mode 100644 index 0000000..f47dbf2 --- /dev/null +++ b/Magic.Core/Filter/LogExceptionHandler.cs @@ -0,0 +1,52 @@ +using Furion; +using Furion.DependencyInjection; +using Furion.EventBus; +using Furion.FriendlyException; +using Furion.Logging.Extensions; +using Magic.Core.Entity; +using Microsoft.AspNetCore.Mvc.Filters; +using System; +using System.Security.Claims; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Magic.Core; + +/// +/// 全局异常处理 +/// +public class LogExceptionHandler : IGlobalExceptionHandler, ISingleton +{ + private readonly IEventPublisher _eventPublisher; + + public LogExceptionHandler(IEventPublisher eventPublisher) + { + _eventPublisher = eventPublisher; + } + + public async Task OnExceptionAsync(ExceptionContext context) + { + var userContext = App.User; + var className = context.Exception.TargetSite.DeclaringType?.FullName; + var groupCollection = Regex.Match(className, "<(.*?)>").Groups; + var methodName = ""; + if (groupCollection.Count > 1) + { + methodName = groupCollection[1].Value; + } + await _eventPublisher.PublishAsync(new ChannelEventSource("Create:ExLog", + new SysLogEx + { + Account = userContext?.FindFirstValue(ClaimConst.CLAINM_ACCOUNT), + Name = userContext?.FindFirstValue(ClaimConst.CLAINM_NAME), + ClassName = className, + MethodName = methodName, + ExceptionName = context.Exception.Message, + ExceptionMsg = context.Exception.Message, + ExceptionSource = context.Exception.Source, + StackTrace = context.Exception.StackTrace, + ParamsObj = context.Exception.TargetSite.GetParameters().ToString(), + ExceptionTime = DateTime.Now + })); + } +} diff --git a/Magic.Core/Filter/RequestActionFilter.cs b/Magic.Core/Filter/RequestActionFilter.cs new file mode 100644 index 0000000..f8a0875 --- /dev/null +++ b/Magic.Core/Filter/RequestActionFilter.cs @@ -0,0 +1,82 @@ +using System; +using System.Diagnostics; +using System.Security.Claims; +using System.Threading.Tasks; +using Furion; +using Furion.EventBus; +using Furion.JsonSerialization; +using Magic.Core.Entity; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Filters; +using UAParser; + +namespace Magic.Core; + +/// +/// 请求日志拦截 +/// +public class RequestActionFilter : IAsyncActionFilter +{ + private readonly IEventPublisher _eventPublisher; + + public RequestActionFilter(IEventPublisher eventPublisher) + { + _eventPublisher = eventPublisher; + } + + public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + var httpContext = context.HttpContext; + var httpRequest = httpContext.Request; + + var sw = new Stopwatch(); + sw.Start(); + var actionContext = await next(); + sw.Stop(); + + //判断是否请求成功(没有异常就是请求成功) + var isRequestSucceed = actionContext.Exception == null; + var headers = httpRequest.Headers; + var clientInfo = headers.ContainsKey("User-Agent") ? Parser.GetDefault().Parse(headers["User-Agent"]) : null; + var actionDescriptor = context.ActionDescriptor as ControllerActionDescriptor; + var isWriteLog = false; + var ip = HttpNewUtil.Ip; + //判断是否需要记录操作日志属性 + foreach (var metadata in actionDescriptor.EndpointMetadata) + { + if (metadata.GetType() == typeof(OpLogAttribute)) + { + isWriteLog = true; + break; + } + } + //请求异常时记录日志 + if (!isRequestSucceed || App.GetOptions().IsGlobalRequestLog) + { + isWriteLog = true; + } + if (isWriteLog) + { + await _eventPublisher.PublishAsync(new ChannelEventSource("Create:OpLog", new SysLogOp + { + Name = httpContext.User?.FindFirstValue(ClaimConst.CLAINM_NAME), + Success = isRequestSucceed ? YesOrNot.Y : YesOrNot.N, + Ip = ip, + Location = httpRequest.GetRequestUrlAddress(), + Browser = clientInfo?.UA.Family + clientInfo?.UA.Major, + Os = clientInfo?.OS.Family + clientInfo?.OS.Major, + Url = httpRequest.Path, + ClassName = context.Controller.ToString(), + MethodName = actionDescriptor?.ActionName, + ReqMethod = httpRequest.Method, + Param = JSON.Serialize(context.ActionArguments.Count < 1 ? "" : context.ActionArguments), + Result = actionContext.Result?.GetType() == typeof(JsonResult) ? JSON.Serialize(actionContext.Result) : "", + ElapsedTime = sw.ElapsedMilliseconds, + OpTime = DateTime.Now, + Account = httpContext.User?.FindFirstValue(ClaimConst.CLAINM_ACCOUNT) + })); + } + } +} diff --git a/Magic.Core/Filter/SqlSugarUnitOfWorkFilter.cs b/Magic.Core/Filter/SqlSugarUnitOfWorkFilter.cs new file mode 100644 index 0000000..67181ef --- /dev/null +++ b/Magic.Core/Filter/SqlSugarUnitOfWorkFilter.cs @@ -0,0 +1,90 @@ +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Filters; +using SqlSugar; +using System.Linq; +using System.Threading.Tasks; + +namespace Magic.Core; + +/// +/// SqlSugar 工作单元拦截器 +/// +public class SqlSugarUnitOfWorkFilter : IAsyncActionFilter, IOrderedFilter +{ + /// + /// 过滤器排序 + /// + internal const int FilterOrder = 9999; + + /// + /// 排序属性 + /// + public int Order => FilterOrder; + + /// + /// SqlSugar 对象 + /// + private readonly SqlSugarClient _sqlSugarClient; + + /// + /// 构造函数 + /// + /// + + public SqlSugarUnitOfWorkFilter(ISqlSugarClient sqlSugarClient) + { + _sqlSugarClient = (SqlSugarClient)sqlSugarClient; + } + + /// + /// + /// + /// + /// + /// + public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + // 获取动作方法描述器 + var actionDescriptor = context.ActionDescriptor as ControllerActionDescriptor; + var method = actionDescriptor.MethodInfo; + + // 判断是否贴有工作单元特性 + if (!method.IsDefined(typeof(SqlSugarUnitOfWorkAttribute), true)) + { + // 调用方法 + _ = await next(); + } + else + { + var attribute = (method.GetCustomAttributes(typeof(SqlSugarUnitOfWorkAttribute), true).FirstOrDefault() as SqlSugarUnitOfWorkAttribute); + + // 开启事务 + _sqlSugarClient.Ado.BeginTran(attribute.IsolationLevel); + + // 调用方法 + var resultContext = await next(); + + if (resultContext.Exception == null) + { + try + { + _sqlSugarClient.Ado.CommitTran(); + } + catch + { + _sqlSugarClient.Ado.RollbackTran(); + } + finally + { + _sqlSugarClient.Ado.Dispose(); + } + } + else + { + // 回滚事务 + _sqlSugarClient.Ado.RollbackTran(); + _sqlSugarClient.Ado.Dispose(); + } + } + } +} diff --git a/Magic.Core/Hubs/ChatHub.cs b/Magic.Core/Hubs/ChatHub.cs new file mode 100644 index 0000000..7690d81 --- /dev/null +++ b/Magic.Core/Hubs/ChatHub.cs @@ -0,0 +1,68 @@ +using Furion.DataEncryption; +using Magic.Core.Entity; +using Magic.Core.Service; +using Microsoft.AspNetCore.SignalR; +using System; +using System.Linq; +using System.Threading.Tasks; + +namespace Magic.Core; + +/// +/// 聊天集线器 +/// +public class ChatHub : Hub +{ + private readonly ISysCacheService _cache; + private readonly SqlSugarRepository _sysOnlineUerRep; // 在线用户表仓储 + + + public ChatHub(ISysCacheService cache, SqlSugarRepository sysOnlineUerRep) + { + _sysOnlineUerRep = sysOnlineUerRep; + _cache = cache; + } + //RuntimeMethodHandle-rf + /// + /// 连接 + /// + /// + public override async Task OnConnectedAsync() + { + var token = Context.GetHttpContext().Request.Query["access_token"]; + var claims = JWTEncryption.ReadJwtToken(token)?.Claims; + var userId = claims.FirstOrDefault(e => e.Type == ClaimConst.CLAINM_USERID)?.Value; + var account= claims.FirstOrDefault(e => e.Type == ClaimConst.CLAINM_ACCOUNT)?.Value; + var name= claims.FirstOrDefault(e => e.Type == ClaimConst.CLAINM_NAME)?.Value; + var tenantId= claims.FirstOrDefault(e => e.Type == ClaimConst.TENANT_ID)?.Value; + var ip = HttpNewUtil.Ip; + if (_sysOnlineUerRep.Any(m => m.Account == account && m.LastLoginIp == ip)) { + await _sysOnlineUerRep.DeleteAsync(m => m.Account == account && m.LastLoginIp == ip); + } + + OnlineUser user = new OnlineUser() { + ConnectionId = Context.ConnectionId, + UserId = long.Parse(userId), + LastTime = DateTime.Now, + LastLoginIp= ip, + Account= account, + Name=name, + TenantId=Convert.ToInt64(tenantId) + }; + await _sysOnlineUerRep.InsertAsync(user); + } + + /// + /// 断开 + /// + /// + /// + public override async Task OnDisconnectedAsync(Exception exception) + { + if (!string.IsNullOrEmpty(Context.ConnectionId)) + { + await _sysOnlineUerRep.DeleteAsync(m => m.ConnectionId == Context.ConnectionId); + } + } + +} diff --git a/Magic.Core/Hubs/IChatClient.cs b/Magic.Core/Hubs/IChatClient.cs new file mode 100644 index 0000000..f1478e6 --- /dev/null +++ b/Magic.Core/Hubs/IChatClient.cs @@ -0,0 +1,11 @@ +using Magic.Core.Entity; +using System.Threading.Tasks; + +namespace Magic.Core; + +public interface IChatClient +{ + Task ForceExist(string str); + + Task AppendNotice(SysNotice notice); +} diff --git a/Magic.Core/Job/LogJobWorker.cs b/Magic.Core/Job/LogJobWorker.cs new file mode 100644 index 0000000..4adb0a3 --- /dev/null +++ b/Magic.Core/Job/LogJobWorker.cs @@ -0,0 +1,254 @@ +using Furion; +using Furion.DependencyInjection; +using Furion.TaskScheduler; +using Magic.Core.Entity; +using Magic.Core.Service; +using Microsoft.Extensions.DependencyInjection; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + +namespace Magic.Core.Job; + +/// +/// 日志定时任务类 +/// +public class LogJobWorker : ISpareTimeWorker +{ + // 日志暂存器,待写入 + private readonly List _sysLogExs = new(); + private readonly List _sysLogOps = new(); + private readonly List _sysLogViss = new(); + + /// + /// 定期删除异常日志 + /// + /// + /// + [SpareTime("@midnight", "LogExDeletionService", Description = "后台定期删除异常日志,配置项参数:{\"daysAgo\": 30},不填默认为30", + DoOnce = false, StartNow = true, ExecuteType = SpareTimeExecuteTypes.Serial)] + public void DoDeleteLogEx(SpareTimer timer, long count) + { + // 判断是否有异常 + if (timer.Exception.Any()) + { + // todo: 增加任务运行日志 + } + + // 默认值 + var daysAgo = 15; + + var sysCache = App.GetRequiredService(); + + // 获取写数据库容量阀值,新增定时任务时会将配置项写入缓存 + if (sysCache != null) + { + var parameters = sysCache.Get>("LogDeletionService_Parameters"); + + // 如果存在相关配置项 + if (parameters != null && parameters.ContainsKey("daysAgo") && + string.IsNullOrEmpty(parameters["daysAgo"])) + daysAgo = int.Parse(parameters["daysAgo"]); + } + + // 生成查询表达式 + Expression> expression = ex => ex.ExceptionTime < DateTime.Now.AddDays(-daysAgo); + + // 执行删除 + DoDeleteWork(expression); + } + + /// + /// 定期删除操作日志 + /// + /// + /// + [SpareTime("@midnight", "LogOpDeletionService", Description = "后台定期删除操作日志,配置项参数:{\"daysAgo\": 7},不填默认为7", + DoOnce = false, StartNow = true, ExecuteType = SpareTimeExecuteTypes.Serial)] + public void DoDeleteLogOp(SpareTimer timer, long count) + { + // 判断是否有异常 + if (timer.Exception.Any()) + { + // todo: 增加任务运行日志 + } + + // 默认值 + var daysAgo = 7; + + var sysCache = App.GetRequiredService(); + + // 获取写数据库容量阀值,新增定时任务时会将配置项写入缓存 + if (sysCache != null) + { + var parameters = sysCache.Get>("LogOpDeletionService_Parameters"); + + // 如果存在相关配置项 + if (parameters != null && parameters.ContainsKey("daysAgo") && + string.IsNullOrEmpty(parameters["daysAgo"])) + daysAgo = int.Parse(parameters["daysAgo"]); + } + + // 生成查询表达式 + Expression> expression = ex => ex.OpTime < DateTime.Now.AddDays(-daysAgo); + + // 执行删除 + DoDeleteWork(expression); + } + + /// + /// 定期删除访问日志 + /// + /// + /// + [SpareTime("@midnight", "LogVisDeletionService", Description = "后台定期删除访问日志,配置项参数:{\"daysAgo\": 15},不填默认为15", + DoOnce = false, StartNow = true, ExecuteType = SpareTimeExecuteTypes.Serial)] + public void DoDeleteLogVis(SpareTimer timer, long count) + { + // 判断是否有异常 + if (timer.Exception.Any()) + { + // todo: 增加任务运行日志 + } + + // 默认值 + var daysAgo = 15; + + var sysCache = App.GetRequiredService(); + + // 获取写数据库容量阀值,新增定时任务时会将配置项写入缓存 + if (sysCache != null) + { + var parameters = sysCache.Get>("LogVisDeletionService_Parameters"); + + // 如果存在相关配置项 + if (parameters != null && parameters.ContainsKey("daysAgo") && + string.IsNullOrEmpty(parameters["daysAgo"])) + daysAgo = int.Parse(parameters["daysAgo"]); + } + + // 生成查询表达式 + Expression> expression = ex => ex.VisTime < DateTime.Now.AddDays(-daysAgo); + + // 执行删除 + DoDeleteWork(expression); + } + + /// + /// 后台批量写错误日志 + /// + /// + /// + [SpareTime(10000, "LogExWritingService", Description = "后台批量写错误日志,配置项参数:{\"quantity\": 2},不填默认为2", + DoOnce = false, StartNow = true, ExecuteType = SpareTimeExecuteTypes.Serial)] + public void DoLogEx(SpareTimer timer, long count) + { + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine($"DoLogEx: {DateTime.Now}"); + return; + //DoWork(timer, count, "LogExWritingService_Parameters", _sysLogExs); + } + + /// + /// 后台批量写操作日志 + /// + /// + /// + [SpareTime(5000, "LogOpWritingService", Description = "后台批量写操作日志,配置项参数:{\"quantity\": 2},不填默认为2", + DoOnce = false, StartNow = true, ExecuteType = SpareTimeExecuteTypes.Serial)] + public void DoLogOp(SpareTimer timer, long count) + { + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine($"DoLogOp: {DateTime.Now}"); + return; + //DoWork(timer, count, "LogOpWritingService_Parameters", _sysLogOps); + } + + /// + /// 后台批量写访问日志 + /// + /// + /// + [SpareTime(8000, "LogVisWritingService", Description = "后台批量写访问日志,配置项参数:{\"quantity\": 2},不填默认为2", + DoOnce = false, StartNow = true, ExecuteType = SpareTimeExecuteTypes.Serial)] + public void DoLogVis(SpareTimer timer, long count) + { + Console.ForegroundColor = ConsoleColor.Cyan; + Console.WriteLine($"DoLogVis: {DateTime.Now}"); + return; + //DoWork(timer, count, "LogVisWritingService_Parameters", _sysLogViss); + } + + /// + /// 写日志 + /// + /// + /// + /// + /// + /// + private void DoWork(SpareTimer timer, long count, string cacheKey, List logs) where T : class, new() + { + // 判断是否有异常 + if (timer.Exception.Any()) + { + // todo: 增加任务运行日志 + } + + Scoped.Create((_, scope) => + { + var services = scope.ServiceProvider; + var logRep =App.GetService(services); + var sysCache = services.GetRequiredService(); + + // 默认值 + var quantity = 2; + + // 获取写数据库容量阀值,新增定时任务时会将配置项写入缓存 + if (sysCache != null) + { + var parameters = sysCache.Get>(cacheKey); + + // 如果存在相关配置项 + if (parameters != null && parameters.ContainsKey("quantity") && + string.IsNullOrEmpty(parameters["quantity"])) + quantity = int.Parse(parameters["quantity"]); + } + + // 后台队列中产生了日志,取出写入暂存器 + int queue = SimpleQueue.Count(); + if (queue > 0) + { + for (var i = 0; i < queue; i++) + { + if (SimpleQueue.Try(out T obj)) + logs.Add(obj); + } + } + + // 达到系统配置的容量则写入数据库 + if (logs.Count > quantity) + { + logRep.Insertable(logs).ExecuteCommand(); + logs.Clear(); + } + }); + } + + /// + /// 根据条件删除日志 + /// + /// + /// + private void DoDeleteWork(Expression> expression) where T : class, new() + { + Scoped.Create((_, scope) => + { + var services = scope.ServiceProvider; + var logRep = App.GetService(services); + logRep.Deleteable(expression); + }); + } +} diff --git a/Magic.Core/JsonConverter/LongJsonConverter.cs b/Magic.Core/JsonConverter/LongJsonConverter.cs new file mode 100644 index 0000000..1b5db42 --- /dev/null +++ b/Magic.Core/JsonConverter/LongJsonConverter.cs @@ -0,0 +1,31 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Magic.Core; + +/// +/// Long 类型Json返回处理 +/// +public class LongJsonConverter : JsonConverter +{ + /// Reads and converts the JSON to type . + /// The reader. + /// The type to convert. + /// An object that specifies serialization options to use. + /// The converted value. + public override long Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + // 这里做处理,前端传入的Long类型可能为String类型,或者Number类型。 + return reader.TokenType == JsonTokenType.String ? long.Parse(reader.GetString()) : reader.GetInt64(); + } + + /// Writes a specified value as JSON. + /// The writer to write to. + /// The value to convert to JSON. + /// An object that specifies serialization options to use. + public override void Write(Utf8JsonWriter writer, long value, JsonSerializerOptions options) + { + writer.WriteStringValue($"{value}"); + } +} diff --git a/Magic.Core/Logging/Component/ConsoleForamtComponent.cs b/Magic.Core/Logging/Component/ConsoleForamtComponent.cs new file mode 100644 index 0000000..e9116b2 --- /dev/null +++ b/Magic.Core/Logging/Component/ConsoleForamtComponent.cs @@ -0,0 +1,21 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Console; +using System; + +namespace Magic.Core; + +public sealed class ConsoleForamtComponent : IWebComponent +{ + public void Load(WebApplicationBuilder builder, ComponentContext componentContext) + { + //builder.Logging.ClearProviders(); + //builder.Logging.AddConsole(options => + //{ + // options.FormatterName = "custom_format"; + //}).AddConsoleFormatter(); + + } + + +} diff --git a/Magic.Core/Logging/Component/LoggingFileComponent.cs b/Magic.Core/Logging/Component/LoggingFileComponent.cs new file mode 100644 index 0000000..2653925 --- /dev/null +++ b/Magic.Core/Logging/Component/LoggingFileComponent.cs @@ -0,0 +1,60 @@ +using Furion.Logging; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using System; +using System.Text; + +namespace Magic.Core; + +/// +/// 日志写入文件的组件 +/// +public sealed class LoggingFileComponent : IServiceComponent +{ + public void Load(IServiceCollection services, ComponentContext componentContext) + { + // 日志记录 + // 每天创建一个日志文件 + services.AddLogging(builder => + { + builder.AddFile("logs/error/{0:yyyyMMdd}_.log", options => + { + SetLogOptions(options, LogLevel.Error); + }); + builder.AddFile("logs/info/{0:yyyyMMdd}_.log", options => + { + SetLogOptions(options, LogLevel.Information); + }); + builder.AddFile("logs/warn/{0:yyyyMMdd}_.log", options => + { + SetLogOptions(options, LogLevel.Warning); + }); + }); + } + + private void SetLogOptions(FileLoggerOptions options, LogLevel logLevel) + { + options.WriteFilter = (logMsg) => + { + return logMsg.LogLevel == logLevel; + }; + options.FileNameRule = fileName => + { + return string.Format(fileName, DateTime.UtcNow); + }; + options.FileSizeLimitBytes = 500 * 1024; + //options.MessageFormat = LoggerFormatter.Json; + //options.MessageFormat = (logMsg) => + //{ + // var stringBuilder = new StringBuilder(); + // stringBuilder.AppendLine("【日志级别】:" + logMsg.LogLevel); + // stringBuilder.AppendLine("【日志时间】:" + DateTime.Now.ToString("yyyy:MM:dd:HH:mm:ss")); + // stringBuilder.AppendLine("【日志内容】:" + logMsg.Message); + // if (logMsg.Exception != null) + // { + // stringBuilder.AppendLine("【异常信息】:" + logMsg.Exception); + // } + // return stringBuilder.ToString(); + //}; + } +} diff --git a/Magic.Core/Logging/Extensions/LoggingFileExtensions.cs b/Magic.Core/Logging/Extensions/LoggingFileExtensions.cs new file mode 100644 index 0000000..f9aacf0 --- /dev/null +++ b/Magic.Core/Logging/Extensions/LoggingFileExtensions.cs @@ -0,0 +1,52 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Console; +namespace Magic.Core; + +/// +/// 日志写入文件扩展 +/// +public static class LoggingFileExtensions +{ + /// + /// 添加workerservice项目控制台日志格式化扩展 + /// + /// + /// + public static IHostBuilder UseLoggingFile(this IHostBuilder builder) + { + builder.ConfigureLogging(logging => + { + logging.ClearProviders(); + logging.AddConsole(options => + { + options.FormatterName = "custom_format"; + }).AddConsoleFormatter(); + + }); + builder.ConfigureServices((hostContext, services) => + { + services.AddComponent(); + }); + return builder; + } + + + /// + /// 添加api项目控制台日志格式化扩展 + /// + /// + /// + public static WebApplicationBuilder UseLoggingFile(this WebApplicationBuilder builder) + { + builder.Logging.ClearProviders(); + builder.Logging.AddConsole(options => + { + options.FormatterName = "custom_format"; + }).AddConsoleFormatter(); + builder.Services.AddComponent(); + return builder; + } +} diff --git a/Magic.Core/Logging/Format/ConsoleForamt.cs b/Magic.Core/Logging/Format/ConsoleForamt.cs new file mode 100644 index 0000000..303acad --- /dev/null +++ b/Magic.Core/Logging/Format/ConsoleForamt.cs @@ -0,0 +1,66 @@ +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Logging.Console; +using Microsoft.Extensions.Options; +using System; +using System.IO; + +namespace Magic.Core; + +public class ConsoleForamt : ConsoleFormatter, IDisposable +{ + private CustomColorOptions _formatterOptions; + private readonly IDisposable _optionsReloadToken; + private bool ConsoleColorFormattingEnabled => + _formatterOptions.ColorBehavior == LoggerColorBehavior.Enabled || + _formatterOptions.ColorBehavior == LoggerColorBehavior.Default && + System.Console.IsOutputRedirected == false; + + private void ReloadLoggerOptions(CustomColorOptions options) => +_formatterOptions = options; + + public ConsoleForamt(IOptionsMonitor options) : base("custom_format") => + (_optionsReloadToken, _formatterOptions) = + (options.OnChange(ReloadLoggerOptions), options.CurrentValue); + + + + public override void Write(in LogEntry logEntry, IExternalScopeProvider scopeProvider, TextWriter textWriter) + { + string message = logEntry.Formatter?.Invoke(logEntry.State, logEntry.Exception); + + if (message is null) + { + return; + } + ConsoleColor color = ConsoleColor.White; + switch (logEntry.LogLevel) + { + + case LogLevel.Information: + color = ConsoleColor.Green; + break; + case LogLevel.Warning: + color = ConsoleColor.Yellow; + break; + case LogLevel.Error: + color = ConsoleColor.Red; + break; + } + + textWriter.WriteWithColor("【日志级别】:" + logEntry.LogLevel, ConsoleColor.Black, color); + textWriter.WriteWithColor("【日志时间】:" + DateTime.Now.ToString("yyyy:MM:dd:HH:mm:ss"), ConsoleColor.Black, color); + textWriter.WriteWithColor("【日志内容】:" + message, ConsoleColor.Black, color); + if (logEntry.Exception != null) + { + textWriter.WriteWithColor("【异常信息】:" + logEntry.Exception, ConsoleColor.Black, color); + } + textWriter.WriteLine(); + } + + + public void Dispose() + { + _optionsReloadToken?.Dispose(); + } +} diff --git a/Magic.Core/Logging/Format/CustomColorOptions.cs b/Magic.Core/Logging/Format/CustomColorOptions.cs new file mode 100644 index 0000000..8717616 --- /dev/null +++ b/Magic.Core/Logging/Format/CustomColorOptions.cs @@ -0,0 +1,13 @@ +using Microsoft.Extensions.Logging.Console; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Magic.Core; + +public class CustomColorOptions : SimpleConsoleFormatterOptions +{ + public string? CustomPrefix { get; set; } +} diff --git a/Magic.Core/Logging/Format/TextWriterExtensions.cs b/Magic.Core/Logging/Format/TextWriterExtensions.cs new file mode 100644 index 0000000..1496e28 --- /dev/null +++ b/Magic.Core/Logging/Format/TextWriterExtensions.cs @@ -0,0 +1,84 @@ +using System; +using System.IO; + +namespace Magic.Core; +public static class TextWriterExtensions +{ + const string DefaultForegroundColor = "\x1B[39m\x1B[22m"; + const string DefaultBackgroundColor = "\x1B[49m"; + + public static void WriteWithColor( + this TextWriter textWriter, + string message, + ConsoleColor? background, + ConsoleColor? foreground) + { + // Order: + // 1. background color + // 2. foreground color + // 3. message + // 4. reset foreground color + // 5. reset background color + + var backgroundColor = background.HasValue ? GetBackgroundColorEscapeCode(background.Value) : null; + var foregroundColor = foreground.HasValue ? GetForegroundColorEscapeCode(foreground.Value) : null; + + if (backgroundColor != null) + { + textWriter.Write(backgroundColor); + } + if (foregroundColor != null) + { + textWriter.Write(foregroundColor); + } + + textWriter.WriteLine(message); + + if (foregroundColor != null) + { + textWriter.Write(DefaultForegroundColor); + } + if (backgroundColor != null) + { + textWriter.Write(DefaultBackgroundColor); + } + } + + static string GetForegroundColorEscapeCode(ConsoleColor color) => + color switch + { + ConsoleColor.Black => "\x1B[30m", + ConsoleColor.DarkRed => "\x1B[31m", + ConsoleColor.DarkGreen => "\x1B[32m", + ConsoleColor.DarkYellow => "\x1B[33m", + ConsoleColor.DarkBlue => "\x1B[34m", + ConsoleColor.DarkMagenta => "\x1B[35m", + ConsoleColor.DarkCyan => "\x1B[36m", + ConsoleColor.Gray => "\x1B[37m", + ConsoleColor.Red => "\x1B[1m\x1B[31m", + ConsoleColor.Green => "\x1B[1m\x1B[32m", + ConsoleColor.Yellow => "\x1B[1m\x1B[33m", + ConsoleColor.Blue => "\x1B[1m\x1B[34m", + ConsoleColor.Magenta => "\x1B[1m\x1B[35m", + ConsoleColor.Cyan => "\x1B[1m\x1B[36m", + ConsoleColor.White => "\x1B[1m\x1B[37m", + + _ => DefaultForegroundColor + }; + + static string GetBackgroundColorEscapeCode(ConsoleColor color) => + color switch + { + ConsoleColor.Black => "\x1B[40m", + ConsoleColor.DarkRed => "\x1B[41m", + ConsoleColor.DarkGreen => "\x1B[42m", + ConsoleColor.DarkYellow => "\x1B[43m", + ConsoleColor.DarkBlue => "\x1B[44m", + ConsoleColor.DarkMagenta => "\x1B[45m", + ConsoleColor.DarkCyan => "\x1B[46m", + ConsoleColor.Gray => "\x1B[47m", + + _ => DefaultBackgroundColor + }; +} + diff --git a/Magic.Core/Magic.Core.csproj b/Magic.Core/Magic.Core.csproj new file mode 100644 index 0000000..5771de8 --- /dev/null +++ b/Magic.Core/Magic.Core.csproj @@ -0,0 +1,73 @@ + + + + net7.0 + 1701;1702;1591 + Magic.Core.xml + 1.0.0 + + + + + + + + + + + + Magic.Core + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Never + + + PreserveNewest + + + + diff --git a/Magic.Core/Magic.Core.xml b/Magic.Core/Magic.Core.xml new file mode 100644 index 0000000..fe796fb --- /dev/null +++ b/Magic.Core/Magic.Core.xml @@ -0,0 +1,10408 @@ + + + + Magic.Core + + + + + 启用用操作日志 + + + + + SqlSugar 工作单元配置特性 + + + + + 构造函数 + + + + + 构造函数 + + + 支持传入事务隔离级别 参数值 + + 事务隔离级别 + + + + 事务隔离级别 + + + 默认:,参见: + 说明:当事务A更新某条数据的时候,不容许其他事务来更新该数据,但可以进行读取操作 + + + + + 缓存接口 + + + + + 用于在 key 存在时删除 key + + 键 + + + + 用于在 key 存在时删除 key + + 键 + + + + + 用于在 key 模板存在时删除 + + key模板 + + + + + 检查给定 key 是否存在 + + 键 + + + + + 检查给定 key 是否存在 + + 键 + + + + + 获取指定 key 的值 + + 键 + + + + + 获取指定 key 的值 + + byte[] 或其他类型 + 键 + + + + + 获取指定 key 的值 + + 键 + + + + + 获取指定 key 的值 + + byte[] 或其他类型 + 键 + + + + + 设置指定 key 的值,所有写入参数object都支持string | byte[] | 数值 | 对象 + + 键 + 值 + + + + 设置指定 key 的值,所有写入参数object都支持string | byte[] | 数值 | 对象 + + 键 + 值 + 有效期 + + + + 设置指定 key 的值,所有写入参数object都支持string | byte[] | 数值 | 对象 + + 键 + 值 + + + + + 设置指定 key 的值,所有写入参数object都支持string | byte[] | 数值 | 对象 + + 键 + 值 + 有效期 + + + + + 获取所有缓存 + + + + + + 内存缓存 + + + + + Redis缓存 + + + + + 点选验证码 + + + + + 生成验证码图片 + + + + + + + + + 转换为相对于图片的百分比单位 + + 图片宽高 + 相对于图片的绝对尺寸 + (int:xPercent, int:yPercent) + + + + 加载字体 + + 字体文件路径,包含字体文件名和后缀名 + 大小 + 字形(常规/粗体/斜体/粗斜体) + + + + 随机绘制字符串 + + + + + + + 验证码验证 + + + + + + + 记录正确位置 + + + + + 点击验证码输入参数 + + + + + 验证码类型 + + + + + 坐标点集合 + + + + + Token + + + + + 验证码输出参数 + + + + + 常规验证码 + + + + + 生成验证码图片 + + + + + + + 验证码验证 + + + + + + + 常规验证码输入 + + + + + 验证码类型 + + + + + 验证码字符 + + + + + Token + + + + + 缓存配置 + + + + + 缓存类型 + + + + + Redis配置 + + + + + 系统配置 + + + + + 超管是否可以查看所有租户的数据 + + + + + 是否开启全局请求日志 + + + + + 雪花Id配置 + + + + + 取值范围0~63,默认1 + + + + + 第三方配置 + + + + + 微信 + + + + + 上传文件 + + + + + 阿里云 + + + + + 头像 + + + + + 文档 + + + + + 商店 + + + + + 编辑器 + + + + + 默认 + + + + + 数据库配置 + + + + + 默认数据库编号 + + + + + 默认数据库类型 + + + + + 默认数据库连接字符串 + + + + + 业务库集合 + + + + + JWT配置 + + + + + 是否验证密钥 + + + + + 密钥 + + + + + 是否验证签发方 + + + + + 签发方 + + + + + 是否验证签收方 + + + + + 签收方 + + + + + 是否验证过期时间 + + + + + 过期时间 + + + + + 过期时间容错值 + + + + + 数据库参数 + + + + + 数据库编号 + + + + + 数据库类型 + + + + + 数据库连接字符串 + + + + + 文件参数 + + + + + 路径 + + + + + 大小 + + + + + 类型 + + + + + 第三方参数 + + + + + id + + + + + key + + + + + 回调地址 + + + + + scope + + + + + 用户Id + + + + + 账号 + + + + + 名称 + + + + + 是否超级管理 + + + + + 租户Id + + + + + 租户类型 + + + + + 租户名称 + + + + + 用户缓存 + + + + + 菜单缓存 + + + + + 权限缓存 + + + + + 数据范围缓存 + + + + + 验证码缓存 + + + + + 库表实体信息缓存 + + + + + 所有权限缓存 + + + + + 程序集 + + + + + 删除字段 + + + + + 自定义租户基类实体 + + + + + 租户id + + + + + 自定义实体基类 + + + + + 创建时间 + + + + + 更新时间 + + + + + 创建者Id + + + + + 创建者名称 + + + + + 修改者Id + + + + + 修改者名称 + + + + + 软删除 + + + + + 更新信息列 + + + + + + 假删除的列,包含更新信息 + + + + + + 递增主键实体基类 + + + + + 主键Id + + + + + 主键实体基类 + + + + + 主键Id + + + + + 文档表 + + + + + 父Id + + + + + 父ID列表 + + + + + 名称 + + + + + 文档类型:文件、文件夹 + + + + + 文件后缀 + + + + + 文件大小kb + + + + + 文件路径 + + + + + 存储后的文件名 + + + + + 标签 + + + + + 备注 + + + + + 是否可见 + + + + + 系统应用表 + + + + + 名称 + + + + + 编码 + + + + + 是否默认激活(Y-是,N-否),只能有一个系统默认激活 + 用户登录后默认展示此系统菜单 + + + + + 状态(字典 0正常 1停用 2删除) + + + + + 排序 + + + + + 代码生成表 + + + + + 作者姓名 + + + + + 是否移除表前缀 + + + + + 生成方式 + + + + + 数据库表名 + + + + + 命名空间 + + + + + 业务名 + + + + + 菜单应用分类(应用编码) + + + + + 菜单编码 + + + + + 代码生成字段配置表 + + + + + 代码生成主表ID + + + + + 数据库字段名 + + + + + 字段描述 + + + + + .NET数据类型 + + + + + 作用类型(字典) + + + + + 外键实体名称 + + + + + 外键显示字段 + + + + + 外键显示字段.NET类型 + + + + + 字典code + + + + + 列表是否缩进(字典) + + + + + 是否必填(字典) + + + + + 是否是查询条件 + + + + + 查询方式 + + + + + 列表显示 + + + + + 增改 + + + + + 主键 + + + + + 数据库中类型(物理类型) + + + + + 是否通用字段 + + + + + 参数配置表 + + + + + 名称 + + + + + 编码 + + + + + 属性值 + + + + + 是否是系统参数(Y-是,N-否) + + + + + 备注 + + + + + 状态(字典 0正常 1停用 2删除) + + + + + 常量所属分类的编码,来自于“常量的分类”字典 + + + + + 字典值表 + + + + + 字典类型Id + + + + + 值 + + + + + 编码 + + + + + 排序 + + + + + 备注 + + + + + 状态(字典 0正常 1停用 2删除) + + + + + 字典类型表 + + + + + 名称 + + + + + 编码 + + + + + 排序 + + + + + 备注 + + + + + 状态(字典 0正常 1停用 2删除) + + + + + 员工表 + + + + + 工号 + + + + + 机构Id + + + + + 机构名称 + + + + + 员工附属机构职位表 + + + + + 员工Id + + + + + 机构Id + + + + + 职位Id + + + + + 员工职位表 + + + + + 员工Id + + + + + 职位Id + + + + + 文件信息表 + + + + + 文件存储位置(1:阿里云,2:腾讯云,3:minio,4:本地) + + + + + 文件仓库 + + + + + 文件名称(上传时候的文件名) + + + + + 文件后缀 + + + + + 文件大小kb + + + + + 文件大小信息,计算后的 + + + + + 存储到bucket的名称(文件唯一标识id) + + + + + 存储路径 + + + + + 系统操作/审计日志表 + + + + + 表名 + + + + + 列名 + + + + + 新值 + + + + + 旧值 + + + + + 操作时间 + + + + + 操作人Id + + + + + 操作人名称 + + + + + 操作方式:新增、更新、删除 + + + + + 异常日志 + + + + + 操作人 + + + + + 名称 + + + + + 类名 + + + + + 方法名 + + + + + 异常名称 + + + + + 异常信息 + + + + + 异常源 + + + + + 堆栈信息 + + + + + 参数对象 + + + + + 异常时间 + + + + + 操作日志表 + + + + + 名称 + + + + + 是否执行成功(Y-是,N-否) + + + + + 具体消息 + + + + + IP + + + + + 地址 + + + + + 浏览器 + + + + + 操作系统 + + + + + 请求地址 + + + + + 类名称 + + + + + 方法名称 + + + + + 请求方式(GET POST PUT DELETE) + + + + + 请求参数 + + + + + 返回结果 + + + + + 耗时(毫秒) + + + + + 操作时间 + + + + + 操作人 + + + + + 访问日志表 + + + + + 名称 + + + + + 是否执行成功(Y-是,N-否) + + + + + 具体消息 + + + + + IP + + + + + 地址 + + + + + 浏览器 + + + + + 操作系统 + + + + + 访问类型 + + + + + 访问时间 + + + + + 访问人 + + + + + 菜单表 + + + + + 父Id + + + + + 父Ids + + + + + 名称 + + + + + 编码 + + + + + 菜单类型(字典 0目录 1菜单 2按钮) + + + + + 图标 + + + + + 路由地址 + + + + + 组件地址 + + + + + 权限标识 + + + + + 应用分类(应用编码) + + + + + 打开方式(字典 0无 1组件 2内链 3外链) + + + + + 是否可见(Y-是,N-否) + + + + + 内链地址 + + + + + 重定向地址 + + + + + 权重(字典 1系统权重 2业务权重) + + + + + 排序 + + + + + 备注 + + + + + 状态(字典 0正常 1停用 2删除) + + + + + 通知公告表 + + + + + 标题 + + + + + 内容 + + + + + 类型(字典 1通知 2公告) + + + + + 发布人Id + + + + + 发布人姓名 + + + + + 发布机构Id + + + + + 发布机构名称 + + + + + 发布时间 + + + + + 撤回时间 + + + + + 状态(字典 0草稿 1发布 2撤回 3删除) + + + + + 通知公告用户表 + + + + + 通知公告Id + + + + + 用户Id + + + + + 阅读时间 + + + + + 状态(字典 0未读 1已读) + + + + + Oauth登录用户表 + + + + + 第三方平台的用户唯一Id + + + + + 用户授权的token + + + + + 昵称 + + + + + 头像 + + + + + 性别 + + + + + 电话 + + + + + 邮箱 + + + + + 位置 + + + + + 用户网址 + + + + + 所在公司 + + + + + 用户来源 + + + + + 用户备注(各平台中的用户个人介绍) + + + + + 在线用户表 + + + + + 连接Id + + + + + 用户Id + + + + + 账号 + + + + + 姓名 + + + + + 最后连接时间 + + + + + 最后登录IP + + + + + 租户id + + + + + 组织机构表 + + + + + 父Id + + + + + 父Ids + + + + + 名称 + + + + + 编码 + + + + + 联系人 + + + + + 电话 + + + + + 排序 + + + + + 备注 + + + + + 状态(字典 0正常 1停用 2删除) + + + + + 职位表 + + + + + 名称 + + + + + 编码 + + + + + 排序 + + + + + 备注 + + + + + 状态(字典 0正常 1停用 2删除) + + + + + 角色表 + + + + + 名称 + + + + + 编码 + + + + + 排序 + + + + + 数据范围类型(字典 1全部数据 2本部门及以下数据 3本部门数据 4仅本人数据 5自定义数据) + + + + + 备注 + + + + + 状态(字典 0正常 1停用 2删除) + + + + + 管理员类型-超级管理员_1、非管理员_2 + + + + + 角色数据范围表 + + + + + 角色Id + + + + + 机构Id + + + + + 角色菜单表 + + + + + 角色Id + + + + + 菜单Id + + + + + 租户表 + + + + + 公司名称 + + + + + 管理员名称 + + + + + 主机 + + + + + 电子邮箱 + + + + + 电话 + + + + + 数据库连接 + + + + + 架构 + + + + + 备注 + + + + + 租户类型 + + + + + 定时任务 + + + + + 任务名称 + + magic + + + + 只执行一次 + + + + + 立即执行(默认等待启动) + + + + + 执行类型(并行、列队) + + + + + 执行间隔时间(单位秒) + + 5 + + + + Cron表达式 + + + + + + 定时器类型 + + + + + 请求url + + + + + 请求参数(Post,Put请求用) + + + + + Headers(可以包含如:Authorization授权认证) + 格式:{"Authorization":"userpassword.."} + + + + + 请求类型 + + 2 + + + + 备注 + + + + + 用户表 + + + + + 账号 + + + + + 密码(默认MD5加密) + + + + + 昵称 + + + + + 姓名 + + + + + 头像 + + + + + 生日 + + + + + 性别-男_1、女_2 + + + + + 邮箱 + + + + + 手机 + + + + + 电话 + + + + + 最后登录IP + + + + + 最后登录时间 + + + + + 管理员类型-超级管理员_1、非管理员_2 + + + + + 状态-正常_0、停用_1、删除_2 + + + + + 用户数据范围表 + + + + + 用户Id + + + + + 机构Id + + + + + 用户角色表 + + + + + 用户Id + + + + + 系统角色Id + + + + + 用户表 + + + + + 账号 + + + + + 密码(默认MD5加密) + + + + + 昵称 + + + + + 姓名 + + + + + 头像 + + + + + 生日 + + + + + 性别-男_1、女_2 + + + + + 邮箱 + + + + + 手机 + + + + + 电话 + + + + + 最后登录IP + + + + + 最后登录时间 + + + + + 管理员类型-超级管理员_1、非管理员_2 + + + + + 状态-正常_0、停用_1、删除_2 + + + + + 账号类型 + + + + + 超级管理员 + + + + + 管理员 + + + + + 普通账号 + + + + + 缓存类型 + + + + + 内存缓存 + + + + + Redis缓存 + + + + + 公共状态 + + + + + 正常 + + + + + 停用 + + + + + 删除 + + + + + 数据操作类型 + + + + + 其它 + + + + + 增加 + + + + + 删除 + + + + + 编辑 + + + + + 更新 + + + + + 查询 + + + + + 详情 + + + + + 树 + + + + + 导入 + + + + + 导出 + + + + + 授权 + + + + + 强退 + + + + + 清空 + + + + + 修改状态 + + + + + 全部数据 + + + + + 本部门及以下数据 + + + + + 本部门数据 + + + + + 仅本人数据 + + + + + 自定义数据 + + + + + 文档类型 + + + + + 文件夹 + + + + + 文件 + + + + + 系统错误码 + + + + + 用户名或密码不正确 + + + + + 非法操作!禁止删除自己 + + + + + 记录不存在 + + + + + 账号已存在 + + + + + 旧密码不匹配 + + + + + 测试数据禁止更改admin密码 + + + + + 数据已存在 + + + + + 数据不存在或含有关联引用,禁止删除 + + + + + 禁止为管理员分配角色 + + + + + 重复数据或记录含有不存在数据 + + + + + 禁止为超级管理员角色分配权限 + + + + + 非法数据 + + + + + Id不能为空 + + + + + 所属机构不在自己的数据范围内 + + + + + 禁止删除超级管理员 + + + + + 禁止修改超级管理员状态 + + + + + 没有权限 + + + + + 账号已冻结 + + + + + 父机构不存在 + + + + + 当前机构Id不能与父机构Id相同 + + + + + 已有相同组织机构,编码或名称相同 + + + + + 没有权限操作机构 + + + + + 该机构下有员工禁止删除 + + + + + 附属机构下有员工禁止删除 + + + + + 只能增加下级机构 + + + + + 字典类型不存在 + + + + + 字典类型已存在 + + + + + 字典类型下面有字典值禁止删除 + + + + + 字典值已存在 + + + + + 字典值不存在 + + + + + 字典状态错误 + + + + + 菜单已存在 + + + + + 路由地址为空 + + + + + 打开方式为空 + + + + + 权限标识格式为空 + + + + + 权限标识格式错误 + + + + + 权限不存在 + + + + + 父级菜单不能为当前节点,请重新选择父级菜单 + + + + + 不能移动根节点 + + + + + 已存在同名或同编码应用 + + + + + 默认激活系统只能有一个 + + + + + 该应用下有菜单禁止删除 + + + + + 已存在同名或同编码应用 + + + + + 已存在同名或同编码职位 + + + + + 该职位下有员工禁止删除 + + + + + 通知公告状态错误 + + + + + 通知公告删除失败 + + + + + 通知公告编辑失败 + + + + + 文件不存在 + + + + + 已存在同名或同编码参数配置 + + + + + 禁止删除系统参数 + + + + + 已存在同名任务调度 + + + + + 任务调度不存在 + + + + + 演示环境禁止修改数据 + + + + + 已存在同名或同主机租户 + + + + + 该表代码模板已经生成过 + + + + + 该类型不存在 + + + + + 该字段不存在 + + + + + 该类型不是枚举类型 + + + + + 该实体不存在 + + + + + 父菜单不存在 + + + + + 已存在同名或同编码项目 + + + + + 已存在相同证件号码人员 + + + + + 检测数据不存在 + + + + + 表单不存在 + + + + + 文件扩展枚举 + + + + + 文件存储位置 + + + + + 阿里云 + + + + + 腾讯云 + + + + + minio服务器 + + + + + 本地 + + + + + 用户 + + + + + 组织 + + + + + 性别 + + + + + 男 + + + + + 女 + + + + + 未知 + + + + + HTTP状态码 + + + + + 客户端可能继续其请求 + + + + + 正在更改协议版本或协议 + + + + + 请求成功,且请求的信息包含在响应中 + + + + + 请求导致在响应被发送前创建新资源 + + + + + 请求已被接受做进一步处理 + + + + + 返回的元信息来自缓存副本而不是原始服务器,因此可能不正确 + + + + + 已成功处理请求并且响应已被设定为无内容 + + + + + 客户端应重置(或重新加载)当前资源 + + + + + 响应是包括字节范围的 GET请求所请求的部分响应 + + + + + 请求的信息有多种表示形式,默认操作是将此状态视为重定向 + + + + + 请求的信息已移到 Location头中指定的 URI 处 + + + + + 请求的信息位于 Location 头中指定的 URI 处 + + + + + 将客户端自动重定向到 Location 头中指定的 URI + + + + + 客户端的缓存副本是最新的 + + + + + 请求应使用位于 Location 头中指定的 URI 的代理服务器 + + + + + 服务器未能识别请求 + + + + + 请求的资源要求身份验证 + + + + + 需要付费 + + + + + 服务器拒绝满足请求 + + + + + 请求的资源不在服务器上 + + + + + 请求的资源上不允许请求方法(POST或 GET) + + + + + 客户端已用 Accept 头指示将不接受资源的任何可用表示形式 + + + + + 请求的代理要求身份验证 + Proxy-authenticate 头包含如何执行身份验证的详细信息 + + + + + 客户端没有在服务器期望请求的时间内发送请求 + + + + + 由于服务器上的冲突而未能执行请求 + + + + + 请求的资源不再可用 + + + + + 缺少必需的 Content-length + + + + + 为此请求设置的条件失败,且无法执行此请求 + 条件是用条件请求标头(如 If-Match、If-None-Match 或 If-Unmodified-Since)设置的。 + + + + + 请求太大,服务器无法处理 + + + + + URI 太长 + + + + + 请求是不支持的类型 + + + + + 无法返回从资源请求的数据范围,因为范围的开头在资源的开头之前,或因为范围的结尾在资源的结尾之后 + + + + + 服务器未能符合Expect头中给定的预期值 + + + + + 服务器拒绝处理客户端使用当前协议发送的请求,但是可以接受其使用升级后的协议发送的请求 + + + + + 服务器上发生了一般错误 + + + + + 服务器不支持请求的函数 + + + + + 中间代理服务器从另一代理或原始服务器接收到错误响应 + + + + + 服务器暂时不可用,通常是由于过多加载或维护 + + + + + 中间代理服务器在等待来自另一个代理或原始服务器的响应时已超时 + + + + + 服务器不支持请求的HTTP版本 + + + + + 登陆类型 + + + + + 登陆 + + + + + 登出 + + + + + 注册 + + + + + 改密 + + + + + 三方授权登陆 + + + + + 系统菜单类型 + + + + + 无 + + + + + 组件 + + + + + 内链 + + + + + 外链 + + + + + 系统菜单类型 + + + + + 目录 + + + + + 菜单 + + + + + 按钮 + + + + + 菜单权重 + + + + + 系统权重 + + + + + 业务权重 + + + + + 通知公告状态 + + + + + 草稿 + + + + + 发布 + + + + + 撤回 + + + + + 删除 + + + + + 通知 + + + + + 公告 + + + + + 通知公告用户状态 + + + + + 未读 + + + + + 已读 + + + + + 查询类型的枚举 + + + + + 等于 + + + + + 模糊 + + + + + 大于 + + + + + 小于 + + + + + 不等于 + + + + + 大于等于 + + + + + 小于等于 + + + + + 不为空 + + + + + http请求类型 + + + + + 执行内部方法 + + + + + GET请求 + + + + + POST请求 + + + + + PUT请求 + + + + + DELETE请求 + + + + + 账号类型 + + + + + 租户管理员角色 + + + + + 租户普通角色 + + + + + 菜单激活类型 + + + + + 是 + + + + + 否 + + + + + B格 + + + + + 数据过滤,默认用户集合 + + ISugarQueryable + 目标表的parameter + 默认用户集合 + 需要过滤的用户id字段,默认CreatedUserId和OrgId + + + + + 检查数据权限,默认用户集合 + + 检测的id + 默认用户集合 + + + + 获取当前数据权限,默认用户集合 + + 默认用户集合 + + + + + 字典扩展 + + + + + 将一个字典转化为 QueryString + + + + + + + + 将一个字符串 URL 编码 + + + + + + + 移除空值项 + + + + + + 枚举扩展 + + + + + 获取枚举对象Key与名称的字典(缓存) + + + + + + + 获取枚举对象Key与名称的字典 + + + + + + + 获取枚举类型key与描述的字典(缓存) + + + + + + + + 获取枚举类型key与描述的字典(没有描述则获取name) + + + + + + + + 从程序集中查找指定枚举类型 + + + + + + + + 从程序集中加载所有枚举类型 + + + + + + + 通用输入扩展参数(带权限) + + + + + 授权菜单 + + + + + 授权角色 + + + + + 授权数据 + + + + + 通用分页输入参数 + + + + + 搜索值 + + + + + 当前页码 + + + + + 页码容量 + + + + + 搜索开始时间 + + + + + 搜索结束时间 + + + + + 排序字段 + + + + + 排序方法,默认升序,否则降序(配合antd前端,约定参数为 Ascend,Dscend) + + + + + 降序排序(不要问我为什么是descend不是desc,前端约定参数就是这样) + + + + + 分页拓展类 + + + + + 分页拓展 + + + + + + + + + 通用输入帮助类 + + + + + 排序方式(默认降序) + + + 是否降序 + + + + + 小诺分页列表结果 + + + + + 替换sqlsugar分页 + + + + + + + 规范化RESTful风格返回值 + + + + + RESTful风格---XIAONUO返回格式 + + + + + + 执行成功 + + + + + 状态码 + + + + + 错误信息 + + + + + 数据 + + + + + 附加数据 + + + + + 时间戳 + + + + + 全局异常处理 + + + + + 请求日志拦截 + + + + + SqlSugar 工作单元拦截器 + + + + + 过滤器排序 + + + + + 排序属性 + + + + + SqlSugar 对象 + + + + + 构造函数 + + + + + + + + + + + + + + 聊天集线器 + + + + + 连接 + + + + + + 断开 + + + + + + + 日志定时任务类 + + + + + 定期删除异常日志 + + + + + + + 定期删除操作日志 + + + + + + + 定期删除访问日志 + + + + + + + 后台批量写错误日志 + + + + + + + 后台批量写操作日志 + + + + + + + 后台批量写访问日志 + + + + + + + 写日志 + + + + + + + + + + 根据条件删除日志 + + + + + + + Long 类型Json返回处理 + + + + Reads and converts the JSON to type . + The reader. + The type to convert. + An object that specifies serialization options to use. + The converted value. + + + Writes a specified value as JSON. + The writer to write to. + The value to convert to JSON. + An object that specifies serialization options to use. + + + + 日志写入文件的组件 + + + + + 日志写入文件扩展 + + + + + 添加workerservice项目控制台日志格式化扩展 + + + + + + + 添加api项目控制台日志格式化扩展 + + + + + + + 用户管理 + + + + + 用户id + + + + + 账号 + + + + + 昵称 + + + + + 是否超级管理员 + + + + + 是否租户管理员 + + + + + AccessToken参数 + + + + + 用户标识 + + + + + Token 类型 + + + + + AccessToken + + + + + 用于刷新 AccessToken 的 Token + + + + + 此 AccessToken 对应的权限 + + + + + AccessToken 过期时间 + + + + + 错误的详细描述 + + + + + 获取的Token是否包含错误 + + + + + + + 微信用户参数 + + + + + 用户特权信息,json 数组,如微信沃卡用户为(chinaunicom) + + + + + 获取的用户是否包含错误 + + + + + + + 发起授权 + + + + + + + 获取微信Token + + + + + + + + 获取微信用户基本信息 + + + + + + + + 刷新微信Token + + + + + + + 系统应用参数 + + + + + 名称 + + + + + 编码 + + + + + 是否默认激活(Y-是,N-否),只能有一个系统默认激活 + 用户登录后默认展示此系统菜单 + + + + + 状态(字典 0正常 1停用 2删除) + + + + + 排序 + + + + + 名称 + + + + + 编码 + + + + + 应用Id + + + + + 应用Id + + + + + 系统应用参数 + + + + + 应用Id + + + + + 名称 + + + + + 编码 + + + + + 是否默认 + + + + + 排序 + + + + + 系统应用服务 + + + + + 获取用户应用相关信息 + + + + + + + 分页查询系统应用 + + + + + + + 增加系统应用 + + + + + + + 删除系统应用 + + + + + + + 更新系统应用 + + + + + + + 获取系统应用 + + + + + + + 获取系统应用列表 + + + + + + + 设为默认应用 + + + + + + + 修改用户状态 + + + + + + + 登录授权相关服务 + + + + + 用户登录 + + + 默认用户名/密码:admin/admin + + + + + 模拟租户登录 + + + 默认用户名/密码:admin/admin + + + + + 获取当前登录用户信息 + + + + + + 退出 + + + + + + 获取验证码开关 + + + + + + 获取验证码(默认点选模式) + + + + + + 校验验证码 + + + + + + + 登录输入参数 + + + + + 租户id + + superAdmin + + + + 用户名 + + superAdmin + + + + 密码 + + 123456 + + + + 用户登录输出参数 + + + + + 主键 + + + + + 账号 + + + + + 昵称 + + + + + 姓名 + + + + + 头像 + + + + + 生日 + + + + + 性别(字典 1男 2女) + + + + + 邮箱 + + + + + 手机 + + + + + 电话 + + + + + 管理员类型(0超级管理员 1非管理员) + + + + + 最后登陆IP + + + + + 最后登陆时间 + + + + + 最后登陆地址 + + + + + 最后登陆所用浏览器 + + + + + 最后登陆所用系统 + + + + + 员工信息 + + + + + 具备应用信息 + + + + + 角色信息 + + + + + 权限信息 + + + + + 登录菜单信息---AntDesign版本菜单 + + + + + 数据范围(机构)信息 + + + + + 注册输入参数 + + + + + 用户名 + + superAdmin + + + + 公司名 + + superAdmin + + + + 密码 + + 123456 + + + + 系统缓存服务 + + + + + 获取数据范围缓存(机构Id集合) + + + + + + + 获取数据范围缓存(用户Id集合) + + + + + + + 缓存数据范围(机构Id集合) + + + + + + + + 缓存数据范围(用户Id集合) + + + + + + + + 获取菜单缓存 + + + + + + + + 缓存菜单 + + + + + + + + + 获取权限缓存(按钮) + + + + + + + 缓存权限 + + + + + + + + 获取所有缓存关键字 + + + + + + 获取所有按钮权限 + + + + + + 设置所有按钮权限 + + + + + + + 删除指定关键字缓存 + + + + + + + 删除指定关键字缓存 + + + + + + + 删除某特征关键字缓存 + + + + + + + 设置缓存 + + + + + + + + 设置缓存 + + + + + + + + 获取缓存 + + + + + + + 获取缓存 + + + + + + + 获取缓存 + + + + + + + + 获取缓存 + + + + + + + + 检查给定 key 是否存在 + + 键 + + + + + 检查给定 key 是否存在 + + 键 + + + + + 代码生成详细配置服务 + + + + + 代码生成详细配置列表 + + + + + + + 增加 + + + + + + + 删除 + + + + + + + 更新 + + + + + + + 详情 + + + + + + + 批量增加 + + + + + + + 代码生成器服务 + + + + + 分页查询 + + + + + + + 增加 + + + + + + + 删除 + + + + + + + 更新 + + + + + + + 详情 + + + + + + + 获取数据库表(实体)集合 + + + + + + 根据表名获取列 + + + + + + 获取数据表列(实体属性)集合 + + + + + + 代码生成_本地项目 + + + + + + 获取模板文件路径集合 + + + + + + 设置生成文件路径 + + + + + + + 代码生成详细配置参数 + + + + + 主键Id + + + + + 代码生成主表ID + + + + + 数据库字段名 + + + + + 数据库字段名(首字母小写) + + + + + 字段描述 + + + + + .NET类型 + + + + + 作用类型(字典) + + + + + 外键实体名称 + + + + + 外键实体名称(首字母小写) + + + + + 外键显示字段 + + + + + 外键显示字段(首字母小写) + + + + + 外键显示字段.NET类型 + + + + + 字典code + + + + + 列表是否缩进(字典) + + + + + 是否必填(字典) + + + + + 是否是查询条件 + + + + + 查询方式 + + + + + 列表显示 + + + + + 增改 + + + + + 主外键 + + + + + 数据库中类型(物理类型) + + + + + 是否是通用字段 + + + + + 代码生成参数类 + + + + + 作者姓名 + + + + + 类名 + + + + + 是否移除表前缀 + + + + + 生成方式 + + + + + 数据库表名 + + + + + 命名空间 + + + + + 业务名(业务代码包名称) + + + + + 功能名(数据库表名称) + + + + + 菜单应用分类(应用编码) + + + + + 菜单父级 + + + + + 数据库表名 + + + + + 业务名(业务代码包名称) + + + + + 命名空间 + + + + + 作者姓名 + + + + + 生成方式 + + + + + 菜单应用分类(应用编码) + + + + + 菜单父级 + + + + + 代码生成器Id + + + + + 代码生成器Id + + + + + 代码生成参数类 + + + + + 代码生成器Id + + + + + 作者姓名 + + + + + 类名 + + + + + 是否移除表前缀 + + + + + 生成方式 + + + + + 数据库表名 + + + + + 包名 + + + + + 业务名(业务代码包名称) + + + + + 功能名(数据库表名称) + + + + + 菜单应用分类(应用编码) + + + + + 菜单父级 + + + + + 数据库表列 + + + + + 字段名 + + + + + 数据库中类型 + + + + + .NET字段类型 + + + + + 字段描述 + + + + + 主外键 + + + + + 数据库表列表参数 + + + + + 表名(字母形式的) + + + + + 实体名称 + + + + + 创建时间 + + + + + 更新时间 + + + + + 表名称描述(注释)(功能名) + + + + + 作者姓名 + + + + + 是否移除表前缀 + + + + + 生成方式 + + + + + 数据库表名 + + + + + 数据库表名(经过组装的) + + + + + 代码包名 + + + + + 生成时间(string类型的) + + + + + 数据库表中字段集合 + + + + + 业务名 + + + + + 获取库表信息 + + + + + + + 参数配置 + + + + + 名称 + + + + + 编码 + + + + + 属性值 + + + + + 是否是系统参数(Y-是,N-否) + + + + + 备注 + + + + + 状态(字典 0正常 1停用 2删除) + + + + + 常量所属分类的编码,来自于“常量的分类”字典 + + + + + 名称 + + + + + 编码 + + + + + 应用Id + + + + + 应用Id + + + + + 系统参数配置服务 + + + + + 分页获取系统参数配置 + + + + + + + 获取系统参数配置列表 + + + + + + + 增加系统参数配置 + + + + + + + 删除系统参数配置 + + + + + + + 更新系统参数配置 + + + + + + + 获取系统参数配置 + + + + + + + 获取配置信息 + + + + + + + 更新配置缓存 + + + + + + + + 获取演示环境开关是否开启,默认为false + + + + + + 获取验证码开关标识 + + + + + + 获取默认密码 + + + + + + 数据库管理 + + + + + 添加列 + + + + + + 删除列 + + + + + + 编辑列 + + + + + + 获取表字段 + + + + + + + 获取所有表 + + + + + + 新增表 + + + + + + 删除表 + + + + + + 编辑表 + + + + + + 生成实体 + + + + + + 获取模板文件路径集合 + + + + + + 设置生成文件路径 + + + + + + + + + student + + + + + + Student + + + + + + AutoIncrementEntity + + + + + + Magic.Application + + + + 字典值参数 + + + + + 字典类型Id + + + + + 值 + + + + + 编码 + + + + + 排序 + + + + + 备注 + + + + + 状态(字典 0正常 1停用 2删除) + + + + + 字典类型Id + + + + + 字典类型Id + + + + + 值 + + + + + 编码 + + + + + 字典值Id + + + + + 字典值Id + + + + + 字典值参数 + + + + + 字典Id + + + + + 字典类型与字典值构造的树 + + + + + Id + + + + + 父Id + + + + + 编码-对应字典值的编码 + + + + + 名称-对应字典值的value + + + + + 子节点集合 + + + + + 字典类型参数 + + + + + 名称 + + + + + 编码 + + + + + 排序 + + + + + 备注 + + + + + 状态(字典 0正常 1停用 2删除) + + + + + 名称 + + + + + 编码 + + + + + 编号Id + + + + + Id + + + + + 编码 + + + + + 字典值服务 + + + + + 分页查询字典值 + + + + + + + 获取某个字典类型下字典值列表 + + + + + + 增加字典值 + + + + + + + 删除字典值 + + + + + + + 更新字典值 + + + + + + + 字典值详情 + + + + + + + 修改字典值状态 + + + + + + + 根据字典类型Id获取字典值集合 + + + + + + + 删除字典下所有值 + + + + + + 根据字典Code返回字典值列表 + + + + + + + 字典类型服务 + + + + + 分页查询字典类型 + + + + + + 获取字典类型列表 + + + + + + 获取字典类型下所有字典值 + + + + + + + 添加字典类型 + + + + + + + 删除字典类型 + + + + + + + 更新字典类型 + + + + + + + 字典类型详情 + + + + + + + 更新字典类型状态 + + + + + + + 字典类型与字典值构造的字典树 + + + + + + 文档服务 + + + + + 分页查询文档 + + + + + + + 文件夹树 + + + + + + 上传文件 + + + + + + + 上传文件夹 + + + + + + + 新建文件夹 + + + + + + + 删除文档 + + + + + + + 批量删除 + + + + + + + 移动文档 + + + + + + + 更新文件夹 + + + + + + + 获取文档 + + + + + + + 下载文件 + + + + + + + 预览文件 + + + + + + + 创建Pids格式 + 如果pid是0顶级节点,pids就是 [0]; + 如果pid不是顶级节点,pids就是 pid文档的 pids + [pid] + , + + + + + + + 获取文件大小 + + + + + + + 上传文件 + + + + + + + + 获取父级 + + + + + + + 文档输出参数 + + + + + Id + + + + + 父Id + + + + + 名称 + + + + + 文档类型:文件、文件夹 + + + + + 文件后缀 + + + + + 文件大小kb + + + + + 标签 + + + + + 备注 + + + + + 文档输入参数 + + + + + 父Id + + + + + 父ID列表 + + + + + 名称 + + + + + 文档类型:文件、文件夹 + + + + + 文件后缀 + + + + + 文件大小kb + + + + + 存储后的文件名 + + + + + 标签 + + + + + 备注 + + + + + 创建开始时间 + + + + + 创建结束时间 + + + + + 修改结束时间 + + + + + 修改结束时间 + + + + + 文件类型 + + + + + 是否删除 + + + + + 上传文件输入参数 + + + + + Id + + + + + 批量删除入参 + + + + + Id列表 + + + + + 移动入参 + + + + + Id列表 + + + + + 父Id + + + + + Id + + + + + 文档输出参数 + + + + + Id + + + + + 父Id + + + + + 名称 + + + + + 文档类型:文件、文件夹 + + + + + 文件类型 + + + + + 文件后缀 + + + + + 文件大小kb + + + + + 文件大小kb + + + + + 标签 + + + + + 标签数组 + + + + + 备注 + + + + + 创建时间 + + + + + 更新时间 + + + + + 创建用户ID + + + + + 创建人用户名 + + + + + 修改人ID + + + + + 修改人用户名 + + + + + 树查询输出 + + + + + Id + + + + + 父Id + + + + + 名称 + + + + + 附属机构和职位参数 + + + + + 员工Id + + + + + 附属机构id + + + + + 附属机构编码 + + + + + 附属机构名称 + + + + + 附属职位id + + + + + 附属职位编码 + + + + + 附属职位名称 + + + + + 员工信息参数 + + + + + 员工Id + + + + + 工号 + + + + + 机构id + + + + + 机构名称 + + + + + 机构与职位信息 + + + + + 职位信息 + + + + + 员工信息参数2 + + + + + 员工Id + + + + + 工号 + + + + + 机构Id + + + + + 机构名称 + + + + + 附属机构 + + + + + 职位集合 + + + + + 员工职位参数 + + + + + 员工Id + + + + + 职位Id + + + + + 职位编码 + + + + + 职位名称 + + + + + 员工附属机构和职位服务 + + + + + 保存或编辑附属机构相关信息 + + + + + + 获取附属机构和职位信息 + + + + + + + 根据机构Id判断该附属机构下是否有员工 + + + + + + + 根据职位Id判断该附属职位下是否有员工 + + + + + + + 根据员工Id删除对应的员工-附属信息 + + + + + + + 员工职位服务 + + + + + 增加或编辑员工职位相关信息 + + 员工Id(用户Id) + 职位id集合 + + + + + 获取所属职位信息 + + 员工Id(用户Id) + + + + 根据职位Id判断该职位下是否有员工 + + + + + + + 根据员工Id删除对用的员工-职位信息 + + + + + + + 员工服务 + + + + + 获取用户员工相关信息(包括登录) + + + + + + + 获取用户员工相关信息 + + + + + + + 增加或编辑员工相关信息 + + + + + + 修改员工相关机构信息 + + + + + + + + 根据机构Id判断该机构下是否有员工 + + + + + + + 根据员工Id删除对应的员工表信息 + + + + + + + 获取员工机构Id + + + + + + + 获取子机构用户 + + + + + + + 枚举输入参数 + + + + + 枚举类型名称 + + Gender + + + + 实体名称 + + + + + 字段名称 + + + + + 枚举输出参数 + + + + + 字典Id + + + + + 字典值 + + + + + 枚举值服务 + + + + + 获取所有枚举值 + + + + + + 通过枚举类型获取枚举值集合 + + + + + + + 通过实体字段类型获取相关集合(目前仅支持枚举类型) + + + + + + + 上传文件参数 + + + + + 文件存储位置(1:阿里云,2:腾讯云,3:minio,4:本地) + + + + + 文件仓库 + + + + + 文件名称(上传时候的文件名) + + + + + 文件后缀 + + + + + 文件大小kb + + + + + 文件大小信息,计算后的 + + + + + 存储到bucket的名称(文件唯一标识id) + + + + + 存储路径 + + + + + 文件Id + + + + + 上传文件参数 + + + + + 文件Id + + + + + 文件服务 + + + + + 分页获取文件列表 + + + + + + + 获取文件列表 + + + + + + + 删除文件 + + + + + + + 获取文件详情 + + + + + + + 预览文件 + + + + + + + 上传文件 + + + + + + + 下载文件 + + + + + + + 上传头像 + + + + + + + 上传文档 + + + + + + + 上传富文本图片 + + + + + + + 上传商店图片 + + + + + + + 上传文件 + + + + + + + + 上传文件 + + 文件 + 存储路径 + 文件存储位置 + + + + + 异常日志参数 + + + + + 操作人 + + + + + 名称 + + + + + 类名 + + + + + 方法名 + + + + + 异常名称 + + + + + 异常信息 + + + + + 异常时间 + + + + + 异常日志参数 + + + + + 请求日志参数 + + + + + 名称 + + + + + 是否执行成功(Y-是,N-否) + + + + + 具体消息 + + + + + ip + + + + + 地址 + + + + + 浏览器 + + + + + 操作系统 + + + + + 请求地址 + + + + + 类名称 + + + + + 方法名称 + + + + + 请求方式(GET POST PUT DELETE) + + + + + 请求参数 + + + + + 返回结果 + + + + + 耗时(毫秒) + + + + + 操作时间 + + + + + 操作人 + + + + + 请求日志参数 + + + + + 访问日志参数 + + + + + 名称 + + + + + 是否执行成功(Y-是,N-否) + + + + + 具体消息 + + + + + IP + + + + + 地址 + + + + + 浏览器 + + + + + 操作系统 + + + + + 访问类型 + + + + + 访问时间 + + + + + 访问人 + + + + + 访问日志参数 + + + + + 异常日志服务 + + + + + 分页查询异常日志 + + + + + + + 清空异常日志 + + + + + + 操作日志服务 + + + + + 分页查询操作日志 + + + + + + + 清空操作日志 + + + + + + 访问日志服务 + + + + + 分页查询访问日志 + + + + + + + 清空访问日志 + + + + + + 登录菜单-AntDesign菜单类型 + + + + + 所属应用 + + + + + id + + + + + 父id + + + + + 路由名称, 必须设置,且不能重名 + + + + + 组件 + + + + + 重定向地址, 访问这个路由时, 自定进行重定向 + + + + + 路由元信息(路由附带扩展信息) + + + + + 路径 + + + + + 控制路由和子路由是否显示在 sidebar + + + + + 路由元信息内部类 + + + + + 路由标题, 用于显示面包屑, 页面标题 *推荐设置 + + + + + 图标 + + + + + 是否可见 + + + + + 如需外部打开,增加:_blank + + + + + 内链打开http链接 + + + + + 菜单参数 + + + + + 父Id + + + + + 名称 + + + + + 编码 + + + + + 菜单类型(字典 0目录 1菜单 2按钮) + + + + + 图标 + + + + + 路由地址 + + + + + 组件地址 + + + + + 权限标识 + + + + + 应用分类(应用编码) + + + + + 打开方式(字典 0无 1组件 2内链 3外链) + + + + + 是否可见(Y-是,N-否) + + + + + 内链地址 + + + + + 重定向地址 + + + + + 权重(字典 1系统权重 2业务权重) + + + + + 排序 + + + + + 备注 + + + + + 菜单类型(字典 0目录 1菜单 2按钮) + + + + + 菜单Id + + + + + 菜单Id + + + + + 父Id + DeleteMenuInput + + + + 应用编码 + DeleteMenuInput + + + + 菜单树(列表形式) + + + + + 菜单Id + + + + + 子节点 + + + + + 应用名称 + + + + + 应用编码 + + + + + 菜单树---授权、新增编辑时选择 + + + + + 主键 + + + + + 父Id + + + + + 名称 + + + + + 值 + + + + + 排序,越小优先级越高 + + + + + 子节点 + + + + + 应用名称 + + + + + 应用编码 + + + + + 引用排序 + + + + + 应用编码 + + + + + 菜单Id集合 + + + + + 系统菜单服务 + + + + + 获取用户权限(按钮权限标识集合) + + + + + + + 获取所有权限集合 + + + + + + 获取用户AntDesign菜单集合 + + + + + + + + 获取用户菜单所属的应用编码集合 + + + + + + + 系统菜单列表(树表) + + + + + + + 创建Pids格式 + 如果pid是0顶级节点,pids就是 [0]; + 如果pid不是顶级节点,pids就是 pid菜单的 pids + [pid] + , + + + + + + + 增加和编辑时检查参数 + + + + + + 增加系统菜单 + + + + + + + 删除系统菜单 + + + + + + + 更新系统菜单 + + + + + + + 获取系统菜单 + + + + + + + 获取系统菜单树,用于新增、编辑时选择上级节点 + + + + + + + 获取系统菜单树,用于给角色授权时选择 + + + + + + + 根据应用编码判断该机构下是否有状态为正常的菜单 + + + + + + + 根据系统应用切换菜单 + + + + + + + 服务器信息服务 + + + + + 获取服务器资源信息 + + + + + + 获取服务器基本参数 + + + + + + 动态获取网络信息 + + + + + + 通知公告参数 + + + + + 标题 + + + + + 内容 + + + + + 类型(字典 1通知 2公告) + + + + + 发布人Id + + + + + 发布人姓名 + + + + + 发布机构Id + + + + + 发布机构名称 + + + + + 发布时间 + + + + + 撤回时间 + + + + + 状态(字典 0草稿 1发布 2撤回 3删除) + + + + + 系统通知公告详情参数 + + + + + 通知到的用户Id集合 + + + + + 通知到的用户阅读信息集合 + + + + + 用户Id + + + + + 用户名称 + + + + + 状态(字典 0未读 1已读) + + + + + 阅读时间 + + + + + 通知公告参数 + + + + + 标题 + + + + + 内容 + + + + + 类型(字典 1通知 2公告) + + + + + 状态(字典 0草稿 1发布 2撤回 3删除) + + + + + 通知到的人 + + + + + 标题 + + + + + 内容 + + + + + 类型(字典 1通知 2公告) + + + + + 状态(字典 0草稿 1发布 2撤回 3删除) + + + + + 通知到的人 + + + + + Id + + + + + Id + + + + + 状态(字典 0草稿 1发布 2撤回 3删除) + + + + + 通知公告接收参数 + + + + + Id + + + + + 阅读状态(字典 0未读 1已读) + + + + + 阅读时间 + + + + + 通知公告服务 + + + + + 分页查询通知公告 + + + + + + + 增加通知公告 + + + + + + + 删除通知公告 + + + + + + + 更新通知公告 + + + + + + + 获取通知公告详情 + + + + + + + 修改通知公告状态 + + + + + + + 获取接收的通知公告 + + + + + + + 未处理消息 + + + + + + + 更新发布信息 + + + + + + 通知公告用户 + + + + + 增加 + + + + + + + + + 更新 + + + + + + + + + 获取通知公告用户列表 + + + + + + + 设置通知公告读取状态 + + + + + + + + + OAuth服务 + + + + + 微信登录授权 + + + + + 微信登录授权回调 + + + + + + + + + 获取微信用户基本信息 + + + + + + + + 在线用户服务 + + + + + 获取在线用户信息 + + + + + + 组织机构参数 + + + + + 父Id + + + + + 父Ids + + + + + 名称 + + + + + 编码 + + + + + 电话 + + + + + 排序 + + + + + 备注 + + + + + 状态(字典 0正常 1停用 2删除) + + + + + 名称 + + + + + 编码 + + + + + 机构Id + + + + + 机构Id + + + + + 组织机构参数 + + + + + 机构Id + + + + + 组织机构树 + + + + + Id + + + + + 父Id + + + + + 名称 + + + + + 值 + + + + + 排序,越小优先级越高 + + + + + 子节点 + + + + + 上一级Id + + + + + 组织机构服务 + + + + + 分页查询组织机构 + + + + + + + (非管理员)获取当前用户数据范围(机构Id) + + + + + + + 获取组织机构列表 + + + + + + + 增加组织机构 + + + + + + + 填充父Ids字段 + + + + + + + 删除组织机构 + + + + + + + 更新组织机构 + + + + + + + 获取组织机构信息 + + + + + + + 根据节点Id获取所有子节点Id集合,包含自己 + + + + + + + 获取组织机构树 + + + + + + 根据数据范围类型获取当前用户的数据范围(机构Id)集合 + + + + + + + + 获取所有的机构组织Id集合 + + + + + + 职位参数 + + + + + 名称 + + + + + 编码 + + + + + 排序 + + + + + 备注 + + + + + 状态(字典 0正常 1停用 2删除) + + + + + 当前页码 + + + + + 页码容量 + + + + + 名称 + + + + + 编码 + + + + + 职位Id + + + + + 职位Id + + + + + 职位服务 + + + + + 分页获取职位 + + + + + + + 获取职位列表 + + + + + + 增加职位 + + + + + + + 删除职位 + + + + + + + 更新职位 + + + + + + + 获取职位 + + + + + + + 角色参数 + + + + + 名称 + + + + + 编码 + + + + + 排序 + + + + + 数据范围类型(字典 1全部数据 2本部门及以下数据 3本部门数据 4仅本人数据 5自定义数据) + + + + + 备注 + + + + + 名称 + + + + + 编码 + + + + + 角色Id + + + + + 角色Id + + + + + 角色Id + + + + + 登录用户角色参数 + + + + + Id + + + + + 编码 + + + + + 名称 + + + + + 角色数据范围服务 + + + + + 授权角色数据范围 + + + + + + + 根据角色Id集合获取角色数据范围集合 + + + + + + + 根据机构Id集合删除对应的角色-数据范围关联信息 + + + + + + + 根据角色Id删除对应的角色-数据范围关联信息 + + + + + + + 角色菜单 + + + + + 获取角色的菜单Id集合 + + + + + + + 授权角色菜单 + + + + + + + 根据菜单Id集合删除对应的角色-菜单表信息 + + + + + + + 根据角色Id删除对应的角色-菜单表关联信息 + + + + + + + 清理租户下角色的权限 + + 租户id + 租户管理员的角色id + + + + + 角色服务 + + + + + 获取用户角色相关信息(登录) + + + + + + + 分页获取角色列表 + + + + + + + 获取角色列表 + + + + + + + 角色下拉(用于授权角色时选择) + + + + + + 增加角色 + + + + + + + 删除角色 + + + + + + + 更新角色 + + + + + + + 获取角色 + + + + + + + 授权角色菜单 + + + + + + + 授权角色数据范围 + + + + + + + 根据角色Id集合获取数据范围Id集合 + + + + + + + + 根据角色Id获取角色名称 + + + + + + + 获取角色拥有菜单Id集合 + + + + + + + 获取角色拥有数据Id集合 + + + + + + + 租户参数 + + + + + 公司名称 + + + + + 管理员名称 + + + + + 主机 + + + + + 电子邮箱 + + + + + 电话号码 + + + + + 模式 + + + + + 数据库连接 + + + + + 备注 + + + + + 创建时间 + + + + + 公司名称 + + + + + 管理员名称 + + + + + 主机名称 + + + + + 数据库连接 + + + + + 电子邮箱 + + + + + 租户Id + + + + + 租户Id + + + + + 租户参数 + + + + + 租户Id + + + + + 名称 + + + + + 名称 + + + + + 主机 + + + + + 电子邮箱 + + + + + 电话号码 + + + + + 模式 + + + + + 数据库连接 + + + + + 备注 + + + + + 创建时间 + + + + + 租户服务 + + + + + 分页查询租户 + + + + + + + 增加租户 + + + + + + + 新增租户时,初始化数据 + + + + + + 删除租户 + + + + + + + 更新租户 + + + + + + + 获取租户 + + + + + + + 授权租户管理员角色菜单 + + + + + + + 获取租户管理员角色拥有菜单Id集合 + + + + + + + 重置租户管理员密码 + + + + + + + 获取租户管理员用户 + + + + + + + 任务调度参数 + + + + + 任务名称 + + + + + 只执行一次 + + + + + 立即执行(默认等待启动) + + + + + 执行类型(并行、列队) + + + + + 执行间隔时间(单位秒) + + 5 + + + + Cron表达式 + + + + + 定时器类型 + + + + + 请求url + + + + + 请求参数(Post,Put请求用) + + + + + Headers(可以包含如:Authorization授权认证) + 格式:{"Authorization":"userpassword.."} + + + + + 请求类型 + + + + + 备注 + + + + + 任务Id + + + + + 任务信息---任务详情 + + + + + Id + + + + + 已执行次数 + + + + + 定时器状态 + + + + + 异常信息 + + + + + 本地任务信息 + + + + + 任务名称 + + + + + 只执行一次 + + + + + 立即执行(默认等待启动) + + + + + 执行类型(并行、列队) + + + + + 执行间隔时间(单位秒) + + + + + Cron表达式 + + + + + 定时器类型 + + + + + 请求url + + + + + 请求类型 + + 2 + + + + 备注 + + + + + 任务方法信息 + + + + + 方法名 + + + + + 方法所属类的Type对象 + + + + + 任务调度服务 + + + + + 分页获取任务列表 + + + + + + + 获取所有本地任务 + + + + + + 增加任务 + + + + + + + 删除任务 + + + + + + + 修改任务 + + + + + + + 查看任务 + + + + + + + 停止任务 + + + + + + + 启动任务 + + + + + + + 新增定时任务 + + + + + + 启动自启动任务 + + + + + 获取所有本地任务 + + + + + + 回收站输出参数 + + + + + Id + + + + + 父Id + + + + + 父ID列表 + + + + + 名称 + + + + + 类型 + + + + + 文件后缀 + + + + + 文件大小kb + + + + + 存储后的文件名 + + + + + 标签 + + + + + 备注 + + + + + 回收站输出参数 + + + + + Id + + + + + 父Id + + + + + 父ID列表 + + + + + 名称 + + + + + 类型 + + + + + 文件后缀 + + + + + 文件大小kb + + + + + 存储后的文件名 + + + + + 标签 + + + + + 备注 + + + + + 回收站服务 + + + + + 分页查询回收站 + + + + + + + 恢复一个 + + + + + + + 恢复多个 + + + + + + + 永久删除 + + + + + + + 批量删除 + + + + + + + 清空 + + + + + + 重命名 + + + + + + + + AuthToken参数 + + + + + OAuth用户参数 + + + + + 用户参数 + + + + + 账号 + + + + + 密码 + + + + + 昵称 + + + + + 姓名 + + + + + 头像 + + + + + 生日 + + + + + 性别-男_1、女_2 + + + + + 邮箱 + + + + + 手机 + + + + + 电话 + + + + + 状态-正常_0、停用_1、删除_2 + + + + + 员工信息 + + + + + 搜索状态(字典 0正常 1停用 2删除) + + + + + 账号 + + + + + 密码 + + + + + 确认密码 + + + + + 用户Id + + + + + 用户Id + + + + + 用户Id + + + + + 密码 + + + + + 新密码 + + + + + 确认密码 + + + + + 用户Id + + + + + 头像文件路径标识 + + + + + 用户参数 + + + + + Id + + + + + 账号 + + + + + 昵称 + + + + + 姓名 + + + + + 头像 + + + + + 生日 + + + + + 性别-男_1、女_2 + + + + + 邮箱 + + + + + 手机 + + + + + 电话 + + + + + 状态-正常_0、停用_1、删除_2 + + + + + 员工信息 + + + + + 所属租户 + + + + + 用户数据范围服务 + + + + + 授权用户数据 + + + + + + + 获取用户的数据范围Id集合 + + + + + + + 根据机构Id集合删除对应的用户-数据范围关联信息 + + + + + + + 根据用户Id删除对应的用户-数据范围关联信息 + + + + + + + 用户角色服务 + + + + + 获取用户的角色Id集合 + + + + + + + 授权用户角色 + + + + + + + 获取用户所有角色的数据范围(组织机构Id集合) + + + + + + + + 根据角色Id删除对应的用户-角色表关联信息 + + + + + + + 根据用户Id删除对应的用户-角色表关联信息 + + + + + + + 用户服务 + + + + + 分页查询用户 + + + + + + + 增加用户 + + + + + + + 删除用户 + + + + + + + 更新用户 + + + + + + + 查看用户 + + + + + + + 修改用户状态 + + + + + + + 授权用户角色 + + + + + + + 授权用户数据范围 + + + + + + + 更新用户信息 + + + + + + + 修改用户密码 + + + + + + + 获取用户拥有角色 + + + + + + + 获取用户拥有数据 + + + + + + + 重置用户密码 + + + + + + + 修改用户头像 + + + + + + + 获取用户选择器 + + + + + + + 用户导出 + + + + + + + 用户导入 + + + + + + + 根据用户Id获取用户 + + + + + + + 将OAuth账号转换成账号 + + + + + + + + 获取用户数据范围(机构Id集合)并缓存 + + + + + + + 检查普通用户数据范围 + + + + + + + 获取用户数据范围(用户Id集合) + + + + + + 检查普通用户数据范围 + + + + + + + 简单泛型队列 + + + + + 新增 + + + + + + 取出 + + + + + + + 总数 + + + + + + 清理 + + + + + 分页泛型集合 + + + + + + 页码 + + + + + 页容量 + + + + + 总条数 + + + + + 总页数 + + + + + 当前页集合 + + + + + 是否有上一页 + + + + + 是否有下一页 + + + + + 分页集合 + + + + + SqlSugar 仓储实现类 + + + + + + 初始化 SqlSugar 客户端 + + + + + 数据库上下文 + + + + + 独立数据库上下文 + + + + + 构造函数 + + + + + + 实体集合 + + + + + 原生 Ado 对象 + + + + + 获取总数 + + + + + + + 获取总数 + + + + + + + 检查是否存在 + + + + + + + 检查是否存在 + + + + + + + 通过主键获取实体 + + + + + + + 获取一个实体 + + + + + + + 获取一个实体 + + + + + + + 获取一个实体 + + + + + + + 获取一个实体 + + + + + + + 获取列表 + + + + + + 获取列表 + + + + + + + 获取列表 + + + + + + + + + 获取列表 + + + + + + 获取列表 + + + + + + + 获取列表 + + + + + + + + + 新增一条记录 + + + + + + + 新增多条记录 + + + + + + + 新增多条记录 + + + + + + + 新增一条记录返回自增Id + + + + + + + 新增一条记录返回雪花Id + + + + + + + 新增一条记录返回实体 + + + + + + + 新增一条记录 + + + + + + + 新增多条记录 + + + + + + + 新增多条记录 + + + + + + + 新增一条记录返回自增Id + + + + + + + 新增一条记录返回雪花Id + + + + + + + 新增一条记录返回实体 + + + + + + + 更新一条记录 + + + + + + + 更新多条记录 + + + + + + + 更新多条记录 + + + + + + + 更新一条记录 + + + + + + + 更新记录 + + 更新的条件 + 更新的内容 + + + + + 更新记录 + + 更新的条件 + 更新的内容 + + + + + 更新多条记录 + + + + + + + 更新多条记录 + + + + + + + 删除一条记录 + + + + + + + 删除一条记录 + + + + + + + 删除多条记录 + + + + + + + 自定义条件删除记录 + + + + + + + 删除一条记录 + + + + + + + 删除一条记录 + + + + + + + 删除多条记录 + + + + + + + 自定义条件删除记录 + + + + + + + 根据表达式查询多条记录 + + + + + + + 根据表达式查询多条记录 + + + + + + + + 构建查询分析器 + + + + + + 构建查询分析器 + + + + + + + 直接返回数据库结果 + + + + + + 直接返回数据库结果 + + + + + + + 直接返回数据库结果 + + + + + + 直接返回数据库结果 + + + + + + + 切换仓储(注意使用环境) + + 实体类型 + 仓储 + + + + 当前db + + + + + 当前db + + + + + 当前db + + + + + 所有db + + + + + 所有db + + + + + 所有db + + + + + SqlsugarScope的配置 + Scope必须用单例注入 + 不可以用Action委托注入 + + + + + + 获取当前租户id + + + + + + 判断是不是超级管理员 + + + + + + 添加 SqlSugar 拓展 + + + + + + + + + 添加 SqlSugar 拓展 + + + + + + + + + 代码生成帮助类 + + + + + 数据类型转显示类型 + + + + + + + 枚举的Entity类 + + + + + 枚举的描述 + + + + + 枚举名称 + + + + + 枚举对象的值 + + + + + 枚举工具类 + + + + + 获取枚举对象Key与名称的字典(缓存) + + + + + + + 获取枚举对象Key与名称的字典 + + + + + + + 获取枚举类型key与描述的字典(缓存) + + + + + + + + 获取枚举类型key与描述的字典(没有描述则获取name) + + + + + + + + 从程序集中查找指定枚举类型 + + + + + + + + 从程序集中加载所有枚举类型 + + + + + + + 获取枚举的Description + + + + + + + 获取枚举的Description + + + + + + + 将枚举转成枚举信息集合 + + + + + + + 枚举ToList + + + + + + + + DateTime扩展 + + + 验证扩展类 + + + 转换扩展类 + + + + + 得到问好 + + + + + + 获取指定年月的第一天 + + + + + + + + + 获取指定年月的第一天 + + + + + + + + + 获取指定年月的最后一天 + + + + + + + + + 获取指定年月的最后一天 + + + + + + + + + 获取当前月的第一天 + + + + + + + 获取当前月的最后一天 + + + + + + + 获取上月的第一天 + + + + + + + 获取上月的最后一天 + + + + + + + 获取本周时间 + + + + + + + 获取上周时间 + + + + + + + 获取当天时间 + + + + + + + 获取昨天时间 + + + + + + + 计算两个时间的差 + + + + + + + + + 检查 Object 是否为 NULL + + + + + + + 检查 Object 是否为 NULL 或者 0 + + + + + + + 检查是否为 AJAX 请求 + + + + + + + 将object转换为long,若转换失败,则返回0。不抛出异常。 + + + + + + + 将object转换为long,若转换失败,则返回指定值。不抛出异常。 + + + + + + + + 将object转换为int,若转换失败,则返回0。不抛出异常。 + + + + + + + 将object转换为int,若转换失败,则返回指定值。不抛出异常。 + null返回默认值 + + + + + + + + 将object转换为short,若转换失败,则返回0。不抛出异常。 + + + + + + + 将object转换为short,若转换失败,则返回指定值。不抛出异常。 + + + + + + + + 将object转换为demical,若转换失败,则返回指定值。不抛出异常。 + + + + + + + + 将object转换为demical,若转换失败,则返回0。不抛出异常。 + + + + + + + 将object转换为bool,若转换失败,则返回false。不抛出异常。 + + + + + + + 将object转换为bool,若转换失败,则返回指定值。不抛出异常。 + + + + + + + + 将object转换为float,若转换失败,则返回0。不抛出异常。 + + + + + + + 将object转换为float,若转换失败,则返回指定值。不抛出异常。 + + + + + + + + 将string转换为Guid,若转换失败,则返回Guid.Empty。不抛出异常。 + + + + + + + 将string转换为DateTime,若转换失败,则返回日期最小值。不抛出异常。 + + + + + + + 将string转换为DateTime,若转换失败,则返回默认值。 + + + + + + + + 将object转换为string,若转换失败,则返回""。不抛出异常。 + + + + + + + + + + + + + + + 将object转换为double,若转换失败,则返回0。不抛出异常。 + + + + + + + 将object转换为double,若转换失败,则返回指定值。不抛出异常。 + + + + + + + + 强制转换类型 + + + + + + + + HTTP网络工具 + + + + + 客户端IP地址 + + + + + 得到客户端IP地址 + + + + + + 得到局域网IP地址 + + + + + + 得到远程Ip地址 + + + + + + 请求UserAgent信息 + + + + + 请求Url + + + + + 得到操作系统版本 + + + + + + 公网信息 + 慎用,如果不是直接请求接口,而是通过代理转发,拿到的是服务器的公网信息 + + + + + + 根据IP地址获取公网信息 + + + + + + UserAgent信息 + + + + + + 远程路径Encode处理,会保证开头是/,结尾也是/ + + + + + + + 标准化远程目录路径,会保证开头是/,结尾也是/ ,如果命名不规范,存在保留字符,会返回空字符 + + 要标准化的远程路径 + + + + + 万网Ip信息Model类 + + + + + Ip地址 + + + + + 省份 + + + + + 省份邮政编码 + + + + + 城市 + + + + + 城市邮政编码 + + + + + 地理信息 + + + + + 运营商 + + + + + UserAgent 信息Model类 + + + + + 手机型号 + + + + + 操作系统(版本) + + + + + 浏览器(版本) + + + + + 天气预报工具类 + + + + + 天气信息 + + + + + 时间 + + + + + 最高温度 + + + + + 风力 + + + + + 最低温度 + + + + + 分向 + + + + + 类型 + + + + + 昨日天气 + + + + + 城市 + + + + + 未来五天天气 + + + + + 感冒 + + + + + 温度 + + + + + 是否成功 + + + + + 失败描述 + + + + + 数据 + + + + + 状态 + + + + + 描述 + + + + + 图片工具类 + + + + + 获取外网Url图片的二进制数组 + + + + + + + 保存二进制流到文件 + + + + + + + 保存外网Url到文件 + + 外网图片Url + 要保存的文件名称 + + + + + 删除文件夹里面所有的文件 + + + + + + + 无损压缩图片 + + 原图片地址 + 压缩后保存图片地址 + 压缩后宽度 + 压缩后高度 + 压缩质量(数字越小压缩率越高) + 压缩后图片的最大大小 + 是否为第一次调用 + + + + + Json序列化工具类 + + + + + JSON 字符串转 Object + + + + + + + + JSON 字符串转 Object + + + + + + + Object 转 JSON字符串 + + + + + + + JSON 字符串转 JObject + + + + + + + Dictionary 字符串转 Object + + + + + + + + 把数组转为逗号连接的字符串 + + + + + + + + 判断是否有交集 + + + + + + + + + 获取服务器信息 + + + + + 获取资源使用信息 + + + + + + 获取基本参数 + + + + + + 动态获取网络信息 + + + + + + 是否Linux + + + + + + 获取CPU使用率 + + + + + + 获取系统运行时间 + + + + + + 获取内存信息 + + + + + + 毫秒转天时分秒 + + + + + + + 获取外网IP和地理位置 + + + + + + 系统Shell命令 + + + + + Bash命令 + + + + + + + cmd命令 + + + + + + + + + + + + + 当前正在联网的网卡信息 + + + + + + 获取当前网卡的网络速度 + + + + + + + 小程序工具类 + + + + + 解密数据获取小程序用户信息 + + 包括敏感数据在内的完整用户信息的加密数据 + auth.code2Session获取的session_key + 加密算法的初始向量 + 如遇异常返回 "" + + + + 基础解析 + + 包括敏感数据在内的完整用户信息的加密数据 + auth.code2Session获取的session_key + 加密算法的初始向量 + + + + + 小程序登录解密后的用户信息Model + + + + + 手机号 + + + + + 纯手机号 + + + + + 区号 + + + + + 阿里云oss文件上传工具类 + + + + + 上传本地文件(走阿里云内网传输) + + + + + + + + 上传一个图片 + + 图片经过base64加密后的结果 + 文件名,例如:Emplyoee/dzzBack.jpg + + + + 上传本地文件 + + + + 返回参数说明 1.本地文件不存在 2.文件oss上已存在 3.上传失败 4.上传成功 + + + + + 上传一个图片 + + 图片字节 + 文件名,例如:Emplyoee/dzzBack.jpg + + + + + 获取鉴权后的URL,URL有效日期默认一小时 + + 文件名,例如:Emplyoee/dzzBack.jpg + + + + + 获取鉴权后的URL + + 文件名,例如:Emplyoee/dzzBack.jpg + URL有效日期,例如:DateTime.Now.AddHours(1) + + + + + 将文件转换成byte[] 数组 + + 文件路径文件名称 + byte[] + + + + 删除文件 + + 文件id + 文件url + + + + 删除文件夹 + + 文件id + 文件url + + + + 判断文件是否存在 + + + + + + + 类型转换 + + + + + + 反射工具 + + + + + 获取字段特性 + + + + + + + + 普通 字符串 转换为 base64 字符串 + + + + + base64 字符串 转换为 普通 字符串 + + + + + 字符串验证帮助类 + + + + + 验证输入字符串为带小数点正数 + + 输入字符 + 返回一个bool类型的值 + + + + 验证输入字符串为带小数点正负数 + + 输入字符 + 返回一个bool类型的值 + + + + 验证中国电话格式是否有效,格式010-85849685 + + 输入字符 + 返回一个bool类型的值 + + + + 验证输入字符串为电话号码 + + 输入字符 + 返回一个bool类型的值 + + + + 验证是否是有效传真号码 + + 输入字符 + 返回一个bool类型的值 + + + + 验证手机号是否合法 号段为13,14,15,16,17,18,19 0,86开头将自动识别 + + 输入字符 + 返回一个bool类型的值 + + + + 验证身份证是否有效 + + 输入字符 + 返回一个bool类型的值 + + + + 验证输入字符串为18位的身份证号码 + + 输入字符 + 返回一个bool类型的值 + + + + 验证输入字符串为15位的身份证号码 + + 输入字符 + 返回一个bool类型的值 + + + + 验证是否是有效邮箱地址 + + 输入字符 + 返回一个bool类型的值 + + + + 验证是否是有效QQ邮箱地址 + + 输入字符 + 返回一个bool类型的值 + + + + 验证是否只含有汉字 + + 输入字符 + + + + + 是否有多余的字符 防止SQL注入 + + 输入字符 + + + + + 是否由数字、26个英文字母或者下划线組成的字串 + + 输入字符 + + + + + 由数字、26个英文字母、汉字組成的字串 + + 输入字符 + + + + + 是否由数字、26个英文字母組成的字串 + + 输入字符 + + + + + 验证输入字符串为邮政编码 + + 输入字符 + 返回一个bool类型的值 + + + + 检查对象的输入长度 + + 输入字符 + 指定的长度 + false 太长,true -太短 + + + + 判断用户输入是否为日期 + + 输入字符 + 返回一个bool类型的值 + + 可判断格式如下(其中-可替换为/,不影响验证) + YYYY | YYYY-MM | YYYY-MM-DD | YYYY-MM-DD HH:MM:SS | YYYY-MM-DD HH:MM:SS.FFF + + + + + 树基类 + + + + + 获取节点id + + + + + + 获取节点父id + + + + + + 设置Children + + + + + + 递归工具类,用于遍历有父子关系的节点,例如菜单树,字典树等等 + + + + + + 顶级节点的父节点Id(默认0) + + + + + 构造树节点 + + + + + + + 构造子节点集合 + + + + + + + diff --git a/Magic.Core/Manager/UserManager.cs b/Magic.Core/Manager/UserManager.cs new file mode 100644 index 0000000..389533a --- /dev/null +++ b/Magic.Core/Manager/UserManager.cs @@ -0,0 +1,35 @@ + +using Furion; + +namespace Magic.Core; + +/// +/// 用户管理 +/// +public static class UserManager +{ + /// + /// 用户id + /// + public static long UserId => long.Parse(App.User.FindFirst(ClaimConst.CLAINM_USERID)?.Value); + + /// + /// 账号 + /// + public static string Account => App.User.FindFirst(ClaimConst.CLAINM_ACCOUNT)?.Value; + + /// + /// 昵称 + /// + public static string Name => App.User.FindFirst(ClaimConst.CLAINM_NAME)?.Value; + + /// + /// 是否超级管理员 + /// + public static bool IsSuperAdmin => App.User.FindFirst(ClaimConst.CLAINM_SUPERADMIN)?.Value == ((int)AdminType.SuperAdmin).ToString(); + + /// + /// 是否租户管理员 + /// + public static bool IsTenantAdmin => App.User.FindFirst(ClaimConst.CLAINM_SUPERADMIN)?.Value == ((int)AdminType.Admin).ToString(); +} diff --git a/Magic.Core/OAuth/IWechatOAuth.cs b/Magic.Core/OAuth/IWechatOAuth.cs new file mode 100644 index 0000000..0e0fefa --- /dev/null +++ b/Magic.Core/OAuth/IWechatOAuth.cs @@ -0,0 +1,11 @@ +using System.Threading.Tasks; + +namespace Magic.Core; + +public interface IWechatOAuth +{ + Task GetAccessTokenAsync(string code, string state = ""); + string GetAuthorizeUrl(string state = ""); + Task GetUserInfoAsync(string accessToken, string openId); + Task GetRefreshTokenAsync(string refreshToken); +} diff --git a/Magic.Core/OAuth/TokenModel.cs b/Magic.Core/OAuth/TokenModel.cs new file mode 100644 index 0000000..2643219 --- /dev/null +++ b/Magic.Core/OAuth/TokenModel.cs @@ -0,0 +1,66 @@ +using System.Text.Json.Serialization; + +namespace Magic.Core; + +/// +/// AccessToken参数 +/// +public class TokenModel +{ + /// + /// 用户标识 + /// + [JsonPropertyName("openid")] + public string OpenId { get; set; } + + /// + /// Token 类型 + /// + [JsonPropertyName("token_type")] + public string TokenType { get; set; } + + /// + /// AccessToken + /// + [JsonPropertyName("access_token")] + public string AccessToken { get; set; } + + /// + /// 用于刷新 AccessToken 的 Token + /// + [JsonPropertyName("refresh_token")] + public string RefreshToken { get; set; } + + /// + /// 此 AccessToken 对应的权限 + /// + [JsonPropertyName("scope")] + public string Scope { get; set; } + + /// + /// AccessToken 过期时间 + /// + [JsonPropertyName("expires_in")] + public dynamic ExpiresIn { get; set; } + + /// + /// 错误的详细描述 + /// + [JsonPropertyName("error_description")] + public string ErrorDescription { get; set; } +} + +public static class AccessTokenModelModelExtensions +{ + /// + /// 获取的Token是否包含错误 + /// + /// + /// + public static bool HasError(this TokenModel accessTokenModel) + { + return accessTokenModel == null || + string.IsNullOrEmpty(accessTokenModel.AccessToken) || + !string.IsNullOrEmpty(accessTokenModel.ErrorDescription); + } +} diff --git a/Magic.Core/OAuth/UserInfoModel.cs b/Magic.Core/OAuth/UserInfoModel.cs new file mode 100644 index 0000000..8bd15eb --- /dev/null +++ b/Magic.Core/OAuth/UserInfoModel.cs @@ -0,0 +1,61 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Magic.Core; + +/// +/// 微信用户参数 +/// +public class UserInfoModel +{ + [JsonPropertyName("nickname")] + public string Name { get; set; } + + [JsonPropertyName("headimgurl")] + public string Avatar { get; set; } + + [JsonPropertyName("language")] + public string Language { get; set; } + + [JsonPropertyName("openid")] + public string Openid { get; set; } + + [JsonPropertyName("sex")] + public int Sex { get; set; } + + [JsonPropertyName("province")] + public string Province { get; set; } + + [JsonPropertyName("city")] + public string City { get; set; } + + [JsonPropertyName("country")] + public string Country { get; set; } + + /// + /// 用户特权信息,json 数组,如微信沃卡用户为(chinaunicom) + /// + [JsonPropertyName("privilege")] + public List Privilege { get; set; } + + [JsonPropertyName("unionid")] + public string UnionId { get; set; } + + [JsonPropertyName("errmsg")] + public string ErrorMessage { get; set; } +} + +public static class UserInfoModelExtensions +{ + /// + /// 获取的用户是否包含错误 + /// + /// + /// + public static bool HasError(this UserInfoModel userInfoModel) + { + return userInfoModel == null || + string.IsNullOrEmpty(userInfoModel.Name) || + !string.IsNullOrEmpty(userInfoModel.ErrorMessage); + } +} diff --git a/Magic.Core/OAuth/WechatOAuth.cs b/Magic.Core/OAuth/WechatOAuth.cs new file mode 100644 index 0000000..b3b33c8 --- /dev/null +++ b/Magic.Core/OAuth/WechatOAuth.cs @@ -0,0 +1,101 @@ +using Furion.DependencyInjection; +using Furion.FriendlyException; +using Furion.RemoteRequest.Extensions; +using Microsoft.Extensions.Options; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.Core; + +public class WechatOAuth : IWechatOAuth, ISingleton +{ + private readonly string _authorizeUrl = "https://open.weixin.qq.com/connect/oauth2/authorize"; + private readonly string _accessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token"; + private readonly string _refreshTokenUrl = "https://api.weixin.qq.com/sns/oauth2/refresh_token"; + private readonly string _userInfoUrl = "https://api.weixin.qq.com/sns/userinfo"; + + private readonly ThirdParty _oauthConfig; + + public WechatOAuth(IOptions options) + { + _oauthConfig = options.Value.Wechat; + } + + /// + /// 发起授权 + /// + /// + /// + public string GetAuthorizeUrl(string state = "") + { + var param = new Dictionary() + { + ["appid"] = _oauthConfig.app_id, + ["redirect_uri"] = _oauthConfig.redirect_uri, + ["response_type"] = "code", + ["scope"] = _oauthConfig.scope, + ["state"] = state + }; + return $"{_authorizeUrl}?{param.ToQueryString()}#wechat_redirect"; + } + + /// + /// 获取微信Token + /// + /// + /// + /// + public async Task GetAccessTokenAsync(string code, string state = "") + { + var param = new Dictionary() + { + ["appid"] = _oauthConfig.app_id, + ["secret"] = _oauthConfig.app_key, + ["code"] = code, + ["grant_type"] = "authorization_code" + }; + var accessTokenModel = await $"{_accessTokenUrl}?{param.ToQueryString()}".GetAsAsync(); + if (accessTokenModel.HasError()) + throw Oops.Oh($"{ accessTokenModel.ErrorDescription}"); + return accessTokenModel; + } + + /// + /// 获取微信用户基本信息 + /// + /// + /// + /// + public async Task GetUserInfoAsync(string accessToken, string openId) + { + var param = new Dictionary() + { + ["access_token"] = accessToken, + ["openid"] = openId, + ["lang"] = "zh_CN", + }; + var userInfoModel = await $"{_userInfoUrl}?{param.ToQueryString()}".GetAsAsync(); + if (userInfoModel.HasError()) + throw Oops.Oh($"{ userInfoModel.ErrorMessage}"); + return userInfoModel; + } + + /// + /// 刷新微信Token + /// + /// + /// + public async Task GetRefreshTokenAsync(string refreshToken) + { + var param = new Dictionary() + { + ["appid"] = _oauthConfig.app_id, + ["grant_type"] = "refresh_token", + ["refresh_token"] = refreshToken + }; + var refreshTokenModel = await $"{_refreshTokenUrl}?{param.ToQueryString()}".GetAsAsync(); + if (refreshTokenModel.HasError()) + throw Oops.Oh($"{ refreshTokenModel.ErrorDescription}"); + return refreshTokenModel; + } +} diff --git a/Magic.Core/Service/App/Dto/AppInput.cs b/Magic.Core/Service/App/Dto/AppInput.cs new file mode 100644 index 0000000..5033ba6 --- /dev/null +++ b/Magic.Core/Service/App/Dto/AppInput.cs @@ -0,0 +1,78 @@ +using System.ComponentModel.DataAnnotations; + +namespace Magic.Core.Service; + +/// +/// 系统应用参数 +/// +public class AppInput : PageInputBase +{ + /// + /// 名称 + /// + public virtual string Name { get; set; } + + /// + /// 编码 + /// + public virtual string Code { get; set; } + + /// + /// 是否默认激活(Y-是,N-否),只能有一个系统默认激活 + /// 用户登录后默认展示此系统菜单 + /// + public string Active { get; set; } + + /// + /// 状态(字典 0正常 1停用 2删除) + /// + public CommonStatus Status { get; set; } + + /// + /// 排序 + /// + public int Sort { get; set; } +} + +public class AddAppInput : AppInput +{ + /// + /// 名称 + /// + [Required(ErrorMessage = "应用名称不能为空")] + public override string Name { get; set; } + + /// + /// 编码 + /// + [Required(ErrorMessage = "应用编码不能为空")] + public override string Code { get; set; } +} + +public class DeleteAppInput +{ + /// + /// 应用Id + /// + [Required(ErrorMessage = "应用Id不能为空")] + public long Id { get; set; } +} + +public class UpdateAppInput : AppInput +{ + /// + /// 应用Id + /// + [Required(ErrorMessage = "应用Id不能为空")] + public long Id { get; set; } +} + +public class QueryAppInput : DeleteAppInput +{ + +} + +public class SetDefaultAppInput : DeleteAppInput +{ + +} diff --git a/Magic.Core/Service/App/Dto/AppOutput.cs b/Magic.Core/Service/App/Dto/AppOutput.cs new file mode 100644 index 0000000..d034015 --- /dev/null +++ b/Magic.Core/Service/App/Dto/AppOutput.cs @@ -0,0 +1,32 @@ +namespace Magic.Core.Service; + +/// +/// 系统应用参数 +/// +public class AppOutput +{ + /// + /// 应用Id + /// + public long Id { get; set; } + + /// + /// 名称 + /// + public string Name { get; set; } + + /// + /// 编码 + /// + public string Code { get; set; } + + /// + /// 是否默认 + /// + public string Active { get; set; } + + /// + /// 排序 + /// + public int Sort { get; set; } +} diff --git a/Magic.Core/Service/App/ISysAppService.cs b/Magic.Core/Service/App/ISysAppService.cs new file mode 100644 index 0000000..fd71842 --- /dev/null +++ b/Magic.Core/Service/App/ISysAppService.cs @@ -0,0 +1,18 @@ +using Magic.Core.Entity; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ISysAppService +{ + Task AddApp(AddAppInput input); + Task DeleteApp(DeleteAppInput input); + Task GetApp([FromQuery] QueryAppInput input); + Task GetAppList([FromQuery] AppInput input); + Task GetLoginApps(long userId); + Task QueryAppPageList([FromQuery] AppInput input); + Task SetAsDefault(SetDefaultAppInput input); + Task UpdateApp(UpdateAppInput input); + Task ChangeUserAppStatus(UpdateAppInput input); +} diff --git a/Magic.Core/Service/App/SysAppService.cs b/Magic.Core/Service/App/SysAppService.cs new file mode 100644 index 0000000..6553b31 --- /dev/null +++ b/Magic.Core/Service/App/SysAppService.cs @@ -0,0 +1,193 @@ + + +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Furion.FriendlyException; +using Magic.Core.Entity; +using Mapster; +using Microsoft.AspNetCore.Mvc; + +using SqlSugar; +using System; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +/// +/// 系统应用服务 +/// +[ApiDescriptionSettings(Name = "App", Order = 100)] +public class SysAppService : ISysAppService, IDynamicApiController, ITransient +{ + private readonly SqlSugarRepository _sysAppRep; // 应用表仓储 + private readonly ISysMenuService _sysMenuService; + + public SysAppService(SqlSugarRepository sysAppRep, + ISysMenuService sysMenuService) + { + _sysAppRep = sysAppRep; + _sysMenuService = sysMenuService; + } + + /// + /// 获取用户应用相关信息 + /// + /// + /// + [NonAction] + public async Task GetLoginApps(long userId) + { + var apps = _sysAppRep.Where(u => u.Status == (int)CommonStatus.ENABLE); + if (!UserManager.IsSuperAdmin) + { + var appCodeList = await _sysMenuService.GetUserMenuAppCodeList(userId); + apps = apps.Where(u => appCodeList.Contains(u.Code)); + } + var appList = await apps.OrderBy(u => u.Active, OrderByType.Desc).OrderBy(u => u.Sort).Select(u => new AppOutput + { + Code = u.Code, + Name = u.Name, + Active = u.Active + }).ToListAsync(); + + return appList; + } + + /// + /// 分页查询系统应用 + /// + /// + /// + [HttpGet("/sysApp/page")] + public async Task QueryAppPageList([FromQuery] AppInput input) + { + var apps = await _sysAppRep.AsQueryable() + .WhereIF(!string.IsNullOrWhiteSpace(input.Name), m => m.Name.Contains(input.Name.Trim())) + .WhereIF(!string.IsNullOrWhiteSpace(input.Code), m => m.Code.Contains(input.Code)) + .ToPagedListAsync(input.PageNo, input.PageSize); + return apps.XnPagedResult(); + } + + /// + /// 增加系统应用 + /// + /// + /// + [HttpPost("/sysApp/add")] + public async Task AddApp(AddAppInput input) + { + var isExist = await _sysAppRep.AnyAsync(u => u.Name == input.Name || u.Code == input.Code); + if (isExist) + throw Oops.Oh(ErrorCode.D5000); + + if (input.Active == YesOrNot.Y.ToString()) + { + isExist = await _sysAppRep.AnyAsync(u => u.Active == input.Active); + if (isExist) + throw Oops.Oh(ErrorCode.D5001); + } + + var app = input.Adapt(); + await _sysAppRep.InsertAsync(app); + } + + /// + /// 删除系统应用 + /// + /// + /// + [HttpPost("/sysApp/delete")] + public async Task DeleteApp(DeleteAppInput input) + { + var app = await _sysAppRep.FirstOrDefaultAsync(u => u.Id == input.Id); + // 该应用下是否有状态为正常的菜单 + var hasMenu = await _sysMenuService.HasMenu(app.Code); + if (hasMenu) + throw Oops.Oh(ErrorCode.D5002); + + await _sysAppRep.DeleteAsync(app); + } + + /// + /// 更新系统应用 + /// + /// + /// + [HttpPost("/sysApp/edit")] + public async Task UpdateApp(UpdateAppInput input) + { + var isExist = await _sysAppRep.AnyAsync(u => (u.Name == input.Name || u.Code == input.Code) && u.Id != input.Id); + if (isExist) + throw Oops.Oh(ErrorCode.D5000); + + if (input.Active == YesOrNot.Y.ToString()) + { + isExist = await _sysAppRep.AnyAsync(u => u.Active == input.Active && u.Id!=input.Id); + if (isExist) + throw Oops.Oh(ErrorCode.D5001); + } + + var app = input.Adapt(); + await _sysAppRep.AsUpdateable(app).IgnoreColumns(it => new { it.Status }).ExecuteCommandAsync(); + } + + /// + /// 获取系统应用 + /// + /// + /// + [HttpGet("/sysApp/detail")] + public async Task GetApp([FromQuery] QueryAppInput input) + { + return await _sysAppRep.FirstOrDefaultAsync(u => u.Id == input.Id); + } + + /// + /// 获取系统应用列表 + /// + /// + /// + [HttpGet("/sysApp/list")] + public async Task GetAppList([FromQuery] AppInput input) + { + return await _sysAppRep.Where(u => u.Status == (int)CommonStatus.ENABLE).ToListAsync(); + } + + /// + /// 设为默认应用 + /// + /// + /// + [HttpPost("/sysApp/setAsDefault")] + public async Task SetAsDefault(SetDefaultAppInput input) + { + var apps = await _sysAppRep.Where(u => u.Status == (int)CommonStatus.ENABLE).ToListAsync(); + apps.ForEach(u => + { + if (u.Id == input.Id) + { + u.Active = YesOrNot.Y.ToString(); + } + else { + u.Active = YesOrNot.N.ToString(); + } + }); + await _sysAppRep.UpdateAsync(apps); + } + + /// + /// 修改用户状态 + /// + /// + /// + [HttpPost("/sysApp/changeStatus")] + public async Task ChangeUserAppStatus(UpdateAppInput input) + { + if (!Enum.IsDefined(typeof(CommonStatus), input.Status)) + throw Oops.Oh(ErrorCode.D3005); + + var app = await _sysAppRep.FirstOrDefaultAsync(u => u.Id == input.Id); + app.Status = input.Status; + await _sysAppRep.UpdateAsync(app); + } +} diff --git a/Magic.Core/Service/Auth/AuthService.cs b/Magic.Core/Service/Auth/AuthService.cs new file mode 100644 index 0000000..a419c5a --- /dev/null +++ b/Magic.Core/Service/Auth/AuthService.cs @@ -0,0 +1,292 @@ +using Furion; +using Furion.DataEncryption; +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Furion.EventBus; +using Furion.FriendlyException; +using Magic.Core.Entity; +using Mapster; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Threading.Tasks; +using UAParser; + +namespace Magic.Core.Service; + +/// +/// 登录授权相关服务 +/// +[ApiDescriptionSettings(Name = "Auth", Order = 160)] +public class AuthService : IAuthService, IDynamicApiController, ITransient +{ + private readonly SqlSugarRepository _sysUserRep; // 用户表仓储 + private readonly SqlSugarRepository _sysLogVisRep; + private readonly SqlSugarRepository _sysTenantRep; + + private readonly IHttpContextAccessor _httpContextAccessor; + private readonly ISysEmpService _sysEmpService; // 系统员工服务 + private readonly ISysRoleService _sysRoleService; // 系统角色服务 + private readonly ISysMenuService _sysMenuService; // 系统菜单服务 + private readonly ISysAppService _sysAppService; // 系统应用服务 + private readonly IClickWordCaptcha _captchaHandle; // 验证码服务 + private readonly ISysConfigService _sysConfigService; // 验证码服务 + private readonly IEventPublisher _eventPublisher; + + + public AuthService(SqlSugarRepository sysUserRep, SqlSugarRepository sysLogVisRep, SqlSugarRepository sysTenantRep, + IHttpContextAccessor httpContextAccessor, + ISysEmpService sysEmpService, ISysRoleService sysRoleService, ISysMenuService sysMenuService, + ISysAppService sysAppService, IClickWordCaptcha captchaHandle, ISysConfigService sysConfigService, + IEventPublisher eventPublisher + ) + { + _sysUserRep = sysUserRep; + _sysLogVisRep = sysLogVisRep; + _sysTenantRep=sysTenantRep; + _httpContextAccessor = httpContextAccessor; + _sysEmpService = sysEmpService; + _sysRoleService = sysRoleService; + _sysMenuService = sysMenuService; + _sysAppService = sysAppService; + _captchaHandle = captchaHandle; + _sysConfigService = sysConfigService; + _eventPublisher = eventPublisher; + } + + /// + /// 用户登录 + /// + /// + /// 默认用户名/密码:admin/admin + /// + [HttpPost("/login")] + [AllowAnonymous] + public async Task LoginAsync([Required] LoginInput input) + { + // 获取加密后的密码 + var encryptPassword = MD5Encryption.Encrypt(input.Password); + + // 判断用户名和密码是否正确(排除全局多租户过滤器)Filter(null,true) + var user = _sysUserRep.AsQueryable().Filter(null, true) + .WhereIF(input.TenantId.HasValue && input.TenantId.Value > 0, m => m.TenantId == input.TenantId).First(u => + u.Account.Equals(input.Account) && u.Password.Equals(encryptPassword) && !u.IsDeleted); + _ = user ?? throw Oops.Oh(ErrorCode.D1000); + + // 验证账号是否被冻结 + if (user.Status == CommonStatus.DISABLE) + throw Oops.Oh(ErrorCode.D1017); + //获取对应租户 + var tenant = _sysTenantRep.Single(user.TenantId); + // 生成Token令牌 + //var accessToken = await _jwtBearerManager.CreateTokenAdmin(user); + var accessToken = JWTEncryption.Encrypt(new Dictionary + { + {ClaimConst.CLAINM_USERID, user.Id}, + {ClaimConst.TENANT_ID, user.TenantId}, + {ClaimConst.CLAINM_ACCOUNT, user.Account}, + {ClaimConst.CLAINM_NAME, user.Name}, + {ClaimConst.CLAINM_SUPERADMIN, user.AdminType}, + { ClaimConst.CLAINM_TENANT_TYPE, tenant.TenantType }, + { ClaimConst.CLAINM_TENANT_NAME, tenant.Name }, + }); + + // 设置Swagger自动登录 + _httpContextAccessor.HttpContext.SigninToSwagger(accessToken); + + // 生成刷新Token令牌 + var refreshToken = JWTEncryption.GenerateRefreshToken(accessToken, 30); + + // 设置刷新Token令牌 + _httpContextAccessor.HttpContext.Response.Headers["x-access-token"] = refreshToken; + + var httpContext = App.HttpContext; + await _eventPublisher.PublishAsync(new ChannelEventSource("Update:UserLoginInfo", + new SysUser {Id = user.Id, LastLoginIp = httpContext.GetLocalIpAddressToIPv4(), LastLoginTime = DateTime.Now})); + return accessToken; + } + + /// + /// 模拟租户登录 + /// + /// + /// 默认用户名/密码:admin/admin + /// + [HttpPost("/simulationTenantLogin")] + public async Task SimulationLoginAsync([Required] LoginInput input) + { + SysTenant tenant = null; + if (input.TenantId.HasValue && input.TenantId.Value > 0) + { + tenant = _sysTenantRep.Single(input.TenantId.Value); + if (tenant == null || (tenant.IsDeleted && tenant.TenantType != TenantTypeEnum.SYSTEM)) + throw Oops.Oh("租户不存在"); + } + // 判断用户名和密码是否正确(排除全局多租户过滤器)Filter(null,true) + var user = _sysUserRep.AsQueryable().Filter(null, true) + .Where(m => m.TenantId == input.TenantId) + .First(u => u.Account.Equals(input.Account) && !u.IsDeleted); + _ = user ?? throw Oops.Oh(ErrorCode.D1000); + + // 验证账号是否被冻结 + if (user.Status == CommonStatus.DISABLE) + throw Oops.Oh(ErrorCode.D1017); + + // 生成Token令牌 + //var accessToken = await _jwtBearerManager.CreateTokenAdmin(user); + var accessToken = JWTEncryption.Encrypt(new Dictionary + { + { ClaimConst.CLAINM_USERID, user.Id }, + { ClaimConst.TENANT_ID, user.TenantId }, + { ClaimConst.CLAINM_ACCOUNT, user.Account }, + { ClaimConst.CLAINM_NAME, user.Name }, + { ClaimConst.CLAINM_SUPERADMIN, user.AdminType }, + { ClaimConst.CLAINM_TENANT_TYPE, tenant.TenantType }, + { ClaimConst.CLAINM_TENANT_NAME, tenant.Name }, + }); + + // 设置Swagger自动登录 + _httpContextAccessor.HttpContext.SigninToSwagger(accessToken); + + // 生成刷新Token令牌 + var refreshToken = JWTEncryption.GenerateRefreshToken(accessToken, 30); + + // 设置刷新Token令牌 + _httpContextAccessor.HttpContext.Response.Headers["x-access-token"] = refreshToken; + + var httpContext = App.HttpContext; + await _eventPublisher.PublishAsync(new ChannelEventSource("Update:UserLoginInfo", + new SysUser { Id = user.Id, LastLoginIp = httpContext.GetLocalIpAddressToIPv4(), LastLoginTime = DateTime.Now })); + return accessToken; + } + + /// + /// 获取当前登录用户信息 + /// + /// + [HttpGet("getLoginUser")] + public async Task GetLoginUserAsync() + { + var user = _sysUserRep.Single(UserManager.UserId); + var userId = user.Id; + + var httpContext = App.GetService().HttpContext; + var loginOutput = user.Adapt(); + + loginOutput.LastLoginTime = user.LastLoginTime = DateTime.Now; + var ip = HttpNewUtil.Ip; + loginOutput.LastLoginIp = user.LastLoginIp = + string.IsNullOrEmpty(user.LastLoginIp) ? HttpNewUtil.Ip : ip; + + var clent = Parser.GetDefault().Parse(httpContext.Request.Headers["User-Agent"]); + loginOutput.LastLoginBrowser = clent.UA.Family + clent.UA.Major; + loginOutput.LastLoginOs = clent.OS.Family + clent.OS.Major; + + // 员工信息 + loginOutput.LoginEmpInfo = await _sysEmpService.GetEmpInfo(userId); + + // 角色信息 + loginOutput.Roles = await _sysRoleService.GetUserRoleList(userId); + + // 权限信息 + loginOutput.Permissions = await _sysMenuService.GetLoginPermissionList(userId); + + // 数据范围信息(机构Id集合) + loginOutput.DataScopes = await DataFilterExtensions.GetDataScopeIdList(); + + // 具备应用信息(多系统,默认激活一个,可根据系统切换菜单),返回的结果中第一个为激活的系统 + loginOutput.Apps = await _sysAppService.GetLoginApps(userId); + + // 菜单信息 + if (loginOutput.Apps.Count > 0) + { + var defaultActiveAppCode = loginOutput.Apps.FirstOrDefault().Code; + loginOutput.Menus = await _sysMenuService.GetLoginMenusAntDesign(userId, ""); + loginOutput.Menus.ForEach(item => { item.Hidden = item.Application != defaultActiveAppCode; }); + } + + // 增加登录日志 + await _eventPublisher.PublishAsync(new ChannelEventSource("Create:VisLog", + new SysLogVis + { + Name = user.Name, + Success = YesOrNot.Y, + Message = "登录成功", + Ip = loginOutput.LastLoginIp, + Browser = loginOutput.LastLoginBrowser, + Os = loginOutput.LastLoginOs, + VisType = LoginType.LOGIN, + VisTime = loginOutput.LastLoginTime, + Account = user.Name + })); + + return loginOutput; + } + + /// + /// 退出 + /// + /// + [HttpGet("logout")] + public async Task LogoutAsync() + { + _httpContextAccessor.HttpContext.SignoutToSwagger(); + var ip = HttpNewUtil.Ip; + var user = _sysUserRep.Single(UserManager.UserId); + // 增加退出日志 + await _eventPublisher.PublishAsync(new ChannelEventSource("Create:VisLog", + new SysLogVis + { + Name = user.Name, + Success = YesOrNot.Y, + Message = "退出成功", + VisType = LoginType.LOGOUT, + VisTime = DateTime.Now, + Account = user.Account, + Ip = ip + })); + + await Task.CompletedTask; + } + + /// + /// 获取验证码开关 + /// + /// + [HttpGet("getCaptchaOpen")] + [AllowAnonymous] + public async Task GetCaptchaOpen() + { + return await _sysConfigService.GetCaptchaOpenFlag(); + } + + /// + /// 获取验证码(默认点选模式) + /// + /// + [HttpPost("captcha/get")] + [AllowAnonymous] + [NonUnify] + public async Task GetCaptcha() + { + // 图片大小要与前端保持一致(坐标范围) + return await Task.FromResult(_captchaHandle.CreateCaptchaImage(_captchaHandle.RandomCode(6), 310, 155)); + } + + /// + /// 校验验证码 + /// + /// + /// + [HttpPost("captcha/check")] + [AllowAnonymous] + [NonUnify] + public async Task VerificationCode(ClickWordCaptchaInput input) + { + return await Task.FromResult(_captchaHandle.CheckCode(input)); + } +} diff --git a/Magic.Core/Service/Auth/Dto/LoginInput.cs b/Magic.Core/Service/Auth/Dto/LoginInput.cs new file mode 100644 index 0000000..3fa447f --- /dev/null +++ b/Magic.Core/Service/Auth/Dto/LoginInput.cs @@ -0,0 +1,30 @@ +using Furion.DependencyInjection; +using System.ComponentModel.DataAnnotations; + +namespace Magic.Core.Service; + +/// +/// 登录输入参数 +/// +[SuppressSniffer] +public class LoginInput +{ + /// + /// 租户id + /// + /// superAdmin + public long? TenantId { get; set; } + /// + /// 用户名 + /// + /// superAdmin + [Required(ErrorMessage = "用户名不能为空"), MinLength(3, ErrorMessage = "用户名不能少于3位字符")] + public string Account { get; set; } + + /// + /// 密码 + /// + /// 123456 + [Required(ErrorMessage = "密码不能为空"), MinLength(5, ErrorMessage = "密码不能少于5位字符")] + public string Password { get; set; } +} diff --git a/Magic.Core/Service/Auth/Dto/LoginOutput.cs b/Magic.Core/Service/Auth/Dto/LoginOutput.cs new file mode 100644 index 0000000..c07e2fa --- /dev/null +++ b/Magic.Core/Service/Auth/Dto/LoginOutput.cs @@ -0,0 +1,162 @@ +using Furion.DependencyInjection; +using System; +using System.Collections.Generic; + +namespace Magic.Core.Service; + +/// +/// 用户登录输出参数 +/// +[SuppressSniffer] +public class LoginOutput +{ + /// + /// 主键 + /// + public long Id { get; set; } + + /// + /// 账号 + /// + public string Account { get; set; } + + /// + /// 昵称 + /// + public string NickName { get; set; } + + /// + /// 姓名 + /// + public string Name { get; set; } + + /// + /// 头像 + /// + public string Avatar { get; set; } + + /// + /// 生日 + /// + public DateTime Birthday { get; set; } + + /// + /// 性别(字典 1男 2女) + /// + public int Sex { get; set; } + + /// + /// 邮箱 + /// + public String Email { get; set; } + + /// + /// 手机 + /// + public String Phone { get; set; } + + /// + /// 电话 + /// + public String Tel { get; set; } + + /// + /// 管理员类型(0超级管理员 1非管理员) + /// + public int AdminType { get; set; } + + /// + /// 最后登陆IP + /// + public string LastLoginIp { get; set; } + + /// + /// 最后登陆时间 + /// + public DateTime LastLoginTime { get; set; } + + /// + /// 最后登陆地址 + /// + public string LastLoginAddress { get; set; } + + /// + /// 最后登陆所用浏览器 + /// + public string LastLoginBrowser { get; set; } + + /// + /// 最后登陆所用系统 + /// + public string LastLoginOs { get; set; } + + /// + /// 员工信息 + /// + public EmpOutput LoginEmpInfo { get; set; } = new EmpOutput(); + + /// + /// 具备应用信息 + /// + public List Apps { get; set; } = new List(); + + /// + /// 角色信息 + /// + public List Roles { get; set; } = new List(); + + /// + /// 权限信息 + /// + public List Permissions { get; set; } = new List(); + + /// + /// 登录菜单信息---AntDesign版本菜单 + /// + public List Menus { get; set; } = new List(); + + /// + /// 数据范围(机构)信息 + /// + public List DataScopes { get; set; } = new List(); + + ///// + ///// 租户信息 + ///// + //public List Tenants { get; set; } + + ///// + ///// 密码 + ///// + //public string Password { get; set; } + + ///// + ///// 账户过期 + ///// + //public string AccountNonExpired { get; set; } + + ///// + ///// 凭证过期 + ///// + //public string CredentialsNonExpired { get; set; } + + ///// + ///// 账户锁定 + ///// + //public bool AccountNonLocked { get; set; } + + ///// + ///// 用户名称 + ///// + //public string UserName { get; set; } + + ///// + ///// 权限 + ///// + //public List Authorities { get; set; } = new List(); + + ///// + ///// 是否启动 + ///// + //public bool Enabled { get; set; } +} diff --git a/Magic.Core/Service/Auth/Dto/RegistInput.cs b/Magic.Core/Service/Auth/Dto/RegistInput.cs new file mode 100644 index 0000000..a42e1e5 --- /dev/null +++ b/Magic.Core/Service/Auth/Dto/RegistInput.cs @@ -0,0 +1,33 @@ +using Furion.DependencyInjection; +using System.ComponentModel.DataAnnotations; + +namespace Magic.Core.Service +{ + /// + /// 注册输入参数 + /// + [SuppressSniffer] + public class RegistInput + { + /// + /// 用户名 + /// + /// superAdmin + [Required(ErrorMessage = "用户名不能为空"), MinLength(3, ErrorMessage = "用户名不能少于3位字符")] + public string Email { get; set; } + + /// + /// 公司名 + /// + /// superAdmin + [Required(ErrorMessage = "公司不能为空"), MinLength(3, ErrorMessage = "公司不能少于3位字符")] + public string CompanyName { get; set; } + + /// + /// 密码 + /// + /// 123456 + [Required(ErrorMessage = "密码不能为空"), MinLength(5, ErrorMessage = "密码不能少于5位字符")] + public string Password { get; set; } + } +} diff --git a/Magic.Core/Service/Auth/IAuthService.cs b/Magic.Core/Service/Auth/IAuthService.cs new file mode 100644 index 0000000..9cd86f6 --- /dev/null +++ b/Magic.Core/Service/Auth/IAuthService.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface IAuthService +{ + Task GetCaptcha(); + Task GetCaptchaOpen(); + Task GetLoginUserAsync(); + Task LoginAsync([Required] LoginInput input); + Task LogoutAsync(); + Task VerificationCode(ClickWordCaptchaInput input); + + Task SimulationLoginAsync([Required] LoginInput input); +} diff --git a/Magic.Core/Service/Cache/ISysCacheService.cs b/Magic.Core/Service/Cache/ISysCacheService.cs new file mode 100644 index 0000000..5d20fa1 --- /dev/null +++ b/Magic.Core/Service/Cache/ISysCacheService.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ISysCacheService +{ + bool Del(string key); + Task DelAsync(string key); + Task DelByPatternAsync(string key); + List GetAllCacheKeys(); + Task> GetDataScope(long userId); + Task> GetUsersDataScope(long userId); + Task> GetMenu(long userId, string appCode); + Task> GetPermission(long userId); + Task SetDataScope(long userId, List dataScopes); + Task SetUsersDataScope(long userId, List dataScopes); + Task SetMenu(long userId, string appCode, List menus); + Task SetPermission(long userId, List permissions); + bool Set(string key, object value); + Task SetAsync(string key, object value); + string Get(string key); + Task GetAsync(string key); + T Get(string key); + Task GetAsync(string key); + bool Exists(string key); + Task ExistsAsync(string key); + Task> GetAllPermission(); + + Task SetAllPermission(List permissions); +} diff --git a/Magic.Core/Service/Cache/SysCacheService.cs b/Magic.Core/Service/Cache/SysCacheService.cs new file mode 100644 index 0000000..9dc27f7 --- /dev/null +++ b/Magic.Core/Service/Cache/SysCacheService.cs @@ -0,0 +1,275 @@ +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +/// +/// 系统缓存服务 +/// +[ApiDescriptionSettings(Name = "Cache", Order = 100)] +public class SysCacheService : ISysCacheService, IDynamicApiController, ISingleton +{ + private readonly ICache _cache; + private readonly CacheOptions _cacheOptions; + + public SysCacheService(IOptions cacheOptions, Func resolveNamed) + { + _cacheOptions = cacheOptions.Value; + _cache = resolveNamed(_cacheOptions.CacheType.ToString(), default) as ICache; + } + + /// + /// 获取数据范围缓存(机构Id集合) + /// + /// + /// + public async Task> GetDataScope(long userId) + { + var cacheKey = CommonConst.CACHE_KEY_DATASCOPE + $"{userId}"; + return await _cache.GetAsync>(cacheKey); + } + /// + /// 获取数据范围缓存(用户Id集合) + /// + /// + /// + public async Task> GetUsersDataScope(long userId) + { + var cacheKey = CommonConst.CACHE_KEY_USERSDATASCOPE + $"{userId}"; + return await _cache.GetAsync>(cacheKey); + } + + /// + /// 缓存数据范围(机构Id集合) + /// + /// + /// + /// + [NonAction] + public async Task SetDataScope(long userId, List dataScopes) + { + var cacheKey = CommonConst.CACHE_KEY_DATASCOPE + $"{userId}"; + await _cache.SetAsync(cacheKey, dataScopes); + } + /// + /// 缓存数据范围(用户Id集合) + /// + /// + /// + /// + [NonAction] + public async Task SetUsersDataScope(long userId, List dataScopes) + { + var cacheKey = CommonConst.CACHE_KEY_USERSDATASCOPE + $"{userId}"; + await _cache.SetAsync(cacheKey, dataScopes); + } + /// + /// 获取菜单缓存 + /// + /// + /// + /// + public async Task> GetMenu(long userId, string appCode) + { + var cacheKey = CommonConst.CACHE_KEY_MENU + $"{userId}-{appCode}"; + return await _cache.GetAsync>(cacheKey); + } + + /// + /// 缓存菜单 + /// + /// + /// + /// + /// + [NonAction] + public async Task SetMenu(long userId, string appCode, List menus) + { + var cacheKey = CommonConst.CACHE_KEY_MENU + $"{userId}-{appCode}"; + await _cache.SetAsync(cacheKey, menus); + } + + /// + /// 获取权限缓存(按钮) + /// + /// + /// + public async Task> GetPermission(long userId) + { + var cacheKey = CommonConst.CACHE_KEY_PERMISSION + $"{userId}"; + return await _cache.GetAsync>(cacheKey); + } + + /// + /// 缓存权限 + /// + /// + /// + /// + [NonAction] + public async Task SetPermission(long userId, List permissions) + { + var cacheKey = CommonConst.CACHE_KEY_PERMISSION + $"{userId}"; + await _cache.SetAsync(cacheKey, permissions); + } + + /// + /// 获取所有缓存关键字 + /// + /// + public List GetAllCacheKeys() + { + var cacheItems = _cache.GetAllKeys(); + if (cacheItems == null) return new List(); + return cacheItems.Where(u => !u.ToString().StartsWith("mini-profiler")).Select(u => u).ToList(); + } + + /// + /// 获取所有按钮权限 + /// + /// + public async Task> GetAllPermission() + { + var cacheKey = CommonConst.CACHE_KEY_ALLPERMISSION; + return await _cache.GetAsync>(cacheKey); + } + + /// + /// 设置所有按钮权限 + /// + /// + /// + public async Task SetAllPermission(List permissions) + { + var cacheKey = CommonConst.CACHE_KEY_ALLPERMISSION; + await _cache.SetAsync(cacheKey, permissions); + } + + /// + /// 删除指定关键字缓存 + /// + /// + /// + [NonAction] + public bool Del(string key) + { + _cache.Del(key); + return true; + } + + /// + /// 删除指定关键字缓存 + /// + /// + /// + public Task DelAsync(string key) + { + _cache.DelAsync(key); + return Task.FromResult(true); + } + + /// + /// 删除某特征关键字缓存 + /// + /// + /// + public Task DelByPatternAsync(string key) + { + _cache.DelByPatternAsync(key); + return Task.FromResult(true); + } + + /// + /// 设置缓存 + /// + /// + /// + /// + [NonAction] + public bool Set(string key, object value) + { + return _cache.Set(key, value); + } + + /// + /// 设置缓存 + /// + /// + /// + /// + public async Task SetAsync(string key, object value) + { + return await _cache.SetAsync(key, value); + } + + /// + /// 获取缓存 + /// + /// + /// + [NonAction] + public string Get(string key) + { + return _cache.Get(key); + } + + /// + /// 获取缓存 + /// + /// + /// + public async Task GetAsync(string key) + { + return await _cache.GetAsync(key); + } + + /// + /// 获取缓存 + /// + /// + /// + /// + [NonAction] + public T Get(string key) + { + return _cache.Get(key); + } + + /// + /// 获取缓存 + /// + /// + /// + /// + public Task GetAsync(string key) + { + return _cache.GetAsync(key); + } + + /// + /// 检查给定 key 是否存在 + /// + /// 键 + /// + [NonAction] + public bool Exists(string key) + { + return _cache.Exists(key); + } + + /// + /// 检查给定 key 是否存在 + /// + /// 键 + /// + public Task ExistsAsync(string key) + { + return _cache.ExistsAsync(key); + } +} diff --git a/Magic.Core/Service/CodeGen/CodeGenConfigService.cs b/Magic.Core/Service/CodeGen/CodeGenConfigService.cs new file mode 100644 index 0000000..5553cab --- /dev/null +++ b/Magic.Core/Service/CodeGen/CodeGenConfigService.cs @@ -0,0 +1,141 @@ + + +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Magic.Core.Entity; +using Mapster; +using Microsoft.AspNetCore.Mvc; + +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +/// +/// 代码生成详细配置服务 +/// +[ApiDescriptionSettings(Name = "CodeGenConfig", Order = 100)] +public class CodeGenConfigService : ICodeGenConfigService, IDynamicApiController, ITransient +{ + private readonly SqlSugarRepository _sysCodeGenConfigRep; // 代码生成详细配置仓储 + + public CodeGenConfigService(SqlSugarRepository sysCodeGenConfigRep) + { + _sysCodeGenConfigRep = sysCodeGenConfigRep; + } + + /// + /// 代码生成详细配置列表 + /// + /// + /// + [HttpGet("/sysCodeGenerateConfig/list")] + public async Task> List([FromQuery] CodeGenConfig input) + { + return await _sysCodeGenConfigRep.Where(u => u.CodeGenId == input.CodeGenId && u.WhetherCommon != YesOrNot.Y.ToString()) + .Select().ToListAsync(); + } + + /// + /// 增加 + /// + /// + /// + [NonAction] + public async Task Add(CodeGenConfig input) + { + var codeGenConfig = input.Adapt(); + await _sysCodeGenConfigRep.InsertAsync(codeGenConfig); + } + + /// + /// 删除 + /// + /// + /// + [NonAction] + public async Task Delete(long codeGenId) + { + await _sysCodeGenConfigRep.DeleteAsync(u => u.CodeGenId == codeGenId); + } + + /// + /// 更新 + /// + /// + /// + [HttpPost("/sysCodeGenerateConfig/edit")] + public async Task Update(List inputList) + { + if (inputList == null || inputList.Count < 1) return; + List list = inputList.Adapt>(); + await _sysCodeGenConfigRep.UpdateAsync(list); + } + + /// + /// 详情 + /// + /// + /// + [HttpGet("/sysCodeGenerateConfig/detail")] + public async Task Detail(CodeGenConfig input) + { + return await _sysCodeGenConfigRep.FirstOrDefaultAsync(u => u.Id == input.Id); + } + + /// + /// 批量增加 + /// + /// + /// + [NonAction] + public void AddList(List tableColumnOuputList, SysCodeGen codeGenerate) + { + if (tableColumnOuputList == null) return; + + var codeGenConfigs = new List(); + + foreach (var tableColumn in tableColumnOuputList) + { + var codeGenConfig = new SysCodeGenConfig(); + + var YesOrNo = YesOrNot.Y.ToString(); + if (Convert.ToBoolean(tableColumn.ColumnKey)) + { + YesOrNo = YesOrNot.N.ToString(); + } + + if (CodeGenUtil.IsCommonColumn(tableColumn.ColumnName)) + { + codeGenConfig.WhetherCommon = YesOrNot.Y.ToString(); + YesOrNo = YesOrNot.N.ToString(); + } + else + { + codeGenConfig.WhetherCommon = YesOrNot.N.ToString(); + } + + codeGenConfig.CodeGenId = codeGenerate.Id; + codeGenConfig.ColumnName = tableColumn.ColumnName; + codeGenConfig.ColumnComment = tableColumn.ColumnComment; + codeGenConfig.NetType = CodeGenUtil.ConvertDataType(tableColumn.DataType); + codeGenConfig.WhetherRetract = YesOrNot.N.ToString(); + + codeGenConfig.WhetherRequired = YesOrNot.N.ToString(); + codeGenConfig.QueryWhether = YesOrNo; + codeGenConfig.WhetherAddUpdate = YesOrNo; + codeGenConfig.WhetherTable = YesOrNo; + + codeGenConfig.ColumnKey = tableColumn.ColumnKey; + + codeGenConfig.DataType = tableColumn.DataType; + codeGenConfig.EffectType = CodeGenUtil.DataTypeToEff(codeGenConfig.NetType); + codeGenConfig.QueryType = "=="; // QueryTypeEnum.eq.ToString(); + codeGenConfigs.Add(codeGenConfig); + } + _sysCodeGenConfigRep.InsertAsync(codeGenConfigs); + } +} diff --git a/Magic.Core/Service/CodeGen/CodeGenService.cs b/Magic.Core/Service/CodeGen/CodeGenService.cs new file mode 100644 index 0000000..9cc4def --- /dev/null +++ b/Magic.Core/Service/CodeGen/CodeGenService.cs @@ -0,0 +1,396 @@ +using Furion; +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Furion.FriendlyException; +using Furion.ViewEngine; +using Magic.Core.Entity; +using Mapster; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +/// +/// 代码生成器服务 +/// +[ApiDescriptionSettings(Name = "CodeGen", Order = 100)] +public class CodeGenService : ICodeGenService, IDynamicApiController, ITransient +{ + private readonly SqlSugarRepository _sysCodeGenRep; // 代码生成器仓储 + private readonly ICodeGenConfigService _codeGenConfigService; + private readonly IViewEngine _viewEngine; + + private readonly SqlSugarRepository _sysMenuRep; // 菜单表仓储 + + private readonly ICommonService _commonService; + + public CodeGenService(SqlSugarRepository sysCodeGenRep, + ICodeGenConfigService codeGenConfigService, + IViewEngine viewEngine, + ICommonService commonService, + SqlSugarRepository sysMenuRep) + { + _sysCodeGenRep = sysCodeGenRep; + _codeGenConfigService = codeGenConfigService; + _viewEngine = viewEngine; + _sysMenuRep = sysMenuRep; + _commonService = commonService; + } + + /// + /// 分页查询 + /// + /// + /// + [HttpGet("/codeGenerate/page")] + public async Task QueryCodeGenPageList([FromQuery] CodeGenInput input) + { + var tableName = !string.IsNullOrEmpty(input.TableName?.Trim()); + var codeGens = await _sysCodeGenRep.AsQueryable() + .WhereIF(!string.IsNullOrWhiteSpace(input.TableName), u => u.TableName.Contains(input.TableName.Trim())) + .ToPagedListAsync(input.PageNo, input.PageSize); + return codeGens.XnPagedResult(); + } + + /// + /// 增加 + /// + /// + /// + [HttpPost("/codeGenerate/add")] + public async Task AddCodeGen(AddCodeGenInput input) + { + var isExist = await _sysCodeGenRep.AnyAsync(u => u.TableName == input.TableName); + if (isExist) + throw Oops.Oh(ErrorCode.D1400); + + var codeGen = input.Adapt(); + var newCodeGen = await _sysCodeGenRep.InsertReturnEntityAsync(codeGen); + // 加入配置表中 + _codeGenConfigService.AddList(GetColumnList(input), newCodeGen); + } + + /// + /// 删除 + /// + /// + /// + [HttpPost("/codeGenerate/delete")] + public async Task DeleteCodeGen(List inputs) + { + if (inputs == null || inputs.Count < 1) return; + + var codeGenConfigTaskList = new List(); + inputs.ForEach(u => + { + _sysCodeGenRep.Delete(u.Id); + + // 删除配置表中 + codeGenConfigTaskList.Add(_codeGenConfigService.Delete(u.Id)); + }); + await Task.WhenAll(codeGenConfigTaskList); + } + + /// + /// 更新 + /// + /// + /// + [HttpPost("/codeGenerate/edit")] + public async Task UpdateCodeGen(UpdateCodeGenInput input) + { + var isExist = await _sysCodeGenRep.AnyAsync(u => u.TableName == input.TableName && u.Id != input.Id); + if (isExist) + throw Oops.Oh(ErrorCode.D1400); + + var codeGen = input.Adapt(); + await _sysCodeGenRep.UpdateAsync(codeGen); + } + + /// + /// 详情 + /// + /// + /// + [HttpGet("/codeGenerate/detail")] + public async Task GetCodeGen([FromQuery] QueryCodeGenInput input) + { + return await _sysCodeGenRep.SingleAsync(m => m.Id == input.Id); + } + + /// + /// 获取数据库表(实体)集合 + /// + /// + [HttpGet("/codeGenerate/InformationList")] + public async Task> GetTableList() + { + IEnumerable entityInfos = await _commonService.GetEntityInfos(false); + List result = new List(); + foreach (var item in entityInfos) + { + result.Add(new TableOutput() + { + EntityName = item.EntityName, + TableName = item.DbTableName, + TableComment = item.TableDescription + }); + } + return result; + } + + /// + /// 根据表名获取列 + /// + /// + [HttpGet("/codeGenerate/ColumnList/{tableName}")] + public List GetColumnListByTableName(string tableName) + { + // 获取实体类型属性 + var entityType = _sysCodeGenRep.Context.DbMaintenance.GetTableInfoList().FirstOrDefault(u => u.Name == tableName); + if (entityType == null) return null; + + // 按原始类型的顺序获取所有实体类型属性(不包含导航属性,会返回null) + return _sysCodeGenRep.Context.DbMaintenance.GetColumnInfosByTableName(entityType.Name).Select(u => new TableColumnOuput + { + ColumnName = u.DbColumnName, + ColumnKey = u.IsPrimarykey.ToString(), + DataType = u.DataType.ToString(), + NetType = CodeGenUtil.ConvertDataType(u.DataType.ToString()), + ColumnComment = u.ColumnDescription + }).ToList(); + } + + /// + /// 获取数据表列(实体属性)集合 + /// + /// + [NonAction] + public List GetColumnList([FromQuery] AddCodeGenInput input) + { + var entityType = _commonService.GetEntityInfos().Result.FirstOrDefault(m => m.EntityName == input.TableName); + if (entityType == null) + return null; + + return _sysCodeGenRep.Context.DbMaintenance.GetColumnInfosByTableName(entityType.DbTableName,false).Select(u => new TableColumnOuput + { + ColumnName = u.DbColumnName, + ColumnKey = u.IsPrimarykey.ToString(), + DataType = u.DataType.ToString(), + ColumnComment = string.IsNullOrWhiteSpace(u.ColumnDescription) ? u.DbColumnName : u.ColumnDescription + }).ToList(); + } + + /// + /// 代码生成_本地项目 + /// + /// + [HttpPost("/codeGenerate/runLocal")] + public async Task RunLocal(SysCodeGen input) + { + // 先删除该表已生成的菜单列表 + var templatePathList = GetTemplatePathList(); + var targetPathList = GetTargetPathList(input); + for (var i = 0; i < templatePathList.Count; i++) + { + var tContent = File.ReadAllText(templatePathList[i]); + + var tableFieldList = await _codeGenConfigService.List(new CodeGenConfig() { CodeGenId = input.Id }); // 字段集合 + if (i >= 5) // 适应前端首字母小写 + { + tableFieldList.ForEach(u => + { + u.ColumnName = u.ColumnName.Substring(0, 1).ToLower() + u.ColumnName[1..]; + }); + } + + var queryWhetherList = tableFieldList.Where(u => u.QueryWhether == YesOrNot.Y.ToString()).ToList(); // 前端查询集合 + var tResult = _viewEngine.RunCompileFromCached(tContent, new + { + input.AuthorName, + input.BusName, + input.NameSpace, + ClassName = input.TableName, + QueryWhetherList = queryWhetherList, + TableField = tableFieldList + }); + + var dirPath = new DirectoryInfo(targetPathList[i]).Parent.FullName; + if (!Directory.Exists(dirPath)) + Directory.CreateDirectory(dirPath); + File.WriteAllText(targetPathList[i], tResult, Encoding.UTF8); + } + + await AddMenu(input.TableName, input.BusName, input.MenuApplication, input.MenuPid); + } + + private async Task AddMenu(string className, string busName, string application, long pid) + { + // 定义菜单编码前缀 + var codePrefix = "magic_" + className.ToLower(); + + // 先删除该表已生成的菜单列表 + await _sysMenuRep.DeleteAsync(u => u.Code.StartsWith(codePrefix)); + + // 如果 pid 为 0 说明为顶级菜单, 需要创建顶级目录 + if (pid == 0) + { + // 目录 + var menuType0 = new SysMenu + { + Pid = 0, + Pids = "[0],", + Name = busName + "管理", + Code = codePrefix, + Type = 1, + Icon = "robot", + Router = "/" + className.ToLower(), + Component = "PageView", + Application = application + }; + pid = (await _sysMenuRep.InsertReturnEntityAsync(menuType0)).Id; + } + // 由于后续菜单会有修改, 需要判断下 pid 是否存在, 不存在报错 + else if (!await _sysMenuRep.AnyAsync(e => e.Id == pid)) + throw Oops.Oh(ErrorCode.D1505); + + // 菜单 + var menuType1 = new SysMenu + { + Pid = pid, + Pids = "[0],[" + pid + "],", + Name = busName + "管理", + Code = codePrefix + "_mgr", + Type = 1, + Router = "/" + className.ToLower(), + Component = "main/" + className + "/index", + Application = application, + OpenType = 1 + }; + var pid1 = (await _sysMenuRep.InsertReturnEntityAsync(menuType1)).Id; + + + + // 按钮-page + var menuType2 = new SysMenu + { + Pid = pid1, + Pids = "[0],[" + pid + "],[" + pid1 + "],", + Name = busName + "查询", + Code = codePrefix + "_mgr_page", + Type = 2, + Permission = className + ":page", + Application = application, + }; + + // 按钮-detail + var menuType2_1 = new SysMenu + { + Pid = pid1, + Pids = "[0],[" + pid + "],[" + pid1 + "],", + Name = busName + "详情", + Code = codePrefix + "_mgr_detail", + Type = 2, + Permission = className + ":detail", + Application = application, + }; + + // 按钮-add + var menuType2_2 = new SysMenu + { + Pid = pid1, + Pids = "[0],[" + pid + "],[" + pid1 + "],", + Name = busName + "增加", + Code = codePrefix + "_mgr_add", + Type = 2, + Permission = className + ":add", + Application = application, + }; + + // 按钮-delete + var menuType2_3 = new SysMenu + { + Pid = pid1, + Pids = "[0],[" + pid + "],[" + pid1 + "],", + Name = busName + "删除", + Code = codePrefix + "_mgr_delete", + Type = 2, + Permission = className + ":delete", + Application = application, + }; + + // 按钮-edit + var menuType2_4 = new SysMenu + { + Pid = pid1, + Pids = "[0],[" + pid + "],[" + pid1 + "],", + Name = busName + "编辑", + Code = codePrefix + "_mgr_edit", + Type = 2, + Permission = className + ":edit", + Application = application, + }; + + List menuList = new List() { menuType2, menuType2_1, menuType2_2, menuType2_3, menuType2_4 }; + await _sysMenuRep.InsertAsync(menuList); + } + + /// + /// 获取模板文件路径集合 + /// + /// + private List GetTemplatePathList() + { + var templatePath = Path.Combine(App.WebHostEnvironment.WebRootPath, "Template"); + return new List() + { + Path.Combine(templatePath , "Service.cs.vm"), + Path.Combine(templatePath , "IService.cs.vm"), + Path.Combine(templatePath , "Input.cs.vm"), + Path.Combine(templatePath , "Output.cs.vm"), + Path.Combine(templatePath , "Dto.cs.vm"), + Path.Combine(templatePath , "index.vue.vm"), + Path.Combine(templatePath , "addForm.vue.vm"), + Path.Combine(templatePath , "editForm.vue.vm"), + Path.Combine(templatePath , "manage.js.vm"), + }; + } + + /// + /// 设置生成文件路径 + /// + /// + /// + private List GetTargetPathList(SysCodeGen input) + { + var backendPath = Path.Combine(new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent.FullName, "Magic.Application", "Service", input.TableName); + var servicePath = Path.Combine(backendPath, input.TableName + "Service.cs"); + var iservicePath = Path.Combine(backendPath, "I" + input.TableName + "Service.cs"); + var inputPath = Path.Combine(backendPath, "Dto", input.TableName + "Input.cs"); + var outputPath = Path.Combine(backendPath, "Dto", input.TableName + "Output.cs"); + var viewPath = Path.Combine(backendPath, "Dto", input.TableName + "Dto.cs"); + var frontendPath = Path.Combine(new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent.Parent.FullName, "frontend", "src", "views", "main"); + var indexPath = Path.Combine(frontendPath, input.TableName, "index.vue"); + var addFormPath = Path.Combine(frontendPath, input.TableName, "addForm.vue"); + var editFormPath = Path.Combine(frontendPath, input.TableName, "editForm.vue"); + var apiJsPath = Path.Combine(new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent.Parent.FullName, "frontend", "src", "api", "modular", "main", input.TableName + "Manage.js"); + + return new List() + { + servicePath, + iservicePath, + inputPath, + outputPath, + viewPath, + indexPath, + addFormPath, + editFormPath, + apiJsPath + }; + } +} diff --git a/Magic.Core/Service/CodeGen/Dto/CodeGenConfig.cs b/Magic.Core/Service/CodeGen/Dto/CodeGenConfig.cs new file mode 100644 index 0000000..a6e63a4 --- /dev/null +++ b/Magic.Core/Service/CodeGen/Dto/CodeGenConfig.cs @@ -0,0 +1,123 @@ +namespace Magic.Core.Service; + +/// +/// 代码生成详细配置参数 +/// +public class CodeGenConfig +{ + /// + /// 主键Id + /// + public long Id { get; set; } + + /// + /// 代码生成主表ID + /// + public long CodeGenId { get; set; } + + /// + /// 数据库字段名 + /// + public string ColumnName { get; set; } + + /// + /// 数据库字段名(首字母小写) + /// + public string LowerColumnName => string.IsNullOrWhiteSpace(ColumnName) + ? null + : ColumnName.Substring(0, 1).ToLower() + ColumnName[1..]; + + /// + /// 字段描述 + /// + public string ColumnComment { get; set; } + + /// + /// .NET类型 + /// + public string NetType { get; set; } + + /// + /// 作用类型(字典) + /// + public string EffectType { get; set; } + + /// + /// 外键实体名称 + /// + public string FkEntityName { get; set; } + + /// + /// 外键实体名称(首字母小写) + /// + public string LowerFkEntityName => string.IsNullOrWhiteSpace(FkEntityName) + ? null + : FkEntityName.Substring(0, 1).ToLower() + FkEntityName[1..]; + + /// + /// 外键显示字段 + /// + public string FkColumnName { get; set; } + + /// + /// 外键显示字段(首字母小写) + /// + public string LowerFkColumnName => string.IsNullOrWhiteSpace(FkColumnName) + ? null + : (FkColumnName.Substring(0, 1).ToLower() + FkColumnName[1..]); + + /// + /// 外键显示字段.NET类型 + /// + public string FkColumnNetType { get; set; } + + /// + /// 字典code + /// + public string DictTypeCode { get; set; } + + /// + /// 列表是否缩进(字典) + /// + public string WhetherRetract { get; set; } + + /// + /// 是否必填(字典) + /// + public string WhetherRequired { get; set; } + + /// + /// 是否是查询条件 + /// + public string QueryWhether { get; set; } + + /// + /// 查询方式 + /// + public string QueryType { get; set; } + + /// + /// 列表显示 + /// + public string WhetherTable { get; set; } + + /// + /// 增改 + /// + public string WhetherAddUpdate { get; set; } + + /// + /// 主外键 + /// + public string ColumnKey { get; set; } + + /// + /// 数据库中类型(物理类型) + /// + public string DataType { get; set; } + + /// + /// 是否是通用字段 + /// + public string WhetherCommon { get; set; } +} diff --git a/Magic.Core/Service/CodeGen/Dto/CodeGenInput.cs b/Magic.Core/Service/CodeGen/Dto/CodeGenInput.cs new file mode 100644 index 0000000..5d1af10 --- /dev/null +++ b/Magic.Core/Service/CodeGen/Dto/CodeGenInput.cs @@ -0,0 +1,145 @@ +using System.ComponentModel.DataAnnotations; + +namespace Magic.Core.Service; + +/// +/// 代码生成参数类 +/// +public class CodeGenInput : InputBase +{ + /// + /// 作者姓名 + /// + public virtual string AuthorName { get; set; } + + /// + /// 类名 + /// + public virtual string ClassName { get; set; } + + /// + /// 是否移除表前缀 + /// + public virtual string TablePrefix { get; set; } + + /// + /// 生成方式 + /// + public virtual string GenerateType { get; set; } + + /// + /// 数据库表名 + /// + public virtual string TableName { get; set; } + + /// + /// 命名空间 + /// + public virtual string NameSpace { get; set; } + + /// + /// 业务名(业务代码包名称) + /// + public virtual string BusName { get; set; } + + /// + /// 功能名(数据库表名称) + /// + public virtual string TableComment { get; set; } + + /// + /// 菜单应用分类(应用编码) + /// + public virtual string MenuApplication { get; set; } + + /// + /// 菜单父级 + /// + public virtual long MenuPid { get; set; } +} + +public class AddCodeGenInput : CodeGenInput +{ + /// + /// 数据库表名 + /// + [Required(ErrorMessage = "数据库表名不能为空")] + public override string TableName { get; set; } + + /// + /// 业务名(业务代码包名称) + /// + [Required(ErrorMessage = "业务名不能为空")] + public override string BusName { get; set; } + + /// + /// 命名空间 + /// + [Required(ErrorMessage = "命名空间不能为空")] + public override string NameSpace { get; set; } + + /// + /// 作者姓名 + /// + [Required(ErrorMessage = "作者姓名不能为空")] + public override string AuthorName { get; set; } + + ///// + ///// 类名 + ///// + //[Required(ErrorMessage = "类名不能为空")] + //public override string ClassName { get; set; } + + ///// + ///// 是否移除表前缀 + ///// + //[Required(ErrorMessage = "是否移除表前缀不能为空")] + //public override string TablePrefix { get; set; } + + /// + /// 生成方式 + /// + [Required(ErrorMessage = "生成方式不能为空")] + public override string GenerateType { get; set; } + + ///// + ///// 功能名(数据库表名称) + ///// + //[Required(ErrorMessage = "数据库表名不能为空")] + //public override string TableComment { get; set; } + + /// + /// 菜单应用分类(应用编码) + /// + [Required(ErrorMessage = "菜单应用分类不能为空")] + public override string MenuApplication { get; set; } + + /// + /// 菜单父级 + /// + [Required(ErrorMessage = "菜单父级不能为空")] + public override long MenuPid { get; set; } +} + +public class DeleteCodeGenInput +{ + /// + /// 代码生成器Id + /// + [Required(ErrorMessage = "代码生成器Id不能为空")] + public long Id { get; set; } +} + +public class UpdateCodeGenInput : CodeGenInput +{ + /// + /// 代码生成器Id + /// + [Required(ErrorMessage = "代码生成器Id不能为空")] + public long Id { get; set; } +} + +public class QueryCodeGenInput : DeleteCodeGenInput +{ + +} diff --git a/Magic.Core/Service/CodeGen/Dto/CodeGenOutput.cs b/Magic.Core/Service/CodeGen/Dto/CodeGenOutput.cs new file mode 100644 index 0000000..a67baff --- /dev/null +++ b/Magic.Core/Service/CodeGen/Dto/CodeGenOutput.cs @@ -0,0 +1,62 @@ +namespace Magic.Core.Service; + +/// +/// 代码生成参数类 +/// +public class CodeGenOutput +{ + /// + /// 代码生成器Id + /// + public long Id { get; set; } + + /// + /// 作者姓名 + /// + public string AuthorName { get; set; } + + /// + /// 类名 + /// + public string ClassName { get; set; } + + /// + /// 是否移除表前缀 + /// + public string TablePrefix { get; set; } + + /// + /// 生成方式 + /// + public string GenerateType { get; set; } + + /// + /// 数据库表名 + /// + public string TableName { get; set; } + + /// + /// 包名 + /// + public string PackageName { get; set; } + + /// + /// 业务名(业务代码包名称) + /// + public string BusName { get; set; } + + /// + /// 功能名(数据库表名称) + /// + public string TableComment { get; set; } + + /// + /// 菜单应用分类(应用编码) + /// + public string MenuApplication { get; set; } + + /// + /// 菜单父级 + /// + public long MenuPid { get; set; } +} diff --git a/Magic.Core/Service/CodeGen/Dto/TableColumnOuput.cs b/Magic.Core/Service/CodeGen/Dto/TableColumnOuput.cs new file mode 100644 index 0000000..91cedb4 --- /dev/null +++ b/Magic.Core/Service/CodeGen/Dto/TableColumnOuput.cs @@ -0,0 +1,32 @@ +namespace Magic.Core.Service; + +/// +/// 数据库表列 +/// +public class TableColumnOuput +{ + /// + /// 字段名 + /// + public string ColumnName { get; set; } + + /// + /// 数据库中类型 + /// + public string DataType { get; set; } + + /// + /// .NET字段类型 + /// + public string NetType { get; set; } + + /// + /// 字段描述 + /// + public string ColumnComment { get; set; } + + /// + /// 主外键 + /// + public string ColumnKey { get; set; } +} diff --git a/Magic.Core/Service/CodeGen/Dto/TableOutput.cs b/Magic.Core/Service/CodeGen/Dto/TableOutput.cs new file mode 100644 index 0000000..b55a608 --- /dev/null +++ b/Magic.Core/Service/CodeGen/Dto/TableOutput.cs @@ -0,0 +1,32 @@ +namespace Magic.Core.Service; + +/// +/// 数据库表列表参数 +/// +public class TableOutput +{ + /// + /// 表名(字母形式的) + /// + public string TableName { get; set; } + + /// + /// 实体名称 + /// + public string EntityName { get; set; } + + /// + /// 创建时间 + /// + public string CreateTime { get; set; } + + /// + /// 更新时间 + /// + public string UpdateTime { get; set; } + + /// + /// 表名称描述(注释)(功能名) + /// + public string TableComment { get; set; } +} diff --git a/Magic.Core/Service/CodeGen/Dto/XnCodeGenOutput.cs b/Magic.Core/Service/CodeGen/Dto/XnCodeGenOutput.cs new file mode 100644 index 0000000..b315628 --- /dev/null +++ b/Magic.Core/Service/CodeGen/Dto/XnCodeGenOutput.cs @@ -0,0 +1,52 @@ +using Magic.Core.Entity; +using System.Collections.Generic; + +namespace Magic.Core.Service; + +public class XnCodeGenOutput +{ + /// + /// 作者姓名 + /// + public string AuthorName { get; set; } + + /// + /// 是否移除表前缀 + /// + public string TablePrefix { get; set; } + + /// + /// 生成方式 + /// + public string GenerateType { get; set; } + + /// + /// 数据库表名 + /// + public string TableName { get; set; } + + /// + /// 数据库表名(经过组装的) + /// + public string TableNameAss { get; set; } + + /// + /// 代码包名 + /// + public string PackageName { get; set; } + + /// + /// 生成时间(string类型的) + /// + public string CreateTimestring { get; set; } + + /// + /// 数据库表中字段集合 + /// + public List ConfigList { get; set; } + + /// + /// 业务名 + /// + public string BusName { get; set; } +} diff --git a/Magic.Core/Service/CodeGen/ICodeGenConfigService.cs b/Magic.Core/Service/CodeGen/ICodeGenConfigService.cs new file mode 100644 index 0000000..0b48b77 --- /dev/null +++ b/Magic.Core/Service/CodeGen/ICodeGenConfigService.cs @@ -0,0 +1,16 @@ +using Magic.Core.Entity; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ICodeGenConfigService +{ + Task Add(CodeGenConfig input); + void AddList(List tableColumnOuputList, SysCodeGen codeGenerate); + Task Delete(long codeGenId); + Task Detail(CodeGenConfig input); + Task> List([FromQuery] CodeGenConfig input); + Task Update(List inputList); +} diff --git a/Magic.Core/Service/CodeGen/ICodeGenService.cs b/Magic.Core/Service/CodeGen/ICodeGenService.cs new file mode 100644 index 0000000..b06bdbe --- /dev/null +++ b/Magic.Core/Service/CodeGen/ICodeGenService.cs @@ -0,0 +1,18 @@ +using Magic.Core.Entity; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ICodeGenService +{ + Task AddCodeGen(AddCodeGenInput input); + Task DeleteCodeGen(List inputs); + Task GetCodeGen([FromQuery] QueryCodeGenInput input); + List GetColumnList(AddCodeGenInput input); + Task> GetTableList(); + Task QueryCodeGenPageList([FromQuery] CodeGenInput input); + Task RunLocal(SysCodeGen input); + Task UpdateCodeGen(UpdateCodeGenInput input); +} diff --git a/Magic.Core/Service/Common/CommonService.cs b/Magic.Core/Service/Common/CommonService.cs new file mode 100644 index 0000000..bfec08f --- /dev/null +++ b/Magic.Core/Service/Common/CommonService.cs @@ -0,0 +1,59 @@ +using Furion; +using Furion.DependencyInjection; +using Microsoft.Extensions.Options; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public class CommonService : ICommonService, IScoped +{ + private readonly ICache _cache; + public CommonService(IOptions cacheOptions, Func resolveNamed, ISqlSugarClient sqlSugarClient) + { + _cache = resolveNamed(cacheOptions.Value.CacheType.ToString(), default) as ICache; + } + + /// + /// 获取库表信息 + /// + /// + /// + public async Task> GetEntityInfos(bool IsCache = true) + { + List entityInfos = IsCache ? (await _cache.GetAsync>(CommonConst.CACHE_KEY_ENTITYINFO) ?? new List()) : new List(); + if (entityInfos != null && entityInfos.Any()) + { + return entityInfos; + } + var type = typeof(SugarTable); + List cosType = App.EffectiveTypes.Where(a => !a.IsAbstract && a.IsClass && a.GetCustomAttributes(typeof(SugarTable), true)?.FirstOrDefault() != null).ToList(); + foreach (var c in cosType) + { + var sugarAttribute = c.GetCustomAttributes(type, true)?.FirstOrDefault(); + + var des = c.GetCustomAttributes(typeof(DescriptionAttribute), true); + var description = ""; + if (des.Length > 0) + { + description = ((DescriptionAttribute)des[0]).Description; + } + entityInfos.Add(new EntityInfo() + { + EntityName = c.Name, + DbTableName = sugarAttribute == null ? c.Name : ((SugarTable)sugarAttribute).TableName, + TableDescription = description + }); + } + + await _cache.SetAsync(CommonConst.CACHE_KEY_ENTITYINFO, entityInfos); + + return entityInfos; + } +} diff --git a/Magic.Core/Service/Common/ICommonService.cs b/Magic.Core/Service/Common/ICommonService.cs new file mode 100644 index 0000000..3f595fe --- /dev/null +++ b/Magic.Core/Service/Common/ICommonService.cs @@ -0,0 +1,13 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ICommonService +{ + Task> GetEntityInfos(bool IsCache=true); +} diff --git a/Magic.Core/Service/Config/Dto/ConfigInput.cs b/Magic.Core/Service/Config/Dto/ConfigInput.cs new file mode 100644 index 0000000..c72c57f --- /dev/null +++ b/Magic.Core/Service/Config/Dto/ConfigInput.cs @@ -0,0 +1,82 @@ +using System.ComponentModel.DataAnnotations; + +namespace Magic.Core.Service; + +/// +/// 参数配置 +/// +public class ConfigInput : PageInputBase +{ + /// + /// 名称 + /// + public virtual string Name { get; set; } + + /// + /// 编码 + /// + public virtual string Code { get; set; } + + /// + /// 属性值 + /// + public virtual string Value { get; set; } + + /// + /// 是否是系统参数(Y-是,N-否) + /// + public virtual string SysFlag { get; set; } + + /// + /// 备注 + /// + public virtual string Remark { get; set; } + + /// + /// 状态(字典 0正常 1停用 2删除) + /// + public virtual int Status { get; set; } + + /// + /// 常量所属分类的编码,来自于“常量的分类”字典 + /// + public virtual string GroupCode { get; set; } +} + +public class AddConfigInput : ConfigInput +{ + /// + /// 名称 + /// + [Required(ErrorMessage = "参数名称不能为空")] + public override string Name { get; set; } + + /// + /// 编码 + /// + [Required(ErrorMessage = "参数编码不能为空")] + public override string Code { get; set; } +} + +public class DeleteConfigInput +{ + /// + /// 应用Id + /// + [Required(ErrorMessage = "参数Id不能为空")] + public long Id { get; set; } +} + +public class UpdateConfigInput : AddConfigInput +{ + /// + /// 应用Id + /// + [Required(ErrorMessage = "应用Id不能为空")] + public long Id { get; set; } +} + +public class QueryConfigInput : DeleteConfigInput +{ + +} diff --git a/Magic.Core/Service/Config/ISysConfigService.cs b/Magic.Core/Service/Config/ISysConfigService.cs new file mode 100644 index 0000000..f8d2dfb --- /dev/null +++ b/Magic.Core/Service/Config/ISysConfigService.cs @@ -0,0 +1,20 @@ +using Magic.Core.Entity; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ISysConfigService +{ + Task AddConfig(AddConfigInput input); + Task DeleteConfig(DeleteConfigInput input); + Task GetConfig([FromQuery] QueryConfigInput input); + Task GetConfigList([FromQuery] ConfigInput input); + Task QueryConfigPageList([FromQuery] ConfigInput input); + Task UpdateConfig(UpdateConfigInput input); + Task GetDemoEnvFlag(); + Task GetCaptchaOpenFlag(); + + Task GetDefaultPassword(); + Task UpdateConfigCache(string code, object value); +} diff --git a/Magic.Core/Service/Config/SysConfigService.cs b/Magic.Core/Service/Config/SysConfigService.cs new file mode 100644 index 0000000..597797b --- /dev/null +++ b/Magic.Core/Service/Config/SysConfigService.cs @@ -0,0 +1,181 @@ + + +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Furion.FriendlyException; +using Magic.Core.Entity; +using Mapster; +using Microsoft.AspNetCore.Mvc; + +using SqlSugar; +using System.Linq; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +/// +/// 系统参数配置服务 +/// +[ApiDescriptionSettings(Name = "Config", Order = 100)] +public class SysConfigService : ISysConfigService, IDynamicApiController, ITransient +{ + private readonly SqlSugarRepository _sysConfigRep; // 参数配置表仓储 + private readonly ISysCacheService _sysCacheService; + + public SysConfigService(SqlSugarRepository sysConfigRep, ISysCacheService sysCacheService) + { + _sysConfigRep = sysConfigRep; + _sysCacheService = sysCacheService; + } + + /// + /// 分页获取系统参数配置 + /// + /// + /// + [HttpGet("/sysConfig/page")] + public async Task QueryConfigPageList([FromQuery] ConfigInput input) + { + var configs = await _sysConfigRep.AsQueryable() + .WhereIF(!string.IsNullOrWhiteSpace(input.Name), u => u.Name.Contains(input.Name.Trim())) + .WhereIF(!string.IsNullOrWhiteSpace(input.Code), u => u.Code.Contains(input.Code.Trim())) + .WhereIF(!string.IsNullOrWhiteSpace(input.GroupCode), u => u.GroupCode == input.GroupCode.Trim()) + .Where(u => u.Status != CommonStatus.DELETED).OrderBy(u => u.GroupCode) + .ToPagedListAsync(input.PageNo, input.PageSize); + return configs.XnPagedResult(); + } + + /// + /// 获取系统参数配置列表 + /// + /// + /// + [HttpGet("/sysConfig/list")] + public async Task GetConfigList([FromQuery] ConfigInput input) + { + return await _sysConfigRep.Where(u => u.Status != CommonStatus.DELETED).ToListAsync(); + } + + /// + /// 增加系统参数配置 + /// + /// + /// + [HttpPost("/sysConfig/add")] + public async Task AddConfig(AddConfigInput input) + { + var isExist = await _sysConfigRep.AnyAsync(u => u.Name == input.Name || u.Code == input.Code); + if (isExist) + throw Oops.Oh(ErrorCode.D9000); + + var config = input.Adapt(); + await _sysConfigRep.InsertAsync(config); + } + + /// + /// 删除系统参数配置 + /// + /// + /// + [HttpPost("/sysConfig/delete")] + public async Task DeleteConfig(DeleteConfigInput input) + { + var config = await _sysConfigRep.FirstOrDefaultAsync(u => u.Id == input.Id); + // 禁止删除系统参数 + if (config.SysFlag == YesOrNot.Y.ToString()) + throw Oops.Oh(ErrorCode.D9001); + + await _sysConfigRep.DeleteAsync(config); + //刷新缓存 + await _sysCacheService.DelAsync(config.Code); + } + + /// + /// 更新系统参数配置 + /// + /// + /// + [HttpPost("/sysConfig/edit")] + public async Task UpdateConfig(UpdateConfigInput input) + { + var isExist = await _sysConfigRep.AnyAsync(u => (u.Name == input.Name || u.Code == input.Code) && u.Id != input.Id); + if (isExist) + throw Oops.Oh(ErrorCode.D9000); + + var config = input.Adapt(); + await _sysConfigRep.AsUpdateable(config).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync(); + //刷新缓存 + await _sysCacheService.SetAsync(input.Code, input.Value); + } + + /// + /// 获取系统参数配置 + /// + /// + /// + [HttpGet("/sysConfig/detail")] + public async Task GetConfig([FromQuery] QueryConfigInput input) + { + return await _sysConfigRep.FirstOrDefaultAsync(u => u.Id == input.Id); + } + + /// + /// 获取配置信息 + /// + /// + /// + private async Task GetConfigCache(string code) + { + var value = await _sysCacheService.GetAsync(code); + if (string.IsNullOrEmpty(value)) + { + var config = await _sysConfigRep.FirstOrDefaultAsync(u => u.Code == code); + value = config != null ? config.Value : ""; + await _sysCacheService.SetAsync(code, value); + } + return value; + } + + /// + /// 更新配置缓存 + /// + /// + /// + /// + public async Task UpdateConfigCache(string code, object value) + { + await _sysCacheService.SetAsync(code, value); + } + + /// + /// 获取演示环境开关是否开启,默认为false + /// + /// + [NonAction] + public async Task GetDemoEnvFlag() + { + var value = await GetConfigCache("DEMO_ENV_FLAG"); + return bool.Parse(value); + } + + /// + /// 获取验证码开关标识 + /// + /// + public async Task GetCaptchaOpenFlag() + { + var value = await GetConfigCache("CAPTCHA_OPEN"); + return bool.Parse(value); + } + + /// + /// 获取默认密码 + /// + /// + public async Task GetDefaultPassword() + { + var value = await GetConfigCache("DEFAULT_PASSWORD"); + return value; + } + +} diff --git a/Magic.Core/Service/DataBase/DataBaseManager.cs b/Magic.Core/Service/DataBase/DataBaseManager.cs new file mode 100644 index 0000000..7085b67 --- /dev/null +++ b/Magic.Core/Service/DataBase/DataBaseManager.cs @@ -0,0 +1,239 @@ +using Furion; +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Furion.FriendlyException; +using Furion.ViewEngine; +using Magic.Core.Service.DataBase.Extension; +using Mapster; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace Magic.Core.Service; + +/// +/// 数据库管理 +/// +[ApiDescriptionSettings(Name = "DataBase", Order = 200)] +public class DataBaseManager : IDataBaseManager, IDynamicApiController, ITransient +{ + private readonly ISqlSugarClient _sqlSugarClient; + private readonly IViewEngine _viewEngine; + + public DataBaseManager(ISqlSugarClient sqlSugarClient, IViewEngine viewEngine) + { + _sqlSugarClient = sqlSugarClient; + _viewEngine = viewEngine; + } + + /// + /// 添加列 + /// + /// + [HttpPost("/column/add")] + public void ColumnAdd(DbColumnInfoInput input) + { + DbColumnInfo column = new DbColumnInfo(); + column.ColumnDescription = input.ColumnDescription; + column.DbColumnName = input.DbColumnName; + column.IsIdentity = input.IsIdentity == 1; + column.IsNullable = input.IsNullable == 1; + column.IsPrimarykey = input.IsPrimarykey == 1; + column.Length = input.Length; + column.DecimalDigits = input.DecimalDigits; + column.DataType = input.DataType; + _sqlSugarClient.DbMaintenance.AddColumn(input.TableName, column); + _sqlSugarClient.DbMaintenance.AddColumnRemarkEx(input.DbColumnName, input.TableName, input.ColumnDescription); + if (column.IsPrimarykey) + { + _sqlSugarClient.DbMaintenance.AddPrimaryKey(input.TableName, input.DbColumnName); + } + } + + /// + /// 删除列 + /// + /// + [HttpPost("/column/delete")] + public void ColumnDelete(DbColumnInfoOutput input) + { + _sqlSugarClient.DbMaintenance.DropColumn(input.TableName, input.DbColumnName); + } + + /// + /// 编辑列 + /// + /// + [HttpPost("/column/edit")] + public void ColumnEdit(EditColumnInput input) + { + _sqlSugarClient.DbMaintenance.RenameColumn(input.TableName, input.OldName, input.DbColumnName); + if (_sqlSugarClient.DbMaintenance.IsAnyColumnRemarkEx(input.DbColumnName, input.TableName)) + { + _sqlSugarClient.DbMaintenance.DeleteColumnRemark(input.DbColumnName, input.TableName); + } + _sqlSugarClient.DbMaintenance.AddColumnRemarkEx(input.DbColumnName, input.TableName, string.IsNullOrWhiteSpace(input.ColumnDescription) ? input.DbColumnName : input.ColumnDescription); + } + + /// + /// 获取表字段 + /// + /// + /// + [HttpGet("/dataBase/columnInfoList")] + public List GetColumnInfosByTableName(string tableName) + { + if (string.IsNullOrWhiteSpace(tableName)) + return new List(); + return _sqlSugarClient.DbMaintenance.GetColumnInfosByTableName(tableName, false).Adapt>(); + } + + /// + /// 获取所有表 + /// + /// + [HttpGet("/dataBase/tableInfoList")] + public List GetTableInfoList() + { + return _sqlSugarClient.DbMaintenance.GetTableInfoList(false); + } + + /// + /// 新增表 + /// + /// + [HttpPost("/table/add")] + public void TableAdd(DbTableInfoInput input) + { + List columns = new List(); + if (input.DbColumnInfoList == null || !input.DbColumnInfoList.Any()) + { + throw Oops.Oh(ErrorCode.db1000); + } + input.DbColumnInfoList.ForEach(m => + { + columns.Add(new DbColumnInfo + { + DbColumnName = m.DbColumnName, + DataType = m.DataType, + Length = m.Length, + ColumnDescription = m.ColumnDescription, + IsNullable = m.IsNullable == 1, + IsIdentity = m.IsIdentity == 1, + IsPrimarykey = m.IsPrimarykey == 1, + DecimalDigits = m.DecimalDigits + }); + }); + _sqlSugarClient.DbMaintenance.CreateTable(input.Name, columns, false); + _sqlSugarClient.DbMaintenance.AddTableRemark(input.Name, input.Description); + if (columns.Any(m => m.IsPrimarykey)) + { + _sqlSugarClient.DbMaintenance.AddPrimaryKey(input.Name, columns.FirstOrDefault(m => m.IsPrimarykey).DbColumnName); + } + input.DbColumnInfoList.ForEach(m => + { + _sqlSugarClient.DbMaintenance.AddColumnRemarkEx(m.DbColumnName, input.Name, m.ColumnDescription); + }); + } + + /// + /// 删除表 + /// + /// + [HttpPost("/table/delete")] + public void TableDelete(DbTableInfo input) + { + _sqlSugarClient.DbMaintenance.DropTable(input.Name); + } + + /// + /// 编辑表 + /// + /// + [HttpPost("/table/edit")] + public void TableEdit(EditTableInput input) + { + _sqlSugarClient.DbMaintenance.RenameTable(input.OldName, input.Name); + if (_sqlSugarClient.DbMaintenance.IsAnyTableRemarkEx(input.Name)) + { + _sqlSugarClient.DbMaintenance.DeleteTableRemark(input.Name); + } + _sqlSugarClient.DbMaintenance.AddTableRemark(input.Name, input.Description); + } + + /// + /// 生成实体 + /// + /// + [HttpPost("/table/createEntity")] + public void CreateEntity(CreateEntityInput input) + { + Type baseType = Type.GetType($"Magic.Core.Entity.{input.BaseClassName}"); + + if (baseType.IsNullOrZero()) + throw Oops.Oh("父类不存在"); + + var baseTypeProperties = baseType.GetProperties().Select(m => m.Name).ToList(); + + input.Position = string.IsNullOrWhiteSpace(input.Position) ? "Magic.Application" : input.Position; + input.BaseClassName = string.IsNullOrWhiteSpace(input.BaseClassName) ? "" : $" : {input.BaseClassName}"; + var templatePath = GetTemplatePath(); + var targetPath = GetTargetPath(input); + DbTableInfo dbTableInfo = _sqlSugarClient.DbMaintenance.GetTableInfoList(false).FirstOrDefault(m => m.Name == input.TableName); + if (dbTableInfo == null) + throw Oops.Oh(ErrorCode.db1001); + List dbColumnInfos = _sqlSugarClient.DbMaintenance.GetColumnInfosByTableName(input.TableName, false).Where(m => !baseTypeProperties.Contains(m.DbColumnName)).ToList(); + dbColumnInfos.ForEach(m => + { + m.DataType = CodeGenUtil.ConvertDataType(m.DataType); + }); + var tContent = File.ReadAllText(templatePath); + var tResult = _viewEngine.RunCompileFromCached(tContent, new + { + input.TableName, + input.EntityName, + input.BaseClassName, + dbTableInfo.Description, + TableField = dbColumnInfos + }); + + #region 检查目录是否存在 + + FileInfo fileInfo = new FileInfo(targetPath); + string entityPath = fileInfo.DirectoryName; + if (!Directory.Exists(entityPath)) + { + Directory.CreateDirectory(entityPath); + } + + #endregion 检查目录是否存在 + + File.WriteAllText(targetPath, tResult, Encoding.UTF8); + } + + /// + /// 获取模板文件路径集合 + /// + /// + private string GetTemplatePath() + { + var templatePath = Path.Combine(App.WebHostEnvironment.WebRootPath, "Template"); + return Path.Combine(templatePath, "Entity.cs.vm"); + } + + /// + /// 设置生成文件路径 + /// + /// + /// + private string GetTargetPath(CreateEntityInput input) + { + var backendPath = Path.Combine(new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent.FullName, input.Position, "Entity"); + var entityPath = Path.Combine(backendPath, input.EntityName + ".cs"); + return entityPath; + } +} \ No newline at end of file diff --git a/Magic.Core/Service/DataBase/Dto/CreateEntityInput.cs b/Magic.Core/Service/DataBase/Dto/CreateEntityInput.cs new file mode 100644 index 0000000..4a3e4f2 --- /dev/null +++ b/Magic.Core/Service/DataBase/Dto/CreateEntityInput.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public class CreateEntityInput +{ + /// + /// + /// + /// student + public string TableName { get; set; } + + /// + /// + /// + /// Student + public string EntityName { get; set; } + + /// + /// + /// + /// AutoIncrementEntity + public string BaseClassName { get; set; } + + /// + /// + /// + /// Magic.Application + public string Position { get; set; } +} diff --git a/Magic.Core/Service/DataBase/Dto/DbColumnInfoInput.cs b/Magic.Core/Service/DataBase/Dto/DbColumnInfoInput.cs new file mode 100644 index 0000000..2ef2b52 --- /dev/null +++ b/Magic.Core/Service/DataBase/Dto/DbColumnInfoInput.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public class DbColumnInfoInput +{ + public string TableName + { + get; + set; + } + public string DbColumnName + { + get; + set; + } + + public string DataType + { + get; + set; + } + + public int Length + { + get; + set; + } + + public string ColumnDescription + { + get; + set; + } + + public int IsNullable + { + get; + set; + } + + public int IsIdentity + { + get; + set; + } + + public int IsPrimarykey + { + get; + set; + } + + public int DecimalDigits + { + get; + set; + } + + +} diff --git a/Magic.Core/Service/DataBase/Dto/DbColumnInfoOutput.cs b/Magic.Core/Service/DataBase/Dto/DbColumnInfoOutput.cs new file mode 100644 index 0000000..94349ce --- /dev/null +++ b/Magic.Core/Service/DataBase/Dto/DbColumnInfoOutput.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public class DbColumnInfoOutput +{ + public string TableName + { + get; + set; + } + + public int TableId + { + get; + set; + } + + public string DbColumnName + { + get; + set; + } + + public string PropertyName + { + get; + set; + } + + public string DataType + { + get; + set; + } + + public int Length + { + get; + set; + } + + public string ColumnDescription + { + get; + set; + } + + public string DefaultValue + { + get; + set; + } + + public bool IsNullable + { + get; + set; + } + + public bool IsIdentity + { + get; + set; + } + + public bool IsPrimarykey + { + get; + set; + } + + public object Value + { + get; + set; + } + + public int DecimalDigits + { + get; + set; + } + + public int Scale + { + get; + set; + } + + public bool IsArray + { + get; + set; + } + + internal bool IsJson + { + get; + set; + } +} diff --git a/Magic.Core/Service/DataBase/Dto/DbTableInfoInput.cs b/Magic.Core/Service/DataBase/Dto/DbTableInfoInput.cs new file mode 100644 index 0000000..1182c73 --- /dev/null +++ b/Magic.Core/Service/DataBase/Dto/DbTableInfoInput.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; + +namespace Magic.Core.Service; + +public class DbTableInfoInput +{ + public string Name + { + get; + set; + } + + public string Description + { + get; + set; + } + + public List DbColumnInfoList { get; set; } +} diff --git a/Magic.Core/Service/DataBase/Dto/EditColumnInput.cs b/Magic.Core/Service/DataBase/Dto/EditColumnInput.cs new file mode 100644 index 0000000..1e1ce9d --- /dev/null +++ b/Magic.Core/Service/DataBase/Dto/EditColumnInput.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public class EditColumnInput +{ + public string TableName { get; set; } + public string OldName { get; set; } + public string DbColumnName { get; set; } + public string ColumnDescription { get; set; } +} diff --git a/Magic.Core/Service/DataBase/Dto/EditTableInput.cs b/Magic.Core/Service/DataBase/Dto/EditTableInput.cs new file mode 100644 index 0000000..8accfe4 --- /dev/null +++ b/Magic.Core/Service/DataBase/Dto/EditTableInput.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public class EditTableInput +{ + public string Name { get; set; } + + public string OldName { get; set; } + + public string Description { get; set; } +} diff --git a/Magic.Core/Service/DataBase/Extension/DbMaintenanceExtension.cs b/Magic.Core/Service/DataBase/Extension/DbMaintenanceExtension.cs new file mode 100644 index 0000000..98b970b --- /dev/null +++ b/Magic.Core/Service/DataBase/Extension/DbMaintenanceExtension.cs @@ -0,0 +1,97 @@ +using Mapster; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Magic.Core.Service.DataBase.Extension +{ + internal static class DbMaintenanceExtension + { + public static bool IsAnyTableRemarkEx(this IDbMaintenance dbMaintenance, string tableName) + { + return dbMaintenance.Context.CurrentConnectionConfig.DbType switch + { + DbType.MySql => new Func(() => + { + string sql = $"select 1 from information_schema.`Tables` where table_name=@tableName"; + return dbMaintenance.Context.Ado.GetDataTable(sql, new SugarParameter("@tableName", tableName)).Rows?.Count > 0; + })(), + _ => dbMaintenance.IsAnyTableRemark(tableName) + }; + } + + public static bool IsAnyColumnRemarkEx(this IDbMaintenance dbMaintenance, string tableName, string columnName) + { + return dbMaintenance.Context.CurrentConnectionConfig.DbType switch + { + DbType.MySql => new Func(() => + { + string sql = $"select 1 from information_schema.`Columns` where table_name=@tableName and column_name=@columnName"; + return dbMaintenance.Context.Ado.GetDataTable(sql, new SugarParameter("@tableName", tableName), new SugarParameter("@columnName", columnName)).Rows?.Count > 0; + })(), + _ => dbMaintenance.IsAnyColumnRemark(columnName, tableName) + }; + } + + public static void AddColumnRemarkEx(this IDbMaintenance dbMaintenance, string columnName, string tableName, string columnDescription) + { + switch (dbMaintenance.Context.CurrentConnectionConfig.DbType) + { + case DbType.MySql: + var colInfo = dbMaintenance.GetColumnInfosByTableName(tableName, false) + .Adapt>() + .Where(x => string.Compare(x.DbColumnName, columnName, true) == 0) + .FirstOrDefault(); + + dbMaintenance.UpdateColumn(tableName, new DbColumnInfo() + { + ColumnDescription = columnDescription, + DataType = $"{colInfo.DataType}{GetSize(colInfo.Length, colInfo.DecimalDigits)} COMMENT '{columnDescription.Replace("\'", "\\\'").Replace("\"", "\\\"")}' ", + DbColumnName = colInfo.DbColumnName, + DefaultValue = colInfo.DefaultValue, + IsArray = colInfo.IsArray, + IsIdentity = colInfo.IsIdentity, + IsNullable = colInfo.IsNullable, + IsPrimarykey = colInfo.IsPrimarykey, + PropertyName = colInfo.PropertyName, + Scale = colInfo.Scale, + TableId = colInfo.TableId, + TableName = colInfo.TableName, + Value = colInfo.Value + }); + break; + + default: + dbMaintenance.AddColumnRemark(columnName, tableName, string.IsNullOrWhiteSpace(columnDescription) ? columnName : columnDescription); + break; + } + } + + private static string GetSize(int size = 0, int decimalDigits = 0) + { + string dataSize = null; + var isMax = size > 4000 || size == -1; + if (isMax) + { + dataSize = size > 0 ? string.Format("({0})", "max") : null; + } + else if (size == 0 && decimalDigits > 0) + { + size = 10; + dataSize = string.Format("({0},{1})", size, decimalDigits); + } + else if (size > 0 && decimalDigits == 0) + { + dataSize = size > 0 ? string.Format("({0})", size) : null; + } + else if (size > 0 && decimalDigits > 0) + { + dataSize = size > 0 ? string.Format("({0},{1})", size, decimalDigits) : null; + } + return dataSize; + } + } +} \ No newline at end of file diff --git a/Magic.Core/Service/DataBase/IDataBaseManager.cs b/Magic.Core/Service/DataBase/IDataBaseManager.cs new file mode 100644 index 0000000..f8b4254 --- /dev/null +++ b/Magic.Core/Service/DataBase/IDataBaseManager.cs @@ -0,0 +1,26 @@ +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface IDataBaseManager +{ + List GetTableInfoList(); + + List GetColumnInfosByTableName(string tableName); + + void TableAdd(DbTableInfoInput input); + void TableEdit(EditTableInput input); + void TableDelete(DbTableInfo input); + + void ColumnAdd(DbColumnInfoInput input); + void ColumnEdit(EditColumnInput input); + void ColumnDelete(DbColumnInfoOutput input); + + void CreateEntity(CreateEntityInput input); +} diff --git a/Magic.Core/Service/Dict/Dto/DictDataInput.cs b/Magic.Core/Service/Dict/Dto/DictDataInput.cs new file mode 100644 index 0000000..aa89d23 --- /dev/null +++ b/Magic.Core/Service/Dict/Dto/DictDataInput.cs @@ -0,0 +1,93 @@ +using Furion.DataValidation; +using System.ComponentModel.DataAnnotations; + +namespace Magic.Core.Service; + +/// +/// 字典值参数 +/// +public class DictDataInput : PageInputBase +{ + /// + /// 字典类型Id + /// + public virtual long TypeId { get; set; } + + /// + /// 值 + /// + public virtual string Value { get; set; } + + /// + /// 编码 + /// + public virtual string Code { get; set; } + + /// + /// 排序 + /// + public virtual int Sort { get; set; } + + /// + /// 备注 + /// + public virtual string Remark { get; set; } + + /// + /// 状态(字典 0正常 1停用 2删除) + /// + public virtual CommonStatus Status { get; set; } +} + +public class QueryDictDataListInput +{ + /// + /// 字典类型Id + /// + [Required(ErrorMessage = "字典类型Id不能为空"), DataValidation(ValidationTypes.Numeric)] + public long TypeId { get; set; } +} + +public class AddDictDataInput : DictDataInput +{ + /// + /// 字典类型Id + /// + [Required(ErrorMessage = "字典类型Id不能为空"), DataValidation(ValidationTypes.Numeric)] + public override long TypeId { get; set; } + + /// + /// 值 + /// + [Required(ErrorMessage = "字典值不能为空")] + public override string Value { get; set; } + + /// + /// 编码 + /// + [Required(ErrorMessage = "字典值编码不能为空")] + public override string Code { get; set; } +} + +public class DeleteDictDataInput +{ + /// + /// 字典值Id + /// + [Required(ErrorMessage = "字典值Id不能为空"), DataValidation(ValidationTypes.Numeric)] + public long Id { get; set; } +} + +public class UpdateDictDataInput : AddDictDataInput +{ + /// + /// 字典值Id + /// + [Required(ErrorMessage = "字典值Id不能为空"), DataValidation(ValidationTypes.Numeric)] + public long Id { get; set; } +} + +public class QueryDictDataInput : DeleteDictDataInput +{ + +} diff --git a/Magic.Core/Service/Dict/Dto/DictDataOutput.cs b/Magic.Core/Service/Dict/Dto/DictDataOutput.cs new file mode 100644 index 0000000..37818d4 --- /dev/null +++ b/Magic.Core/Service/Dict/Dto/DictDataOutput.cs @@ -0,0 +1,12 @@ +namespace Magic.Core.Service; + +/// +/// 字典值参数 +/// +public class DictDataOutput : DictDataInput +{ + /// + /// 字典Id + /// + public virtual long Id { get; set; } +} diff --git a/Magic.Core/Service/Dict/Dto/DictTreeOutput.cs b/Magic.Core/Service/Dict/Dto/DictTreeOutput.cs new file mode 100644 index 0000000..730eab6 --- /dev/null +++ b/Magic.Core/Service/Dict/Dto/DictTreeOutput.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; + +namespace Magic.Core.Service; + +/// +/// 字典类型与字典值构造的树 +/// +public class DictTreeOutput +{ + /// + /// Id + /// + public long Id { get; set; } + + /// + /// 父Id + /// + public long Pid { get; set; } + + /// + /// 编码-对应字典值的编码 + /// + public string Code { get; set; } + + /// + /// 名称-对应字典值的value + /// + public string Name { get; set; } + + /// + /// 子节点集合 + /// + public List Children { get; set; } = new List(); +} diff --git a/Magic.Core/Service/Dict/Dto/DictTypeInput.cs b/Magic.Core/Service/Dict/Dto/DictTypeInput.cs new file mode 100644 index 0000000..5271a38 --- /dev/null +++ b/Magic.Core/Service/Dict/Dto/DictTypeInput.cs @@ -0,0 +1,84 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace Magic.Core.Service; + +/// +/// 字典类型参数 +/// +public class DictTypeInput : PageInputBase +{ + /// + /// 名称 + /// + public virtual string Name { get; set; } + + /// + /// 编码 + /// + public virtual string Code { get; set; } + + /// + /// 排序 + /// + public virtual int Sort { get; set; } + + /// + /// 备注 + /// + public virtual string Remark { get; set; } + + /// + /// 状态(字典 0正常 1停用 2删除) + /// + public virtual CommonStatus Status { get; set; } +} + +public class AddDictTypeInput : DictTypeInput +{ + /// + /// 名称 + /// + [Required(ErrorMessage = "字典类型名称不能为空")] + public override string Name { get; set; } + + /// + /// 编码 + /// + [Required(ErrorMessage = "字典类型编码不能为空")] + public override string Code { get; set; } + + public List DictDataList { get; set; } +} + +public class DeleteDictTypeInput +{ + /// + /// 编号Id + /// + [Required(ErrorMessage = "字典类型Id不能为空")] + public long Id { get; set; } +} + +public class UpdateDictTypeInput : AddDictTypeInput +{ + /// + /// Id + /// + [Required(ErrorMessage = "字典类型Id不能为空")] + public long Id { get; set; } +} + +public class DropDownDictTypeInput +{ + /// + /// 编码 + /// + [Required(ErrorMessage = "字典类型编码不能为空")] + public string Code { get; set; } +} + +public class QueryDictTypeInfoInput : DeleteDictTypeInput +{ + +} diff --git a/Magic.Core/Service/Dict/ISysDictDataService.cs b/Magic.Core/Service/Dict/ISysDictDataService.cs new file mode 100644 index 0000000..304a437 --- /dev/null +++ b/Magic.Core/Service/Dict/ISysDictDataService.cs @@ -0,0 +1,20 @@ +using Magic.Core.Entity; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ISysDictDataService +{ + Task AddDictData(AddDictDataInput input); + Task ChangeDictDataStatus(UpdateDictDataInput input); + Task DeleteByTypeId(long dictTypeId); + Task DeleteDictData(DeleteDictDataInput input); + Task GetDictData([FromQuery] QueryDictDataInput input); + Task GetDictDataList([FromQuery] QueryDictDataListInput input); + Task GetDictDataListByDictTypeId(long dictTypeId); + Task QueryDictDataPageList([FromQuery] DictDataInput input); + Task UpdateDictData(UpdateDictDataInput input); + Task> GetDictDataByCode(string code); +} diff --git a/Magic.Core/Service/Dict/ISysDictTypeService.cs b/Magic.Core/Service/Dict/ISysDictTypeService.cs new file mode 100644 index 0000000..4509593 --- /dev/null +++ b/Magic.Core/Service/Dict/ISysDictTypeService.cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ISysDictTypeService +{ + Task AddDictType(AddDictTypeInput input); + Task ChangeDictTypeStatus(UpdateDictTypeInput input); + Task DeleteDictType(DeleteDictTypeInput input); + Task> GetDictTree(); + Task GetDictType([FromQuery] QueryDictTypeInfoInput input); + Task GetDictTypeDropDown([FromQuery] DropDownDictTypeInput input); + Task GetDictTypeList(); + Task QueryDictTypePageList([FromQuery] DictTypeInput input); + Task UpdateDictType(UpdateDictTypeInput input); +} diff --git a/Magic.Core/Service/Dict/SysDictDataService.cs b/Magic.Core/Service/Dict/SysDictDataService.cs new file mode 100644 index 0000000..3343ae1 --- /dev/null +++ b/Magic.Core/Service/Dict/SysDictDataService.cs @@ -0,0 +1,177 @@ + + +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Furion.FriendlyException; +using Magic.Core.Entity; +using Mapster; +using Microsoft.AspNetCore.Mvc; + +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +/// +/// 字典值服务 +/// +[ApiDescriptionSettings(Name = "DictData", Order = 100)] +public class SysDictDataService : ISysDictDataService, IDynamicApiController, ITransient +{ + private readonly SqlSugarRepository _sysDictDataRep; // 字典类型表仓储 + + public SysDictDataService(SqlSugarRepository sysDictDataRep) + { + _sysDictDataRep = sysDictDataRep; + } + + /// + /// 分页查询字典值 + /// + /// + /// + [HttpGet("/sysDictData/page")] + public async Task QueryDictDataPageList([FromQuery] DictDataInput input) + { + var code = !string.IsNullOrEmpty(input.Code?.Trim()); + var value = !string.IsNullOrEmpty(input.Value?.Trim()); + var dictDatas = await _sysDictDataRep + .Where(u => u.TypeId == input.TypeId) + .WhereIF(!string.IsNullOrWhiteSpace(input.Code), u => u.Code.Contains(input.Code.Trim())) + .WhereIF(!string.IsNullOrWhiteSpace(input.Value), u => u.Value.Contains(input.Value.Trim())) + .Where(u => u.Status != CommonStatus.DELETED).OrderBy(u => u.Sort) + .Select() + .ToPagedListAsync(input.PageNo, input.PageSize); + return dictDatas.XnPagedResult(); + } + + /// + /// 获取某个字典类型下字典值列表 + /// + /// + [HttpGet("/sysDictData/list")] + public async Task GetDictDataList([FromQuery] QueryDictDataListInput input) + { + return await _sysDictDataRep.AsQueryable() + .WhereIF(input.TypeId > 0, u => u.TypeId == input.TypeId) + .Where(u => u.Status != CommonStatus.DELETED).OrderBy(u => u.Sort).ToListAsync(); + } + + /// + /// 增加字典值 + /// + /// + /// + [HttpPost("/sysDictData/add")] + public async Task AddDictData(AddDictDataInput input) + { + var isExist = await _sysDictDataRep.AnyAsync(u => (u.Code == input.Code || u.Value == input.Value) && u.TypeId == input.TypeId); + if (isExist) throw Oops.Oh(ErrorCode.D3003); + + var dictData = input.Adapt(); + await _sysDictDataRep.InsertAsync(dictData); + } + + /// + /// 删除字典值 + /// + /// + /// + [HttpPost("/sysDictData/delete")] + public async Task DeleteDictData(DeleteDictDataInput input) + { + var dictData = await _sysDictDataRep.FirstOrDefaultAsync(u => u.Id == input.Id); + if (dictData == null) throw Oops.Oh(ErrorCode.D3004); + + await _sysDictDataRep.DeleteAsync(dictData); + } + + /// + /// 更新字典值 + /// + /// + /// + [HttpPost("/sysDictData/edit")] + public async Task UpdateDictData(UpdateDictDataInput input) + { + var isExist = await _sysDictDataRep.AnyAsync(u => u.Id == input.Id); + if (!isExist) throw Oops.Oh(ErrorCode.D3004); + + // 排除自己并且判断与其他是否相同 + isExist = await _sysDictDataRep.AnyAsync(u => (u.Value == input.Value || u.Code == input.Code) && u.TypeId == input.TypeId && u.Id != input.Id); + if (isExist) throw Oops.Oh(ErrorCode.D3003); + + var dictData = input.Adapt(); + await _sysDictDataRep.AsUpdateable(dictData).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync(); + } + + /// + /// 字典值详情 + /// + /// + /// + [HttpGet("/sysDictData/detail")] + public async Task GetDictData([FromQuery] QueryDictDataInput input) + { + return await _sysDictDataRep.FirstOrDefaultAsync(u => u.Id == input.Id); + } + + /// + /// 修改字典值状态 + /// + /// + /// + [HttpPost("/sysDictData/changeStatus")] + public async Task ChangeDictDataStatus(UpdateDictDataInput input) + { + var dictData = await _sysDictDataRep.FirstOrDefaultAsync(u => u.Id == input.Id); + if (dictData == null) throw Oops.Oh(ErrorCode.D3004); + + if (!Enum.IsDefined(typeof(CommonStatus), input.Status)) + throw Oops.Oh(ErrorCode.D3005); + dictData.Status = input.Status; + } + + /// + /// 根据字典类型Id获取字典值集合 + /// + /// + /// + [NonAction] + public async Task GetDictDataListByDictTypeId(long dictTypeId) + { + return await _sysDictDataRep.Where(u => u.TypeId == dictTypeId) + .Where(u => u.Status != CommonStatus.DELETED).OrderBy(u => u.Sort) + .Select(u => new + { + u.Code, + u.Value + }).ToListAsync(); + } + + /// + /// 删除字典下所有值 + /// + /// + [NonAction] + public async Task DeleteByTypeId(long dictTypeId) + { + await _sysDictDataRep.DeleteAsync(u => u.TypeId == dictTypeId); + } + + + /// + /// 根据字典Code返回字典值列表 + /// + /// + /// + [NonAction] + public async Task> GetDictDataByCode(string code) + { + var payment = await _sysDictDataRep.AsQueryable().InnerJoin((d, t) => d.TypeId == t.Id).Where((d, t) => t.Code == code).Select().ToListAsync(); + return payment; + } +} diff --git a/Magic.Core/Service/Dict/SysDictTypeService.cs b/Magic.Core/Service/Dict/SysDictTypeService.cs new file mode 100644 index 0000000..e315c28 --- /dev/null +++ b/Magic.Core/Service/Dict/SysDictTypeService.cs @@ -0,0 +1,188 @@ + + +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Furion.FriendlyException; +using Magic.Core.Entity; +using Mapster; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +/// +/// 字典类型服务 +/// +[ApiDescriptionSettings(Name = "DictType", Order = 100)] +public class SysDictTypeService : ISysDictTypeService, IDynamicApiController, ITransient +{ + private readonly SqlSugarRepository _sysDictTypeRep; // 字典类型表仓储 + private readonly ISysDictDataService _sysDictDataService; + + public SysDictTypeService(ISysDictDataService sysDictDataService, + SqlSugarRepository sysDictTypeRep) + { + _sysDictDataService = sysDictDataService; + _sysDictTypeRep = sysDictTypeRep; + } + + /// + /// 分页查询字典类型 + /// + /// + [HttpGet("/sysDictType/page")] + public async Task QueryDictTypePageList([FromQuery] DictTypeInput input) + { + var dictTypes = await _sysDictTypeRep.AsQueryable() + .WhereIF(!string.IsNullOrWhiteSpace(input.Code), u => u.Code.Contains(input.Code.Trim())) + .WhereIF(!string.IsNullOrWhiteSpace(input.Name), u => u.Name.Contains(input.Name.Trim())) + .Where(u => u.Status != CommonStatus.DELETED).OrderBy(u => u.Sort) + .ToPagedListAsync(input.PageNo, input.PageSize); + return dictTypes.XnPagedResult(); + } + + /// + /// 获取字典类型列表 + /// + /// + [HttpGet("/sysDictType/list")] + public async Task GetDictTypeList() + { + return await _sysDictTypeRep.Where(u => u.Status != CommonStatus.DELETED).ToListAsync(); + } + + /// + /// 获取字典类型下所有字典值 + /// + /// + /// + [AllowAnonymous] + [HttpGet("/sysDictType/dropDown")] + public async Task GetDictTypeDropDown([FromQuery] DropDownDictTypeInput input) + { + var dictType = await _sysDictTypeRep.FirstOrDefaultAsync(u => u.Code == input.Code); + if (dictType == null) throw Oops.Oh(ErrorCode.D3000); + return await _sysDictDataService.GetDictDataListByDictTypeId(dictType.Id); + } + + /// + /// 添加字典类型 + /// + /// + /// + [HttpPost("/sysDictType/add")] + public async Task AddDictType(AddDictTypeInput input) + { + var isExist = await _sysDictTypeRep.AnyAsync(u => u.Name == input.Name || u.Code == input.Code); + if (isExist) throw Oops.Oh(ErrorCode.D3001); + + var dictType = input.Adapt(); + var typeId = (await _sysDictTypeRep.InsertReturnEntityAsync(dictType)).Id; + if (input.DictDataList != null && input.DictDataList.Any()) { + foreach (var item in input.DictDataList) + { + item.TypeId= typeId; + await _sysDictDataService.AddDictData(item); + } + } + } + + /// + /// 删除字典类型 + /// + /// + /// + [HttpPost("/sysDictType/delete")] + public async Task DeleteDictType(DeleteDictTypeInput input) + { + var dictType = await _sysDictTypeRep.FirstOrDefaultAsync(u => u.Id == input.Id); + if (dictType == null) throw Oops.Oh(ErrorCode.D3000); + await _sysDictTypeRep.DeleteAsync(dictType); + await _sysDictDataService.DeleteByTypeId(input.Id); + } + + /// + /// 更新字典类型 + /// + /// + /// + [HttpPost("/sysDictType/edit"),] + public async Task UpdateDictType(UpdateDictTypeInput input) + { + var isExist = await _sysDictTypeRep.AnyAsync(u => u.Id == input.Id); + if (!isExist) throw Oops.Oh(ErrorCode.D3000); + + // 排除自己并且判断与其他是否相同 + isExist = await _sysDictTypeRep.AnyAsync(u => (u.Name == input.Name || u.Code == input.Code) && u.Id != input.Id); + if (isExist) throw Oops.Oh(ErrorCode.D3001); + + var dictType = input.Adapt(); + await _sysDictTypeRep.AsUpdateable(dictType).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync(); + } + + /// + /// 字典类型详情 + /// + /// + /// + [HttpGet("/sysDictType/detail")] + public async Task GetDictType([FromQuery] QueryDictTypeInfoInput input) + { + return await _sysDictTypeRep.FirstOrDefaultAsync(u => u.Id == input.Id); + } + + /// + /// 更新字典类型状态 + /// + /// + /// + [HttpPost("/sysDictType/changeStatus")] + public async Task ChangeDictTypeStatus(UpdateDictTypeInput input) + { + var dictType = await _sysDictTypeRep.FirstOrDefaultAsync(u => u.Id == input.Id); + if (dictType == null) throw Oops.Oh(ErrorCode.D3000); + + if (!Enum.IsDefined(typeof(CommonStatus), input.Status)) + throw Oops.Oh(ErrorCode.D3005); + dictType.Status = input.Status; + await _sysDictTypeRep.AsUpdateable(dictType).ExecuteCommandAsync(); + } + + /// + /// 字典类型与字典值构造的字典树 + /// + /// + [AllowAnonymous] + [HttpGet("/sysDictType/tree")] + public async Task> GetDictTree() + { + List typeList = await GetDictTypeList(); + List dataList = await _sysDictDataService.GetDictDataList(new QueryDictDataListInput()); + + List list = new List(); + + foreach (var item in typeList) + { + list.Add(new DictTreeOutput + { + Id = item.Id, + Code = item.Code, + Name = item.Name, + Children = dataList.Where(m => m.TypeId == item.Id).Select(m => new DictTreeOutput + { + Id = m.Id, + Pid = m.TypeId, + Code = m.Code, + Name = m.Value + }).ToList() + }); + } + return list; + } +} diff --git a/Magic.Core/Service/Document/DocumentService.cs b/Magic.Core/Service/Document/DocumentService.cs new file mode 100644 index 0000000..337471e --- /dev/null +++ b/Magic.Core/Service/Document/DocumentService.cs @@ -0,0 +1,529 @@ +using Furion; +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Furion.FriendlyException; +using Magic.Core.Entity; +using Mapster; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using Yitter.IdGenerator; + + +namespace Magic.Core.Service; + +/// +/// 文档服务 +/// +[ApiDescriptionSettings(Name = "Document", Order = 150)] +public class DocumentService : IDocumentService, IDynamicApiController, ITransient +{ + private readonly SqlSugarRepository _rep; + private readonly ISysDictDataService _sysDictDataService; + private readonly UploadFileOptions _options; + private readonly ILogger _logger; + public DocumentService(ILogger logger, SqlSugarRepository rep, IOptions options, ISysDictDataService sysDictDataService) + { + this._logger = logger; + _rep = rep; + this._sysDictDataService = sysDictDataService; + this._options = options.Value; + } + #region API + /// + /// 分页查询文档 + /// + /// + /// + [HttpGet("/Document/page")] + public async Task Page([FromQuery] DocumentInput input) + { + //获取字典 + var fileTypes = await _sysDictDataService.GetDictDataByCode("file_type"); + List fileTypeList = null; + #region 判断是否根据类型搜索 + if (!string.IsNullOrEmpty(input.FileType)) + { + if (input.FileType == "文件夹") + { + input.DocumentType = DocumentType.Folder; + } + else + { + var data = fileTypes.Where(it => it.Value == input.FileType).FirstOrDefault(); + if (data != null) + { + fileTypeList = new List(); + data.Code.Split(",").ToList().ForEach(it => + { + fileTypeList.Add($".{it}"); + }); + + } + } + + } + #endregion + var entities = await _rep.AsQueryable() + .WhereIF(!string.IsNullOrWhiteSpace(input.Name), u => u.Name.Contains(input.Name.Trim())) + .WhereIF(fileTypeList != null, u => fileTypeList.Contains(u.FileSuffix)) + .WhereIF(input.Label != null, u => u.Label == input.Label) + .WhereIF(input.DocumentType != null, u => u.DocumentType == input.DocumentType) + .WhereIF(input.CreateTimeStart != null && input.CreateTimeEnd != null, u => SqlFunc.Between(u.CreatedTime, input.CreateTimeStart, input.CreateTimeEnd)) + .WhereIF(input.UpdateTimeStart != null && input.UpdateTimeEnd != null, u => SqlFunc.Between(u.UpdatedTime, input.UpdateTimeStart, input.UpdateTimeEnd)) + .WhereIF(input.PId != null, u => u.PId == input.PId) + .Where(u => u.IsDeleted == input.IsDelete && u.Visible == true) + .Filter(null, true) + .OrderBy(u => u.DocumentType) + .Select() + .Mapper(async it => + { + if (it.FileSizeKb != null) + { + it.FileSize = GetUnit(it.FileSizeKb.Value);//文件大小转成字符串 + } + + }) + .ToPagedListAsync(input.PageNo, input.PageSize); + + #region 获取文件类型 + + //遍历获取到的数据 + foreach (var it in entities.Items) + { + if (string.IsNullOrWhiteSpace(it.FileSuffix)) + { + it.FileType = "文件夹"; + } + else + { + //获取后缀名 + var fileSuffix = it.FileSuffix.Split(".")[1]; + foreach (var filetype in fileTypes) + { + var types = filetype.Code.Split(',').ToArray();//获取所有后缀名 + if (types.Contains(fileSuffix))//是否存在 + { + it.FileType = filetype.Value; + break; + } + } + if (string.IsNullOrEmpty(it.FileType)) + { + it.FileType = "文件"; + } + + } + + } + #endregion + + return entities.XnPagedResult(); + } + + + /// + /// 文件夹树 + /// + /// + [HttpGet("/Document/tree")] + public async Task Tree() + { + + var tree = await _rep + .Where(it => it.DocumentType == DocumentType.Folder) + .ToTreeAsync(it => it.Children, it => it.PId, 0); + var result = tree.Adapt>(); + return result; + } + + /// + /// 上传文件 + /// + /// + /// + [HttpPost("/Document/upload")] + public async Task Upload([FromForm] DocumentUploadInput input) + { + var fileNames = input.Files.Select(it => it.FileName).ToList();//获取文件列表名称 + var exist = await _rep.Where(it => fileNames.Contains(it.Name) && it.PId == input.PId).Select(it => it.Name).ToListAsync();//获取数据库中同名文件 + if (exist.Count > 0) + { + throw Oops.Oh($"同级目录下已存在相同文件名称{string.Join(",", exist)}"); + } + else + { + foreach (var file in input.Files) + { + await UploadFile(file, input.PId.Value); + } + + } + + } + + /// + /// 上传文件夹 + /// + /// + /// + [HttpPost("/Document/uploadfolder")] + public async Task UploadFolder([FromForm] DocumentUploadInput input) + { + var pid = input.PId.Value; + long firtId = 0;//主文件夹的ID + Dictionary> fileDic = new Dictionary>(); + input.Files.ForEach(it => + { + fileDic.Add(it.FileName, it.FileName.Split('/').ToList());//将文件名和分割的数组加到字典 + + }); + + //循环从0开始,小于字典中value最多的数量-1,因为后面要加2去拿 + for (int i = 0; i < fileDic.OrderByDescending(it => it.Value.Count).First().Value.Count - 1; i++) + { + //重新获取新的字典 + var files = fileDic.Where(it => it.Value.Count == i + 2).ToDictionary(it => it.Key, it => it.Value); + if (firtId != 0) pid = firtId;//如果主文件夹id不为0表示创建过第一层的文件夹,后面的文件夹在第一层文件夹下面创建 + //循环创建文件夹 + var folders = files.ElementAt(0).Value; + + folders.RemoveAt(folders.Count - 1);//删掉最后一个文件夹名字 + bool isFirst = folders.Count == 1 ? true : false;//只有一个表示顶层文件夹 + if (folders.Count > 1) + { + folders.RemoveAt(0);//删掉第一层 + } + foreach (var folder in folders) + { + Console.WriteLine($"新建文件夹:{folder}"); + pid = await Add(new AddDocumentInput { PId = pid, Name = folder });//创建文件夹 + } + if (isFirst)//表示顶层 + { + firtId = pid; + } + foreach (var dic in files) + { + var info = fileDic.Where(it => it.Key == dic.Key).First();//文件信息 + //var filename = dic.Value[i + 1]; + var file = input.Files.Where(it => it.FileName == info.Key).First(); + await UploadFile(file, pid); + } + } + } + + + /// + /// 新建文件夹 + /// + /// + /// + [HttpPost("/Document/add")] + public async Task Add(AddDocumentInput input) + { + var entity = input.Adapt(); + entity.DocumentType = DocumentType.Folder; + var exist = await _rep.AnyAsync(it => it.Name == input.Name && it.PId == input.PId); + if (exist) { throw Oops.Oh("ErrorMessage.E2000"); } + var result = await _rep.AsInsertable(entity).IgnoreColumns(true).ExecuteReturnEntityAsync(); + return result.Id; + } + + /// + /// 删除文档 + /// + /// + /// + [HttpPost("/Document/delete")] + public async Task Delete(DeleteDocumentInput input) + { + var entity = await _rep.FirstOrDefaultAsync(it => it.Id == input.Id); + if (entity != null) + { + entity.IsDeleted = true; + await _rep.UpdateAsync(entity); + } + else + { + throw Oops.Oh("ErrorMessage.E404"); + + } + } + + + /// + /// 批量删除 + /// + /// + /// + [HttpPost("/Document/deletes")] + public async Task Deletes(DeletesDocumentInput input) + { + #region 所有isdelete=true + var documents = await _rep.ToListAsync(it => input.Ids.Contains(it.Id)); + #endregion + documents.ForEach(document => document.IsDeleted = true); + await _rep.AsUpdateable(documents).UpdateColumns(it => new { it.IsDeleted, it.UpdatedTime, it.UpdatedUserId, it.UpdatedUserName }).ExecuteCommandAsync(); + } + + /// + /// 移动文档 + /// + /// + /// + [HttpPost("/Document/move")] + public async Task Move(MoveDocumentInput input) + { + + var tree = await GetParentList(input.PId.Value);//获取上级 + var ids = tree.Select(it => it.Id).ToList();//获取id列表 + if (ids.Count > 0)//去掉自己 + { + ids.Remove(input.PId.Value); + } + var same = ids.Intersect(input.Ids).ToArray();//检查目标ID的父ID是否有选中的文件 + if (ids.Contains(input.PId.Value) || same.Length > 0)//判断父ID是否在列表 + { + throw Oops.Oh("ErrorMessage.E2001"); + } + + //判断有没有相同名称的文件或者文件夹 + var names = await _rep.Where(it => input.Ids.Contains(it.Id)).Select(it => it.Name).ToListAsync();//文档列表 + var existName = await _rep.Where(it => it.PId == input.PId && names.Contains(it.Name)).AnyAsync();//文档列表 + if (existName) + { + throw Oops.Oh("ErrorMessage.E2002"); + } + var pFolder = _rep.FirstOrDefault(it => it.Id == input.PId.Value);//获取父文件夹 + _rep.CurrentBeginTran(); + try + { + await _rep.UpdateAsync(it => input.Ids.Contains(it.Id), it => new Documentation { PId = input.PId.Value }); + if (pFolder != null) + { + await _rep.AsUpdateable(pFolder).UpdateColumns(it => new { it.UpdatedTime, it.UpdatedUserId, it.UpdatedUserName }).ExecuteCommandAsync(); + } + _rep.CurrentCommitTran(); + } + catch (Exception ex) + { + _rep.CurrentRollbackTran(); + _logger.LogError(ex, $"移动失败:{ex.Message}"); + throw Oops.Oh("ErrorMessage.E500"); + } + } + + + /// + /// 更新文件夹 + /// + /// + /// + [HttpPost("/Document/edit")] + public async Task Update(UpdateDocumentInput input) + { + var exist = await _rep.FirstOrDefaultAsync(it => it.Id == input.Id); + if (exist != null) + { + if (!string.IsNullOrEmpty(exist.FileSuffix))//如果有后缀名加上后缀名 + { + input.Name += $".{exist.FileSuffix}"; + } + exist.Name = input.Name; + exist.Remark = input.Remark; + exist.Label = input.Label; + //获取上级 + var tree = await GetParentList(exist.Id); + _rep.CurrentBeginTran(); + try + { + if (tree.Count > 0) + { + //更新上级的修改时间 + await _rep.AsUpdateable(tree).UpdateColumns(it => new { it.UpdatedTime, it.UpdatedUserId, it.UpdatedUserName }).ExecuteCommandAsync(); + } + await _rep.AsUpdateable(exist).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync(); + _rep.CurrentCommitTran(); + } + catch (Exception ex) + { + _rep.CurrentRollbackTran(); + _logger.LogError(ex, $"更新文件夹失败:{ex.Message}"); + throw Oops.Oh("ErrorMessage.E500"); + } + } + else + { + throw Oops.Oh(ErrorCode.D1002); + } + + } + + + + + /// + /// 获取文档 + /// + /// + /// + [HttpGet("/Document/detail")] + public async Task Get([FromQuery] QueryeDocumentInput input) + { + var file = await _rep.FirstOrDefaultAsync(u => u.Id == input.Id); + if (file == null) + throw Oops.Oh(ErrorCode.D1002); + return file; + } + + + /// + /// 下载文件 + /// + /// + /// + + [HttpGet("/Document/download")] + public async Task Download([FromQuery] QueryeDocumentInput input) + { + var file = await Get(input); + var filePath = Path.Combine(App.WebHostEnvironment.WebRootPath, file.FilePath, file.FileObjectName); + var fileName = HttpUtility.UrlEncode(file.Name, Encoding.GetEncoding("UTF-8")); + var result = new FileStreamResult(new FileStream(filePath, FileMode.Open), "application/octet-stream") { FileDownloadName = fileName }; + return result; + } + + /// + /// 预览文件 + /// + /// + /// + [HttpGet("/Document/preview")] + public async Task Preview([FromQuery] QueryeDocumentInput input) + { + var file = await Get(input); + return $"{file.FilePath}/{file.FileObjectName}"; + } + + + #endregion + + #region 方法 + + /// + /// 创建Pids格式 + /// 如果pid是0顶级节点,pids就是 [0]; + /// 如果pid不是顶级节点,pids就是 pid文档的 pids + [pid] + , + /// + /// + /// + private async Task CreateNewPids(long pid) + { + if (pid == 0L) + { + return "0,"; + } + else + { + var pmenu = await _rep.FirstOrDefaultAsync(u => u.Id == pid); + return pmenu.PIds + $"{pid},"; + } + } + + /// + /// 获取文件大小 + /// + /// + /// + [NonAction] + private string GetUnit(int fileSizeKb) + { + + var b = fileSizeKb * 1024; + const int MB = 1024 * 1024; + const int KB = 1024; + if (b / MB >= 1) + { + return Math.Round(b / (float)MB, 2) + "MB"; + } + + if (b / KB >= 1) + { + return Math.Round(b / (float)KB, 2) + "KB"; + } + if (b == 0) + { + return "0B"; + } + return null; + } + + /// + /// 上传文件 + /// + /// + /// + /// + [NonAction] + private async Task UploadFile(IFormFile file, long pid) + { + var now = DateTime.Now.ToString("d"); + var localPath = $"{_options.Document.path}/{now}"; + var filePath = Path.Combine(App.WebHostEnvironment.WebRootPath, localPath); + if (!Directory.Exists(filePath)) + Directory.CreateDirectory(filePath); + + var fileSizeKb = (int)(file.Length / 1024.0); // 文件大小KB + var originalFilename = Path.GetFileName(file.FileName); // 文件原始名称 + var fileSuffix = Path.GetExtension(file.FileName).ToLower(); // 文件后缀 + var objectName = $"{ YitIdHelper.NextId()}{fileSuffix}";//存储文件名 + Documentation document = new Documentation + { + PId = pid, + Name = originalFilename, + FileSuffix = fileSuffix, + FileSizeKb = fileSizeKb, + DocumentType = DocumentType.File, + FileObjectName = objectName, + FilePath = localPath, + }; + var result = await _rep.InsertAsync(document);//添加到数据库 + if (result > 0) + { + try + { + //上传文件 + using (var stream = File.Create(Path.Combine(filePath, objectName))) + { + await file.CopyToAsync(stream); + } + } + catch (Exception ex) + { + throw Oops.Oh($"保存文件{originalFilename}失败,请重新上传"); + } + + } + } + + /// + /// 获取父级 + /// + /// + /// + private async Task> GetParentList(long id) + { + return await _rep.Where(it => it.DocumentType == DocumentType.Folder).ToParentListAsync(it => it.PId, id); + } + #endregion +} diff --git a/Magic.Core/Service/Document/Dto/DocumentDto.cs b/Magic.Core/Service/Document/Dto/DocumentDto.cs new file mode 100644 index 0000000..0912814 --- /dev/null +++ b/Magic.Core/Service/Document/Dto/DocumentDto.cs @@ -0,0 +1,61 @@ +using System; + + +namespace Magic.Core.Service; + +/// +/// 文档输出参数 +/// +public class DocumentDto +{ + /// + /// Id + /// + public long Id { get; set; } + + /// + /// 父Id + /// + public long PId { get; set; } + + /// + /// 父ID列表 + /// + //public string PIds { get; set; } + + /// + /// 名称 + /// + public string Name { get; set; } + + /// + /// 文档类型:文件、文件夹 + /// + public DocumentType DocumentType { get; set; } + + /// + /// 文件后缀 + /// + public int FileSuffix { get; set; } + + /// + /// 文件大小kb + /// + public int FileSizeKb { get; set; } + + /// + /// 存储后的文件名 + /// + //public string FileObjectName { get; set; } + + /// + /// 标签 + /// + public int? Label { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } + +} diff --git a/Magic.Core/Service/Document/Dto/DocumentInput.cs b/Magic.Core/Service/Document/Dto/DocumentInput.cs new file mode 100644 index 0000000..80e5f20 --- /dev/null +++ b/Magic.Core/Service/Document/Dto/DocumentInput.cs @@ -0,0 +1,171 @@ + +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace Magic.Core.Service; + +/// +/// 文档输入参数 +/// +public class DocumentInput : PageInputBase +{ + /// + /// 父Id + /// + public virtual long? PId { get; set; } = 0; + + /// + /// 父ID列表 + /// + public virtual string PIds { get; set; } + + /// + /// 名称 + /// + public virtual string Name { get; set; } + + /// + /// 文档类型:文件、文件夹 + /// + public virtual DocumentType? DocumentType { get; set; } + + /// + /// 文件后缀 + /// + public virtual string FileSuffix { get; set; } + + /// + /// 文件大小kb + /// + public virtual int? FileSizeKb { get; set; } + + /// + /// 存储后的文件名 + /// + public virtual string FileObjectName { get; set; } + + /// + /// 标签 + /// + public virtual int? Label { get; set; } + + /// + /// 备注 + /// + public virtual string Remark { get; set; } + + /// + /// 创建开始时间 + /// + public DateTime? CreateTimeStart { get; set; } + + /// + /// 创建结束时间 + /// + public DateTime? CreateTimeEnd { get; set; } + + /// + /// 修改结束时间 + /// + public DateTime? UpdateTimeStart { get; set; } + + /// + /// 修改结束时间 + /// + public DateTime? UpdateTimeEnd { get; set; } + + /// + /// 文件类型 + /// + public string FileType { get; set; } + + /// + /// 是否删除 + /// + public bool IsDelete = false; + +} + +public class AddDocumentInput : DocumentInput +{ + +} + +/// +/// 上传文件输入参数 +/// +public class DocumentUploadInput : DocumentInput +{ + + public List Files { get; set; } +} + +public class DeleteDocumentInput +{ + /// + /// Id + /// + [Required(ErrorMessage = "Id不能为空")] + public long Id { get; set; } + +} + + +/// +/// 批量删除入参 +/// +public class DeletesDocumentInput +{ + /// + /// Id列表 + /// + [Required(ErrorMessage = "Id列表不能为空")] + public List? Ids { get; set; } + +} + +/// +/// 移动入参 +/// +public class MoveDocumentInput +{ + /// + /// Id列表 + /// + [Required(ErrorMessage = "Id列表不能为空")] + public List? Ids { get; set; } + + /// + /// 父Id + /// + public long? PId { get; set; } + +} + + +public class UpdateDocumentInput : DocumentInput, IValidatableObject +{ + /// + /// Id + /// + [Required(ErrorMessage = "Id不能为空")] + public long? Id { get; set; } + + public IEnumerable Validate(ValidationContext validationContext) + { + if (Name.Split(".").Length > 1) + { + yield return new ValidationResult( + "名称不能带'.'" + , new[] { nameof(Name) } + ); + } + } +} + +public class QueryeDocumentInput : DeleteDocumentInput +{ + +} diff --git a/Magic.Core/Service/Document/Dto/DocumentOutput.cs b/Magic.Core/Service/Document/Dto/DocumentOutput.cs new file mode 100644 index 0000000..8cdd03a --- /dev/null +++ b/Magic.Core/Service/Document/Dto/DocumentOutput.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; + +namespace Magic.Core.Service; + +/// +/// 文档输出参数 +/// +public class DocumentOutput +{ + /// + /// Id + /// + public long Id { get; set; } + + /// + /// 父Id + /// + public long PId { get; set; } + + /// + /// 父ID列表 + /// + //public string PIds { get; set; } + + /// + /// 名称 + /// + public string Name { get; set; } + + /// + /// 文档类型:文件、文件夹 + /// + public DocumentType DocumentType { get; set; } + + + /// + /// 文件类型 + /// + public string FileType { get; set; } + + /// + /// 文件后缀 + /// + public string FileSuffix { get; set; } + + /// + /// 文件大小kb + /// + public int? FileSizeKb { get; set; } + + /// + /// 文件大小kb + /// + public string FileSize { get; set; } + + /// + /// 存储后的文件名 + /// + //public string FileObjectName { get; set; } + + /// + /// 标签 + /// + public int? Label { get; set; } + + /// + /// 标签数组 + /// + public string[] Tags { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } + + /// + /// 创建时间 + /// + + public DateTime? CreatedTime { get; set; } + /// + /// 更新时间 + /// + + public DateTime? UpdatedTime { get; set; } + /// + /// 创建用户ID + /// + public long? CreatedUserId { get; set; } + /// + /// 创建人用户名 + /// + public string CreatedUserName { get; set; } + /// + /// 修改人ID + /// + public long? UpdatedUserId { get; set; } + + /// + /// 修改人用户名 + /// + public string UpdatedUserName { get; set; } + + +} + +/// +/// 树查询输出 +/// +public class DocumentTreeOutPut +{ + /// + /// Id + /// + public long Id { get; set; } + + /// + /// 父Id + /// + public long PId { get; set; } + + /// + /// 父ID列表 + /// + //public string PIds { get; set; } + + /// + /// 名称 + /// + public string Name { get; set; } + + public List Children { get; set; } +} diff --git a/Magic.Core/Service/Document/IDocumentService.cs b/Magic.Core/Service/Document/IDocumentService.cs new file mode 100644 index 0000000..4de0918 --- /dev/null +++ b/Magic.Core/Service/Document/IDocumentService.cs @@ -0,0 +1,14 @@ + +using Magic.Core.Entity; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +namespace Magic.Core.Service; + +public interface IDocumentService +{ + Task Add(AddDocumentInput input); + Task Delete(DeleteDocumentInput input); + Task Get([FromQuery] QueryeDocumentInput input); + Task Page([FromQuery] DocumentInput input); + Task Update(UpdateDocumentInput input); +} diff --git a/Magic.Core/Service/Emp/Dto/EmpExtOrgPosOutput.cs b/Magic.Core/Service/Emp/Dto/EmpExtOrgPosOutput.cs new file mode 100644 index 0000000..9f8bbbc --- /dev/null +++ b/Magic.Core/Service/Emp/Dto/EmpExtOrgPosOutput.cs @@ -0,0 +1,41 @@ +namespace Magic.Core.Service; + +/// +/// 附属机构和职位参数 +/// +public class EmpExtOrgPosOutput +{ + /// + /// 员工Id + /// + public long SysEmpId { get; set; } + /// + /// 附属机构id + /// + public long OrgId { get; set; } + + /// + /// 附属机构编码 + /// + public string OrgCode { get; set; } + + /// + /// 附属机构名称 + /// + public string OrgName { get; set; } + + /// + /// 附属职位id + /// + public long PosId { get; set; } + + /// + /// 附属职位编码 + /// + public string PosCode { get; set; } + + /// + /// 附属职位名称 + /// + public string PosName { get; set; } +} diff --git a/Magic.Core/Service/Emp/Dto/EmpOutput.cs b/Magic.Core/Service/Emp/Dto/EmpOutput.cs new file mode 100644 index 0000000..4a205a8 --- /dev/null +++ b/Magic.Core/Service/Emp/Dto/EmpOutput.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; + +namespace Magic.Core.Service; + +/// +/// 员工信息参数 +/// +public class EmpOutput +{ + /// + /// 员工Id + /// + public long Id { get; set; } + + /// + /// 工号 + /// + public string JobNum { get; set; } + + /// + /// 机构id + /// + public string OrgId { get; set; } + + /// + /// 机构名称 + /// + public string OrgName { get; set; } + + /// + /// 机构与职位信息 + /// + public List ExtOrgPos { get; set; } = new List(); + + /// + /// 职位信息 + /// + public List Positions { get; set; } = new List(); +} diff --git a/Magic.Core/Service/Emp/Dto/EmpOutput2.cs b/Magic.Core/Service/Emp/Dto/EmpOutput2.cs new file mode 100644 index 0000000..17c4e21 --- /dev/null +++ b/Magic.Core/Service/Emp/Dto/EmpOutput2.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; + +namespace Magic.Core.Service; + +/// +/// 员工信息参数2 +/// +public class EmpOutput2 +{ + /// + /// 员工Id + /// + public string Id { get; set; } + + /// + /// 工号 + /// + public string JobNum { get; set; } + + /// + /// 机构Id + /// + public string OrgId { get; set; } + + /// + /// 机构名称 + /// + public string OrgName { get; set; } + + /// + /// 附属机构 + /// + public List ExtIds { get; set; } = new List(); + + /// + /// 职位集合 + /// + public List PosIdList { get; set; } = new List(); +} diff --git a/Magic.Core/Service/Emp/Dto/EmpPosOutput.cs b/Magic.Core/Service/Emp/Dto/EmpPosOutput.cs new file mode 100644 index 0000000..64fc1cc --- /dev/null +++ b/Magic.Core/Service/Emp/Dto/EmpPosOutput.cs @@ -0,0 +1,26 @@ +namespace Magic.Core.Service; + +/// +/// 员工职位参数 +/// +public class EmpPosOutput +{ + /// + /// 员工Id + /// + public long SysEmpId { get; set; } + /// + /// 职位Id + /// + public long PosId { get; set; } + + /// + /// 职位编码 + /// + public string PosCode { get; set; } + + /// + /// 职位名称 + /// + public string PosName { get; set; } +} diff --git a/Magic.Core/Service/Emp/ISysEmpExtOrgPosService.cs b/Magic.Core/Service/Emp/ISysEmpExtOrgPosService.cs new file mode 100644 index 0000000..914ffbc --- /dev/null +++ b/Magic.Core/Service/Emp/ISysEmpExtOrgPosService.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ISysEmpExtOrgPosService +{ + Task AddOrUpdate(long empId, List extIdList); + Task DeleteEmpExtInfoByUserId(long empId); + Task> GetEmpExtOrgPosList(long empId); + Task> GetEmpExtOrgPosList(List empIds); + Task HasExtOrgEmp(long orgId); + Task HasExtPosEmp(long posId); +} diff --git a/Magic.Core/Service/Emp/ISysEmpPosService.cs b/Magic.Core/Service/Emp/ISysEmpPosService.cs new file mode 100644 index 0000000..908639c --- /dev/null +++ b/Magic.Core/Service/Emp/ISysEmpPosService.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ISysEmpPosService +{ + Task AddOrUpdate(long empId, List posIdList); + Task DeleteEmpPosInfoByUserId(long empId); + Task> GetEmpPosList(long empId); + Task> GetEmpPosList(List empIds); + Task HasPosEmp(long posId); +} diff --git a/Magic.Core/Service/Emp/ISysEmpService.cs b/Magic.Core/Service/Emp/ISysEmpService.cs new file mode 100644 index 0000000..3444e55 --- /dev/null +++ b/Magic.Core/Service/Emp/ISysEmpService.cs @@ -0,0 +1,17 @@ +using Magic.Core.Entity; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ISysEmpService +{ + Task AddOrUpdate(EmpOutput2 sysEmpParam); + Task DeleteEmpInfoByUserId(long empId); + Task GetEmpInfo(long empId); + Task> GetEmpInfo(List empIds); + Task GetEmpOrgId(long empId); + Task HasOrgEmp(long orgId); + Task UpdateEmpOrgInfo(long orgId, string orgName); + Task> HasOrgEmp(List orgIds); +} diff --git a/Magic.Core/Service/Emp/SysEmpExtOrgPosService.cs b/Magic.Core/Service/Emp/SysEmpExtOrgPosService.cs new file mode 100644 index 0000000..240e6d5 --- /dev/null +++ b/Magic.Core/Service/Emp/SysEmpExtOrgPosService.cs @@ -0,0 +1,127 @@ + + +using Furion.DependencyInjection; +using Magic.Core.Entity; +using SqlSugar; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +/// +/// 员工附属机构和职位服务 +/// +public class SysEmpExtOrgPosService : ISysEmpExtOrgPosService, ITransient +{ + private readonly SqlSugarRepository _sysEmpExtOrgPosRep; // 附属机构表仓储 + + public SysEmpExtOrgPosService(SqlSugarRepository sysEmpExtOrgPosRep) + { + _sysEmpExtOrgPosRep = sysEmpExtOrgPosRep; + } + + /// + /// 保存或编辑附属机构相关信息 + /// + /// + public async Task AddOrUpdate(long empId, List extIdList) + { + try + { + _sysEmpExtOrgPosRep.CurrentBeginTran(); + // 先删除 + await DeleteEmpExtInfoByUserId(empId); + + if (extIdList != null && extIdList.Any()) + { + var tasks = new List(); + extIdList.ForEach(u => + { + tasks.Add(new SysEmpExtOrgPos + { + SysEmpId = empId, + SysOrgId = u.OrgId, + SysPosId = u.PosId + }); + }); + await _sysEmpExtOrgPosRep.InsertAsync(tasks); + } + _sysEmpExtOrgPosRep.CurrentCommitTran(); + } + catch (System.Exception) + { + _sysEmpExtOrgPosRep.CurrentRollbackTran(); + throw; + } + + } + + /// + /// 获取附属机构和职位信息 + /// + /// + /// + public async Task> GetEmpExtOrgPosList(long empId) + { + return await _sysEmpExtOrgPosRep.AsQueryable().InnerJoin((e,p) => e.SysPosId == p.Id) + .InnerJoin((e, p, o)=> e.SysOrgId == o.Id) + .Where((e, p, o) => e.SysEmpId == empId) + .Select((e, p, o) => new EmpExtOrgPosOutput + { + SysEmpId = e.SysEmpId, + OrgId = o.Id, + OrgCode = o.Code, + OrgName = o.Name, + PosId = p.Id, + PosCode = p.Code, + PosName = p.Name + }).ToListAsync(); + } + + public async Task> GetEmpExtOrgPosList(List empIds) + { + return await _sysEmpExtOrgPosRep.AsQueryable().InnerJoin((e, p) => e.SysPosId == p.Id) + .InnerJoin((e, p, o) => e.SysOrgId == o.Id) + .Where((e, p, o) => empIds.Contains(e.SysEmpId)) + .Select((e, p, o) => new EmpExtOrgPosOutput + { + OrgId = o.Id, + OrgCode = o.Code, + OrgName = o.Name, + PosId = p.Id, + PosCode = p.Code, + PosName = p.Name + }).ToListAsync(); + } + + /// + /// 根据机构Id判断该附属机构下是否有员工 + /// + /// + /// + public async Task HasExtOrgEmp(long orgId) + { + return await _sysEmpExtOrgPosRep.AnyAsync(u => u.SysOrgId == orgId); + } + + /// + /// 根据职位Id判断该附属职位下是否有员工 + /// + /// + /// + public async Task HasExtPosEmp(long posId) + { + return await _sysEmpExtOrgPosRep.AnyAsync(u => u.SysPosId == posId); + } + + /// + /// 根据员工Id删除对应的员工-附属信息 + /// + /// + /// + public async Task DeleteEmpExtInfoByUserId(long empId) + { + await _sysEmpExtOrgPosRep.DeleteAsync(u => u.SysEmpId == empId); + } +} diff --git a/Magic.Core/Service/Emp/SysEmpPosService.cs b/Magic.Core/Service/Emp/SysEmpPosService.cs new file mode 100644 index 0000000..588a97e --- /dev/null +++ b/Magic.Core/Service/Emp/SysEmpPosService.cs @@ -0,0 +1,108 @@ + + +using Furion.DependencyInjection; +using Magic.Core.Entity; +using SqlSugar; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +/// +/// 员工职位服务 +/// +public class SysEmpPosService : ISysEmpPosService, ITransient +{ + private readonly SqlSugarRepository _sysEmpPosRep; // 员工职位表仓储 + + public SysEmpPosService(SqlSugarRepository sysEmpPosRep) + { + _sysEmpPosRep = sysEmpPosRep; + } + + /// + /// 增加或编辑员工职位相关信息 + /// + /// 员工Id(用户Id) + /// 职位id集合 + /// + public async Task AddOrUpdate(long empId, List posIdList) + { + try + { + _sysEmpPosRep.CurrentBeginTran(); + // 先删除 + await DeleteEmpPosInfoByUserId(empId); + + if (posIdList != null && posIdList.Any()) + { + List list = new List(); + posIdList.ForEach(u => + { + list.Add(new SysEmpPos + { + SysEmpId = empId, + SysPosId = u + }); + }); + await _sysEmpPosRep.InsertAsync(list); + } + _sysEmpPosRep.CurrentCommitTran(); + } + catch (System.Exception) + { + _sysEmpPosRep.CurrentRollbackTran(); + throw; + } + + } + + /// + /// 获取所属职位信息 + /// + /// 员工Id(用户Id) + public async Task> GetEmpPosList(long empId) + { + return await _sysEmpPosRep.AsQueryable().InnerJoin((e, p) => e.SysPosId == p.Id) + .Where((e, p) => e.SysEmpId == empId) + .Select((e, p) => new EmpPosOutput + { + PosId = p.Id, + PosCode = p.Code, + PosName = p.Name + }).ToListAsync(); + } + + public async Task> GetEmpPosList(List empIds) + { + return await _sysEmpPosRep.AsQueryable().InnerJoin((e, p) => e.SysPosId == p.Id) + .Where((e, p) => empIds.Contains(e.SysEmpId)) + .Select((e, p) => new EmpPosOutput + { + PosId = p.Id, + PosCode = p.Code, + PosName = p.Name + }).ToListAsync(); + } + + /// + /// 根据职位Id判断该职位下是否有员工 + /// + /// + /// + public async Task HasPosEmp(long posId) + { + return await _sysEmpPosRep.AnyAsync(u => u.SysPosId == posId); + } + + /// + /// 根据员工Id删除对用的员工-职位信息 + /// + /// + /// + public async Task DeleteEmpPosInfoByUserId(long empId) + { + await _sysEmpPosRep.DeleteAsync(u => u.SysEmpId == empId); + } +} diff --git a/Magic.Core/Service/Emp/SysEmpService.cs b/Magic.Core/Service/Emp/SysEmpService.cs new file mode 100644 index 0000000..355505a --- /dev/null +++ b/Magic.Core/Service/Emp/SysEmpService.cs @@ -0,0 +1,178 @@ + + +using Furion.DependencyInjection; +using Magic.Core.Entity; +using Mapster; + +using SqlSugar; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +/// +/// 员工服务 +/// +public class SysEmpService : ISysEmpService, ITransient +{ + private readonly SqlSugarRepository _sysEmpRep; // 员工表仓储 + + private readonly ISysEmpExtOrgPosService _sysEmpExtOrgPosService; + private readonly ISysEmpPosService _sysEmpPosService; + + public SysEmpService(SqlSugarRepository sysEmpRep, + ISysEmpExtOrgPosService sysEmpExtOrgPosService, + ISysEmpPosService sysEmpPosService) + { + _sysEmpRep = sysEmpRep; + _sysEmpExtOrgPosService = sysEmpExtOrgPosService; + _sysEmpPosService = sysEmpPosService; + } + + /// + /// 获取用户员工相关信息(包括登录) + /// + /// + /// + public async Task GetEmpInfo(long empId) + { + var empInfoOutput = new EmpOutput(); + var sysEmp = await _sysEmpRep.FirstOrDefaultAsync(u => u.Id == empId); + if (sysEmp == null) return empInfoOutput; + + empInfoOutput = sysEmp.Adapt(); + empInfoOutput.ExtOrgPos = await _sysEmpExtOrgPosService.GetEmpExtOrgPosList(empId); + empInfoOutput.Positions = await _sysEmpPosService.GetEmpPosList(empId); + return empInfoOutput; + } + + /// + /// 获取用户员工相关信息 + /// + /// + /// + public async Task> GetEmpInfo(List empIds) + { + List empInfoOutputs = new List(); + List sysEmps=await _sysEmpRep.Where(m=>empIds.Contains(m.Id)).ToListAsync(); + if (sysEmps == null || !sysEmps.Any()) return empInfoOutputs; + empInfoOutputs = sysEmps.Adapt>(); + + var extOrgPoses = await _sysEmpExtOrgPosService.GetEmpExtOrgPosList(empIds); + var positions = await _sysEmpPosService.GetEmpPosList(empIds); + + foreach (var empInfoOutput in empInfoOutputs) + { + empInfoOutput.ExtOrgPos = extOrgPoses.Where(m => m.SysEmpId == empInfoOutput.Id).ToList(); + empInfoOutput.Positions = positions.Where(m => m.SysEmpId == empInfoOutput.Id).ToList(); + } + return empInfoOutputs; + } + + /// + /// 增加或编辑员工相关信息 + /// + /// + public async Task AddOrUpdate(EmpOutput2 sysEmpParam) + { + try + { + _sysEmpRep.CurrentBeginTran(); + // 先删除员工信息 + await _sysEmpRep.DeleteAsync(u => u.Id == long.Parse(sysEmpParam.Id)); + + // 再新增新员工信息 + var emp = sysEmpParam.Adapt(); + await _sysEmpRep.InsertAsync(emp); + + // 更新附属机构职位信息 + await _sysEmpExtOrgPosService.AddOrUpdate(emp.Id, sysEmpParam.ExtIds); + + // 更新职位信息 + await _sysEmpPosService.AddOrUpdate(emp.Id, sysEmpParam.PosIdList); + _sysEmpRep.CurrentCommitTran(); + } + catch (System.Exception) + { + _sysEmpRep.CurrentRollbackTran(); + throw; + } + + } + + /// + /// 修改员工相关机构信息 + /// + /// + /// + /// + public async Task UpdateEmpOrgInfo(long orgId, string orgName) + { + var emps = await _sysEmpRep.Where(u => u.OrgId == orgId).ToListAsync(); + emps.ForEach(u => + { + u.OrgName = orgName; + }); + await _sysEmpRep.UpdateAsync(emps); + } + + /// + /// 根据机构Id判断该机构下是否有员工 + /// + /// + /// + public async Task HasOrgEmp(long orgId) + { + return await _sysEmpRep.AnyAsync(u => u.OrgId == orgId); + } + + /// + /// 根据员工Id删除对应的员工表信息 + /// + /// + /// + public async Task DeleteEmpInfoByUserId(long empId) + { + try + { + _sysEmpRep.CurrentBeginTran(); + + var emp = await _sysEmpRep.FirstOrDefaultAsync(u => u.Id == empId); + // 级联删除对应的员工-附属信息 + await _sysEmpExtOrgPosService.DeleteEmpExtInfoByUserId(empId); + + // 级联删除对用的员工-职位信息 + await _sysEmpPosService.DeleteEmpPosInfoByUserId(empId); + // 删除员工信息 + await _sysEmpRep.DeleteAsync(emp); + _sysEmpRep.CurrentCommitTran(); + } + catch (System.Exception) + { + _sysEmpRep.CurrentRollbackTran(); + throw; + } + + } + + /// + /// 获取员工机构Id + /// + /// + /// + public async Task GetEmpOrgId(long empId) + { + return (await _sysEmpRep.FirstOrDefaultAsync(u => u.Id == empId)).OrgId; + } + + /// + /// 获取子机构用户 + /// + /// + /// + public async Task> HasOrgEmp(List orgIds) + { + return await _sysEmpRep.Where(u => orgIds.Contains(u.OrgId)).ToListAsync(); + } +} diff --git a/Magic.Core/Service/Enum/Dto/EnumDataInput.cs b/Magic.Core/Service/Enum/Dto/EnumDataInput.cs new file mode 100644 index 0000000..cf9e6eb --- /dev/null +++ b/Magic.Core/Service/Enum/Dto/EnumDataInput.cs @@ -0,0 +1,31 @@ +using System.ComponentModel.DataAnnotations; + +namespace Magic.Core.Service; + +/// +/// 枚举输入参数 +/// +public class EnumDataInput +{ + /// + /// 枚举类型名称 + /// + /// Gender + [Required(ErrorMessage = "枚举类型不能为空")] + public string EnumName { get; set; } +} + +public class QueryEnumDataInput +{ + /// + /// 实体名称 + /// + [Required(ErrorMessage = "实体名称不能为空")] + public string EntityName { get; set; } + + /// + /// 字段名称 + /// + [Required(ErrorMessage = "字段名称不能为空")] + public string FieldName { get; set; } +} diff --git a/Magic.Core/Service/Enum/Dto/EnumDataOutput.cs b/Magic.Core/Service/Enum/Dto/EnumDataOutput.cs new file mode 100644 index 0000000..fa2e1c2 --- /dev/null +++ b/Magic.Core/Service/Enum/Dto/EnumDataOutput.cs @@ -0,0 +1,17 @@ +namespace Magic.Core.Service; + +/// +/// 枚举输出参数 +/// +public class EnumDataOutput +{ + /// + /// 字典Id + /// + public int Code { get; set; } + + /// + /// 字典值 + /// + public string Value { get; set; } +} diff --git a/Magic.Core/Service/Enum/ISysEnumDataService.cs b/Magic.Core/Service/Enum/ISysEnumDataService.cs new file mode 100644 index 0000000..4115ad2 --- /dev/null +++ b/Magic.Core/Service/Enum/ISysEnumDataService.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ISysEnumDataService +{ + dynamic GetEnumTypeList(); + Task GetEnumDataList([FromQuery] EnumDataInput input); + Task GetEnumDataListByField([FromQuery] QueryEnumDataInput input); +} diff --git a/Magic.Core/Service/Enum/SysEnumDataService.cs b/Magic.Core/Service/Enum/SysEnumDataService.cs new file mode 100644 index 0000000..3d9d151 --- /dev/null +++ b/Magic.Core/Service/Enum/SysEnumDataService.cs @@ -0,0 +1,120 @@ +using Furion; +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Furion.FriendlyException; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +/// +/// 枚举值服务 +/// +[ApiDescriptionSettings(Name = "EnumData", Order = 1000)] +[AllowAnonymous] +public class SysEnumDataService : ISysEnumDataService, IDynamicApiController, ITransient +{ + + + /// + /// 获取所有枚举值 + /// + /// + [HttpGet("/sysEnumData/enumTypeList")] + public dynamic GetEnumTypeList() + { + + List result = new List(); + var enumTypeList = App.EffectiveTypes.Where(t => t.IsEnum && t.FullName.StartsWith("Magic.")).ToList(); + + foreach (var item in enumTypeList) + { + result.Add(GetEnumDescription(item)); + } + return result; + } + + private dynamic GetEnumDescription(Type type) + { + + string description = type.Name; + var attrs = type.GetCustomAttributes(typeof(DescriptionAttribute), false); + if (!attrs.IsNullOrZero() && attrs.Any()) + { + //获取到:超级管理员 + var att = ((DescriptionAttribute[])attrs)[0]; + description = att.Description; + } + return new + { + Name = description, + Code = type.Name, + Sort = 100, + Remark = description + }; + } + + /// + /// 通过枚举类型获取枚举值集合 + /// + /// + /// + [HttpGet("/sysEnumData/list")] + public async Task GetEnumDataList([FromQuery] EnumDataInput input) + { + // 查找枚举 + var enumType = App.EffectiveTypes.FirstOrDefault(t => t.IsEnum && t.Name == input.EnumName); + if (enumType == null) + throw Oops.Oh(ErrorCode.D1502).StatusCode(405); + + //// 获取枚举的Key和描述 + return await Task.Run(() => + EnumExtensions.GetEnumDescDictionary(enumType) + .Select(x => new EnumDataOutput + { + Code = x.Key, + Value = x.Value + })); + } + + /// + /// 通过实体字段类型获取相关集合(目前仅支持枚举类型) + /// + /// + /// + [HttpGet("/sysEnumData/listByFiled")] + public async Task GetEnumDataListByField([FromQuery] QueryEnumDataInput input) + { + + // 获取实体类型属性 + Type entityType = null; + + foreach (var item in CommonConst.ENTITY_ASSEMBLY_NAME) + { + entityType = Type.GetType($"{item}.Entity.{input.EntityName}"); + if (entityType != null) + break; + } + if (entityType == null) throw Oops.Oh(ErrorCode.D1504); + + // 获取字段类型 + var fieldType = entityType.GetProperties().FirstOrDefault(p => p.Name == input.FieldName)?.PropertyType; + if (fieldType is not { IsEnum: true }) + throw Oops.Oh(ErrorCode.D1503); + + // 获取枚举的Key和描述 + return await Task.Run(() => + EnumExtensions.GetEnumDescDictionary(fieldType) + .Select(x => new EnumDataOutput + { + Code = x.Key, + Value = x.Value + })); + } +} diff --git a/Magic.Core/Service/File/Dto/FileInput.cs b/Magic.Core/Service/File/Dto/FileInput.cs new file mode 100644 index 0000000..77de05a --- /dev/null +++ b/Magic.Core/Service/File/Dto/FileInput.cs @@ -0,0 +1,64 @@ +using Microsoft.AspNetCore.Http; +using System.ComponentModel.DataAnnotations; + +namespace Magic.Core.Service; + +/// +/// 上传文件参数 +/// +public class FileInput : PageInputBase +{ + /// + /// 文件存储位置(1:阿里云,2:腾讯云,3:minio,4:本地) + /// + public int FileLocation { get; set; } + + /// + /// 文件仓库 + /// + public string FileBucket { get; set; } + + /// + /// 文件名称(上传时候的文件名) + /// + public string FileOriginName { get; set; } + + /// + /// 文件后缀 + /// + public string FileSuffix { get; set; } + + /// + /// 文件大小kb + /// + public string FileSizeKb { get; set; } + + /// + /// 文件大小信息,计算后的 + /// + public string FileSizeInfo { get; set; } + + /// + /// 存储到bucket的名称(文件唯一标识id) + /// + public string FileObjectName { get; set; } + + /// + /// 存储路径 + /// + public string FilePath { get; set; } +} + +public class DeleteFileInfoInput +{ + /// + /// 文件Id + /// + [Required(ErrorMessage = "文件Id不能为空")] + public long Id { get; set; } +} + +public class QueryFileInoInput : DeleteFileInfoInput +{ + +} diff --git a/Magic.Core/Service/File/Dto/FileOutput.cs b/Magic.Core/Service/File/Dto/FileOutput.cs new file mode 100644 index 0000000..b37f560 --- /dev/null +++ b/Magic.Core/Service/File/Dto/FileOutput.cs @@ -0,0 +1,12 @@ +namespace Magic.Core.Service; + +/// +/// 上传文件参数 +/// +public class FileOutput : FileInput +{ + /// + /// 文件Id + /// + public long Id { get; set; } +} diff --git a/Magic.Core/Service/File/ISysFileService.cs b/Magic.Core/Service/File/ISysFileService.cs new file mode 100644 index 0000000..7f00759 --- /dev/null +++ b/Magic.Core/Service/File/ISysFileService.cs @@ -0,0 +1,22 @@ +using Magic.Core.Entity; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ISysFileService +{ + Task DeleteFileInfo(DeleteFileInfoInput input); + Task DownloadFileInfo([FromQuery] QueryFileInoInput input); + Task GetFileInfo([FromQuery] QueryFileInoInput input); + Task> GetFileInfoList([FromQuery] FileOutput input); + Task PreviewFileInfo([FromQuery] QueryFileInoInput input); + Task QueryFileInfoPageList([FromQuery] FileInput input); + Task UploadFileAvatar(IFormFile file); + Task UploadFileEditor(IFormFile file); + Task UploadFileDefault(IFormFile file); + Task UploadFileDocument(IFormFile file); + Task UploadFileShop(IFormFile file); +} diff --git a/Magic.Core/Service/File/SysFileService.cs b/Magic.Core/Service/File/SysFileService.cs new file mode 100644 index 0000000..a5d1f77 --- /dev/null +++ b/Magic.Core/Service/File/SysFileService.cs @@ -0,0 +1,269 @@ +using Furion; +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Furion.FriendlyException; +using Magic.Core.Entity; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; +using SqlSugar; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using Yitter.IdGenerator; + +namespace Magic.Core.Service; + +/// +/// 文件服务 +/// +[ApiDescriptionSettings(Name = "File", Order = 100)] +public class SysFileService : ISysFileService, IDynamicApiController, ITransient +{ + private readonly SqlSugarRepository _sysFileInfoRep; // 文件信息表仓储 + + private readonly UploadFileOptions _options; + + public SysFileService(SqlSugarRepository sysFileInfoRep, IOptions options) + { + _sysFileInfoRep = sysFileInfoRep; + _options = options.Value; + } + + /// + /// 分页获取文件列表 + /// + /// + /// + [HttpGet("/sysFileInfo/page")] + public async Task QueryFileInfoPageList([FromQuery] FileInput input) + { + var fileBucket = !string.IsNullOrEmpty(input.FileBucket?.Trim()); + var fileOriginName = !string.IsNullOrEmpty(input.FileOriginName?.Trim()); + + var files = await _sysFileInfoRep.AsQueryable() + .WhereIF(input.FileLocation > 0, u => u.FileLocation == input.FileLocation) + .WhereIF(!string.IsNullOrWhiteSpace(input.FileBucket), u => u.FileBucket.Contains(input.FileBucket.Trim())) + .WhereIF(!string.IsNullOrWhiteSpace(input.FileOriginName), u => u.FileOriginName.Contains(input.FileOriginName.Trim())) + .Select() + .ToPagedListAsync(input.PageNo, input.PageSize); + return files.XnPagedResult(); + } + + /// + /// 获取文件列表 + /// + /// + /// + [HttpGet("/sysFileInfo/list")] + public async Task> GetFileInfoList([FromQuery] FileOutput input) + { + return await _sysFileInfoRep.ToListAsync(); + } + + /// + /// 删除文件 + /// + /// + /// + [HttpPost("/sysFileInfo/delete")] + public async Task DeleteFileInfo(DeleteFileInfoInput input) + { + var file = await _sysFileInfoRep.FirstOrDefaultAsync(u => u.Id == input.Id); + if (file != null) + { + await _sysFileInfoRep.DeleteAsync(file); + + var filePath = Path.Combine(App.WebHostEnvironment.WebRootPath, file.FileBucket, file.FileObjectName); + if (File.Exists(filePath)) + File.Delete(filePath); + } + } + + /// + /// 获取文件详情 + /// + /// + /// + [HttpGet("/sysFileInfo/detail")] + public async Task GetFileInfo([FromQuery] QueryFileInoInput input) + { + var file = await _sysFileInfoRep.FirstOrDefaultAsync(u => u.Id == input.Id); + if (file == null) + throw Oops.Oh(ErrorCode.D8000); + return file; + } + + /// + /// 预览文件 + /// + /// + /// + [HttpGet("/sysFileInfo/preview")] + public async Task PreviewFileInfo([FromQuery] QueryFileInoInput input) + { + return await DownloadFileInfo(input); + } + + /// + /// 上传文件 + /// + /// + /// + [HttpPost("/sysFileInfo/upload")] + public async Task UploadFileDefault(IFormFile file) + { + // 可以读取系统配置来决定将文件存储到什么地方 + await UploadFile(file, _options.Default.path, FileLocation.LOCAL); + } + + /// + /// 下载文件 + /// + /// + /// + [HttpGet("/sysFileInfo/download")] + public async Task DownloadFileInfo([FromQuery] QueryFileInoInput input) + { + var file = await GetFileInfo(input); + var filePath = Path.Combine(App.WebHostEnvironment.WebRootPath, file.FilePath, file.FileObjectName); + var fileName = HttpUtility.UrlEncode(file.FileOriginName, Encoding.GetEncoding("UTF-8")); + var result = new FileStreamResult(new FileStream(filePath, FileMode.Open), "application/octet-stream") { FileDownloadName = fileName }; + return result; + } + + /// + /// 上传头像 + /// + /// + /// + [HttpPost("/sysFileInfo/uploadAvatar")] + public async Task UploadFileAvatar(IFormFile file) + { + return await UploadFile(file, _options.Avatar.path); + } + + /// + /// 上传文档 + /// + /// + /// + [HttpPost("/sysFileInfo/uploadDocument")] + public async Task UploadFileDocument(IFormFile file) + { + await UploadFile(file, _options.Document.path); + } + /// + /// 上传富文本图片 + /// + /// + /// + [HttpPost("/sysFileInfo/uploadEditor")] + public async Task UploadFileEditor(IFormFile file) + { + var id = await UploadFile(file, _options.Editor.path, FileLocation.LOCAL); + var fileInfo = _sysFileInfoRep.Single(id); + return Path.Combine(fileInfo.FilePath, fileInfo.FileObjectName); + + } + /// + /// 上传商店图片 + /// + /// + /// + [HttpPost("/sysFileInfo/uploadShop")] + public async Task UploadFileShop(IFormFile file) + { + await UploadFile(file, _options.Shop.path); + } + + /// + /// 上传文件 + /// + /// + /// + /// + private static async Task UploadFile(IFormFile file, string pathType) + { + var filePath = Path.Combine(App.WebHostEnvironment.WebRootPath, pathType); + if (!Directory.Exists(filePath)) + Directory.CreateDirectory(filePath); + + var fileSizeKb = (long)(file.Length / 1024.0); // 文件大小KB + var originalFilename = file.FileName; // 文件原始名称 + var fileSuffix = Path.GetExtension(file.FileName).ToLower(); // 文件后缀 + + // 先存库获取Id + var id = YitIdHelper.NextId(); + var newFile = new SysFile + { + Id=id, + FileLocation = (int)FileLocation.LOCAL, + FileBucket = FileLocation.LOCAL.ToString(), + FileObjectName = $"{id}{fileSuffix}", + FileOriginName = originalFilename, + FileSuffix = fileSuffix.TrimStart('.'), + FileSizeKb = fileSizeKb.ToString(), + FilePath = pathType + }; + newFile = await App.GetService().Insertable(newFile).ExecuteReturnEntityAsync(); + using (var stream = File.Create(Path.Combine(filePath, newFile.FileObjectName))) + { + await file.CopyToAsync(stream); + } + return newFile.Id; // 返回文件唯一标识 + } + + /// + /// 上传文件 + /// + /// 文件 + /// 存储路径 + /// 文件存储位置 + /// + private static async Task UploadFile(IFormFile file, string pathType, FileLocation fileLocation) + { + var fileSizeKb = (long)(file.Length / 1024.0); // 文件大小KB + var originalFilename = file.FileName; // 文件原始名称 + var fileSuffix = Path.GetExtension(file.FileName).ToLower(); // 文件后缀 + + // 先存库获取Id + var id = YitIdHelper.NextId(); + var newFile = new SysFile + { + Id = id, + FileLocation = (int)FileLocation.LOCAL, + FileBucket = FileLocation.LOCAL.ToString(), + FileObjectName = $"{YitIdHelper.NextId()}{fileSuffix}", + FileOriginName = originalFilename, + FileSuffix = fileSuffix.TrimStart('.'), + FileSizeKb = fileSizeKb.ToString(), + FilePath = pathType + }; + newFile = await App.GetService().Insertable(newFile).ExecuteReturnEntityAsync(); + + var finalName = newFile.FileObjectName; // 生成文件的最终名称 + if (fileLocation == FileLocation.LOCAL) // 本地存储 + { + var filePath = Path.Combine(App.WebHostEnvironment.WebRootPath, pathType); + if (!Directory.Exists(filePath)) + Directory.CreateDirectory(filePath); + using (var stream = File.Create(Path.Combine(filePath, finalName))) + { + await file.CopyToAsync(stream); + } + } + else if (fileLocation == FileLocation.ALIYUN) // 阿里云OSS + { + var filePath = pathType + finalName; + OSSClientUtil.DeletefileCode(filePath); + + var stream = file.OpenReadStream(); + OSSClientUtil.PushMedia(stream, filePath); + } + newFile.FileObjectName = finalName; + return newFile.Id; // 返回文件唯一标识 + } +} diff --git a/Magic.Core/Service/Menu/Dto/AntDesignTreeNode.cs b/Magic.Core/Service/Menu/Dto/AntDesignTreeNode.cs new file mode 100644 index 0000000..432b322 --- /dev/null +++ b/Magic.Core/Service/Menu/Dto/AntDesignTreeNode.cs @@ -0,0 +1,82 @@ +namespace Magic.Core.Service; + +/// +/// 登录菜单-AntDesign菜单类型 +/// +public class AntDesignTreeNode +{ + /// + /// 所属应用 + /// + public string Application { get; set; } + /// + /// id + /// + public long? Id { get; set; } + + /// + /// 父id + /// + public long? Pid { get; set; } + + /// + /// 路由名称, 必须设置,且不能重名 + /// + public string Name { get; set; } + + /// + /// 组件 + /// + public string Component { get; set; } + + /// + /// 重定向地址, 访问这个路由时, 自定进行重定向 + /// + public string Redirect { get; set; } + + /// + /// 路由元信息(路由附带扩展信息) + /// + public Meta Meta { get; set; } + + /// + /// 路径 + /// + public string Path { get; set; } + + /// + /// 控制路由和子路由是否显示在 sidebar + /// + public bool Hidden { get; set; } +} + +/// +/// 路由元信息内部类 +/// +public class Meta +{ + /// + /// 路由标题, 用于显示面包屑, 页面标题 *推荐设置 + /// + public string Title { get; set; } + + /// + /// 图标 + /// + public string Icon { get; set; } + + /// + /// 是否可见 + /// + public bool Show { get; set; } + + /// + /// 如需外部打开,增加:_blank + /// + public string Target { get; set; } + + /// + /// 内链打开http链接 + /// + public string Link { get; set; } +} diff --git a/Magic.Core/Service/Menu/Dto/MenuInput.cs b/Magic.Core/Service/Menu/Dto/MenuInput.cs new file mode 100644 index 0000000..dbf3556 --- /dev/null +++ b/Magic.Core/Service/Menu/Dto/MenuInput.cs @@ -0,0 +1,136 @@ +using System.ComponentModel.DataAnnotations; + +namespace Magic.Core.Service; + +/// +/// 菜单参数 +/// +public class MenuInput +{ + /// + /// 父Id + /// + public virtual long Pid { get; set; } + + /// + /// 名称 + /// + public virtual string Name { get; set; } + + /// + /// 编码 + /// + public virtual string Code { get; set; } + + /// + /// 菜单类型(字典 0目录 1菜单 2按钮) + /// + public virtual string Type { get; set; } + + /// + /// 图标 + /// + public string Icon { get; set; } + + /// + /// 路由地址 + /// + public virtual string Router { get; set; } + + /// + /// 组件地址 + /// + public virtual string Component { get; set; } + + /// + /// 权限标识 + /// + public virtual string Permission { get; set; } + + /// + /// 应用分类(应用编码) + /// + public virtual string Application { get; set; } + + /// + /// 打开方式(字典 0无 1组件 2内链 3外链) + /// + public virtual string OpenType { get; set; } + + /// + /// 是否可见(Y-是,N-否) + /// + public string Visible { get; set; } + + /// + /// 内链地址 + /// + public string Link { get; set; } + + /// + /// 重定向地址 + /// + public string Redirect { get; set; } + + /// + /// 权重(字典 1系统权重 2业务权重) + /// + public string Weight { get; set; } + + /// + /// 排序 + /// + public int Sort { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } +} + +public class AddMenuInput : MenuInput +{ + /// + /// 菜单类型(字典 0目录 1菜单 2按钮) + /// + [Required(ErrorMessage = "菜单类型不能为空")] + public override string Type { get; set; } +} + +public class DeleteMenuInput +{ + /// + /// 菜单Id + /// + [Required(ErrorMessage = "菜单Id不能为空")] + public long Id { get; set; } +} + +public class UpdateMenuInput : AddMenuInput +{ + /// + /// 菜单Id + /// + [Required(ErrorMessage = "菜单Id不能为空")] + public long Id { get; set; } + + /// + /// 父Id + /// DeleteMenuInput + [Required(ErrorMessage = "父级菜单Id不能为空")] + public override long Pid { get; set; } +} + +public class QueryMenuInput : DeleteMenuInput +{ + +} + +public class ChangeAppMenuInput : MenuInput +{ + /// + /// 应用编码 + /// DeleteMenuInput + [Required(ErrorMessage = "应用编码不能为空")] + public override string Application { get; set; } +} diff --git a/Magic.Core/Service/Menu/Dto/MenuOutput.cs b/Magic.Core/Service/Menu/Dto/MenuOutput.cs new file mode 100644 index 0000000..41a8320 --- /dev/null +++ b/Magic.Core/Service/Menu/Dto/MenuOutput.cs @@ -0,0 +1,35 @@ +using System.Collections; +using System.Collections.Generic; + +namespace Magic.Core.Service; + +/// +/// 菜单树(列表形式) +/// +public class MenuOutput : MenuInput, ITreeNode +{ + /// + /// 菜单Id + /// + public long Id { get; set; } + + /// + /// 子节点 + /// + public List Children { get; set; } = new List(); + + public long GetId() + { + return Id; + } + + public long GetPid() + { + return Pid; + } + + public void SetChildren(IList children) + { + Children = (List)children; + } +} diff --git a/Magic.Core/Service/Menu/Dto/MenuTreeAppOutput.cs b/Magic.Core/Service/Menu/Dto/MenuTreeAppOutput.cs new file mode 100644 index 0000000..d2feb15 --- /dev/null +++ b/Magic.Core/Service/Menu/Dto/MenuTreeAppOutput.cs @@ -0,0 +1,16 @@ +namespace Magic.Core.Service; + +public class MenuTreeAppOutput +{ + /// + /// 应用名称 + /// + public string AppName { get; set; } + + /// + /// 应用编码 + /// + public string AppCode { get; set; } +} + + diff --git a/Magic.Core/Service/Menu/Dto/MenuTreeOutput.cs b/Magic.Core/Service/Menu/Dto/MenuTreeOutput.cs new file mode 100644 index 0000000..653f490 --- /dev/null +++ b/Magic.Core/Service/Menu/Dto/MenuTreeOutput.cs @@ -0,0 +1,72 @@ +using System.Collections; +using System.Collections.Generic; + +namespace Magic.Core.Service; + +/// +/// 菜单树---授权、新增编辑时选择 +/// +public class MenuTreeOutput : ITreeNode +{ + /// + /// 主键 + /// + public long Id { get; set; } + + /// + /// 父Id + /// + public long ParentId { get; set; } + + /// + /// 名称 + /// + public string Title { get; set; } + + /// + /// 值 + /// + public string Value { get; set; } + + /// + /// 排序,越小优先级越高 + /// + public int Weight { get; set; } + + /// + /// 子节点 + /// + public List Children { get; set; } = new List(); + + /// + /// 应用名称 + /// + [System.Text.Json.Serialization.JsonIgnore] + public string AppName { get; set; } + + /// + /// 应用编码 + /// + public string AppCode { get; set; } + + /// + /// 引用排序 + /// + [System.Text.Json.Serialization.JsonIgnore] + public int AppSort { get; set; } + + public long GetId() + { + return Id; + } + + public long GetPid() + { + return ParentId; + } + + public void SetChildren(IList children) + { + Children = (List)children; + } +} diff --git a/Magic.Core/Service/Menu/Dto/OwnMenuOutput.cs b/Magic.Core/Service/Menu/Dto/OwnMenuOutput.cs new file mode 100644 index 0000000..922f0fc --- /dev/null +++ b/Magic.Core/Service/Menu/Dto/OwnMenuOutput.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public class OwnMenuOutput +{ + /// + /// 应用编码 + /// + public string AppCode { get; set; } + + /// + /// 菜单Id集合 + /// + public List MenuIdList { get; set; } +} diff --git a/Magic.Core/Service/Menu/ISysMenuService.cs b/Magic.Core/Service/Menu/ISysMenuService.cs new file mode 100644 index 0000000..65f3464 --- /dev/null +++ b/Magic.Core/Service/Menu/ISysMenuService.cs @@ -0,0 +1,22 @@ +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ISysMenuService +{ + Task AddMenu(AddMenuInput input); + Task> ChangeAppMenu(ChangeAppMenuInput input); + Task DeleteMenu(DeleteMenuInput input); + Task> GetLoginMenusAntDesign(long userId, string appCode); + Task> GetLoginPermissionList(long userId); + Task GetMenu(QueryMenuInput input); + Task GetMenuList([FromQuery] MenuInput input); + Task GetMenuTree([FromQuery] MenuInput input); + Task> GetUserMenuAppCodeList(long userId); + Task HasMenu(string appCode); + Task TreeForGrant([FromQuery] MenuInput input); + Task UpdateMenu(UpdateMenuInput input); + Task> GetAllPermission(); +} diff --git a/Magic.Core/Service/Menu/SysMenuService.cs b/Magic.Core/Service/Menu/SysMenuService.cs new file mode 100644 index 0000000..e2eb9e9 --- /dev/null +++ b/Magic.Core/Service/Menu/SysMenuService.cs @@ -0,0 +1,485 @@ + + +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Furion.FriendlyException; +using Magic.Core.Entity; +using Mapster; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +using SqlSugar; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +/// +/// 系统菜单服务 +/// +[ApiDescriptionSettings(Name = "Menu", Order = 146)] +public class SysMenuService : ISysMenuService, IDynamicApiController, ITransient +{ + private readonly SqlSugarRepository _sysMenuRep; // 菜单表仓储 + + private readonly ISysCacheService _sysCacheService; + private readonly ISysUserRoleService _sysUserRoleService; + private readonly ISysRoleMenuService _sysRoleMenuService; + + public SysMenuService(SqlSugarRepository sysMenuRep, + ISysCacheService sysCacheService, + ISysUserRoleService sysUserRoleService, + ISysRoleMenuService sysRoleMenuService) + { + _sysMenuRep = sysMenuRep; + _sysCacheService = sysCacheService; + _sysUserRoleService = sysUserRoleService; + _sysRoleMenuService = sysRoleMenuService; + } + + /// + /// 获取用户权限(按钮权限标识集合) + /// + /// + /// + [NonAction] + public async Task> GetLoginPermissionList(long userId) + { + var permissions = await _sysCacheService.GetPermission(userId); // 先从缓存里面读取 + if (permissions == null || permissions.Count < 1) + { + if (!UserManager.IsSuperAdmin) + { + var roleIdList = await _sysUserRoleService.GetUserRoleIdList(userId); + var menuIdList = await _sysRoleMenuService.GetRoleMenuIdList(roleIdList); + permissions = await _sysMenuRep.Where(u => menuIdList.Contains(u.Id)) + .Where(u => u.Type == (int)MenuType.BTN) + .Where(u => u.Status == (int)CommonStatus.ENABLE) + .Select(u => u.Permission).ToListAsync(); + } + else + { + permissions = await _sysMenuRep.Where(u => u.Type == (int)MenuType.BTN) + .Where(u => u.Status == (int)CommonStatus.ENABLE) + .Select(u => u.Permission).ToListAsync(); + } + await _sysCacheService.SetPermission(userId, permissions); // 缓存结果 + } + return permissions; + } + + /// + /// 获取所有权限集合 + /// + /// + [NonAction] + public async Task> GetAllPermission() + { + var permissions = await _sysCacheService.GetAllPermission(); // 先从缓存里面读取 + if (permissions == null || permissions.Count < 1) + { + permissions = await _sysMenuRep.Where(u => u.Type == (int)MenuType.BTN) + .Where(u => u.Status == (int)CommonStatus.ENABLE) + .Select(u => u.Permission).ToListAsync(); + await _sysCacheService.SetAllPermission(permissions); // 缓存结果 + } + + return permissions; + } + + + /// + /// 获取用户AntDesign菜单集合 + /// + /// + /// + /// + [NonAction] + public async Task> GetLoginMenusAntDesign(long userId, string appCode) + { + var antDesignTreeNodes = await _sysCacheService.GetMenu(userId, appCode); // 先从缓存里面读取 + if (antDesignTreeNodes == null || antDesignTreeNodes.Count < 1) + { + var sysMenuList = new List(); + // 管理员则展示所有系统菜单 + if (UserManager.IsSuperAdmin) + { + sysMenuList = await _sysMenuRep + .Where(u => u.Status == (int)CommonStatus.ENABLE) + .WhereIF(!string.IsNullOrWhiteSpace(appCode), u => u.Application == appCode) + .Where(u => u.Type != (int)MenuType.BTN) + //.Where(u => u.Weight != (int)MenuWeight.DEFAULT_WEIGHT) + .OrderBy(u => u.Sort).ToListAsync(); + } + else + { + // 非管理员则获取自己角色所拥有的菜单集合 + var roleIdList = await _sysUserRoleService.GetUserRoleIdList(userId); + var menuIdList = await _sysRoleMenuService.GetRoleMenuIdList(roleIdList); + sysMenuList = await _sysMenuRep + .Where(u => menuIdList.Contains(u.Id)) + .Where(u => u.Status == (int)CommonStatus.ENABLE) + .WhereIF(!string.IsNullOrWhiteSpace(appCode), u => u.Application == appCode) + .Where(u => u.Type != (int)MenuType.BTN) + .OrderBy(u => u.Sort).ToListAsync(); + } + // 转换成登录菜单 + antDesignTreeNodes = sysMenuList.Select(u => new AntDesignTreeNode + { + Application=u.Application, + Id = u.Id, + Pid = u.Pid, + Name = u.Code, + Component = u.Component, + Redirect = u.OpenType == (int)MenuOpenType.OUTER ? u.Link : u.Redirect, + Path = u.OpenType == (int)MenuOpenType.OUTER ? u.Link : u.Router, + Meta = new Meta + { + Title = u.Name, + Icon = u.Icon, + Show = u.Visible == YesOrNot.Y.ToString(), + Link = u.Link, + Target = u.OpenType == (int)MenuOpenType.OUTER ? "_blank" : "" + } + }).ToList(); + await _sysCacheService.SetMenu(userId, appCode, antDesignTreeNodes); // 缓存结果 + } + return antDesignTreeNodes; + } + + /// + /// 获取用户菜单所属的应用编码集合 + /// + /// + /// + [NonAction] + public async Task> GetUserMenuAppCodeList(long userId) + { + var roleIdList = await _sysUserRoleService.GetUserRoleIdList(userId); + var menuIdList = await _sysRoleMenuService.GetRoleMenuIdList(roleIdList); + return await _sysMenuRep.Where(u => menuIdList.Contains(u.Id)) + .Where(u => u.Status == (int)CommonStatus.ENABLE) + .Select(u => u.Application).ToListAsync(); + } + + /// + /// 系统菜单列表(树表) + /// + /// + /// + [HttpGet("/sysMenu/list")] + public async Task GetMenuList([FromQuery] MenuInput input) + { + var menus = await _sysMenuRep.AsQueryable() + .WhereIF(!string.IsNullOrWhiteSpace(input.Application), u => u.Application == input.Application.Trim()) + .WhereIF(!string.IsNullOrWhiteSpace(input.Name), u => u.Name.Contains(input.Name.Trim())) + .Where(u => u.Status == (int)CommonStatus.ENABLE).OrderBy(u => u.Sort) + .Select() + .ToListAsync(); + return new TreeBuildUtil().DoTreeBuild(menus); + } + + /// + /// 创建Pids格式 + /// 如果pid是0顶级节点,pids就是 [0]; + /// 如果pid不是顶级节点,pids就是 pid菜单的 pids + [pid] + , + /// + /// + /// + private async Task CreateNewPids(long pid) + { + if (pid == 0L) + { + return "[0],"; + } + else + { + var pmenu = await _sysMenuRep.FirstOrDefaultAsync(u => u.Id == pid); + return pmenu.Pids + "[" + pid + "],"; + } + } + + /// + /// 增加和编辑时检查参数 + /// + /// + private static void CheckMenuParam(MenuInput input) + { + var type = input.Type; + var router = input.Router; + var permission = input.Permission; + var openType = input.OpenType; + + if (type.Equals((int)MenuType.DIR)) + { + if (string.IsNullOrEmpty(router)) + throw Oops.Oh(ErrorCode.D4001); + } + else if (type.Equals((int)MenuType.MENU)) + { + if (string.IsNullOrEmpty(router)) + throw Oops.Oh(ErrorCode.D4001); + if (string.IsNullOrEmpty(openType)) + throw Oops.Oh(ErrorCode.D4002); + } + else if (type.Equals((int)MenuType.BTN)) + { + if (string.IsNullOrEmpty(permission)) + throw Oops.Oh(ErrorCode.D4003); + if (!permission.Contains(":")) + throw Oops.Oh(ErrorCode.D4004); + // 判断该资源是否存在 + //permission = ":" + permission; + //var urlSet = resourceCache.getAllResources(); + //if (!urlSet.Contains(permission.Replace(":","/"))) + // throw Oops.Oh(ErrorCode.meu1005); + } + } + + /// + /// 增加系统菜单 + /// + /// + /// + [HttpPost("/sysMenu/add")] + public async Task AddMenu(AddMenuInput input) + { + var isExist = await _sysMenuRep.AnyAsync(u => u.Code == input.Code); // u.Name == input.Name + if (isExist) + throw Oops.Oh(ErrorCode.D4000); + + // 校验参数 + CheckMenuParam(input); + + var menu = input.Adapt(); + menu.Pids = await CreateNewPids(input.Pid); + menu.Status = (int)CommonStatus.ENABLE; + await _sysMenuRep.InsertAsync(menu); + + // 清除缓存 + + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_MENU); + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_ALLPERMISSION); + } + + /// + /// 删除系统菜单 + /// + /// + /// + [HttpPost("/sysMenu/delete")] + public async Task DeleteMenu(DeleteMenuInput input) + { + var childIdList = await _sysMenuRep.Where(u => u.Pids.Contains(input.Id.ToString())) + .Select(u => u.Id).ToListAsync(); + childIdList.Add(input.Id); + try + { + _sysMenuRep.CurrentBeginTran(); + await _sysMenuRep.DeleteAsync(u => childIdList.Contains(u.Id)); + // 级联删除该菜单及子菜单对应的角色-菜单表信息 + await _sysRoleMenuService.DeleteRoleMenuListByMenuIdList(childIdList); + + // 清除缓存 + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_MENU); + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_ALLPERMISSION); + _sysMenuRep.CurrentCommitTran(); + } + catch (System.Exception) + { + _sysMenuRep.CurrentRollbackTran(); + throw; + } + + } + + /// + /// 更新系统菜单 + /// + /// + /// + [HttpPost("/sysMenu/edit"),] + public async Task UpdateMenu(UpdateMenuInput input) + { + // Pid和Id不能一致,一致会导致无限递归 + if (input.Id == input.Pid) + throw Oops.Oh(ErrorCode.D4006); + + var isExist = await _sysMenuRep.AnyAsync(u => u.Code == input.Code && u.Id != input.Id); // u.Name == input.Name + if (isExist) + throw Oops.Oh(ErrorCode.D4000); + + // 校验参数 + CheckMenuParam(input); + + var menuList = new List(); + + // 如果是编辑,父id不能为自己的子节点 + var childIdList = await _sysMenuRep.Where(u => u.Pids.Contains(input.Id.ToString())) + .Select(u => u.Id).ToListAsync(); + if (childIdList.Contains(input.Pid)) + throw Oops.Oh(ErrorCode.D4006); + + var oldMenu = await _sysMenuRep.FirstOrDefaultAsync(u => u.Id == input.Id); + + // 生成新的pids + var newPids = await CreateNewPids(input.Pid); + + // 是否更新子应用的标识 + var updateSubAppsFlag = false; + // 是否更新子节点的pids的标识 + var updateSubPidsFlag = false; + + // 如果应用有变化 + if (input.Application != oldMenu.Application) + { + // 父节点不是根节点不能移动应用 + if (oldMenu.Pid != 0L) + throw Oops.Oh(ErrorCode.D4007); + updateSubAppsFlag = true; + } + // 父节点有变化 + if (input.Pid != oldMenu.Pid) + updateSubPidsFlag = true; + + // 开始更新所有子节点的配置 + if (updateSubAppsFlag || updateSubPidsFlag) + { + // 查找所有叶子节点,包含子节点的子节点 + menuList = await _sysMenuRep.Where(u => u.Pids.Contains(oldMenu.Id.ToString())).ToListAsync(); + // 更新所有子节点的应用为当前菜单的应用 + if (menuList.Count > 0) + { + // 更新所有子节点的application + if (updateSubAppsFlag) + { + menuList.ForEach(u => + { + u.Application = input.Application; + }); + } + + // 更新所有子节点的pids + if (updateSubPidsFlag) + { + menuList.ForEach(u => + { + // 子节点pids组成 = 当前菜单新pids + 当前菜单id + 子节点自己的pids后缀 + var oldParentCodesPrefix = oldMenu.Pids + "[" + oldMenu.Id + "],"; + var oldParentCodesSuffix = u.Pids.Substring(oldParentCodesPrefix.Length); + var menuParentCodes = newPids + "[" + oldMenu.Id + "]," + oldParentCodesSuffix; + u.Pids = menuParentCodes; + }); + } + } + } + + // 更新当前菜单 + oldMenu = input.Adapt(); + oldMenu.Pids = newPids; + + menuList.Add(oldMenu); + + await _sysMenuRep.UpdateAsync(menuList); + + // 清除缓存 + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_MENU); + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_ALLPERMISSION); + } + + /// + /// 获取系统菜单 + /// + /// + /// + [HttpPost("/sysMenu/detail")] + public async Task GetMenu(QueryMenuInput input) + { + return await _sysMenuRep.FirstOrDefaultAsync(u => u.Id == input.Id); + } + + /// + /// 获取系统菜单树,用于新增、编辑时选择上级节点 + /// + /// + /// + [HttpGet("/sysMenu/tree")] + public async Task GetMenuTree([FromQuery] MenuInput input) + { + var menus = await _sysMenuRep.AsQueryable() + .WhereIF(!string.IsNullOrWhiteSpace(input.Application), u => u.Application == input.Application.Trim()) + .Where(u => u.Status == (int)CommonStatus.ENABLE) + .Where(u => u.Type == (int)MenuType.DIR || u.Type == (int)MenuType.MENU) + .OrderBy(u => u.Sort) + .Select(u => new MenuTreeOutput + { + Id = u.Id, + ParentId = u.Pid, + Value = u.Id.ToString(), + Title = u.Name, + Weight = u.Sort + }).ToListAsync(); + return new TreeBuildUtil().DoTreeBuild(menus); + } + + /// + /// 获取系统菜单树,用于给角色授权时选择 + /// + /// + /// + [HttpGet("/sysMenu/treeForGrant")] + public async Task TreeForGrant([FromQuery] MenuInput input) + { + var menuIdList = new List(); + if (!UserManager.IsSuperAdmin) + { + var roleIdList = await _sysUserRoleService.GetUserRoleIdList(UserManager.UserId); + menuIdList = await _sysRoleMenuService.GetRoleMenuIdList(roleIdList); + } + + var menus = await _sysMenuRep.AsQueryable().LeftJoin((t1, t2) => t1.Application == t2.Code) + .Where(t1 => t1.Status == (int)CommonStatus.ENABLE).WhereIF(menuIdList.Any(), t1 => menuIdList.Contains(t1.Id)) + .OrderBy(t1 => t1.Sort).Select((t1, t2) => new MenuTreeOutput + { + Id = t1.Id, + ParentId = t1.Pid, + Value = t1.Id.ToString(), + Title = t1.Name, + Weight = t1.Sort, + AppName = t2.Name, + AppCode = t2.Code, + AppSort = t2.Sort + }).ToListAsync(); + + // 获取所有应用 + var appList = menus.OrderBy(ob => ob.AppSort) + .Select(sl => new MenuTreeAppOutput { AppName = sl.AppName, AppCode = sl.AppCode }).DistinctBy(db => db.AppCode) + .ToList(); + + return new { AppList = appList, MenuTree = new TreeBuildUtil().DoTreeBuild(menus) }; + } + + /// + /// 根据应用编码判断该机构下是否有状态为正常的菜单 + /// + /// + /// + [NonAction] + public async Task HasMenu(string appCode) + { + return await _sysMenuRep.AnyAsync(u => u.Application == appCode && u.Status != CommonStatus.DELETED); + } + + /// + /// 根据系统应用切换菜单 + /// + /// + /// + [AllowAnonymous] + [HttpPost("/sysMenu/change")] + public async Task> ChangeAppMenu(ChangeAppMenuInput input) + { + return await GetLoginMenusAntDesign(UserManager.UserId, input.Application); + } +} diff --git a/Magic.Core/Service/Monitor/IMachineService.cs b/Magic.Core/Service/Monitor/IMachineService.cs new file mode 100644 index 0000000..3db87f3 --- /dev/null +++ b/Magic.Core/Service/Monitor/IMachineService.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface IMachineService +{ + Task GetMachineBaseInfo(); + Task GetMachineNetWorkInfo(); + Task GetMachineUseInfo(); +} diff --git a/Magic.Core/Service/Monitor/MachineService.cs b/Magic.Core/Service/Monitor/MachineService.cs new file mode 100644 index 0000000..9740f28 --- /dev/null +++ b/Magic.Core/Service/Monitor/MachineService.cs @@ -0,0 +1,52 @@ +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +/// +/// 服务器信息服务 +/// +[AllowAnonymous] +[ApiDescriptionSettings(Name = "Machine", Order = 100)] +public class MachineService : IMachineService, IDynamicApiController, ITransient +{ + public MachineService() + { + + } + + /// + /// 获取服务器资源信息 + /// + /// + [HttpGet("/sysMachine/use")] + public async Task GetMachineUseInfo() + { + var useInfo = MachineUtil.GetMachineUseInfo(); + return await Task.FromResult(useInfo); + } + + /// + /// 获取服务器基本参数 + /// + /// + [HttpGet("/sysMachine/base")] + public async Task GetMachineBaseInfo() + { + return await MachineUtil.GetMachineBaseInfo(); + } + + /// + /// 动态获取网络信息 + /// + /// + [HttpGet("/sysMachine/network")] + public async Task GetMachineNetWorkInfo() + { + var baseInfo = MachineUtil.GetMachineNetWorkInfo(); + return await Task.FromResult(baseInfo); + } +} diff --git a/Magic.Core/Service/Notice/Dto/NoticeBase.cs b/Magic.Core/Service/Notice/Dto/NoticeBase.cs new file mode 100644 index 0000000..db3ac8c --- /dev/null +++ b/Magic.Core/Service/Notice/Dto/NoticeBase.cs @@ -0,0 +1,59 @@ +using System; + +namespace Magic.Core.Service; + +/// +/// 通知公告参数 +/// +public class NoticeBase +{ + /// + /// 标题 + /// + public string Title { get; set; } + + /// + /// 内容 + /// + public string Content { get; set; } + + /// + /// 类型(字典 1通知 2公告) + /// + public int Type { get; set; } + + /// + /// 发布人Id + /// + public long PublicUserId { get; set; } + + /// + /// 发布人姓名 + /// + public string PublicUserName { get; set; } + + /// + /// 发布机构Id + /// + public long PublicOrgId { get; set; } + + /// + /// 发布机构名称 + /// + public string PublicOrgName { get; set; } + + /// + /// 发布时间 + /// + public DateTime PublicTime { get; set; } + + /// + /// 撤回时间 + /// + public DateTime CancelTime { get; set; } + + /// + /// 状态(字典 0草稿 1发布 2撤回 3删除) + /// + public int Status { get; set; } +} diff --git a/Magic.Core/Service/Notice/Dto/NoticeDetailOutput.cs b/Magic.Core/Service/Notice/Dto/NoticeDetailOutput.cs new file mode 100644 index 0000000..6383940 --- /dev/null +++ b/Magic.Core/Service/Notice/Dto/NoticeDetailOutput.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; + +namespace Magic.Core.Service; + +/// +/// 系统通知公告详情参数 +/// +public class NoticeDetailOutput : NoticeBase +{ + /// + /// 通知到的用户Id集合 + /// + public List NoticeUserIdList { get; set; } + + /// + /// 通知到的用户阅读信息集合 + /// + public List NoticeUserReadInfoList { get; set; } +} + +public class NoticeUserRead +{ + /// + /// 用户Id + /// + public long UserId { get; set; } + + /// + /// 用户名称 + /// + public string UserName { get; set; } + + /// + /// 状态(字典 0未读 1已读) + /// + public NoticeUserStatus ReadStatus { get; set; } + + /// + /// 阅读时间 + /// + public DateTime ReadTime { get; set; } +} diff --git a/Magic.Core/Service/Notice/Dto/NoticeInput.cs b/Magic.Core/Service/Notice/Dto/NoticeInput.cs new file mode 100644 index 0000000..dd59526 --- /dev/null +++ b/Magic.Core/Service/Notice/Dto/NoticeInput.cs @@ -0,0 +1,100 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace Magic.Core.Service; + +/// +/// 通知公告参数 +/// +public class NoticeInput : PageInputBase +{ + /// + /// 标题 + /// + public virtual string Title { get; set; } + + /// + /// 内容 + /// + public virtual string Content { get; set; } + + /// + /// 类型(字典 1通知 2公告) + /// + public virtual NoticeType Type { get; set; } + + /// + /// 状态(字典 0草稿 1发布 2撤回 3删除) + /// + public virtual NoticeStatus Status { get; set; } + + /// + /// 通知到的人 + /// + public virtual List NoticeUserIdList { get; set; } +} + +public class AddNoticeInput : NoticeInput +{ + /// + /// 标题 + /// + [Required(ErrorMessage = "标题不能为空")] + public override string Title { get; set; } + + /// + /// 内容 + /// + [Required(ErrorMessage = "内容不能为空")] + public override string Content { get; set; } + + /// + /// 类型(字典 1通知 2公告) + /// + [Required(ErrorMessage = "类型不能为空")] + public override NoticeType Type { get; set; } + + /// + /// 状态(字典 0草稿 1发布 2撤回 3删除) + /// + [Required(ErrorMessage = "状态不能为空")] + public override NoticeStatus Status { get; set; } + + /// + /// 通知到的人 + /// + [Required(ErrorMessage = "通知到的人不能为空")] + public override List NoticeUserIdList { get; set; } +} + +public class DeleteNoticeInput +{ + /// + /// Id + /// + [Required(ErrorMessage = "通知公告Id不能为空")] + public long Id { get; set; } +} + +public class UpdateNoticeInput : AddNoticeInput +{ + /// + /// Id + /// + [Required(ErrorMessage = "通知公告Id不能为空")] + public long Id { get; set; } +} + +public class QueryNoticeInput : DeleteNoticeInput +{ + +} + +public class ChangeStatusNoticeInput : DeleteNoticeInput +{ + /// + /// 状态(字典 0草稿 1发布 2撤回 3删除) + /// + [Required(ErrorMessage = "状态不能为空")] + public NoticeStatus Status { get; set; } +} diff --git a/Magic.Core/Service/Notice/Dto/NoticeReceiveOutput.cs b/Magic.Core/Service/Notice/Dto/NoticeReceiveOutput.cs new file mode 100644 index 0000000..3cecf14 --- /dev/null +++ b/Magic.Core/Service/Notice/Dto/NoticeReceiveOutput.cs @@ -0,0 +1,24 @@ +using System; + +namespace Magic.Core.Service; + +/// +/// 通知公告接收参数 +/// +public class NoticeReceiveOutput : NoticeBase +{ + /// + /// Id + /// + public long Id { get; set; } + + /// + /// 阅读状态(字典 0未读 1已读) + /// + public int ReadStatus { get; set; } + + /// + /// 阅读时间 + /// + public DateTime ReadTime { get; set; } +} diff --git a/Magic.Core/Service/Notice/ISysNoticeService.cs b/Magic.Core/Service/Notice/ISysNoticeService.cs new file mode 100644 index 0000000..85d3016 --- /dev/null +++ b/Magic.Core/Service/Notice/ISysNoticeService.cs @@ -0,0 +1,15 @@ +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ISysNoticeService +{ + Task AddNotice(AddNoticeInput input); + Task ChangeStatus(ChangeStatusNoticeInput input); + Task DeleteNotice(DeleteNoticeInput input); + Task GetNotice([FromQuery] QueryNoticeInput input); + Task QueryNoticePageList([FromQuery] NoticeInput input); + Task ReceivedNoticePageList([FromQuery] NoticeInput input); + Task UpdateNotice(UpdateNoticeInput input); +} diff --git a/Magic.Core/Service/Notice/ISysNoticeUserService.cs b/Magic.Core/Service/Notice/ISysNoticeUserService.cs new file mode 100644 index 0000000..d36f8b4 --- /dev/null +++ b/Magic.Core/Service/Notice/ISysNoticeUserService.cs @@ -0,0 +1,16 @@ +using Magic.Core.Entity; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ISysNoticeUserService +{ + Task Add(long noticeId, List noticeUserIdList, NoticeUserStatus noticeUserStatus); + + Task> GetNoticeUserListByNoticeId(long noticeId); + + Task Read(long noticeId, long userId, NoticeUserStatus status); + + Task Update(long noticeId, List noticeUserIdList, NoticeUserStatus noticeUserStatus); +} diff --git a/Magic.Core/Service/Notice/SysNoticeService.cs b/Magic.Core/Service/Notice/SysNoticeService.cs new file mode 100644 index 0000000..bc2013a --- /dev/null +++ b/Magic.Core/Service/Notice/SysNoticeService.cs @@ -0,0 +1,263 @@ +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Furion.FriendlyException; +using Magic.Core.Entity; +using Mapster; +using Microsoft.AspNetCore.Mvc; + +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +/// +/// 通知公告服务 +/// +[ApiDescriptionSettings(Name = "Notice", Order = 100)] +public class SysNoticeService : ISysNoticeService, IDynamicApiController, ITransient +{ + private readonly SqlSugarRepository _sysNoticeRep; // 通知公告表仓储 + private readonly ISysOnlineUserService _sysOnlineUserService; + + private readonly ISysNoticeUserService _sysNoticeUserService; + private readonly SqlSugarRepository _sysEmpRep; + + public SysNoticeService(SqlSugarRepository sysNoticeRep, + ISysNoticeUserService sysNoticeUserService, ISysOnlineUserService sysOnlineUserService, SqlSugarRepository sysEmpRep) + { + _sysNoticeRep = sysNoticeRep; + _sysNoticeUserService = sysNoticeUserService; + _sysOnlineUserService = sysOnlineUserService; + _sysEmpRep=sysEmpRep; + } + + /// + /// 分页查询通知公告 + /// + /// + /// + [HttpGet("/sysNotice/page")] + public async Task QueryNoticePageList([FromQuery] NoticeInput input) + { + var notices = await _sysNoticeRep.AsQueryable() + .WhereIF(!string.IsNullOrWhiteSpace(input.SearchValue), u => u.Title.Contains(input.SearchValue.Trim()) || u.Content.Contains(input.SearchValue.Trim())) + .WhereIF(input.Type > 0, u => u.Type == input.Type) + .Where(u => u.Status != NoticeStatus.DELETED) + .ToPagedListAsync(input.PageNo, input.PageSize); + return notices.XnPagedResult(); + } + + /// + /// 增加通知公告 + /// + /// + /// + [HttpPost("/sysNotice/add")] + public async Task AddNotice(AddNoticeInput input) + { + if (input.Status != NoticeStatus.DRAFT && input.Status != NoticeStatus.PUBLIC) + throw Oops.Oh(ErrorCode.D7000); + + var notice = input.Adapt(); + await UpdatePublicInfo(notice); + // 如果是发布,则设置发布时间 + if (input.Status == NoticeStatus.PUBLIC) + notice.PublicTime = DateTime.Now; + var newItem =await _sysNoticeRep.InsertReturnEntityAsync(notice); + + // 通知到的人 + var noticeUserIdList = input.NoticeUserIdList; + var noticeUserStatus = NoticeUserStatus.UNREAD; + await _sysNoticeUserService.Add(newItem.Id, noticeUserIdList, noticeUserStatus); + if (newItem.Status == NoticeStatus.PUBLIC) { + await _sysOnlineUserService.PushNotice(newItem, noticeUserIdList); + } + + } + + /// + /// 删除通知公告 + /// + /// + /// + [HttpPost("/sysNotice/delete")] + public async Task DeleteNotice(DeleteNoticeInput input) + { + var notice = await _sysNoticeRep.FirstOrDefaultAsync(u => u.Id == input.Id); + if (notice.Status != NoticeStatus.DRAFT && notice.Status != NoticeStatus.CANCEL) // 只能删除草稿和撤回的 + throw Oops.Oh(ErrorCode.D7001); + + await _sysNoticeRep.DeleteAsync(notice); + } + + /// + /// 更新通知公告 + /// + /// + /// + [HttpPost("/sysNotice/edit")] + public async Task UpdateNotice(UpdateNoticeInput input) + { + if (input.Status != NoticeStatus.DRAFT && input.Status != NoticeStatus.PUBLIC) + throw Oops.Oh(ErrorCode.D7000); + + // 非草稿状态 + if (input.Status != NoticeStatus.DRAFT) + throw Oops.Oh(ErrorCode.D7002); + + var notice = input.Adapt(); + if (input.Status == NoticeStatus.PUBLIC) + { + notice.PublicTime = DateTime.Now; + await UpdatePublicInfo(notice); + } + await _sysNoticeRep.UpdateAsync(notice); + + // 通知到的人 + var noticeUserIdList = input.NoticeUserIdList; + var noticeUserStatus = NoticeUserStatus.UNREAD; + await _sysNoticeUserService.Update(input.Id, noticeUserIdList, noticeUserStatus); + if (notice.Status == NoticeStatus.PUBLIC) + { + await _sysOnlineUserService.PushNotice(notice, noticeUserIdList); + } + } + + /// + /// 获取通知公告详情 + /// + /// + /// + [HttpGet("/sysNotice/detail")] + public async Task GetNotice([FromQuery] QueryNoticeInput input) + { + var notice = await _sysNoticeRep.FirstOrDefaultAsync(u => u.Id == input.Id); + + // 获取通知到的用户 + var noticeUserList = await _sysNoticeUserService.GetNoticeUserListByNoticeId(input.Id); + var noticeUserIdList = new List(); + var noticeUserReadInfoList = new List(); + if (noticeUserList != null) + { + noticeUserList.ForEach(u => + { + noticeUserIdList.Add(u.UserId.ToString()); + var noticeUserRead = new NoticeUserRead + { + UserId = u.UserId, + UserName = UserManager.Name, + ReadStatus = u.ReadStatus, + ReadTime = u.ReadTime + }; + noticeUserReadInfoList.Add(noticeUserRead); + }); + } + var noticeResult = notice.Adapt(); + noticeResult.NoticeUserIdList = noticeUserIdList; + noticeResult.NoticeUserReadInfoList = noticeUserReadInfoList; + // 如果该条通知公告为已发布,则将当前用户的该条通知公告设置为已读 + if (notice.Status == NoticeStatus.PUBLIC) + await _sysNoticeUserService.Read(notice.Id, UserManager.UserId, NoticeUserStatus.READ); + return noticeResult; + } + + /// + /// 修改通知公告状态 + /// + /// + /// + [HttpPost("/sysNotice/changeStatus")] + public async Task ChangeStatus(ChangeStatusNoticeInput input) + { + // 状态应为撤回或删除或发布 + if (input.Status != NoticeStatus.CANCEL && input.Status != NoticeStatus.DELETED && input.Status != NoticeStatus.PUBLIC) + throw Oops.Oh(ErrorCode.D7000); + + var notice = await _sysNoticeRep.FirstOrDefaultAsync(u => u.Id == input.Id); + notice.Status = input.Status; + + if (input.Status == NoticeStatus.CANCEL) + { + notice.CancelTime = DateTime.Now; + } + else if (input.Status == NoticeStatus.PUBLIC) + { + notice.PublicTime = DateTime.Now; + } + await _sysNoticeRep.UpdateAsync(notice); + if (notice.Status == NoticeStatus.PUBLIC) + { + // 获取通知到的用户 + var noticeUserList = await _sysNoticeUserService.GetNoticeUserListByNoticeId(input.Id); + await _sysOnlineUserService.PushNotice(notice, noticeUserList.Select(m => m.UserId).ToList()); + } + } + + /// + /// 获取接收的通知公告 + /// + /// + /// + [HttpGet("/sysNotice/received")] + public async Task ReceivedNoticePageList([FromQuery] NoticeInput input) + { + var notices = await _sysNoticeRep.AsQueryable().InnerJoin((n, u) => n.Id == u.NoticeId) + .Where((n, u) => u.UserId == UserManager.UserId) + .WhereIF(!string.IsNullOrWhiteSpace(input.SearchValue), n => n.Title.Contains(input.SearchValue.Trim()) || n.Content.Contains(input.SearchValue.Trim())) + .WhereIF(input.Type > 0, (n, u) => n.Type == input.Type) + .Select() + .ToPagedListAsync(input.PageNo, input.PageSize); + return notices.XnPagedResult(); + } + + /// + /// 未处理消息 + /// + /// + /// + [HttpGet("/sysNotice/unread")] + public async Task UnReadNoticeList([FromQuery] NoticeInput input) { + var dic = typeof(NoticeType).EnumToList(); + var notices = await _sysNoticeRep.AsQueryable().InnerJoin((n, u) => n.Id == u.NoticeId) + .Where((n, u) => u.UserId == UserManager.UserId && u.ReadStatus== NoticeUserStatus.UNREAD).PartitionBy(n => n.Type).OrderBy(n=>n.CreatedTime,OrderByType.Desc).Take(input.PageSize).Select() + .ToListAsync(); + var count = await _sysNoticeRep.AsQueryable().InnerJoin((n, u) => n.Id == u.NoticeId).Where((n, u) => u.UserId == UserManager.UserId && u.ReadStatus == NoticeUserStatus.UNREAD).CountAsync(); + + List noticeClays = new List(); + int index = 0; + foreach (var item in dic) + { + noticeClays.Add( + new + { + Index= index++, + Key = item.Describe, + Value = item.Value, + NoticeData = notices.Where(m => m.Type == item.Value).ToList() + } + ); + } + return new + { + Rows = noticeClays, + TotalRows = count + }; + } + + /// + /// 更新发布信息 + /// + /// + [NonAction] + private async Task UpdatePublicInfo(SysNotice notice) + { + var emp = await _sysEmpRep.FirstOrDefaultAsync(u => u.Id == UserManager.UserId); + notice.PublicUserId = UserManager.UserId; + notice.PublicUserName = UserManager.Name; + notice.PublicOrgId = emp.OrgId; + notice.PublicOrgName = emp.OrgName; + } +} diff --git a/Magic.Core/Service/Notice/SysNoticeUserService.cs b/Magic.Core/Service/Notice/SysNoticeUserService.cs new file mode 100644 index 0000000..8a4701e --- /dev/null +++ b/Magic.Core/Service/Notice/SysNoticeUserService.cs @@ -0,0 +1,84 @@ + + +using Furion.DependencyInjection; +using Magic.Core.Entity; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +/// +/// 通知公告用户 +/// +public class SysNoticeUserService : ISysNoticeUserService, ITransient +{ + private readonly SqlSugarRepository _sysNoticeUserRep; // 通知公告用户表仓储 + + public SysNoticeUserService(SqlSugarRepository sysNoticeUserRep) + { + _sysNoticeUserRep = sysNoticeUserRep; + } + + /// + /// 增加 + /// + /// + /// + /// + /// + public async Task Add(long noticeId, List noticeUserIdList, NoticeUserStatus noticeUserStatus) + { + List list = new List(); + noticeUserIdList.ForEach(u => + { + list.Add(new SysNoticeUser + { + NoticeId = noticeId, + UserId = u, + ReadStatus = noticeUserStatus + }); + }); + await _sysNoticeUserRep.InsertAsync(list); + } + + /// + /// 更新 + /// + /// + /// + /// + /// + public async Task Update(long noticeId, List noticeUserIdList, NoticeUserStatus noticeUserStatus) + { + await _sysNoticeUserRep.DeleteAsync(u => u.NoticeId == noticeId); + + await Add(noticeId, noticeUserIdList, noticeUserStatus); + } + + /// + /// 获取通知公告用户列表 + /// + /// + /// + public async Task> GetNoticeUserListByNoticeId(long noticeId) + { + return await _sysNoticeUserRep.Where(u => u.NoticeId == noticeId).ToListAsync(); + } + + /// + /// 设置通知公告读取状态 + /// + /// + /// + /// + /// + public async Task Read(long noticeId, long userId, NoticeUserStatus status) + { + await _sysNoticeUserRep.UpdateAsync(m => m.NoticeId == noticeId && m.UserId == userId, m => new SysNoticeUser + { + ReadStatus = status, + ReadTime = DateTime.Now + }); + } +} diff --git a/Magic.Core/Service/OAuth/ISysOauthService.cs b/Magic.Core/Service/OAuth/ISysOauthService.cs new file mode 100644 index 0000000..cdc5e48 --- /dev/null +++ b/Magic.Core/Service/OAuth/ISysOauthService.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ISysOauthService +{ + Task GetWechatUserInfo([FromQuery] string token, [FromQuery] string openId); + Task WechatLogin(); + Task WechatLoginCallback([FromQuery] string code, [FromQuery] string state, [FromQuery] string error_description = ""); +} diff --git a/Magic.Core/Service/OAuth/SysOauthService.cs b/Magic.Core/Service/OAuth/SysOauthService.cs new file mode 100644 index 0000000..09b1dc6 --- /dev/null +++ b/Magic.Core/Service/OAuth/SysOauthService.cs @@ -0,0 +1,66 @@ +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Furion.FriendlyException; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +/// +/// OAuth服务 +/// +[ApiDescriptionSettings(Name = "OAuth", Order = 159)] +[AllowAnonymous] +public class SysOauthService : ISysOauthService, IDynamicApiController, ITransient +{ + private readonly HttpContext _httpContext; + private readonly WechatOAuth _wechatOAuth; + + public SysOauthService(IHttpContextAccessor httpContextAccessor, WechatOAuth wechatOAuth) + { + _httpContext = httpContextAccessor.HttpContext; + _wechatOAuth = wechatOAuth; + } + + /// + /// 微信登录授权 + /// + [HttpGet("oauth/wechat")] + public Task WechatLogin() + { + _httpContext.Response.Redirect(_wechatOAuth.GetAuthorizeUrl("Magic")); + return Task.CompletedTask; + } + + /// + /// 微信登录授权回调 + /// + /// + /// + /// + /// + [HttpGet("oauth/wechatcallback")] + public async Task WechatLoginCallback([FromQuery] string code, [FromQuery] string state, [FromQuery] string error_description = "") + { + if (!string.IsNullOrEmpty(error_description)) + throw Oops.Oh(error_description); + + var accessTokenModel = await _wechatOAuth.GetAccessTokenAsync(code, state); + //var userInfoModel = await _wechatOAuth.GetUserInfoAsync(accessTokenModel.AccessToken, accessTokenModel.OpenId); + await _httpContext.Response.WriteAsJsonAsync(accessTokenModel); + } + + /// + /// 获取微信用户基本信息 + /// + /// + /// + /// + [HttpGet("oauth/wechat/user")] + public async Task GetWechatUserInfo([FromQuery] string token, [FromQuery] string openId) + { + return await _wechatOAuth.GetUserInfoAsync(token, openId); + } +} diff --git a/Magic.Core/Service/OnlineUser/ISysOnlineUserService.cs b/Magic.Core/Service/OnlineUser/ISysOnlineUserService.cs new file mode 100644 index 0000000..549ef1a --- /dev/null +++ b/Magic.Core/Service/OnlineUser/ISysOnlineUserService.cs @@ -0,0 +1,14 @@ +using Magic.Core.Entity; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ISysOnlineUserService +{ + Task List(PageInputBase input); + + Task ForceExist(OnlineUser user); + + Task PushNotice(SysNotice notice, List userIds); +} diff --git a/Magic.Core/Service/OnlineUser/SysOnlineUserService.cs b/Magic.Core/Service/OnlineUser/SysOnlineUserService.cs new file mode 100644 index 0000000..8431459 --- /dev/null +++ b/Magic.Core/Service/OnlineUser/SysOnlineUserService.cs @@ -0,0 +1,65 @@ + +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Magic.Core.Entity; +using Magic.Core.Service; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.SignalR; + +using SqlSugar; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +/// +/// 在线用户服务 +/// +[ApiDescriptionSettings(Name = "OnlineUser", Order = 100)] +public class SysOnlineUserService : ISysOnlineUserService, IDynamicApiController, ITransient +{ + private readonly ISysCacheService _sysCacheService; + private readonly SqlSugarRepository _sysOnlineUerRep; // 在线用户表仓储 + private readonly IHubContext _chatHubContext; + + public SysOnlineUserService(ISysCacheService sysCacheService + ,SqlSugarRepository sysOnlineUerRep + , IHubContext chatHubContext) + { + _sysCacheService = sysCacheService; + _sysOnlineUerRep = sysOnlineUerRep; + _chatHubContext = chatHubContext; + } + + /// + /// 获取在线用户信息 + /// + /// + [HttpGet("/sysOnlineUser/list")] + public async Task List([FromQuery] PageInputBase input) + { + var list = await _sysOnlineUerRep.AsQueryable().ToPagedListAsync(input.PageNo, input.PageSize); + return list.XnPagedResult(); + } + + [HttpPost("/sysOnlineUser/forceExist")] + [NonValidation] + public async Task ForceExist(OnlineUser user) { + await _chatHubContext.Clients.Client(user.ConnectionId).ForceExist("7777777"); + await _sysOnlineUerRep.DeleteAsync(user); + } + + [NonAction] + public async Task PushNotice(SysNotice notice,List userIds) + { + var userList = _sysOnlineUerRep.Where(m => userIds.Contains(m.UserId)).ToList(); + if (userList.Any()) { + foreach (var item in userList) + { + await _chatHubContext.Clients.Client(item.ConnectionId).AppendNotice(notice); + } + } + + } +} diff --git a/Magic.Core/Service/Org/Dto/OrgInput.cs b/Magic.Core/Service/Org/Dto/OrgInput.cs new file mode 100644 index 0000000..9793a4b --- /dev/null +++ b/Magic.Core/Service/Org/Dto/OrgInput.cs @@ -0,0 +1,92 @@ +using System.ComponentModel.DataAnnotations; + +namespace Magic.Core.Service; + +/// +/// 组织机构参数 +/// +public class OrgInput : InputBase +{ + /// + /// 父Id + /// + public string Pid { get; set; } + + /// + /// 父Ids + /// + public string Pids { get; set; } + + /// + /// 名称 + /// + public virtual string Name { get; set; } + + /// + /// 编码 + /// + public virtual string Code { get; set; } + + /// + /// 电话 + /// + public virtual string Tel { get; set; } + + /// + /// 排序 + /// + public int Sort { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } + + /// + /// 状态(字典 0正常 1停用 2删除) + /// + public int Status { get; set; } +} + +public class AddOrgInput : OrgInput +{ + /// + /// 名称 + /// + [Required(ErrorMessage = "机构名称不能为空")] + public override string Name { get; set; } + + /// + /// 编码 + /// + [Required(ErrorMessage = "机构编码不能为空")] + public override string Code { get; set; } +} + +public class DeleteOrgInput +{ + /// + /// 机构Id + /// + [Required(ErrorMessage = "机构Id不能为空")] + public string Id { get; set; } +} + +public class UpdateOrgInput : AddOrgInput +{ + /// + /// 机构Id + /// + [Required(ErrorMessage = "机构Id不能为空")] + public string Id { get; set; } +} + +public class QueryOrgInput : DeleteOrgInput +{ + +} + +public class PageOrgInput : OrgInput +{ + public string Id { get; set; } +} diff --git a/Magic.Core/Service/Org/Dto/OrgOutput.cs b/Magic.Core/Service/Org/Dto/OrgOutput.cs new file mode 100644 index 0000000..279576d --- /dev/null +++ b/Magic.Core/Service/Org/Dto/OrgOutput.cs @@ -0,0 +1,12 @@ +namespace Magic.Core.Service; + +/// +/// 组织机构参数 +/// +public class OrgOutput : OrgInput +{ + /// + /// 机构Id + /// + public string Id { get; set; } +} diff --git a/Magic.Core/Service/Org/Dto/OrgTreeNode.cs b/Magic.Core/Service/Org/Dto/OrgTreeNode.cs new file mode 100644 index 0000000..2b7c28c --- /dev/null +++ b/Magic.Core/Service/Org/Dto/OrgTreeNode.cs @@ -0,0 +1,60 @@ +using System.Collections; +using System.Collections.Generic; + +namespace Magic.Core.Service; + +/// +/// 组织机构树 +/// +public class OrgTreeNode : ITreeNode +{ + /// + /// Id + /// + public long Id { get; set; } + + /// + /// 父Id + /// + public long ParentId { get; set; } + + /// + /// 名称 + /// + public string Title { get; set; } + + /// + /// 值 + /// + public string Value { get; set; } + + /// + /// 排序,越小优先级越高 + /// + public int Weight { get; set; } + + /// + /// 子节点 + /// + public List Children { get; set; } = new List(); + + /// + /// 上一级Id + /// + public long Pid { get; set; } + + public long GetId() + { + return Id; + } + + public long GetPid() + { + return ParentId; + } + + public void SetChildren(IList children) + { + Children = (List)children; + } +} diff --git a/Magic.Core/Service/Org/ISysOrgService.cs b/Magic.Core/Service/Org/ISysOrgService.cs new file mode 100644 index 0000000..d9a4a1c --- /dev/null +++ b/Magic.Core/Service/Org/ISysOrgService.cs @@ -0,0 +1,19 @@ +using Magic.Core.Entity; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ISysOrgService +{ + Task AddOrg(AddOrgInput input); + Task DeleteOrg(DeleteOrgInput input); + Task> GetDataScopeListByDataScopeType(int dataScopeType, long orgId); + Task GetOrg([FromQuery] QueryOrgInput input); + Task> GetOrgList([FromQuery] OrgInput input); + Task GetOrgTree([FromQuery] OrgInput input); + Task QueryOrgPageList([FromQuery] PageOrgInput input); + Task UpdateOrg(UpdateOrgInput input); + Task> GetAllDataScopeIdList(); +} diff --git a/Magic.Core/Service/Org/SysOrgService.cs b/Magic.Core/Service/Org/SysOrgService.cs new file mode 100644 index 0000000..0d38d8a --- /dev/null +++ b/Magic.Core/Service/Org/SysOrgService.cs @@ -0,0 +1,379 @@ +using Furion; +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Furion.FriendlyException; +using Magic.Core.Entity; +using Mapster; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +/// +/// 组织机构服务 +/// +[ApiDescriptionSettings(Name = "Org", Order = 148)] +public class SysOrgService : ISysOrgService, IDynamicApiController, ITransient +{ + private readonly SqlSugarRepository _sysOrgRep; // 组织机构表仓储 + private readonly SqlSugarRepository _sysUserDataScopeRep; + private readonly ISysCacheService _sysCacheService; + private readonly ISysEmpService _sysEmpService; + private readonly ISysEmpExtOrgPosService _sysEmpExtOrgPosService; + + public SysOrgService(SqlSugarRepository sysOrgRep, + SqlSugarRepository sysUserDataScopeRep, + ISysCacheService sysCacheService, + ISysEmpService sysEmpService, + ISysEmpExtOrgPosService sysEmpExtOrgPosService) + { + _sysOrgRep = sysOrgRep; + _sysUserDataScopeRep = sysUserDataScopeRep; + _sysCacheService = sysCacheService; + _sysEmpService = sysEmpService; + _sysEmpExtOrgPosService = sysEmpExtOrgPosService; + } + + /// + /// 分页查询组织机构 + /// + /// + /// + [HttpGet("/sysOrg/page")] + public async Task QueryOrgPageList([FromQuery] PageOrgInput input) + { + var dataScopeList = GetDataScopeList(await DataFilterExtensions.GetDataScopeIdList(FilterType.Org)); + var orgs = await _sysOrgRep.AsQueryable() + .WhereIF(!string.IsNullOrWhiteSpace(input.Name), u => u.Name.Contains(input.Name.Trim())) + .WhereIF(!string.IsNullOrWhiteSpace(input.Id), u => u.Id == long.Parse(input.Id.Trim())) + .WhereIF(!string.IsNullOrWhiteSpace(input.Pid), u => u.Pids.Contains(input.Pid.Trim()) || u.Id == long.Parse(input.Pid.Trim())) + .WhereIF(dataScopeList.Any(), u => dataScopeList.Contains(u.Id)) // 非管理员范围限制 + .Where(u => u.Status != CommonStatus.DELETED) + .OrderBy(u => u.Sort) + .Select() + .ToPagedListAsync(input.PageNo, input.PageSize); + return orgs.XnPagedResult(); + } + + /// + /// (非管理员)获取当前用户数据范围(机构Id) + /// + /// + /// + private List GetDataScopeList(List dataScopes) + { + var dataScopeList = new List(); + // 如果是超级管理员则获取所有组织机构,否则只获取其数据范围的机构数据 + if (!UserManager.IsSuperAdmin && !UserManager.IsTenantAdmin) + { + if (dataScopes.Count < 1) + return dataScopeList; + + // 此处获取所有的上级节点,用于构造完整树 + dataScopes.ForEach(u => + { + var sysOrg = _sysOrgRep.FirstOrDefault(c => c.Id == u); + var parentAndChildIdListWithSelf = sysOrg.Pids.TrimEnd(',').Replace("[", "").Replace("]", "") + .Split(",").Select(u => long.Parse(u)).ToList(); + parentAndChildIdListWithSelf.Add(sysOrg.Id); + dataScopeList.AddRange(parentAndChildIdListWithSelf); + }); + } + + return dataScopeList; + } + + /// + /// 获取组织机构列表 + /// + /// + /// + [HttpGet("/sysOrg/list")] + public async Task> GetOrgList([FromQuery] OrgInput input) + { + var dataScopeList = GetDataScopeList(await DataFilterExtensions.GetDataScopeIdList(FilterType.Org)); + var orgs = await _sysOrgRep.AsQueryable() + .WhereIF(!string.IsNullOrWhiteSpace(input.Pid), u => u.Pid == long.Parse(input.Pid)) + .Where(u => u.Status != CommonStatus.DELETED) + .WhereIF(dataScopeList.Any(), u => dataScopeList.Contains(u.Id)) // 非管理员范围限制 + .OrderBy(u => u.Sort) + .ToListAsync(); + return orgs.Adapt>(); + } + + /// + /// 增加组织机构 + /// + /// + /// + [HttpPost("/sysOrg/add")] + public async Task AddOrg(AddOrgInput input) + { + var isExist = await _sysOrgRep.AnyAsync(u => u.Name == input.Name || u.Code == input.Code); + if (isExist) + throw Oops.Oh(ErrorCode.D2002); + if (!UserManager.IsSuperAdmin) + { + // 如果新增的机构父Id不是0,则进行数据权限校验 + if (input.Pid != "0" && !string.IsNullOrEmpty(input.Pid)) + { + // 新增组织机构的父机构不在自己的数据范围内 + long.Parse(input.Pid).CheckDataScope(FilterType.Org); + } + else + throw Oops.Oh(ErrorCode.D2006); + } + + var sysOrg = input.Adapt(); + await FillPids(sysOrg); + var newOrg = await _sysOrgRep.InsertReturnEntityAsync(sysOrg); + // 当前用户不是超级管理员时,将新增的公司加到用户的数据权限 + if (App.User.FindFirst(ClaimConst.CLAINM_SUPERADMIN)?.Value != ((int)AdminType.SuperAdmin).ToString()) + { + var userId = App.User.FindFirst(ClaimConst.CLAINM_USERID)?.Value; + await _sysUserDataScopeRep.InsertAsync(new SysUserDataScope + { + SysUserId = long.Parse(userId), + SysOrgId = newOrg.Id + }); + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_DATASCOPE); + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_USERSDATASCOPE); + } + } + + /// + /// 填充父Ids字段 + /// + /// + /// + private async Task FillPids(SysOrg sysOrg) + { + if (sysOrg.Pid == 0L) + { + sysOrg.Pids = "[" + 0 + "],"; + } + else + { + var t = await _sysOrgRep.FirstOrDefaultAsync(u => u.Id == sysOrg.Pid); + sysOrg.Pids = t.Pids + "[" + t.Id + "],"; + } + } + + /// + /// 删除组织机构 + /// + /// + /// + [HttpPost("/sysOrg/delete")] + public async Task DeleteOrg(DeleteOrgInput input) + { + var sysOrg = await _sysOrgRep.FirstOrDefaultAsync(u => u.Id == long.Parse(input.Id)); + + // 检测数据范围能不能操作这个机构 + long.Parse(input.Id).CheckDataScope(FilterType.Org); + + // 该机构下有员工,则不能删 + var hasOrgEmp = await _sysEmpService.HasOrgEmp(sysOrg.Id); + if (hasOrgEmp) + throw Oops.Oh(ErrorCode.D2004); + + // 该机构下面子机构若有员工,则不能删 + var orgIds = await _sysOrgRep.Where(u => u.Pids.Contains(input.Id)).Select(u => u.Id).ToListAsync(); + var emps = await _sysEmpService.HasOrgEmp(orgIds); + if (emps.Count > 0) + throw Oops.Oh(ErrorCode.D2004); + + // 该附属机构下若有员工,则不能删 + var hasExtOrgEmp = await _sysEmpExtOrgPosService.HasExtOrgEmp(sysOrg.Id); + if (hasExtOrgEmp) + throw Oops.Oh(ErrorCode.D2005); + + // 级联删除子节点 + var childIdList = await GetChildIdListWithSelfById(sysOrg.Id); + + try + { + _sysOrgRep.CurrentBeginTran(); + + + // 级联删除该机构及子机构对应的角色-数据范围关联信息 + await _sysOrgRep.Change().DeleteAsync(u => childIdList.Contains(u.SysOrgId)); + + // 级联删除该机构子机构对应的用户-数据范围关联信息 + await _sysOrgRep.Change().DeleteAsync(u => childIdList.Contains(u.SysOrgId)); + + await _sysOrgRep.DeleteAsync(u => childIdList.Contains(u.Id)); + _sysOrgRep.CurrentCommitTran(); + + } + catch (System.Exception) + { + _sysOrgRep.CurrentRollbackTran(); + throw; + } + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_DATASCOPE); + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_USERSDATASCOPE); + + } + + /// + /// 更新组织机构 + /// + /// + /// + [HttpPost("/sysOrg/edit")] + public async Task UpdateOrg(UpdateOrgInput input) + { + if (input.Pid != "0" && !string.IsNullOrEmpty(input.Pid)) + { + var org = await _sysOrgRep.FirstOrDefaultAsync(u => u.Id == long.Parse(input.Pid)); + _ = org ?? throw Oops.Oh(ErrorCode.D2000); + } + if (input.Id == input.Pid) + throw Oops.Oh(ErrorCode.D2001); + + // 如果是编辑,父id不能为自己的子节点 + var childIdListById = await GetChildIdListWithSelfById(long.Parse(input.Id)); + if (childIdListById.Contains(long.Parse(input.Pid))) + throw Oops.Oh(ErrorCode.D2001); + + var sysOrg = await _sysOrgRep.FirstOrDefaultAsync(u => u.Id == long.Parse(input.Id)); + + // 检测数据范围能不能操作这个机构 + sysOrg.Id.CheckDataScope(FilterType.Org); + + var isExist = await _sysOrgRep.AnyAsync(u => (u.Name == input.Name || u.Code == input.Code) && u.Id != sysOrg.Id); + if (isExist) + throw Oops.Oh(ErrorCode.D2002); + + try + { + _sysOrgRep.CurrentBeginTran(); + // 如果名称有变化,则修改对应员工的机构相关信息 + if (!sysOrg.Name.Equals(input.Name)) + await _sysEmpService.UpdateEmpOrgInfo(sysOrg.Id, input.Name); + + var isChangePid = sysOrg.Pid.ToString() != input.Pid; + var oldPids=sysOrg.Pids; + + sysOrg = input.Adapt(); + await FillPids(sysOrg); + + //如果父级菜单有变化,则修改该机构所有子级的pids + if (isChangePid) + await _sysOrgRep.UpdateAsync(m=>m.Pids.Contains(sysOrg.Id.ToString()),m=> new SysOrg { Pids = m.Pids.Replace(oldPids, sysOrg.Pids) }); + + await _sysOrgRep.AsUpdateable(sysOrg).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync(); + + _sysOrgRep.CurrentCommitTran(); + + } + catch (System.Exception) + { + _sysOrgRep.CurrentRollbackTran(); + throw; + } + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_DATASCOPE); + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_USERSDATASCOPE); + + } + + /// + /// 获取组织机构信息 + /// + /// + /// + [HttpGet("/sysOrg/detail")] + public async Task GetOrg([FromQuery] QueryOrgInput input) + { + return await _sysOrgRep.FirstOrDefaultAsync(u => u.Id == long.Parse(input.Id)); + } + + /// + /// 根据节点Id获取所有子节点Id集合,包含自己 + /// + /// + /// + private async Task> GetChildIdListWithSelfById(long id) + { + var childIdList = await _sysOrgRep + .Where(u => u.Pids.Contains(id.ToString())) + .Select(u => u.Id) + .ToListAsync(); + childIdList.Add(id); + return childIdList; + } + + /// + /// 获取组织机构树 + /// + /// + [HttpGet("/sysOrg/tree")] + public async Task GetOrgTree([FromQuery] OrgInput input) + { + var dataScopeList = new List(); + if (!UserManager.IsSuperAdmin && !UserManager.IsTenantAdmin) + { + var dataScopes = await DataFilterExtensions.GetDataScopeIdList(FilterType.Org); + if (dataScopes.Count < 1) + return dataScopeList; + dataScopeList = GetDataScopeList(dataScopes); + } + var orgs = await _sysOrgRep.Where(dataScopeList.Any(), u => dataScopeList.Contains(u.Id)) + .Where(u => u.Status == (int)CommonStatus.ENABLE).OrderBy(u => u.Sort) + .Select(u => new OrgTreeNode + { + Id = u.Id, + ParentId = u.Pid, + Title = u.Name, + Value = u.Id.ToString(), + Weight = u.Sort + }).ToListAsync(); + + return new TreeBuildUtil().DoTreeBuild(orgs); + } + + /// + /// 根据数据范围类型获取当前用户的数据范围(机构Id)集合 + /// + /// + /// + /// + [NonAction] + public async Task> GetDataScopeListByDataScopeType(int dataScopeType, long orgId) + { + var orgIdList = new List(); + if (orgId < 0) + return orgIdList; + + // 如果是范围类型是全部数据,则获取当前所有的组织架构Id + if (dataScopeType == (int)DataScopeType.ALL) + { + orgIdList = await _sysOrgRep.Where(u => u.Status == (int)CommonStatus.ENABLE).Select(u => u.Id).ToListAsync(); + } + // 如果范围类型是本部门及以下部门,则查询本节点和子节点集合,包含本节点 + else if (dataScopeType == (int)DataScopeType.DEPT_WITH_CHILD) + { + orgIdList = await GetChildIdListWithSelfById(orgId); + } + // 如果数据范围是本部门,不含子节点,则直接返回本部门 + else if (dataScopeType == (int)DataScopeType.DEPT) + { + orgIdList.Add(orgId); + } + return orgIdList; + } + + /// + /// 获取所有的机构组织Id集合 + /// + /// + [NonAction] + public async Task> GetAllDataScopeIdList() + { + return await _sysOrgRep.AsQueryable().Select(u => u.Id).ToListAsync(); + } + } diff --git a/Magic.Core/Service/Pos/Dto/PosInput.cs b/Magic.Core/Service/Pos/Dto/PosInput.cs new file mode 100644 index 0000000..44501f2 --- /dev/null +++ b/Magic.Core/Service/Pos/Dto/PosInput.cs @@ -0,0 +1,82 @@ +using System.ComponentModel.DataAnnotations; + +namespace Magic.Core.Service; + +/// +/// 职位参数 +/// +public class PosInput +{ + /// + /// 名称 + /// + public virtual string Name { get; set; } + + /// + /// 编码 + /// + public virtual string Code { get; set; } + + /// + /// 排序 + /// + public int Sort { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } + + /// + /// 状态(字典 0正常 1停用 2删除) + /// + public int Status { get; set; } + + /// + /// 当前页码 + /// + public int PageNo { get; set; } = 1; + + /// + /// 页码容量 + /// + public int PageSize { get; set; } = 20; +} + +public class AddPosInput : PosInput +{ + /// + /// 名称 + /// + [Required(ErrorMessage ="职位名称不能为空")] + public override string Name { get; set; } + + /// + /// 编码 + /// + [Required(ErrorMessage = "职位编码不能为空")] + public override string Code { get; set; } +} + +public class DeletePosInput +{ + /// + /// 职位Id + /// + [Required(ErrorMessage = "职位Id不能为空")] + public long Id { get; set; } +} + +public class UpdatePosInput : AddPosInput +{ + /// + /// 职位Id + /// + [Required(ErrorMessage = "职位Id不能为空")] + public long Id { get; set; } +} + +public class QueryPosInput : DeletePosInput +{ + +} diff --git a/Magic.Core/Service/Pos/ISysPosService.cs b/Magic.Core/Service/Pos/ISysPosService.cs new file mode 100644 index 0000000..f73975b --- /dev/null +++ b/Magic.Core/Service/Pos/ISysPosService.cs @@ -0,0 +1,15 @@ +using Magic.Core.Entity; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ISysPosService +{ + Task AddPos(AddPosInput input); + Task DeletePos(DeletePosInput input); + Task GetPos([FromQuery] QueryPosInput input); + Task GetPosList([FromQuery] PosInput input); + Task QueryPosPageList([FromQuery] PosInput input); + Task UpdatePos(UpdatePosInput input); +} diff --git a/Magic.Core/Service/Pos/SysPosService.cs b/Magic.Core/Service/Pos/SysPosService.cs new file mode 100644 index 0000000..615fe99 --- /dev/null +++ b/Magic.Core/Service/Pos/SysPosService.cs @@ -0,0 +1,124 @@ + +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Furion.FriendlyException; +using Magic.Core.Entity; +using Mapster; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +/// +/// 职位服务 +/// +[ApiDescriptionSettings(Name = "Pos", Order = 147)] +public class SysPosService : ISysPosService, IDynamicApiController, ITransient +{ + private readonly SqlSugarRepository _sysPosRep; // 职位表仓储 + + private readonly ISysEmpPosService _sysEmpPosService; + private readonly ISysEmpExtOrgPosService _sysEmpExtOrgPosService; + + public SysPosService(SqlSugarRepository sysPosRep, + ISysEmpPosService sysEmpPosService, + ISysEmpExtOrgPosService sysEmpExtOrgPosService) + { + _sysPosRep = sysPosRep; + _sysEmpPosService = sysEmpPosService; + _sysEmpExtOrgPosService = sysEmpExtOrgPosService; + } + + /// + /// 分页获取职位 + /// + /// + /// + [HttpGet("/sysPos/page")] + public async Task QueryPosPageList([FromQuery] PosInput input) + { + var pos = await _sysPosRep.AsQueryable() + .WhereIF(!string.IsNullOrWhiteSpace(input.Name), u => u.Name.Contains(input.Name.Trim())) + .WhereIF(!string.IsNullOrWhiteSpace(input.Code), u => u.Code.Contains(input.Code.Trim())) + .Where(u => u.Status == CommonStatus.ENABLE).OrderBy(u => u.Sort) + .ToPagedListAsync(input.PageNo, input.PageSize); + return pos.XnPagedResult(); + } + + /// + /// 获取职位列表 + /// + /// + [HttpGet("/sysPos/list")] + public async Task GetPosList([FromQuery] PosInput input) + { + return await _sysPosRep.AsQueryable() + .WhereIF(!string.IsNullOrWhiteSpace(input.Code), u => u.Code.Contains(input.Code.Trim())) + .Where(u => u.Status != CommonStatus.DELETED) + .OrderBy(u => u.Sort).ToListAsync(); + } + + /// + /// 增加职位 + /// + /// + /// + [HttpPost("/sysPos/add")] + public async Task AddPos(AddPosInput input) + { + var isExist = await _sysPosRep.AnyAsync(u => u.Name == input.Name || u.Code == input.Code); + if (isExist) + throw Oops.Oh(ErrorCode.D6000); + + var pos = input.Adapt(); + await _sysPosRep.InsertAsync(pos); + } + + /// + /// 删除职位 + /// + /// + /// + [HttpPost("/sysPos/delete")] + public async Task DeletePos(DeletePosInput input) + { + // 该职位下是否有员工 + var hasPosEmp = await _sysEmpPosService.HasPosEmp(input.Id); + if (hasPosEmp) + throw Oops.Oh(ErrorCode.D6001); + + // 该附属职位下是否有员工 + var hasExtPosEmp = await _sysEmpExtOrgPosService.HasExtPosEmp(input.Id); + if (hasExtPosEmp) + throw Oops.Oh(ErrorCode.D6001); + + await _sysPosRep.DeleteAsync(u => u.Id == input.Id); + } + + /// + /// 更新职位 + /// + /// + /// + [HttpPost("/sysPos/edit")] + public async Task UpdatePos(UpdatePosInput input) + { + var isExist = await _sysPosRep.AnyAsync(u => (u.Name == input.Name || u.Code == input.Code) && u.Id != input.Id); + if (isExist) + throw Oops.Oh(ErrorCode.D6000); + + var pos = input.Adapt(); + await _sysPosRep.AsUpdateable(pos).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync(); + } + + /// + /// 获取职位 + /// + /// + /// + [HttpGet("/sysPos/detail")] + public async Task GetPos([FromQuery] QueryPosInput input) + { + return await _sysPosRep.FirstOrDefaultAsync(u => u.Id == input.Id); + } +} diff --git a/Magic.Core/Service/Role/Dto/RoleInput.cs b/Magic.Core/Service/Role/Dto/RoleInput.cs new file mode 100644 index 0000000..9dcec34 --- /dev/null +++ b/Magic.Core/Service/Role/Dto/RoleInput.cs @@ -0,0 +1,86 @@ +using System.ComponentModel.DataAnnotations; + +namespace Magic.Core.Service; + +/// +/// 角色参数 +/// +public class RoleInput : InputBase +{ + /// + /// 名称 + /// + public virtual string Name { get; set; } + + /// + /// 编码 + /// + public virtual string Code { get; set; } + + /// + /// 排序 + /// + public int Sort { get; set; } + + /// + /// 数据范围类型(字典 1全部数据 2本部门及以下数据 3本部门数据 4仅本人数据 5自定义数据) + /// + public DataScopeType DataScopeType { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } +} + +public class AddRoleInput : RoleInput +{ + /// + /// 名称 + /// + [Required(ErrorMessage = "角色名称不能为空")] + public override string Name { get; set; } + + /// + /// 编码 + /// + [Required(ErrorMessage = "角色编码不能为空")] + public override string Code { get; set; } +} + +public class DeleteRoleInput +{ + /// + /// 角色Id + /// + [Required(ErrorMessage = "角色Id不能为空")] + public long Id { get; set; } +} + +public class UpdateRoleInput : AddRoleInput +{ + /// + /// 角色Id + /// + [Required(ErrorMessage = "角色Id不能为空")] + public long Id { get; set; } +} + +public class QueryRoleInput : DeleteRoleInput +{ + +} + +public class GrantRoleMenuInput : RoleInput +{ + /// + /// 角色Id + /// + [Required(ErrorMessage = "角色Id不能为空")] + public long Id { get; set; } +} + +public class GrantRoleDataInput : GrantRoleMenuInput +{ + +} diff --git a/Magic.Core/Service/Role/Dto/RoleOutput.cs b/Magic.Core/Service/Role/Dto/RoleOutput.cs new file mode 100644 index 0000000..4e613b2 --- /dev/null +++ b/Magic.Core/Service/Role/Dto/RoleOutput.cs @@ -0,0 +1,22 @@ +namespace Magic.Core.Service; + +/// +/// 登录用户角色参数 +/// +public class RoleOutput +{ + /// + /// Id + /// + public long Id { get; set; } + + /// + /// 编码 + /// + public string Code { get; set; } + + /// + /// 名称 + /// + public string Name { get; set; } +} diff --git a/Magic.Core/Service/Role/ISysRoleDataScopeService.cs b/Magic.Core/Service/Role/ISysRoleDataScopeService.cs new file mode 100644 index 0000000..ff0b082 --- /dev/null +++ b/Magic.Core/Service/Role/ISysRoleDataScopeService.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ISysRoleDataScopeService +{ + Task DeleteRoleDataScopeListByOrgIdList(List orgIdList); + Task DeleteRoleDataScopeListByRoleId(long roleId); + Task> GetRoleDataScopeIdList(List roleIdList); + Task GrantDataScope(GrantRoleDataInput input); +} diff --git a/Magic.Core/Service/Role/ISysRoleMenuService.cs b/Magic.Core/Service/Role/ISysRoleMenuService.cs new file mode 100644 index 0000000..9c5a064 --- /dev/null +++ b/Magic.Core/Service/Role/ISysRoleMenuService.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ISysRoleMenuService +{ + Task DeleteRoleMenuListByMenuIdList(List menuIdList); + Task DeleteRoleMenuListByRoleId(long roleId); + Task> GetRoleMenuIdList(List roleIdList); + Task GrantMenu(GrantRoleMenuInput input); + Task ClearRoleMenuListByTenantId(long tenantId, long manageRoleId); +} diff --git a/Magic.Core/Service/Role/ISysRoleService.cs b/Magic.Core/Service/Role/ISysRoleService.cs new file mode 100644 index 0000000..380c81e --- /dev/null +++ b/Magic.Core/Service/Role/ISysRoleService.cs @@ -0,0 +1,24 @@ +using Magic.Core.Entity; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ISysRoleService +{ + Task AddRole(AddRoleInput input); + Task DeleteRole(DeleteRoleInput input); + Task GetNameByRoleId(long roleId); + Task GetRoleDropDown(); + Task GetRoleInfo([FromQuery] QueryRoleInput input); + Task GetRoleList([FromQuery] RoleInput input); + Task> GetUserDataScopeIdList(List roleIdList, long orgId); + Task> GetUserRoleList(long userId); + Task GrantData(GrantRoleDataInput input); + Task GrantMenu(GrantRoleMenuInput input); + Task> OwnData([FromQuery] QueryRoleInput input); + Task> OwnMenu([FromQuery] QueryRoleInput input); + Task QueryRolePageList([FromQuery] RoleInput input); + Task UpdateRole(UpdateRoleInput input); +} diff --git a/Magic.Core/Service/Role/SysRoleDataScopeService.cs b/Magic.Core/Service/Role/SysRoleDataScopeService.cs new file mode 100644 index 0000000..d3d8c25 --- /dev/null +++ b/Magic.Core/Service/Role/SysRoleDataScopeService.cs @@ -0,0 +1,89 @@ + + +using Furion.DependencyInjection; +using Magic.Core.Entity; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +/// +/// 角色数据范围服务 +/// +public class SysRoleDataScopeService : ISysRoleDataScopeService, ITransient +{ + private readonly SqlSugarRepository _sysRoleDataScopeRep; // 角色数据范围表仓储 + private readonly SqlSugarRepository _roleRep; + + public SysRoleDataScopeService(SqlSugarRepository sysRoleDataScopeRep, SqlSugarRepository roleRep) + { + _sysRoleDataScopeRep = sysRoleDataScopeRep; + _roleRep = roleRep; + } + + /// + /// 授权角色数据范围 + /// + /// + /// + public async Task GrantDataScope(GrantRoleDataInput input) + { + try + { + _sysRoleDataScopeRep.CurrentBeginTran(); + await _sysRoleDataScopeRep.DeleteAsync(u => u.SysRoleId == input.Id); + + var grantOrgIdList = new List(); + input.GrantOrgIdList.ForEach(u => + { + grantOrgIdList.Add( + new SysRoleDataScope + { + SysRoleId = input.Id, + SysOrgId = u + }); + }); + await _roleRep.UpdateAsync(m => m.Id == input.Id,m => new SysRole() { DataScopeType = input.DataScopeType }); + await _sysRoleDataScopeRep.InsertAsync(grantOrgIdList); + _sysRoleDataScopeRep.CurrentCommitTran(); + } + catch (System.Exception) + { + _sysRoleDataScopeRep.CurrentRollbackTran(); + throw; + } + + } + + /// + /// 根据角色Id集合获取角色数据范围集合 + /// + /// + /// + public async Task> GetRoleDataScopeIdList(List roleIdList) + { + return await _sysRoleDataScopeRep + .Where(u => roleIdList.Contains(u.SysRoleId)) + .Select(u => u.SysOrgId).ToListAsync(); + } + + /// + /// 根据机构Id集合删除对应的角色-数据范围关联信息 + /// + /// + /// + public async Task DeleteRoleDataScopeListByOrgIdList(List orgIdList) + { + await _sysRoleDataScopeRep.DeleteAsync(u => orgIdList.Contains(u.SysOrgId)); + } + + /// + /// 根据角色Id删除对应的角色-数据范围关联信息 + /// + /// + /// + public async Task DeleteRoleDataScopeListByRoleId(long roleId) + { + await _sysRoleDataScopeRep.DeleteAsync(u => u.SysRoleId == roleId); + } +} diff --git a/Magic.Core/Service/Role/SysRoleMenuService.cs b/Magic.Core/Service/Role/SysRoleMenuService.cs new file mode 100644 index 0000000..c359d0b --- /dev/null +++ b/Magic.Core/Service/Role/SysRoleMenuService.cs @@ -0,0 +1,108 @@ + + +using Furion.DependencyInjection; +using Magic.Core.Entity; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +/// +/// 角色菜单 +/// +public class SysRoleMenuService : ISysRoleMenuService, ITransient +{ + private readonly SqlSugarRepository _sysRoleMenuRep; // 角色菜单表仓储 + private readonly ISysCacheService _sysCacheService; + private readonly SqlSugarRepository _sysRoleRep; + + public SysRoleMenuService(SqlSugarRepository sysRoleMenuRep, ISysCacheService sysCacheService, SqlSugarRepository sysRoleRep) + { + _sysRoleMenuRep = sysRoleMenuRep; + _sysCacheService = sysCacheService; + _sysRoleRep = sysRoleRep; + } + + /// + /// 获取角色的菜单Id集合 + /// + /// + /// + public async Task> GetRoleMenuIdList(List roleIdList) + { + return await _sysRoleMenuRep + .Where(u => roleIdList.Contains(u.SysRoleId)) + .Select(u => u.SysMenuId).ToListAsync(); + } + + /// + /// 授权角色菜单 + /// + /// + /// + public async Task GrantMenu(GrantRoleMenuInput input) + { + try + { + _sysRoleMenuRep.CurrentBeginTran(); + await _sysRoleMenuRep.DeleteAsync(u => u.SysRoleId == input.Id); + + var grantMenuIdList = new List(); + + input.GrantMenuIdList.ForEach(u => + { + grantMenuIdList.Add( + new SysRoleMenu + { + SysRoleId = input.Id, + SysMenuId = u + }); + }); + await _sysRoleMenuRep.InsertAsync(grantMenuIdList); + _sysRoleMenuRep.CurrentCommitTran(); + } + catch (System.Exception) + { + _sysRoleMenuRep.CurrentRollbackTran(); + throw; + } + // 清除缓存 + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_MENU); + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_PERMISSION); + } + + /// + /// 根据菜单Id集合删除对应的角色-菜单表信息 + /// + /// + /// + public async Task DeleteRoleMenuListByMenuIdList(List menuIdList) + { + await _sysRoleMenuRep.DeleteAsync(u => menuIdList.Contains(u.SysMenuId)); + } + + /// + /// 根据角色Id删除对应的角色-菜单表关联信息 + /// + /// + /// + public async Task DeleteRoleMenuListByRoleId(long roleId) + { + await _sysRoleMenuRep.DeleteAsync(u => u.SysRoleId == roleId); + } + + /// + /// 清理租户下角色的权限 + /// + /// 租户id + /// 租户管理员的角色id + /// + public async Task ClearRoleMenuListByTenantId(long tenantId, long manageRoleId) + { + List roleIds = await _sysRoleRep.Where(m => m.TenantId == tenantId).Select(m => m.Id).ToListAsync(); + roleIds.Remove(manageRoleId); + var managePermissionList = await _sysRoleMenuRep.Where(m => m.SysRoleId == manageRoleId).Select(m => m.SysMenuId).ToListAsync(); + + await _sysRoleMenuRep.DeleteAsync(m => roleIds.Contains(m.SysRoleId) && !managePermissionList.Contains(m.SysMenuId)); + } +} diff --git a/Magic.Core/Service/Role/SysRoleService.cs b/Magic.Core/Service/Role/SysRoleService.cs new file mode 100644 index 0000000..decb2dc --- /dev/null +++ b/Magic.Core/Service/Role/SysRoleService.cs @@ -0,0 +1,336 @@ +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Furion.FriendlyException; +using Magic.Core.Entity; +using Mapster; +using Microsoft.AspNetCore.Mvc; + +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +/// +/// 角色服务 +/// +[ApiDescriptionSettings(Name = "Role", Order = 149)] +public class SysRoleService : ISysRoleService, IDynamicApiController, ITransient +{ + private readonly SqlSugarRepository _sysRoleRep; // 角色表仓储 + private readonly SqlSugarRepository _sysUserRoleRep; // 用户角色表仓储 + + private readonly ISysRoleDataScopeService _sysRoleDataScopeService; + private readonly ISysOrgService _sysOrgService; + private readonly ISysRoleMenuService _sysRoleMenuService; + private readonly ISysCacheService _sysCacheService; + + public SysRoleService(SqlSugarRepository sysRoleRep, + SqlSugarRepository sysUserRoleRep, + ISysRoleDataScopeService sysRoleDataScopeService, + ISysOrgService sysOrgService, + ISysRoleMenuService sysRoleMenuService, + ISysCacheService sysCacheService) + { + _sysRoleRep = sysRoleRep; + _sysUserRoleRep = sysUserRoleRep; + _sysRoleDataScopeService = sysRoleDataScopeService; + _sysOrgService = sysOrgService; + _sysRoleMenuService = sysRoleMenuService; + _sysCacheService = sysCacheService; + } + + /// + /// 获取用户角色相关信息(登录) + /// + /// + /// + [NonAction] + public async Task> GetUserRoleList(long userId) + { + return await _sysRoleRep.AsQueryable().InnerJoin((r, u) => r.Id == u.SysRoleId) + .Where((r, u) => u.SysUserId == userId) + .Select((r, u) => new RoleOutput() + { + Id = r.Id, + Code = r.Code, + Name = r.Name + }).ToListAsync(); + } + + /// + /// 分页获取角色列表 + /// + /// + /// + [HttpGet("/sysRole/page")] + public async Task QueryRolePageList([FromQuery] RoleInput input) + { + var roles = await _sysRoleRep.AsQueryable() + .WhereIF(!string.IsNullOrWhiteSpace(input.Name), u => u.Name.Contains(input.Name.Trim())) + .WhereIF(!string.IsNullOrWhiteSpace(input.Code), u => u.Code.Contains(input.Code.Trim())) + .Where(u => u.Status == (int)CommonStatus.ENABLE) + .OrderBy(u => u.Sort) + .ToPagedListAsync(input.PageNo, input.PageSize); + return roles.XnPagedResult(); + } + + /// + /// 获取角色列表 + /// + /// + /// + [NonAction] + public async Task GetRoleList([FromQuery] RoleInput input) + { + return await _sysRoleRep.AsQueryable() + .WhereIF(!string.IsNullOrWhiteSpace(input.Name), u => u.Name.Contains(input.Name.Trim())) + .WhereIF(!string.IsNullOrWhiteSpace(input.Code), u => u.Code.Contains(input.Code.Trim())) + .Where(u => u.Status == (int)CommonStatus.ENABLE).OrderBy(u => u.Sort) + .Select(u => new + { + u.Id, + Name = u.Name + "[" + u.Code + "]" + }).ToListAsync(); + } + + /// + /// 角色下拉(用于授权角色时选择) + /// + /// + [HttpGet("/sysRole/dropDown")] + public async Task GetRoleDropDown() + { + // 如果不是超级管理员,则查询自己拥有的角色集合 + var roles = UserManager.IsSuperAdmin + ? await _sysUserRoleRep.Where(u => u.SysUserId == UserManager.UserId).Select(u => u.SysRoleId).ToListAsync() + : new List(); + + return await _sysRoleRep + .Where(roles.Any(), u => roles.Contains(u.Id)) + .Where(u => u.Status == (int)CommonStatus.ENABLE) + .Select(u => new + { + u.Id, + u.Code, + u.Name + }).ToListAsync(); + } + + /// + /// 增加角色 + /// + /// + /// + [HttpPost("/sysRole/add")] + public async Task AddRole(AddRoleInput input) + { + var isExist = await _sysRoleRep.AnyAsync(u => u.Code == input.Code || u.Name == input.Name); + if (isExist) + throw Oops.Oh(ErrorCode.D1006); + + var role = input.Adapt(); + role.RoleType = RoleType.NormalRole; + role.DataScopeType = DataScopeType.ALL; // 新角色默认全部数据范围 + await _sysRoleRep.InsertAsync(role); + } + + /// + /// 删除角色 + /// + /// + /// + [HttpPost("/sysRole/delete")] + public async Task DeleteRole(DeleteRoleInput input) + { + var sysRole = await _sysRoleRep.FirstOrDefaultAsync(u => u.Id == input.Id); + if (sysRole.IsNullOrZero()) + throw Oops.Oh(ErrorCode.D1006); + if (sysRole.RoleType==RoleType.AdminRole) + throw Oops.Oh("请勿删除管理员角色"); + try + { + _sysRoleRep.CurrentBeginTran(); + await _sysRoleRep.DeleteAsync(sysRole); + //级联删除该角色对应的角色-数据范围关联信息 + await _sysRoleDataScopeService.DeleteRoleDataScopeListByRoleId(sysRole.Id); + ////级联删除该角色对应的用户-角色表关联信息 + await _sysUserRoleRep.DeleteAsync(u => u.SysRoleId == sysRole.Id); + //级联删除该角色对应的角色-菜单表关联信息 + await _sysRoleMenuService.DeleteRoleMenuListByRoleId(sysRole.Id); + _sysRoleRep.CurrentCommitTran(); + } + catch (Exception) + { + _sysRoleRep.CurrentRollbackTran(); + throw; + } + + + } + + /// + /// 更新角色 + /// + /// + /// + [HttpPost("/sysRole/edit")] + public async Task UpdateRole(UpdateRoleInput input) + { + var role = await _sysRoleRep.FirstOrDefaultAsync(u => u.Id == input.Id); + if (role.IsNullOrZero()) + throw Oops.Oh(ErrorCode.D1002); + if (role.RoleType == RoleType.AdminRole) + throw Oops.Oh("请勿修改管理员角色"); + if (await _sysRoleRep.IsExistsAsync(u => (u.Name == input.Name || u.Code == input.Code) && u.Id != input.Id)) + throw Oops.Oh(ErrorCode.D1006); + var sysRole = input.Adapt(); + await _sysRoleRep.AsUpdateable(sysRole).IgnoreColumns(ignoreAllNullColumns: true).IgnoreColumns(u => new { u.DataScopeType }).ExecuteCommandAsync(); + + } + + /// + /// 获取角色 + /// + /// + /// + [HttpGet("/sysRole/detail")] + public async Task GetRoleInfo([FromQuery] QueryRoleInput input) + { + return await _sysRoleRep.FirstOrDefaultAsync(u => u.Id == input.Id); + } + + /// + /// 授权角色菜单 + /// + /// + /// + [HttpPost("/sysRole/grantMenu")] + public async Task GrantMenu(GrantRoleMenuInput input) + { + await _sysRoleMenuService.GrantMenu(input); + } + + /// + /// 授权角色数据范围 + /// + /// + /// + [HttpPost("/sysRole/grantData")] + public async Task GrantData(GrantRoleDataInput input) + { + // 清除所有用户数据范围缓存 + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_DATASCOPE); + + var role = await _sysRoleRep.FirstOrDefaultAsync(u => u.Id == input.Id); + var dataScopeType = input.DataScopeType; + if (!UserManager.IsSuperAdmin) + { + //如果授权的角色的数据范围类型为全部,则没权限,只有超级管理员有 + //if (DataScopeType.ALL == dataScopeType) + // throw Oops.Oh(ErrorCode.D1016); + + //如果授权的角色数据范围类型为自定义,则要判断授权的数据范围是否在自己的数据范围内 + if (DataScopeType.DEFINE == dataScopeType) + { + var dataScopes = await DataFilterExtensions.GetDataScopeIdList(FilterType.Org); + var grantOrgIdList = input.GrantOrgIdList; //要授权的数据范围列表 + if (grantOrgIdList.Count > 0) + { + if (dataScopes.Count < 1) + throw Oops.Oh(ErrorCode.D1016); + else if (!dataScopes.All(u => grantOrgIdList.Any(c => c == u))) + throw Oops.Oh(ErrorCode.D1016); + } + } + } + role.DataScopeType = dataScopeType; + await _sysRoleDataScopeService.GrantDataScope(input); + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_USERSDATASCOPE); + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_DATASCOPE); + } + + /// + /// 根据角色Id集合获取数据范围Id集合 + /// + /// + /// + /// + [NonAction] + public async Task> GetUserDataScopeIdList(List roleIdList, long orgId) + { + // 定义角色中最大数据范围的类型,目前按最大范围策略来,如果你同时拥有ALL和SELF的权限,最后按ALL返回 + int strongerDataScopeType = (int)DataScopeType.SELF; + + var customDataScopeRoleIdList = new List(); + if (roleIdList != null && roleIdList.Count > 0) + { + var roles = await _sysRoleRep.Where(u => roleIdList.Contains(u.Id)).ToListAsync(); + roles.ForEach(u => + { + if (u.DataScopeType == DataScopeType.DEFINE) + customDataScopeRoleIdList.Add(u.Id); + else if ((int)u.DataScopeType <= strongerDataScopeType) + strongerDataScopeType = (int)u.DataScopeType; + }); + } + + // 自定义数据范围的角色对应的数据范围 + var roleDataScopeIdList = await _sysRoleDataScopeService.GetRoleDataScopeIdList(customDataScopeRoleIdList); + + // 角色中拥有最大数据范围类型的数据范围 + var dataScopeIdList = await _sysOrgService.GetDataScopeListByDataScopeType(strongerDataScopeType, orgId); + + return roleDataScopeIdList.Concat(dataScopeIdList).Distinct().ToList(); //并集 + } + + /// + /// 根据角色Id获取角色名称 + /// + /// + /// + [NonAction] + public async Task GetNameByRoleId(long roleId) + { + var role = await _sysRoleRep.FirstOrDefaultAsync(u => u.Id == roleId); + if (role == null) + throw Oops.Oh(ErrorCode.D1002); + return role.Name; + } + + /// + /// 获取角色拥有菜单Id集合 + /// + /// + /// + [HttpGet("/sysRole/ownMenu")] + public async Task> OwnMenu([FromQuery] QueryRoleInput input) + { + //return await _sysRoleMenuService.GetRoleMenuIdList(new List { input.Id }); + var menuList = await _sysRoleRep.Change().AsQueryable().LeftJoin((t1, t2) => t1.SysMenuId == t2.Id) + .Where(t1 => t1.SysRoleId == input.Id) + .Select((t1, t2) => new SysMenu { Id = t1.SysMenuId, Application = t2.Application }).ToListAsync(); + + // 拿出所有应用编码 + var appCodeList = menuList.Select(sl => sl.Application).Distinct().ToList(); + + return appCodeList.Select(appCode => new OwnMenuOutput + { + AppCode = appCode, + MenuIdList = menuList.FindAll(f => f.Application == appCode).Select(sl => sl.Id).ToList() + }).ToList(); + } + + /// + /// 获取角色拥有数据Id集合 + /// + /// + /// + [HttpGet("/sysRole/ownData")] + public async Task> OwnData([FromQuery] QueryRoleInput input) + { + return await _sysRoleDataScopeService.GetRoleDataScopeIdList(new List { input.Id }); + } +} diff --git a/Magic.Core/Service/Tenant/Dto/TenantInput.cs b/Magic.Core/Service/Tenant/Dto/TenantInput.cs new file mode 100644 index 0000000..adab238 --- /dev/null +++ b/Magic.Core/Service/Tenant/Dto/TenantInput.cs @@ -0,0 +1,108 @@ +using System.ComponentModel.DataAnnotations; + +namespace Magic.Core.Service; + +/// +/// 租户参数 +/// +public class TenantInput : PageInputBase +{ + /// + /// 公司名称 + /// + public virtual string Name { get; set; } + + /// + /// 管理员名称 + /// + public virtual string AdminName { get; set; } + + /// + /// 主机 + /// + public virtual string Host { get; set; } + + /// + /// 电子邮箱 + /// + public virtual string Email { get; set; } + + /// + /// 电话号码 + /// + public string Phone { get; set; } + + /// + /// 模式 + /// + public string Schema { get; set; } + + /// + /// 数据库连接 + /// + public virtual string Connection { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } + + /// + /// 创建时间 + /// + public string CreatedTime { get; set; } +} + +public class AddTenantInput : TenantInput +{ + /// + /// 公司名称 + /// + [Required(ErrorMessage = "公司名称")] + public override string Name { get; set; } + + /// + /// 管理员名称 + /// + [Required(ErrorMessage = "管理员名称")] + public override string AdminName { get; set; } + + /// + /// 主机名称 + /// + public override string Host { get; set; } + + /// + /// 数据库连接 + /// + public override string Connection { get; set; } + + /// + /// 电子邮箱 + /// + [Required(ErrorMessage = "电子邮箱")] + public override string Email { get; set; } +} + +public class DeleteTenantInput +{ + /// + /// 租户Id + /// + [Required(ErrorMessage = "租户Id不能为空")] + public long Id { get; set; } +} + +public class UpdateTenantInput : TenantInput +{ + /// + /// 租户Id + /// + [Required(ErrorMessage = "租户Id不能为空")] + public long Id { get; set; } +} + +public class QueryTenantInput : DeleteTenantInput +{ + +} diff --git a/Magic.Core/Service/Tenant/Dto/TenantOutput.cs b/Magic.Core/Service/Tenant/Dto/TenantOutput.cs new file mode 100644 index 0000000..58e0593 --- /dev/null +++ b/Magic.Core/Service/Tenant/Dto/TenantOutput.cs @@ -0,0 +1,57 @@ +namespace Magic.Core.Service; + +/// +/// 租户参数 +/// +public class TenantOutput +{ + /// + /// 租户Id + /// + public long Id { get; set; } + + /// + /// 名称 + /// + public string Name { get; set; } + + /// + /// 名称 + /// + public string AdminName { get; set; } + + /// + /// 主机 + /// + public string Host { get; set; } + + /// + /// 电子邮箱 + /// + public string Email { get; set; } + + /// + /// 电话号码 + /// + public string Phone { get; set; } + + /// + /// 模式 + /// + public string Schema { get; set; } + + /// + /// 数据库连接 + /// + public string Connection { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } + + /// + /// 创建时间 + /// + public string CreatedTime { get; set; } +} diff --git a/Magic.Core/Service/Tenant/ISysTenantService.cs b/Magic.Core/Service/Tenant/ISysTenantService.cs new file mode 100644 index 0000000..6d46002 --- /dev/null +++ b/Magic.Core/Service/Tenant/ISysTenantService.cs @@ -0,0 +1,20 @@ +using Magic.Core.Entity; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ISysTenantService +{ + Task AddTenant(AddTenantInput input); + Task DeleteTenant(DeleteTenantInput input); + Task GetTenant([FromQuery] QueryTenantInput input); + Task GrantMenu(GrantRoleMenuInput input); + Task InitNewTenant(SysTenant newTenant); + //Task> OwnMenu([FromQuery] QueryTenantInput input); + Task> OwnMenu([FromQuery] QueryTenantInput input); + Task QueryTenantPageList([FromQuery] TenantInput input); + Task ResetUserPwd(QueryTenantInput input); + Task UpdateTenant(UpdateTenantInput input); +} diff --git a/Magic.Core/Service/Tenant/SysTenantService.cs b/Magic.Core/Service/Tenant/SysTenantService.cs new file mode 100644 index 0000000..9070c5f --- /dev/null +++ b/Magic.Core/Service/Tenant/SysTenantService.cs @@ -0,0 +1,335 @@ + + +using Furion.DataEncryption; +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Furion.FriendlyException; +using Magic.Core.Entity; +using Mapster; +using Microsoft.AspNetCore.Mvc; + +using SqlSugar; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +/// +/// 租户服务 +/// +[ApiDescriptionSettings(Name = "Tenant", Order = 100)] +public class SysTenantService : ISysTenantService, IDynamicApiController, ITransient +{ + + private readonly SqlSugarRepository _sysTenantRep; // 租户表仓储 + private readonly SqlSugarRepository _sysUserRep; + private readonly SqlSugarRepository _sysOrgRep; + private readonly SqlSugarRepository _sysRoleRep; + private readonly SqlSugarRepository _sysEmpRep; + private readonly SqlSugarRepository _sysPosRep; + private readonly SqlSugarRepository _sysEmpPosRep; + private readonly SqlSugarRepository _sysUserRoleRep; + private readonly SqlSugarRepository _sysUserDataScopeRep; + private readonly SqlSugarRepository _sysRoleDataScopeRep; + private readonly ISysCacheService _sysCacheService; + + private readonly ISysRoleMenuService _sysRoleMenuService; + private readonly ISysUserRoleService _sysUserRoleService; + private readonly ISysConfigService _sysConfigService; + + public SysTenantService( + ISqlSugarClient sqlSugarClient, + SqlSugarRepository sysTenantRep, + SqlSugarRepository sysOrgRep, + SqlSugarRepository sysRoleRep, + SqlSugarRepository sysEmpRep, + SqlSugarRepository sysPosRep, + SqlSugarRepository sysUserService, + SqlSugarRepository sysEmpPosRep, + SqlSugarRepository sysUserRoleRep, + SqlSugarRepository sysUserDataScopeRep, + SqlSugarRepository sysRoleDataScopeRep, + ISysRoleMenuService sysRoleMenuService, + ISysUserRoleService sysUserRoleService, + ISysConfigService sysConfigService, + ISysCacheService sysCacheService + ) + { + _sysTenantRep = sysTenantRep; + _sysOrgRep = sysOrgRep; + _sysRoleRep = sysRoleRep; + _sysEmpRep = sysEmpRep; + _sysPosRep = sysPosRep; + _sysUserRep = sysUserService; + _sysEmpPosRep = sysEmpPosRep; + _sysUserRoleRep = sysUserRoleRep; + _sysUserDataScopeRep = sysUserDataScopeRep; + _sysRoleDataScopeRep = sysRoleDataScopeRep; + _sysRoleMenuService = sysRoleMenuService; + _sysUserRoleService = sysUserRoleService; + _sysConfigService = sysConfigService; + _sysCacheService = sysCacheService; + } + + /// + /// 分页查询租户 + /// + /// + /// + [HttpGet("/sysTenant/page")] + public async Task QueryTenantPageList([FromQuery] TenantInput input) + { + var tenants = await _sysTenantRep.AsQueryable() + .Where(m => m.TenantType != TenantTypeEnum.SYSTEM) + .WhereIF(!string.IsNullOrWhiteSpace(input.Name), u => u.Name.Contains(input.Name.Trim())) + .WhereIF(!string.IsNullOrWhiteSpace(input.Host), u => u.Host.Contains(input.Host.Trim())) + .Select() + .ToPagedListAsync(input.PageNo, input.PageSize); + return tenants.XnPagedResult(); + } + + /// + /// 增加租户 + /// + /// + /// + [HttpPost("/sysTenant/add")] + public async Task AddTenant(AddTenantInput input) + { + var isExist = await _sysTenantRep.AnyAsync(u => u.Name == input.Name || u.Email == input.Email); + if (isExist) + throw Oops.Oh(ErrorCode.D1300); + + var tenant = input.Adapt(); + tenant.TenantType = TenantTypeEnum.COMMON; + var newTenant = await _sysTenantRep.InsertReturnEntityAsync(tenant); + await InitNewTenant(newTenant); + } + + /// + /// 新增租户时,初始化数据 + /// + /// + public async Task InitNewTenant(SysTenant newTenant) + { + long tenantId = newTenant.Id; + string email = newTenant.Email; + string companyName = newTenant.Name; + + + // 初始化公司(组织结构) + var newOrg = new SysOrg + { + TenantId = tenantId, + Pid = 0, + Pids = "[0],", + Name = companyName, + Code = "1", + Contacts = newTenant.AdminName, + Tel = newTenant.Phone + }; + newOrg = await _sysOrgRep.InsertReturnEntityAsync(newOrg); + + + // 初始化角色 + var newRole = new SysRole + { + TenantId = tenantId, + DataScopeType = DataScopeType.ALL, + Code = "1", + Name = "系统管理员", + RoleType = RoleType.AdminRole + }; + + newRole = await _sysRoleRep.InsertReturnEntityAsync(newRole); + + // 初始化租户管理员 + var newUser = new SysUser + { + TenantId = tenantId, + Account = email, + Password = "e10adc3949ba59abbe56e057f20f883e", + Name = newTenant.AdminName, + NickName = newTenant.AdminName, + Email = newTenant.Email, + Phone = newTenant.Phone, + AdminType = AdminType.Admin, + Sex=Gender.MALE + }; + newUser = await _sysUserRep.InsertReturnEntityAsync(newUser); + + // 初始化职工 + var sysEmp = new SysEmp + { + Id = newUser.Id, + JobNum = "1", + OrgId = newOrg.Id, + OrgName = newOrg.Name + }; + await _sysEmpRep.InsertAsync(sysEmp); + + //初始化用户角色 + var sysUserRole = new SysUserRole + { + SysUserId = newUser.Id, + SysRoleId = newRole.Id + }; + await _sysUserRoleRep.InsertAsync(sysUserRole); + + //初始化用户机构 + var sysUserDataScope = new SysUserDataScope + { + SysUserId = newUser.Id, + SysOrgId = newOrg.Id + }; + await _sysUserDataScopeRep.InsertAsync(sysUserDataScope); + + var sysRoleDataScope = new SysRoleDataScope + { + SysOrgId = newOrg.Id, + SysRoleId = newRole.Id + }; + await _sysRoleDataScopeRep.InsertAsync(sysRoleDataScope); + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_USERSDATASCOPE); + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_DATASCOPE); + } + + /// + /// 删除租户 + /// + /// + /// + [HttpPost("/sysTenant/delete")] + public async Task DeleteTenant(DeleteTenantInput input) + { + SysTenant sysTenant = await GetTenant(new QueryTenantInput() { Id = input.Id }); + List userList = await _sysUserRep.AsQueryable().Filter(null, true).Where(m => m.TenantId == input.Id).ToListAsync(); + sysTenant.IsDeleted = true; + + try + { + _sysUserRep.CurrentBeginTran(); + await _sysTenantRep.UpdateAsync(sysTenant); + + if (userList.Any()) + { + userList.ForEach(m => { m.IsDeleted = true; }); + await _sysUserRep.UpdateAsync(userList); + } + _sysUserRep.CurrentCommitTran(); + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_USERSDATASCOPE); + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_DATASCOPE); + } + catch (System.Exception) + { + _sysUserRep.CurrentRollbackTran(); + } + + + } + + /// + /// 更新租户 + /// + /// + /// + [HttpPost("/sysTenant/edit")] + public async Task UpdateTenant(UpdateTenantInput input) + { + var isExist = await _sysTenantRep.AnyAsync(u => (u.Name == input.Name || u.Host == input.Host || u.Email == input.Email) && u.Id != input.Id && u.TenantType != TenantTypeEnum.SYSTEM); + if (isExist) + throw Oops.Oh(ErrorCode.D1300); + + var tenant = input.Adapt(); + tenant.TenantType = TenantTypeEnum.COMMON; + await _sysTenantRep.AsUpdateable(tenant).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync(); + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_USERSDATASCOPE); + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_DATASCOPE); + } + + /// + /// 获取租户 + /// + /// + /// + [HttpGet("/sysTenant/detail")] + public async Task GetTenant([FromQuery] QueryTenantInput input) + { + var sysTenant = await _sysTenantRep.AsQueryable().FirstAsync(u => u.Id == input.Id && u.TenantType != TenantTypeEnum.SYSTEM); + if (sysTenant == null) + throw Oops.Oh(ErrorCode.D1002); + return sysTenant; + } + + /// + /// 授权租户管理员角色菜单 + /// + /// + /// + [HttpPost("/sysTenant/grantMenu")] + public async Task GrantMenu(GrantRoleMenuInput input) + { + var tenantAdminUser = await GetTenantAdminUser(input.Id); + if (tenantAdminUser == null) return; + var roleIds = await _sysUserRoleService.GetUserRoleIdList(tenantAdminUser.Id); + input.Id = roleIds[0]; // 重置租户管理员角色Id + await _sysRoleMenuService.GrantMenu(input); + //处理该租户下角色的权限 + await _sysRoleMenuService.ClearRoleMenuListByTenantId(tenantAdminUser.TenantId.Value, input.Id); + } + + /// + /// 获取租户管理员角色拥有菜单Id集合 + /// + /// + /// + [HttpGet("/sysTenant/ownMenu")] + public async Task> OwnMenu([FromQuery] QueryTenantInput input) + { + var tenantAdminUser = await GetTenantAdminUser(input.Id); + if (tenantAdminUser == null) + return new List(); + var roleIds = await _sysUserRoleService.GetUserRoleIdList(tenantAdminUser.Id); + var tenantAdminRoleId = roleIds[0]; // 租户管理员角色Id + + var menuList = await _sysRoleRep.Change().AsQueryable().LeftJoin((t1, t2) => t1.SysMenuId == t2.Id) + .Where(t1 => t1.SysRoleId == tenantAdminRoleId) + .Select((t1, t2) => new SysMenu { Id = t1.SysMenuId, Application = t2.Application }).ToListAsync(); + + // 拿出所有应用编码 + var appCodeList = menuList.Select(sl => sl.Application).Distinct().ToList(); + + return appCodeList.Select(appCode => new OwnMenuOutput + { + AppCode = appCode, + MenuIdList = menuList.FindAll(f => f.Application == appCode).Select(sl => sl.Id).ToList() + }).ToList(); + } + + /// + /// 重置租户管理员密码 + /// + /// + /// + [HttpPost("/sysTenant/resetPwd")] + public async Task ResetUserPwd(QueryTenantInput input) + { + var tenantAdminUser = await GetTenantAdminUser(input.Id); + tenantAdminUser.Password = MD5Encryption.Encrypt(await _sysConfigService.GetDefaultPassword()); + // 更新密码 + await _sysUserRep.AsUpdateable(tenantAdminUser) + .Where(wh => wh.Id.Equals(tenantAdminUser.Id)).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync(); + } + + /// + /// 获取租户管理员用户 + /// + /// + /// + private async Task GetTenantAdminUser(long tenantId) + { + return await _sysUserRep.AsQueryable().Filter(null, true).FirstAsync(u => u.TenantId == tenantId && u.AdminType == AdminType.Admin); + } + +} diff --git a/Magic.Core/Service/Timer/Dto/JobInput.cs b/Magic.Core/Service/Timer/Dto/JobInput.cs new file mode 100644 index 0000000..7d6e9ae --- /dev/null +++ b/Magic.Core/Service/Timer/Dto/JobInput.cs @@ -0,0 +1,93 @@ +using Furion.DataValidation; +using Furion.TaskScheduler; +using System.ComponentModel.DataAnnotations; + +namespace Magic.Core.Service; + +/// +/// 任务调度参数 +/// +public class JobInput : PageInputBase +{ + /// + /// 任务名称 + /// + + public string JobName { get; set; } + + /// + /// 只执行一次 + /// + public bool DoOnce { get; set; } = false; + + /// + /// 立即执行(默认等待启动) + /// + public bool StartNow { get; set; } = false; + + /// + /// 执行类型(并行、列队) + /// + public SpareTimeExecuteTypes ExecuteType { get; set; } + + /// + /// 执行间隔时间(单位秒) + /// + /// 5 + public int Interval { get; set; } + + /// + /// Cron表达式 + /// + public string Cron { get; set; } + + /// + /// 定时器类型 + /// + public SpareTimeTypes TimerType { get; set; } + + /// + /// 请求url + /// + public string RequestUrl { get; set; } + + /// + /// 请求参数(Post,Put请求用) + /// + public string RequestParameters { get; set; } + + /// + /// Headers(可以包含如:Authorization授权认证) + /// 格式:{"Authorization":"userpassword.."} + /// + public string Headers { get; set; } + + /// + /// 请求类型 + /// + public RequestTypeEnum RequestType { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } +} + +public class DeleteJobInput : JobInput +{ + /// + /// 任务Id + /// + [Required(ErrorMessage = "任务Id不能为空"), DataValidation(ValidationTypes.Numeric)] + public long Id { get; set; } +} + +public class UpdateJobInput : DeleteJobInput +{ + +} + +public class QueryJobInput : DeleteJobInput +{ + +} diff --git a/Magic.Core/Service/Timer/Dto/JobOutput.cs b/Magic.Core/Service/Timer/Dto/JobOutput.cs new file mode 100644 index 0000000..8daea13 --- /dev/null +++ b/Magic.Core/Service/Timer/Dto/JobOutput.cs @@ -0,0 +1,104 @@ +using Furion.TaskScheduler; +using System; + +namespace Magic.Core.Service; + +/// +/// 任务信息---任务详情 +/// +public class JobOutput : LocalJobOutput +{ + /// + /// Id + /// + public long Id { get; set; } + + /// + /// 已执行次数 + /// + public long? RunNumber { get; set; } + + + /// + /// 定时器状态 + /// + public SpareTimeStatus TimerStatus { get; set; } = SpareTimeStatus.Stopped; + + /// + /// 异常信息 + /// + public string Exception { get; set; } +} + +/// +/// 本地任务信息 +/// +public class LocalJobOutput +{ + /// + /// 任务名称 + /// + public string JobName { get; set; } + + /// + /// 只执行一次 + /// + public bool DoOnce { get; set; } = false; + + /// + /// 立即执行(默认等待启动) + /// + public bool StartNow { get; set; } = false; + + /// + /// 执行类型(并行、列队) + /// + public SpareTimeExecuteTypes ExecuteType { get; set; } + + /// + /// 执行间隔时间(单位秒) + /// + public int Interval { get; set; } + + /// + /// Cron表达式 + /// + public string Cron { get; set; } + + /// + /// 定时器类型 + /// + public SpareTimeTypes TimerType { get; set; } + + /// + /// 请求url + /// + public string RequestUrl { get; set; } + + /// + /// 请求类型 + /// + /// 2 + public RequestTypeEnum RequestType { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } +} + +/// +/// 任务方法信息 +/// +public class TaskMethodInfo : LocalJobOutput +{ + /// + /// 方法名 + /// + public string MethodName { get; set; } + + /// + /// 方法所属类的Type对象 + /// + public Type DeclaringType { get; set; } +} diff --git a/Magic.Core/Service/Timer/ISysTimerService.cs b/Magic.Core/Service/Timer/ISysTimerService.cs new file mode 100644 index 0000000..2e1cce0 --- /dev/null +++ b/Magic.Core/Service/Timer/ISysTimerService.cs @@ -0,0 +1,17 @@ +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ISysTimerService +{ + Task AddTimer(JobInput input); + void AddTimerJob(JobInput input); + Task DeleteTimer(DeleteJobInput input); + Task GetTimer([FromQuery] QueryJobInput input); + Task GetTimerPageList([FromQuery] JobInput input); + void StartTimerJob(JobInput input); + void StopTimerJob(JobInput input); + Task UpdateTimber(UpdateJobInput input); + void StartTimerJob(); +} diff --git a/Magic.Core/Service/Timer/SysTimerService.cs b/Magic.Core/Service/Timer/SysTimerService.cs new file mode 100644 index 0000000..6a51b42 --- /dev/null +++ b/Magic.Core/Service/Timer/SysTimerService.cs @@ -0,0 +1,331 @@ +using Furion; + + +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Furion.FriendlyException; +using Furion.JsonSerialization; +using Furion.RemoteRequest.Extensions; +using Furion.TaskScheduler; +using Magic.Core.Entity; +using Mapster; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +/// +/// 任务调度服务 +/// +[ApiDescriptionSettings(Name = "Timer", Order = 100)] +public class SysTimerService : ISysTimerService, IDynamicApiController, IScoped +{ + private readonly SqlSugarRepository _sysTimerRep; // 任务表仓储 + private readonly ISysCacheService _cache; + + public SysTimerService(SqlSugarRepository sysTimerRep, ISysCacheService cache) + { + _sysTimerRep = sysTimerRep; + _cache = cache; + } + + /// + /// 分页获取任务列表 + /// + /// + /// + [HttpGet("/sysTimers/page")] + public async Task GetTimerPageList([FromQuery] JobInput input) + { + var workers = SpareTime.GetWorkers().ToList(); + + var timers = await _sysTimerRep.AsQueryable() + .WhereIF(!string.IsNullOrWhiteSpace(input.JobName), u => u.JobName.Contains(input.JobName.Trim())) + .Select() + .ToPagedListAsync(input.PageNo, input.PageSize); + + timers.Items.ToList().ForEach(u => + { + var timer = workers.FirstOrDefault(m => m.WorkerName == u.JobName); + if (timer != null) + { + u.TimerStatus = timer.Status; + u.RunNumber = timer.Tally; + u.Exception = ""; // JSON.Serialize(timer.Exception); + } + }); + return timers.XnPagedResult(); + } + + /// + /// 获取所有本地任务 + /// + /// + [HttpGet("/sysTimers/localJobList")] + public async Task GetLocalJobList() + { + // 获取本地所有任务方法 + var LocalJobs = await GetTaskMethods(); + + // TaskMethodInfo继承自LocalJobOutput,直接强转为LocalJobOutput再返回 + return LocalJobs.Select(t => (LocalJobOutput)t); + } + + /// + /// 增加任务 + /// + /// + /// + [HttpPost("/sysTimers/add")] + public async Task AddTimer(JobInput input) + { + var isExist = await _sysTimerRep.AnyAsync(u => u.JobName == input.JobName); + if (isExist) + throw Oops.Oh(ErrorCode.D1100); + + var timer = input.Adapt(); + await _sysTimerRep.InsertAsync(timer); + + // 添加到任务调度里 + AddTimerJob(input); + } + + /// + /// 删除任务 + /// + /// + /// + [HttpPost("/sysTimers/delete")] + public async Task DeleteTimer(DeleteJobInput input) + { + var timer = await _sysTimerRep.FirstOrDefaultAsync(u => u.Id == input.Id); + if (timer == null) + throw Oops.Oh(ErrorCode.D1101); + + await _sysTimerRep.DeleteAsync(timer); + + // 从调度器里取消 + SpareTime.Cancel(timer.JobName); + } + + /// + /// 修改任务 + /// + /// + /// + [HttpPost("/sysTimers/edit")] + public async Task UpdateTimber(UpdateJobInput input) + { + // 排除自己并且判断与其他是否相同 + var isExist = await _sysTimerRep.AnyAsync(u => u.JobName == input.JobName && u.Id != input.Id); + if (isExist) throw Oops.Oh(ErrorCode.D1100); + + // 先从调度器里取消 + var oldTimer = await _sysTimerRep.FirstOrDefaultAsync(u => u.Id == input.Id); + SpareTime.Cancel(oldTimer.JobName); + + var timer = input.Adapt(); + await _sysTimerRep.AsUpdateable(timer).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync(); + + // 再添加到任务调度里 + AddTimerJob(input); + } + + /// + /// 查看任务 + /// + /// + /// + [HttpGet("/sysTimers/detail")] + public async Task GetTimer([FromQuery] QueryJobInput input) + { + return await _sysTimerRep.FirstOrDefaultAsync(u => u.Id == input.Id); + } + + /// + /// 停止任务 + /// + /// + /// + [HttpPost("/sysTimers/stop")] + public void StopTimerJob(JobInput input) + { + var timer = _sysTimerRep.FirstOrDefault(m => m.JobName == input.JobName); + if (timer == null) + throw Oops.Oh(ErrorCode.D1002); + timer.StartNow = false; + _sysTimerRep.AsUpdateable(timer).ExecuteCommand(); + SpareTime.Stop(input.JobName); + } + + /// + /// 启动任务 + /// + /// + /// + [HttpPost("/sysTimers/start")] + public void StartTimerJob(JobInput input) + { + var dbTimer = _sysTimerRep.FirstOrDefault(m => m.JobName == input.JobName); + if (dbTimer == null) + throw Oops.Oh(ErrorCode.D1002); + dbTimer.StartNow = true; + _sysTimerRep.AsUpdateable(dbTimer).ExecuteCommand(); + + var timer = SpareTime.GetWorkers().ToList().Find(u => u.WorkerName == input.JobName); + if (timer == null) + AddTimerJob(input); + + + // 如果 StartNow 为 flase , 执行 AddTimerJob 并不会启动任务 + SpareTime.Start(input.JobName); + } + + /// + /// 新增定时任务 + /// + /// + [NonAction] + public void AddTimerJob(JobInput input) + { + Action action = null; + + switch (input.RequestType) + { + // 创建本地方法委托 + case RequestTypeEnum.Run: + { + // 查询符合条件的任务方法 + var taskMethod = GetTaskMethods().Result.FirstOrDefault(m => m.RequestUrl == input.RequestUrl); + if (taskMethod == null) break; + + // 创建任务对象 + var typeInstance = Activator.CreateInstance(taskMethod.DeclaringType); + + // 创建委托 + action = (Action)Delegate.CreateDelegate(typeof(Action), typeInstance, taskMethod.MethodName); + break; + } + // 创建网络任务委托 + default: + { + action = async (_, _) => + { + var requestUrl = input.RequestUrl.Trim(); + requestUrl = requestUrl?.IndexOf("http") == 0 ? requestUrl : "http://" + requestUrl; + var requestParameters = input.RequestParameters; + var headersString = input.Headers; + var headers = string.IsNullOrEmpty(headersString) + ? null + : JSON.Deserialize>(headersString); + + switch (input.RequestType) + { + case RequestTypeEnum.Get: + await requestUrl.SetHeaders(headers).GetAsync(); + break; + case RequestTypeEnum.Post: + await requestUrl.SetHeaders(headers).SetQueries(requestParameters).PostAsync(); + break; + case RequestTypeEnum.Put: + await requestUrl.SetHeaders(headers).SetQueries(requestParameters).PutAsync(); + break; + case RequestTypeEnum.Delete: + await requestUrl.SetHeaders(headers).DeleteAsync(); + break; + } + }; + break; + } + } + + if (action == null) + throw Oops.Oh($"定时任务委托创建失败!JobName:{input.JobName}"); + + // 缓存任务配置参数,以供任务运行时读取 + if (input.RequestType == RequestTypeEnum.Run) + { + var jobParametersName = $"{input.JobName}_Parameters"; + var jobParameters = _cache.Exists(jobParametersName); + var requestParametersIsNull = string.IsNullOrEmpty(input.RequestParameters); + + // 如果没有任务配置却又存在缓存,则删除缓存 + if (requestParametersIsNull && jobParameters) + _cache.Del(jobParametersName); + else if (!requestParametersIsNull) + _cache.Set(jobParametersName, JSON.Deserialize>(input.RequestParameters)); + } + + // 创建定时任务 + switch (input.TimerType) + { + case SpareTimeTypes.Interval: + if (input.DoOnce) + SpareTime.DoOnce(input.Interval * 1000, action, input.JobName, input.Remark, input.StartNow, executeType: input.ExecuteType); + else + SpareTime.Do(input.Interval * 1000, action, input.JobName, input.Remark, input.StartNow, executeType: input.ExecuteType); + break; + case SpareTimeTypes.Cron: + SpareTime.Do(input.Cron, action, input.JobName, input.Remark, input.StartNow, executeType: input.ExecuteType); + break; + } + } + + /// + /// 启动自启动任务 + /// + [NonAction] + public void StartTimerJob() + { + var sysTimerList = _sysTimerRep.Where(t => t.StartNow).Select().ToList(); + sysTimerList.ForEach(AddTimerJob); + } + + /// + /// 获取所有本地任务 + /// + /// + [NonAction] + public async Task> GetTaskMethods() + { + // 有缓存就返回缓存 + var taskMethods = await _cache.GetAsync>("TaskMethodInfos"); + if (taskMethods != null) return taskMethods; + + // 获取所有本地任务方法,必须有spareTimeAttribute特性 + taskMethods = App.EffectiveTypes + .Where(u => u.IsClass && !u.IsInterface && !u.IsAbstract && typeof(ISpareTimeWorker).IsAssignableFrom(u)) + .SelectMany(u => u.GetMethods(BindingFlags.Public | BindingFlags.Instance) + .Where(m => m.IsDefined(typeof(SpareTimeAttribute), false) && + m.GetParameters().Length == 2 && + m.GetParameters()[0].ParameterType == typeof(SpareTimer) && + m.GetParameters()[1].ParameterType == typeof(long) && m.ReturnType == typeof(void)) + .Select(m => + { + // 默认获取第一条任务特性 + var spareTimeAttribute = m.GetCustomAttribute(); + return new TaskMethodInfo + { + JobName = spareTimeAttribute.WorkerName, + RequestUrl = $"{m.DeclaringType.Name}/{m.Name}", + Cron = spareTimeAttribute.CronExpression, + DoOnce = spareTimeAttribute.DoOnce, + ExecuteType = spareTimeAttribute.ExecuteType, + Interval = (int)spareTimeAttribute.Interval / 1000, + StartNow = spareTimeAttribute.StartNow, + RequestType = RequestTypeEnum.Run, + Remark = spareTimeAttribute.Description, + TimerType = string.IsNullOrEmpty(spareTimeAttribute.CronExpression) ? SpareTimeTypes.Interval : SpareTimeTypes.Cron, + MethodName = m.Name, + DeclaringType = m.DeclaringType + }; + })); + + await _cache.SetAsync("TaskMethodInfos", taskMethods); + return taskMethods; + } +} diff --git a/Magic.Core/Service/Trash/Dto/TrashDto.cs b/Magic.Core/Service/Trash/Dto/TrashDto.cs new file mode 100644 index 0000000..3050679 --- /dev/null +++ b/Magic.Core/Service/Trash/Dto/TrashDto.cs @@ -0,0 +1,61 @@ +using System; + + +namespace Magic.Core.Service; + +/// +/// 回收站输出参数 +/// +public class TrashDto +{ + /// + /// Id + /// + public long Id { get; set; } + + /// + /// 父Id + /// + public long PId { get; set; } + + /// + /// 父ID列表 + /// + public string PIds { get; set; } + + /// + /// 名称 + /// + public string Name { get; set; } + + /// + /// 类型 + /// + public int DocumentType { get; set; } + + /// + /// 文件后缀 + /// + public string FileSuffix { get; set; } + + /// + /// 文件大小kb + /// + public int FileSizeKb { get; set; } + + /// + /// 存储后的文件名 + /// + public string FileObjectName { get; set; } + + /// + /// 标签 + /// + public int Label { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } + +} diff --git a/Magic.Core/Service/Trash/Dto/TrashOutput.cs b/Magic.Core/Service/Trash/Dto/TrashOutput.cs new file mode 100644 index 0000000..4be628f --- /dev/null +++ b/Magic.Core/Service/Trash/Dto/TrashOutput.cs @@ -0,0 +1,60 @@ +using System; + +namespace Magic.Core.Service; + +/// +/// 回收站输出参数 +/// +public class TrashOutput +{ + /// + /// Id + /// + public long Id { get; set; } + + /// + /// 父Id + /// + public long PId { get; set; } + + /// + /// 父ID列表 + /// + public string PIds { get; set; } + + /// + /// 名称 + /// + public string Name { get; set; } + + /// + /// 类型 + /// + public int DocumentType { get; set; } + + /// + /// 文件后缀 + /// + public string FileSuffix { get; set; } + + /// + /// 文件大小kb + /// + public int FileSizeKb { get; set; } + + /// + /// 存储后的文件名 + /// + public string FileObjectName { get; set; } + + /// + /// 标签 + /// + public int Label { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } + +} diff --git a/Magic.Core/Service/Trash/ITrashService.cs b/Magic.Core/Service/Trash/ITrashService.cs new file mode 100644 index 0000000..6e736d6 --- /dev/null +++ b/Magic.Core/Service/Trash/ITrashService.cs @@ -0,0 +1,10 @@ + +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +namespace Magic.Core.Service; + +public interface ITrashService +{ + Task Delete(DeleteDocumentInput input); + Task Page([FromQuery] DocumentInput input); +} diff --git a/Magic.Core/Service/Trash/TrashService.cs b/Magic.Core/Service/Trash/TrashService.cs new file mode 100644 index 0000000..a7935fa --- /dev/null +++ b/Magic.Core/Service/Trash/TrashService.cs @@ -0,0 +1,186 @@ + +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Furion.EventBus; +using Furion.FriendlyException; +using Magic.Core.Entity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using SqlSugar; +using System; +using System.Linq; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +/// +/// 回收站服务 +/// +[ApiDescriptionSettings(Name = "Trash", Order = 150)] +public class TrashService : ITrashService, IDynamicApiController, ITransient +{ + private readonly SqlSugarRepository _rep; + private readonly IDocumentService _documentService; + private readonly IEventPublisher _eventPublisher; + private readonly ILogger _logger; + public TrashService(ILogger logger, SqlSugarRepository rep, IDocumentService documentService, IEventPublisher eventPublisher) + { + this._logger = logger; + _rep = rep; + this._documentService = documentService; + this._eventPublisher = eventPublisher; + } + #region API + /// + /// 分页查询回收站 + /// + /// + /// + [HttpGet("/Trash/page")] + public async Task Page([FromQuery] DocumentInput input) + { + input.IsDelete = true; + input.PId = null; + var result = await _documentService.Page(input); + return result; + } + + + /// + /// 恢复一个 + /// + /// + /// + [HttpPost("/Trash/recover")] + public async Task Recover(DeleteDocumentInput input) + { + var entity = await _rep.AsQueryable().Filter(null, true).Where(it => it.Id == input.Id).FirstAsync(); + if (entity != null) + { + var exist = await _rep.AnyAsync(it => it.PId == entity.PId && it.Name == entity.Name); + if (exist) + { + if (entity.DocumentType == DocumentType.Folder) + { + entity.Name += $"({ DateTime.Now.ToString("yyyyMMddHHmmss")})";//如果是文件夹直接后面加 + } + else + { + var sp = entity.Name.Split("."); + entity.Name = $"({sp[0]}{ DateTime.Now.ToString("yyyyMMddHHmmss")}).{sp[1]}"; + } + } + entity.IsDeleted = false; + await _rep.UpdateAsync(entity); + } + else + { + throw Oops.Oh("ErrorMessage.E404"); + } + } + + /// + /// 恢复多个 + /// + /// + /// + [HttpPost("/Trash/recovers")] + public async Task Recovers(DeletesDocumentInput input) + { + var documents = await _rep.AsQueryable().Filter(null, true).Where(it => input.Ids.Contains(it.Id)).ToListAsync(); + var docGroup = documents.GroupBy(it => it.PId).ToList(); + docGroup.ForEach(it => + { + var docs = it.ToList(); + var i = 0; + docs.ForEach(doc => + { + var document = documents.Where(u => u.Id == doc.Id).First(); + var existDb = _rep.Any(it => it.PId == doc.PId && it.Name == doc.Name);//先判断数据库有没有重名 + var exist = docs.Any(it => it.Id != doc.Id && it.Name == doc.Name);//判断列表有没有重名 + if (existDb || exist) + { + document.Name = Ren(doc.Name, i); + } + document.IsDeleted = false; + i++; + }); + }); + await _rep.UpdateAsync(documents); + } + + + /// + /// 永久删除 + /// + /// + /// + [HttpPost("/Trash/delete")] + public async Task Delete(DeleteDocumentInput input) + { + var file = await _rep.AsQueryable().Filter(null, true).Where(u => u.Id == input.Id).FirstAsync(); + if (file != null) + { + file.Visible = false; + await _rep.UpdateAsync(file);//删除当前 + //await _eventPublisher.PublishAsync(new ChannelEventSource(ZxzyConst.Event_Doc_Delete, file));//事件总线里删除子集 + } + else + { + throw Oops.Oh("ErrorMessage.E404"); + } + + } + + /// + ///批量删除 + /// + /// + /// + [HttpPost("/Trash/deletes")] + public async Task Deletes(DeletesDocumentInput input) + { + await _rep.UpdateAsync(it => input.Ids.Contains(it.Id), it => new Documentation + { + Visible = false + });//删除当前 + //await _eventPublisher.PublishAsync(new ChannelEventSource(ZxzyConst.Event_Doc_Deletes, input.Ids));//事件总线里删除子集 + } + + /// + /// 清空 + /// + /// + [HttpPost("/Trash/empty")] + public async Task Empty() + { + await _rep.UpdateAsync(it => it.IsDeleted == true,it=>new Documentation { + Visible = false + });//删除当前 + //await _eventPublisher.PublishAsync(new ChannelEventSource(ZxzyConst.Event_Doc_Empty));//事件总线里删除子集 + } + #endregion + #region 方法 + + + /// + /// 重命名 + /// + /// + /// + /// + [NonAction] + private string Ren(string name, int i) + { + if (i == 0) + { + return name + $"({DateTime.Now.ToString("yyyyMMddHHmmss")})"; + } + else + { + return name + $"({DateTime.Now.ToString("yyyyMMddHHmmss")})({i})"; + } + + } + #endregion +} diff --git a/Magic.Core/Service/User/Dto/AuthToken.cs b/Magic.Core/Service/User/Dto/AuthToken.cs new file mode 100644 index 0000000..55dd398 --- /dev/null +++ b/Magic.Core/Service/User/Dto/AuthToken.cs @@ -0,0 +1,26 @@ +namespace Magic.Core.Service; + +/// +/// AuthToken参数 +/// +public class AuthToken +{ + public string AccessToken { get; set; } + public int ExpireIn { get; set; } + public string RefreshToken { get; set; } + public string Uid { get; set; } + public string OpenId { get; set; } + public string AccessCode { get; set; } + public string UnionId { get; set; } + public string Scope { get; set; } + public string TokenType { get; set; } + public string IdToken { get; set; } + public string MacAlgorithm { get; set; } + public string MacKey { get; set; } + public string Code { get; set; } + public string OauthToken { get; set; } + public string OauthTokenSecret { get; set; } + public string UserId { get; set; } + public string ScreenName { get; set; } + public bool OauthCallbackConfirmed { get; set; } +} diff --git a/Magic.Core/Service/User/Dto/AuthUserInput.cs b/Magic.Core/Service/User/Dto/AuthUserInput.cs new file mode 100644 index 0000000..63bf266 --- /dev/null +++ b/Magic.Core/Service/User/Dto/AuthUserInput.cs @@ -0,0 +1,21 @@ +namespace Magic.Core.Service; + +/// +/// OAuth用户参数 +/// +public class AuthUserInput +{ + public string Uuid { get; set; } + public string Username { get; set; } + public string Nickname { get; set; } + public string Avatar { get; set; } + public string Blog { get; set; } + public string Company { get; set; } + public string Location { get; set; } + public string Email { get; set; } + public string Eemark { get; set; } + public Gender Gender { get; set; } + public string Source { get; set; } + public AuthToken Token { get; set; } + public string RawUserInfo { get; set; } +} diff --git a/Magic.Core/Service/User/Dto/UserInput.cs b/Magic.Core/Service/User/Dto/UserInput.cs new file mode 100644 index 0000000..ac25741 --- /dev/null +++ b/Magic.Core/Service/User/Dto/UserInput.cs @@ -0,0 +1,162 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Magic.Core.Service; + +/// +/// 用户参数 +/// +public class UserInput : InputBase +{ + /// + /// 账号 + /// + public virtual string Account { get; set; } + + /// + /// 密码 + /// + public virtual string Password { get; set; } + + /// + /// 昵称 + /// + public virtual string NickName { get; set; } + + /// + /// 姓名 + /// + public virtual string Name { get; set; } + + /// + /// 头像 + /// + public virtual string Avatar { get; set; } + + /// + /// 生日 + /// + public virtual DateTime? Birthday { get; set; } + + /// + /// 性别-男_1、女_2 + /// + public virtual int Sex { get; set; } + + /// + /// 邮箱 + /// + public virtual string Email { get; set; } + + /// + /// 手机 + /// + public virtual string Phone { get; set; } + + /// + /// 电话 + /// + public virtual string Tel { get; set; } + + /// + /// 状态-正常_0、停用_1、删除_2 + /// + public virtual CommonStatus Status { get; set; } + + /// + /// 员工信息 + /// + public EmpOutput2 SysEmpParam { get; set; } = new EmpOutput2(); + + /// + /// 搜索状态(字典 0正常 1停用 2删除) + /// + public CommonStatus SearchStatus { get; set; } = CommonStatus.ENABLE; +} + +public class AddUserInput : UserInput +{ + /// + /// 账号 + /// + [Required(ErrorMessage = "账号名称不能为空")] + public override string Account { get; set; } + + /// + /// 密码 + /// + [Required(ErrorMessage = "密码不能为空")] + public override string Password { get; set; } + + /// + /// 确认密码 + /// + [Required(ErrorMessage = "确认密码不能为空"), Compare(nameof(Password), ErrorMessage = "两次密码不一致")] + public string Confirm { get; set; } +} + +public class DeleteUserInput : UserInput +{ + /// + /// 用户Id + /// + [Required(ErrorMessage = "用户Id不能为空")] + public long Id { get; set; } +} + +public class UpdateUserInput : UserInput +{ + /// + /// 用户Id + /// + [Required(ErrorMessage = "用户Id不能为空")] + public long Id { get; set; } +} + +public class QueryUserInput : UpdateUserInput +{ + +} + +public class ChangePasswordUserInput +{ + /// + /// 用户Id + /// + [Required(ErrorMessage = "用户Id不能为空")] + public long Id { get; set; } + + /// + /// 密码 + /// + [Required(ErrorMessage = "旧密码不能为空")] + public string Password { get; set; } + + /// + /// 新密码 + /// + [Required(ErrorMessage = "新密码不能为空")] + [StringLength(32, MinimumLength = 5, ErrorMessage = "密码需要大于5个字符")] + public string NewPassword { get; set; } + + /// + /// 确认密码 + /// + [Required(ErrorMessage = "确认密码不能为空"), Compare(nameof(NewPassword), ErrorMessage = "两次密码不一致")] + public string Confirm { get; set; } +} + +public class UploadAvatarInput +{ + /// + /// 用户Id + /// + [Required(ErrorMessage = "用户Id不能为空")] + public long Id { get; set; } + + /// + /// 头像文件路径标识 + /// + [Required(ErrorMessage = "头像文件路径标识不能为空")] + public long Avatar { get; set; } +} diff --git a/Magic.Core/Service/User/Dto/UserOutput.cs b/Magic.Core/Service/User/Dto/UserOutput.cs new file mode 100644 index 0000000..69fe960 --- /dev/null +++ b/Magic.Core/Service/User/Dto/UserOutput.cs @@ -0,0 +1,76 @@ +using System; + +namespace Magic.Core.Service; + +/// +/// 用户参数 +/// +public class UserOutput +{ + /// + /// Id + /// + public virtual string Id { get; set; } + + /// + /// 账号 + /// + public virtual string Account { get; set; } + + /// + /// 昵称 + /// + public virtual string NickName { get; set; } + + /// + /// 姓名 + /// + public virtual string Name { get; set; } + + /// + /// 头像 + /// + public virtual string Avatar { get; set; } + + /// + /// 生日 + /// + public virtual DateTime Birthday { get; set; } + + /// + /// 性别-男_1、女_2 + /// + public virtual int Sex { get; set; } + + /// + /// 邮箱 + /// + public virtual string Email { get; set; } + + /// + /// 手机 + /// + public virtual string Phone { get; set; } + + /// + /// 电话 + /// + public virtual string Tel { get; set; } + + /// + /// 状态-正常_0、停用_1、删除_2 + /// + public virtual int Status { get; set; } + + /// + /// 员工信息 + /// + public EmpOutput SysEmpInfo { get; set; } + + /// + /// 所属租户 + /// + public long? TenantId { get; set; } + + public string TenantName { get; set; } +} diff --git a/Magic.Core/Service/User/ISysUserDataScopeService.cs b/Magic.Core/Service/User/ISysUserDataScopeService.cs new file mode 100644 index 0000000..c2b3446 --- /dev/null +++ b/Magic.Core/Service/User/ISysUserDataScopeService.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ISysUserDataScopeService +{ + Task DeleteUserDataScopeListByOrgIdList(List orgIdList); + Task DeleteUserDataScopeListByUserId(long userId); + Task> GetUserDataScopeIdList(long userId); + Task GrantData(UpdateUserInput input); +} diff --git a/Magic.Core/Service/User/ISysUserRoleService.cs b/Magic.Core/Service/User/ISysUserRoleService.cs new file mode 100644 index 0000000..582ed2e --- /dev/null +++ b/Magic.Core/Service/User/ISysUserRoleService.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ISysUserRoleService +{ + Task DeleteUserRoleListByRoleId(long roleId); + Task DeleteUserRoleListByUserId(long userId); + Task> GetUserRoleDataScopeIdList(long userId, long orgId); + Task> GetUserRoleIdList(long userId); + Task GrantRole(UpdateUserInput input); +} diff --git a/Magic.Core/Service/User/ISysUserService.cs b/Magic.Core/Service/User/ISysUserService.cs new file mode 100644 index 0000000..0c6482f --- /dev/null +++ b/Magic.Core/Service/User/ISysUserService.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +public interface ISysUserService +{ + Task AddUser(AddUserInput input); + Task ChangeUserStatus(UpdateUserInput input); + Task DeleteUser(DeleteUserInput input); + Task ExportUser([FromQuery] UserInput input); + Task ImportUser(IFormFile file); + Task GetUser([FromQuery] QueryUserInput input); + Task GetUserById(long userId); + Task> GetUserDataScopeIdList(long userId = 0); + Task GetUserOwnData([FromQuery] QueryUserInput input); + Task GetUserOwnRole([FromQuery] QueryUserInput input); + Task GetUserSelector([FromQuery] UserInput input); + Task GrantUserData(UpdateUserInput input); + Task GrantUserRole(UpdateUserInput input); + Task QueryUserPageList([FromQuery] UserInput input); + Task ResetUserPwd(QueryUserInput input); + Task SaveAuthUserToUser(AuthUserInput authUser, UserInput sysUser); + Task UpdateAvatar(UploadAvatarInput input); + Task UpdateUser(UpdateUserInput input); + Task UpdateUserInfo(UpdateUserInput input); + Task UpdateUserPwd(ChangePasswordUserInput input); + Task> GetDataScopeIdUserList(long userId = 0); + void CheckDataScopeByUserId(long userId); + void CheckDataScope(long orgId); +} diff --git a/Magic.Core/Service/User/SysUserDataScopeService.cs b/Magic.Core/Service/User/SysUserDataScopeService.cs new file mode 100644 index 0000000..6552303 --- /dev/null +++ b/Magic.Core/Service/User/SysUserDataScopeService.cs @@ -0,0 +1,86 @@ + + +using Furion.DependencyInjection; +using Magic.Core.Entity; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +/// +/// 用户数据范围服务 +/// +public class SysUserDataScopeService : ISysUserDataScopeService, ITransient +{ + private readonly SqlSugarRepository _sysUserDataScopeRep; // 用户数据范围表仓储 + + public SysUserDataScopeService(SqlSugarRepository sysUserDataScopeRep) + { + _sysUserDataScopeRep = sysUserDataScopeRep; + } + + /// + /// 授权用户数据 + /// + /// + /// + public async Task GrantData(UpdateUserInput input) + { + try + { + _sysUserDataScopeRep.CurrentBeginTran(); + await _sysUserDataScopeRep.DeleteAsync(u => u.SysUserId == input.Id); + var grantOrgIdList = new List(); + input.GrantOrgIdList.ForEach(u => + { + grantOrgIdList.Add( + new SysUserDataScope + { + SysUserId = input.Id, + SysOrgId = u + }); + }); + await _sysUserDataScopeRep.InsertAsync(grantOrgIdList); + _sysUserDataScopeRep.CurrentCommitTran(); + } + catch (System.Exception) + { + _sysUserDataScopeRep.CurrentRollbackTran(); + throw; + } + + + } + + /// + /// 获取用户的数据范围Id集合 + /// + /// + /// + public async Task> GetUserDataScopeIdList(long userId) + { + return await _sysUserDataScopeRep + .Where(u => u.SysUserId == userId) + .Select(u => u.SysOrgId).ToListAsync(); + } + + /// + /// 根据机构Id集合删除对应的用户-数据范围关联信息 + /// + /// + /// + public async Task DeleteUserDataScopeListByOrgIdList(List orgIdList) + { + await _sysUserDataScopeRep.DeleteAsync(u => orgIdList.Contains(u.SysOrgId)); + } + + /// + /// 根据用户Id删除对应的用户-数据范围关联信息 + /// + /// + /// + public async Task DeleteUserDataScopeListByUserId(long userId) + { + await _sysUserDataScopeRep.DeleteAsync(u => u.SysUserId == userId); + } +} diff --git a/Magic.Core/Service/User/SysUserRoleService.cs b/Magic.Core/Service/User/SysUserRoleService.cs new file mode 100644 index 0000000..39f7689 --- /dev/null +++ b/Magic.Core/Service/User/SysUserRoleService.cs @@ -0,0 +1,108 @@ + + +using Furion.DependencyInjection; +using Magic.Core.Entity; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.Core.Service; + +/// +/// 用户角色服务 +/// +public class SysUserRoleService : ISysUserRoleService, ITransient +{ + private readonly SqlSugarRepository _sysUserRoleRep; // 用户权限表仓储 + + private readonly ISysRoleService _sysRoleService; + private readonly ISysCacheService _sysCacheService; + + public SysUserRoleService(SqlSugarRepository sysUserRoleRep, ISysRoleService sysRoleService,ISysCacheService sysCacheService) + { + _sysUserRoleRep = sysUserRoleRep; + _sysRoleService = sysRoleService; + _sysCacheService = sysCacheService; + } + + /// + /// 获取用户的角色Id集合 + /// + /// + /// + public async Task> GetUserRoleIdList(long userId) + { + return await _sysUserRoleRep.Where(u => u.SysUserId == userId).Select(u => u.SysRoleId).ToListAsync(); + } + + /// + /// 授权用户角色 + /// + /// + /// + public async Task GrantRole(UpdateUserInput input) + { + try + { + _sysUserRoleRep.CurrentBeginTran(); + await _sysUserRoleRep.DeleteAsync(u => u.SysUserId == input.Id); + var grantRoleIdList = new List(); + input.GrantRoleIdList.ForEach(u => + { + grantRoleIdList.Add( + new SysUserRole + { + SysUserId = input.Id, + SysRoleId = u + }); + }); + await _sysUserRoleRep.InsertAsync(grantRoleIdList); + _sysUserRoleRep.CurrentCommitTran(); + //清除缓存 + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_MENU); + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_PERMISSION); + } + catch (System.Exception) + { + _sysUserRoleRep.CurrentRollbackTran(); + throw; + } + + } + + /// + /// 获取用户所有角色的数据范围(组织机构Id集合) + /// + /// + /// + /// + public async Task> GetUserRoleDataScopeIdList(long userId, long orgId) + { + var roleIdList = await GetUserRoleIdList(userId); + + // 获取这些角色对应的数据范围 + if (roleIdList.Count > 0) + return await _sysRoleService.GetUserDataScopeIdList(roleIdList, orgId); + + return roleIdList; + } + + /// + /// 根据角色Id删除对应的用户-角色表关联信息 + /// + /// + /// + public async Task DeleteUserRoleListByRoleId(long roleId) + { + await _sysUserRoleRep.DeleteAsync(u => u.SysRoleId == roleId); + } + + /// + /// 根据用户Id删除对应的用户-角色表关联信息 + /// + /// + /// + public async Task DeleteUserRoleListByUserId(long userId) + { + await _sysUserRoleRep.DeleteAsync(u => u.SysUserId == userId); + } +} diff --git a/Magic.Core/Service/User/SysUserService.cs b/Magic.Core/Service/User/SysUserService.cs new file mode 100644 index 0000000..cfdc401 --- /dev/null +++ b/Magic.Core/Service/User/SysUserService.cs @@ -0,0 +1,535 @@ + +using Furion.DataEncryption; +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Furion.FriendlyException; +using Magic.Core.Entity; +using Mapster; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using MiniExcelLibs; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Yitter.IdGenerator; + +namespace Magic.Core.Service; + +/// +/// 用户服务 +/// +[ApiDescriptionSettings(Name = "User", Order = 150)] +public class SysUserService : ISysUserService, IDynamicApiController, ITransient +{ + private readonly SqlSugarRepository _sysUserRep; // 用户表仓储 + + private readonly ISysCacheService _sysCacheService; + private readonly ISysConfigService _sysConfigService; + private readonly ISysEmpService _sysEmpService; + private readonly ISysUserDataScopeService _sysUserDataScopeService; + private readonly ISysUserRoleService _sysUserRoleService; + + public SysUserService(SqlSugarRepository sysUserRep, + ISysCacheService sysCacheService, + ISysEmpService sysEmpService, + ISysUserDataScopeService sysUserDataScopeService, + ISysUserRoleService sysUserRoleService, + ISysConfigService sysConfigService) + { + _sysUserRep = sysUserRep; + _sysCacheService = sysCacheService; + _sysEmpService = sysEmpService; + _sysUserDataScopeService = sysUserDataScopeService; + _sysUserRoleService = sysUserRoleService; + _sysConfigService = sysConfigService; + } + + /// + /// 分页查询用户 + /// + /// + /// + [HttpGet("/sysUser/page")] + public async Task QueryUserPageList([FromQuery] UserInput input) + { + var superAdmin = UserManager.IsSuperAdmin; + var searchValue = input.SearchValue; + var pid = input.SysEmpParam.OrgId; + var users = await _sysUserRep.AsQueryable().InnerJoin((u, e) => u.Id == e.Id) + .InnerJoin((u, e, o)=> e.OrgId == o.Id) + .InnerJoin((u, e, o, t) => u.TenantId == t.Id) + .WhereIF(!string.IsNullOrWhiteSpace(searchValue), (u, e, o) => u.Account.Contains(input.SearchValue.Trim()) || + u.Name.Contains(input.SearchValue.Trim()) || + u.Phone.Contains(input.SearchValue.Trim())) + .WhereIF(!string.IsNullOrWhiteSpace(pid), (u, e, o) => e.OrgId == long.Parse(pid) || + o.Pids.Contains(pid.Trim())) + .WhereIF(Enum.IsDefined(typeof(CommonStatus), input.SearchStatus), (u, e, o) => u.Status == input.SearchStatus) + .Where((u, e, o) => u.AdminType == AdminType.None) + .Select("u.*,t.Name As TenantName ").ToDataFilter("u","Id",FilterType.User).ToPagedListAsync(input.PageNo, input.PageSize); + + var empInfos =await _sysEmpService.GetEmpInfo(users.Items.Select(m => long.Parse(m.Id)).ToList()); + foreach (var user in users.Items) + { + user.SysEmpInfo = empInfos.FirstOrDefault(m => m.Id == long.Parse(user.Id)); + } + + //foreach (var user in users.Items) + //{ + // user.SysEmpInfo = await _sysEmpService.GetEmpInfo(long.Parse(user.Id)); + //} + return users.XnPagedResult(); + } + + /// + /// 增加用户 + /// + /// + /// + [HttpPost("/sysUser/add")] + public async Task AddUser(AddUserInput input) + { + // 数据范围检查 + CheckDataScope(input.SysEmpParam == null || string.IsNullOrEmpty(input.SysEmpParam.OrgId) ? 0 : long.Parse(input.SysEmpParam.OrgId)); + + var isExist = await _sysUserRep.AnyAsync(u => u.Account == input.Account); + if (isExist) throw Oops.Oh(ErrorCode.D1003); + + var user = input.Adapt(); + user.AdminType = AdminType.None; + user.Password = MD5Encryption.Encrypt(input.Password); + if (string.IsNullOrEmpty(user.Name)) + user.Name = user.Account; + if (string.IsNullOrEmpty(user.NickName)) + user.NickName = user.Account; + + try + { + _sysUserRep.CurrentBeginTran(); + var newUser = await _sysUserRep.InsertReturnEntityAsync(user); + input.SysEmpParam.Id = newUser.Id.ToString(); + // 增加员工信息 + await _sysEmpService.AddOrUpdate(input.SysEmpParam); + _sysUserRep.CurrentCommitTran(); + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_USERSDATASCOPE); + } + catch (Exception) + { + _sysUserRep.CurrentRollbackTran(); + throw; + } + + + } + + /// + /// 删除用户 + /// + /// + /// + [HttpPost("/sysUser/delete")] + public async Task DeleteUser(DeleteUserInput input) + { + var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Id == input.Id); + if (user.AdminType != AdminType.None) + throw Oops.Oh(ErrorCode.D1014); + + if (user.Account == UserManager.Account) + { + throw Oops.Oh(ErrorCode.D1001); + } + + // 数据范围检查 + CheckDataScopeByUserId(input.Id); + + try + { + _sysUserRep.CurrentBeginTran(); + // 直接删除用户 + await _sysUserRep.AsUpdateable(new SysUser {IsDeleted = true}).UpdateColumns(user.FalseDeleteColumn()).Where(wh => wh.Id == user.Id).ExecuteCommandAsync(); + + // 删除员工及附属机构职位信息 + await _sysEmpService.DeleteEmpInfoByUserId(user.Id); + + //删除该用户对应的用户-角色表关联信息 + await _sysUserRoleService.DeleteUserRoleListByUserId(user.Id); + + //删除该用户对应的用户-数据范围表关联信息 + await _sysUserDataScopeService.DeleteUserDataScopeListByUserId(user.Id); + _sysUserRep.CurrentCommitTran(); + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_USERSDATASCOPE); + } + catch (Exception) + { + _sysUserRep.CurrentRollbackTran(); + throw; + } + + + + } + + /// + /// 更新用户 + /// + /// + /// + [HttpPost("/sysUser/edit")] + public async Task UpdateUser(UpdateUserInput input) + { + // 数据范围检查 + CheckDataScopeByUserId(input.Id); + + // 排除自己并且判断与其他是否相同 + var isExist = await _sysUserRep.AnyAsync(u => u.Account == input.Account && u.Id != input.Id); + if (isExist) throw Oops.Oh(ErrorCode.D1003); + + var user = input.Adapt(); + + try + { + _sysUserRep.CurrentBeginTran(); + await _sysUserRep.AsUpdateable(user).IgnoreColumns(it => new { it.Password, it.Status, it.AdminType }).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync(); + input.SysEmpParam.Id = user.Id.ToString(); + // 更新员工及附属机构职位信息 + await _sysEmpService.AddOrUpdate(input.SysEmpParam); + _sysUserRep.CurrentCommitTran(); + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_USERSDATASCOPE); + } + catch (Exception) + { + _sysUserRep.CurrentRollbackTran(); + throw; + } + + + } + + /// + /// 查看用户 + /// + /// + /// + [HttpGet("/sysUser/detail")] + public async Task GetUser([FromQuery] QueryUserInput input) + { + var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Id == input.Id); + var userDto = user.Adapt(); + if (userDto != null) + { + userDto.SysEmpInfo = await _sysEmpService.GetEmpInfo(user.Id); + } + return userDto; + } + + /// + /// 修改用户状态 + /// + /// + /// + [HttpPost("/sysUser/changeStatus")] + public async Task ChangeUserStatus(UpdateUserInput input) + { + var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Id == input.Id); + if (user.AdminType == AdminType.SuperAdmin) + throw Oops.Oh(ErrorCode.D1015); + + if (!Enum.IsDefined(typeof(CommonStatus), input.Status)) + throw Oops.Oh(ErrorCode.D3005); + user.Status = input.Status; + await _sysUserRep.AsUpdateable(user).ExecuteCommandAsync(); + } + + /// + /// 授权用户角色 + /// + /// + /// + [HttpPost("/sysUser/grantRole")] + public async Task GrantUserRole(UpdateUserInput input) + { + // 数据范围检查 + CheckDataScopeByUserId(input.Id); + await _sysUserRoleService.GrantRole(input); + } + + /// + /// 授权用户数据范围 + /// + /// + /// + [HttpPost("/sysUser/grantData")] + public async Task GrantUserData(UpdateUserInput input) + { + // 清除缓存 + await _sysCacheService.DelAsync(CommonConst.CACHE_KEY_DATASCOPE + $"{input.Id}"); + await _sysCacheService.DelAsync(CommonConst.CACHE_KEY_USERSDATASCOPE + $"{input.Id}"); + // 数据范围检查 + CheckDataScopeByUserId(input.Id); + await _sysUserDataScopeService.GrantData(input); + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_USERSDATASCOPE); + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_DATASCOPE); + } + + /// + /// 更新用户信息 + /// + /// + /// + [HttpPost("/sysUser/updateInfo")] + public async Task UpdateUserInfo(UpdateUserInput input) + { + var user = input.Adapt(); + await _sysUserRep.AsUpdateable(user) + .IgnoreColumns(ignoreAllNullColumns: true) + .IgnoreColumns(it => new { it.AdminType, it.LastLoginTime }) + .ExecuteCommandAsync(); + await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_USERSDATASCOPE); + } + + /// + /// 修改用户密码 + /// + /// + /// + [HttpPost("/sysUser/updatePwd")] + public async Task UpdateUserPwd(ChangePasswordUserInput input) + { + var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Id == input.Id); + if (MD5Encryption.Encrypt(input.Password) != user.Password) + throw Oops.Oh(ErrorCode.D1004); + user.Password = MD5Encryption.Encrypt(input.NewPassword); + await _sysUserRep.AsUpdateable(user).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync(); + } + + /// + /// 获取用户拥有角色 + /// + /// + /// + [HttpGet("/sysUser/ownRole")] + public async Task GetUserOwnRole([FromQuery] QueryUserInput input) + { + return await _sysUserRoleService.GetUserRoleIdList(input.Id); + } + + /// + /// 获取用户拥有数据 + /// + /// + /// + [HttpGet("/sysUser/ownData")] + public async Task GetUserOwnData([FromQuery] QueryUserInput input) + { + return await _sysUserDataScopeService.GetUserDataScopeIdList(input.Id); + } + + /// + /// 重置用户密码 + /// + /// + /// + [HttpPost("/sysUser/resetPwd")] + public async Task ResetUserPwd(QueryUserInput input) + { + var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Id == input.Id); + user.Password = MD5Encryption.Encrypt(await _sysConfigService.GetDefaultPassword()); + await _sysUserRep.AsUpdateable(user).IgnoreColumns(it => new { it.AdminType }).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync(); + } + + /// + /// 修改用户头像 + /// + /// + /// + [HttpPost("/sysUser/updateAvatar")] + public async Task UpdateAvatar(UploadAvatarInput input) + { + var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Id == input.Id); + user.Avatar = input.Avatar.ToString(); + await _sysUserRep.AsUpdateable(user).IgnoreColumns(it => new { it.AdminType }).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync(); + } + + /// + /// 获取用户选择器 + /// + /// + /// + [HttpGet("/sysUser/selector")] + public async Task GetUserSelector([FromQuery] UserInput input) + { + return await _sysUserRep.AsQueryable() + .WhereIF(!string.IsNullOrWhiteSpace(input.Name), u => (u.Name.Contains(input.Name.Trim()))) + .Where(u => u.Status != CommonStatus.DELETED) + .Where(u => u.AdminType != AdminType.SuperAdmin) + .Select(u => new + { + u.Id, + u.Name + }).ToListAsync(); + } + + /// + /// 用户导出 + /// + /// + /// + [HttpGet("/sysUser/export")] + public async Task ExportUser([FromQuery] UserInput input) + { + + //这里如果报错看下AdminType的值 不能是0,必须是在枚举值内的 + var users = await _sysUserRep.ToListAsync(); + if(!users.Any()) + throw Oops.Oh("没有数据"); + var memoryStream = new MemoryStream(); + memoryStream.SaveAs(users); + memoryStream.Seek(0, SeekOrigin.Begin); + return await Task.FromResult(new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") + { + FileDownloadName = "user.xlsx" + }); + } + + /// + /// 用户导入 + /// + /// + /// + [HttpPost("/sysUser/import")] + public async Task ImportUser(IFormFile file) + { + var path = Path.Combine(Path.GetTempPath(), $"{YitIdHelper.NextId()}.xlsx"); + using (var stream = File.Create(path)) + { + await file.CopyToAsync(stream); + } + throw Oops.Oh("请自行完善入库操作"); + + //var rows = MiniExcel.Query(path); // 解析 + //foreach (var row in rows) + //{ + // var a = row.A; + // var b = row.B; + // // 入库等操作 + + //} + } + + /// + /// 根据用户Id获取用户 + /// + /// + /// + [NonAction] + public async Task GetUserById(long userId) + { + return await _sysUserRep.FirstOrDefaultAsync(u => u.Id == userId); + } + + /// + /// 将OAuth账号转换成账号 + /// + /// + /// + /// + [NonAction] + public async Task SaveAuthUserToUser(AuthUserInput authUser, UserInput sysUser) + { + var user = sysUser.Adapt(); + user.AdminType = AdminType.None; // 非管理员 + + // oauth账号与系统账号判断 + var isExist = await _sysUserRep.AnyAsync(u => u.Account == authUser.Username); + user.Account = isExist ? authUser.Username + DateTime.Now.Ticks : authUser.Username; + user.Name = user.NickName = authUser.Nickname; + user.Email = authUser.Email; + user.Sex = authUser.Gender; + await _sysUserRep.InsertAsync(user); + } + + /// + /// 获取用户数据范围(机构Id集合)并缓存 + /// + /// + /// + [NonAction] + public async Task> GetUserDataScopeIdList(long userId = 0) + { + userId = userId <= 0 ? UserManager.UserId : userId; + var dataScopes = await _sysCacheService.GetDataScope(userId); // 先从缓存里面读取 + if (dataScopes == null || dataScopes.Count < 1) + { + if (!UserManager.IsSuperAdmin && !UserManager.IsTenantAdmin) + { + var orgId = await _sysEmpService.GetEmpOrgId(userId); + // 获取该用户对应的数据范围集合 + var userDataScopeIdListForUser = await _sysUserDataScopeService.GetUserDataScopeIdList(userId); + // 获取该用户的角色对应的数据范围集合 + var userDataScopeIdListForRole = await _sysUserRoleService.GetUserRoleDataScopeIdList(userId, orgId); + dataScopes = userDataScopeIdListForUser.Concat(userDataScopeIdListForRole).Distinct().ToList(); // 并集 + } + else + { + dataScopes = await _sysUserRep.Change().AsQueryable().Select(u => u.Id).ToListAsync(); + } + await _sysCacheService.SetDataScope(userId, dataScopes); // 缓存结果 + } + return dataScopes; + } + + /// + /// 检查普通用户数据范围 + /// + /// + /// + [NonAction] + public async void CheckDataScope(long orgId) + { + // 如果当前用户不是超级管理员,则进行数据范围校验 + if (!UserManager.IsSuperAdmin) + { + var dataScopes = await GetUserDataScopeIdList(UserManager.UserId); + if (dataScopes == null ||orgId <= 0|| !dataScopes.Contains(orgId)) + throw Oops.Oh(ErrorCode.D1013); + } + } + /// + /// 获取用户数据范围(用户Id集合) + /// + /// + [NonAction] + public async Task> GetDataScopeIdUserList(long userId = 0) + { + userId = userId<=0? UserManager.UserId: userId; + var list = await _sysCacheService.GetUsersDataScope(userId); // 先从缓存里面读取 + if (list == null || list.Count < 1) + { + var dataScopes = await GetUserDataScopeIdList(userId); + list = (await _sysEmpService.HasOrgEmp(dataScopes)).Select(a => a.Id).ToList(); + list.Add(userId); + list = list.Distinct().ToList(); + await _sysCacheService.SetUsersDataScope(userId, list); // 缓存结果 + } + return list; + } + + /// + /// 检查普通用户数据范围 + /// + /// + /// + [NonAction] + public async void CheckDataScopeByUserId(long userId) + { + // 如果当前用户不是超级管理员,则进行数据范围校验 + if (!UserManager.IsSuperAdmin) + { + var dataScopes = await GetDataScopeIdUserList(UserManager.UserId); + if (dataScopes == null || userId <= 0 || !dataScopes.Contains(userId)) + throw Oops.Oh(ErrorCode.D1013); + } + } +} diff --git a/Magic.Core/SimpleQueue/SimpleQueue.cs b/Magic.Core/SimpleQueue/SimpleQueue.cs new file mode 100644 index 0000000..8d8e4d7 --- /dev/null +++ b/Magic.Core/SimpleQueue/SimpleQueue.cs @@ -0,0 +1,53 @@ + +using System.Collections.Concurrent; + +namespace Magic.Core; + +/// +/// 简单泛型队列 +/// +public static class SimpleQueue where T : new() +{ + private static ConcurrentQueue _simpleQueue; + + static SimpleQueue() + { + _simpleQueue = new ConcurrentQueue(); + } + + /// + /// 新增 + /// + /// + public static void Add(T obj) + { + _simpleQueue.Enqueue(obj); + } + + /// + /// 取出 + /// + /// + /// + public static bool Try(out T obj) + { + return _simpleQueue.TryDequeue(out obj); + } + + /// + /// 总数 + /// + /// + public static int Count() + { + return _simpleQueue.Count; + } + + /// + /// 清理 + /// + public static void Clear() + { + _simpleQueue.Clear(); + } +} diff --git a/Magic.Core/SqlSugar/SqlSugarPagedList.cs b/Magic.Core/SqlSugar/SqlSugarPagedList.cs new file mode 100644 index 0000000..95dcfe6 --- /dev/null +++ b/Magic.Core/SqlSugar/SqlSugarPagedList.cs @@ -0,0 +1,52 @@ +using System.Collections.Generic; + +namespace Magic.Core; + +/// +/// 分页泛型集合 +/// +/// +public class SqlSugarPagedList +{ + /// + /// 页码 + /// + public int PageIndex { get; set; } + + /// + /// 页容量 + /// + public int PageSize { get; set; } + + /// + /// 总条数 + /// + public int TotalCount { get; set; } + + /// + /// 总页数 + /// + public int TotalPages { get; set; } + + /// + /// 当前页集合 + /// + public IEnumerable Items { get; set; } + + /// + /// 是否有上一页 + /// + public bool HasPrevPages { get; set; } + + /// + /// 是否有下一页 + /// + public bool HasNextPages { get; set; } +} + +/// +/// 分页集合 +/// +public class PagedModel : SqlSugarPagedList +{ +} diff --git a/Magic.Core/SqlSugar/SqlSugarRepository.cs b/Magic.Core/SqlSugar/SqlSugarRepository.cs new file mode 100644 index 0000000..d204619 --- /dev/null +++ b/Magic.Core/SqlSugar/SqlSugarRepository.cs @@ -0,0 +1,666 @@ +using Furion; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading.Tasks; + +namespace Magic.Core; + +/// +/// SqlSugar 仓储实现类 +/// +/// +public partial class SqlSugarRepository +where TEntity : class, new() +{ + private readonly string[] UpdateIgnoreColumns=new string[] { "CreatedTime", "CreatedUserId", "CreatedUserName" }; + + #region 属性 + /// + /// 初始化 SqlSugar 客户端 + /// + private readonly SqlSugarScope _db; + + /// + /// 数据库上下文 + /// + public virtual SqlSugarScope Context { get; } + /// + /// 独立数据库上下文 + /// + public virtual SqlSugarProvider EntityContext { get; } + /// + /// 构造函数 + /// + /// + public SqlSugarRepository(ISqlSugarClient db) + { + Context = _db = (SqlSugarScope)db; + EntityContext = _db.GetConnectionWithAttr(); + Ado = EntityContext.Ado; + } + /// + /// 实体集合 + /// + public virtual ISugarQueryable Entities => EntityContext.Queryable(); + + /// + /// 原生 Ado 对象 + /// + public virtual IAdo Ado { get; } + #endregion + + #region 查询 + /// + /// 获取总数 + /// + /// + /// + public int Count(Expression> whereExpression) + { + return Entities.Count(whereExpression); + } + + /// + /// 获取总数 + /// + /// + /// + public Task CountAsync(Expression> whereExpression) + { + return Entities.CountAsync(whereExpression); + } + + /// + /// 检查是否存在 + /// + /// + /// + public bool Any(Expression> whereExpression) + { + return Entities.Any(whereExpression); + } + + /// + /// 检查是否存在 + /// + /// + /// + public async Task AnyAsync(Expression> whereExpression) + { + return await Entities.AnyAsync(whereExpression); + } + + /// + /// 通过主键获取实体 + /// + /// + /// + public TEntity Single(dynamic Id) + { + return Entities.InSingle(Id); + } + + /// + /// 获取一个实体 + /// + /// + /// + public TEntity Single(Expression> whereExpression) + { + return Entities.Single(whereExpression); + } + + /// + /// 获取一个实体 + /// + /// + /// + public Task SingleAsync(Expression> whereExpression) + { + return Entities.SingleAsync(whereExpression); + } + + /// + /// 获取一个实体 + /// + /// + /// + public TEntity FirstOrDefault(Expression> whereExpression) + { + return Entities.First(whereExpression); + } + + /// + /// 获取一个实体 + /// + /// + /// + public async Task FirstOrDefaultAsync(Expression> whereExpression) + { + return await Entities.FirstAsync(whereExpression); + } + + /// + /// 获取列表 + /// + /// + public List ToList() + { + return Entities.ToList(); + } + + /// + /// 获取列表 + /// + /// + /// + public List ToList(Expression> whereExpression) + { + return Entities.Where(whereExpression).ToList(); + } + + /// + /// 获取列表 + /// + /// + /// + /// + /// + public List ToList(Expression> whereExpression, Expression> orderByExpression = null, OrderByType orderByType = OrderByType.Asc) + { + return Entities.OrderByIF(orderByExpression != null, orderByExpression, orderByType).Where(whereExpression).ToList(); + } + + /// + /// 获取列表 + /// + /// + public Task> ToListAsync() + { + return Entities.ToListAsync(); + } + + /// + /// 获取列表 + /// + /// + /// + public Task> ToListAsync(Expression> whereExpression) + { + return Entities.Where(whereExpression).ToListAsync(); + } + + /// + /// 获取列表 + /// + /// + /// + /// + /// + public Task> ToListAsync(Expression> whereExpression, Expression> orderByExpression = null, OrderByType orderByType = OrderByType.Asc) + { + return Entities.OrderByIF(orderByExpression != null, orderByExpression, orderByType).Where(whereExpression).ToListAsync(); + } + #endregion + + #region 新增 + public virtual IInsertable AsInsertable(TEntity entity) + { + return EntityContext.Insertable(entity); + } + + public virtual IInsertable AsInsertable(params TEntity[] entities) + { + return EntityContext.Insertable(entities); + } + + /// + /// 新增一条记录 + /// + /// + /// + public virtual int Insert(TEntity entity) + { + return EntityContext.Insertable(entity).ExecuteCommand(); + } + + /// + /// 新增多条记录 + /// + /// + /// + public virtual int Insert(params TEntity[] entities) + { + return EntityContext.Insertable(entities).ExecuteCommand(); + } + + /// + /// 新增多条记录 + /// + /// + /// + public virtual int Insert(IEnumerable entities) + { + return EntityContext.Insertable(entities.ToArray()).ExecuteCommand(); + } + + /// + /// 新增一条记录返回自增Id + /// + /// + /// + public virtual int InsertReturnIdentity(TEntity insertObj) + { + return EntityContext.Insertable(insertObj).ExecuteReturnIdentity(); + } + + /// + /// 新增一条记录返回雪花Id + /// + /// + /// + public virtual long InsertReturnSnowflakeId(TEntity entity) + { + return EntityContext.Insertable(entity).ExecuteReturnSnowflakeId(); + } + + /// + /// 新增一条记录返回实体 + /// + /// + /// + public virtual TEntity InsertReturnEntity(TEntity entity) + { + return EntityContext.Insertable(entity).ExecuteReturnEntity(); + } + + + + /// + /// 新增一条记录 + /// + /// + /// + public virtual Task InsertAsync(TEntity entity) + { + return EntityContext.Insertable(entity).ExecuteCommandAsync(); + } + + /// + /// 新增多条记录 + /// + /// + /// + public virtual Task InsertAsync(params TEntity[] entities) + { + return EntityContext.Insertable(entities).ExecuteCommandAsync(); + } + + /// + /// 新增多条记录 + /// + /// + /// + public virtual Task InsertAsync(IEnumerable entities) + { + if (entities != null && entities.Any()) + { + return EntityContext.Insertable(entities.ToArray()).ExecuteCommandAsync(); + } + return Task.FromResult(0); + } + + /// + /// 新增一条记录返回自增Id + /// + /// + /// + public virtual async Task InsertReturnIdentityAsync(TEntity entity) + { + return await EntityContext.Insertable(entity).ExecuteReturnBigIdentityAsync(); + } + + /// + /// 新增一条记录返回雪花Id + /// + /// + /// + public virtual async Task InsertReturnSnowflakeIdAsync(TEntity entity) + { + return await EntityContext.Insertable(entity).ExecuteReturnSnowflakeIdAsync(); + } + + /// + /// 新增一条记录返回实体 + /// + /// + /// + public virtual async Task InsertReturnEntityAsync(TEntity entity) + { + return await EntityContext.Insertable(entity).ExecuteReturnEntityAsync(); + } + #endregion + + #region 更新 + + /// + /// 更新一条记录 + /// + /// + /// + public virtual int Update(TEntity entity) + { + return EntityContext.Updateable(entity).IgnoreColumns(UpdateIgnoreColumns).ExecuteCommand(); + } + + /// + /// 更新多条记录 + /// + /// + /// + public virtual int Update(params TEntity[] entities) + { + return EntityContext.Updateable(entities).IgnoreColumns(UpdateIgnoreColumns).ExecuteCommand(); + } + /// + /// 更新多条记录 + /// + /// + /// + public virtual int Update(IEnumerable entities) + { + return EntityContext.Updateable(entities.ToArray()).IgnoreColumns(UpdateIgnoreColumns).ExecuteCommand(); + } + + /// + /// 更新一条记录 + /// + /// + /// + public virtual async Task UpdateAsync(TEntity entity) + { + return await EntityContext.Updateable(entity).IgnoreColumns(UpdateIgnoreColumns).ExecuteCommandAsync(); + } + /// + /// 更新记录 + /// + /// 更新的条件 + /// 更新的内容 + /// + public virtual int Update(Expression> predicate, Expression> content) + { + return EntityContext.Updateable(content).Where(predicate).IgnoreColumns(UpdateIgnoreColumns).ExecuteCommand(); + } + + /// + /// 更新记录 + /// + /// 更新的条件 + /// 更新的内容 + /// + public virtual async Task UpdateAsync(Expression> predicate, Expression> content) + { + return await EntityContext.Updateable(content).Where(predicate).IgnoreColumns(UpdateIgnoreColumns).ExecuteCommandAsync(); + } + + /// + /// 更新多条记录 + /// + /// + /// + public virtual Task UpdateAsync(params TEntity[] entities) + { + return EntityContext.Updateable(entities).IgnoreColumns(UpdateIgnoreColumns).ExecuteCommandAsync(); + } + + /// + /// 更新多条记录 + /// + /// + /// + public virtual Task UpdateAsync(IEnumerable entities) + { + return EntityContext.Updateable(entities.ToArray()).IgnoreColumns(UpdateIgnoreColumns).ExecuteCommandAsync(); + } + + public virtual IUpdateable AsUpdateable(TEntity entity) + { + return EntityContext.Updateable(entity).IgnoreColumns(UpdateIgnoreColumns); + } + + public virtual IUpdateable AsUpdateable(IEnumerable entities) + { + return EntityContext.Updateable(entities).IgnoreColumns(UpdateIgnoreColumns); + } + #endregion + + #region 删除 + /// + /// 删除一条记录 + /// + /// + /// + public virtual int Delete(TEntity entity) + { + return EntityContext.Deleteable(entity).ExecuteCommand(); + } + + /// + /// 删除一条记录 + /// + /// + /// + public virtual int Delete(object key) + { + return EntityContext.Deleteable().In(key).ExecuteCommand(); + } + + /// + /// 删除多条记录 + /// + /// + /// + public virtual int Delete(params object[] keys) + { + return EntityContext.Deleteable().In(keys).ExecuteCommand(); + } + + /// + /// 自定义条件删除记录 + /// + /// + /// + public int Delete(Expression> whereExpression) + { + return EntityContext.Deleteable().Where(whereExpression).ExecuteCommand(); + } + + /// + /// 删除一条记录 + /// + /// + /// + public virtual Task DeleteAsync(TEntity entity) + { + return EntityContext.Deleteable(entity).ExecuteCommandAsync(); + } + + /// + /// 删除一条记录 + /// + /// + /// + public virtual Task DeleteAsync(object key) + { + return EntityContext.Deleteable().In(key).ExecuteCommandAsync(); + } + + /// + /// 删除多条记录 + /// + /// + /// + public virtual Task DeleteAsync(params object[] keys) + { + return EntityContext.Deleteable().In(keys).ExecuteCommandAsync(); + } + + /// + /// 自定义条件删除记录 + /// + /// + /// + public async Task DeleteAsync(Expression> whereExpression) + { + return await EntityContext.Deleteable().Where(whereExpression).ExecuteCommandAsync(); + } + #endregion + + #region 其他 + /// + /// 根据表达式查询多条记录 + /// + /// + /// + public virtual ISugarQueryable Where(Expression> predicate) + { + return AsQueryable(predicate); + } + + /// + /// 根据表达式查询多条记录 + /// + /// + /// + /// + public virtual ISugarQueryable Where(bool condition, Expression> predicate) + { + return AsQueryable().WhereIF(condition, predicate); + } + + /// + /// 构建查询分析器 + /// + /// + public virtual ISugarQueryable AsQueryable() + { + return Entities; + } + + /// + /// 构建查询分析器 + /// + /// + /// + public virtual ISugarQueryable AsQueryable(Expression> predicate) + { + return Entities.Where(predicate); + } + + /// + /// 直接返回数据库结果 + /// + /// + public virtual List AsEnumerable() + { + return AsQueryable().ToList(); + } + + /// + /// 直接返回数据库结果 + /// + /// + /// + public virtual List AsEnumerable(Expression> predicate) + { + return AsQueryable(predicate).ToList(); + } + + /// + /// 直接返回数据库结果 + /// + /// + public virtual Task> AsAsyncEnumerable() + { + return AsQueryable().ToListAsync(); + } + + /// + /// 直接返回数据库结果 + /// + /// + /// + public virtual Task> AsAsyncEnumerable(Expression> predicate) + { + return AsQueryable(predicate).ToListAsync(); + } + + public virtual bool IsExists(Expression> whereExpression) + { + return Entities.Any(whereExpression); + } + + public virtual Task IsExistsAsync(Expression> whereExpression) + { + return Entities.AnyAsync(whereExpression); + } + #endregion + + #region 仓储事务 + /// + /// 切换仓储(注意使用环境) + /// + /// 实体类型 + /// 仓储 + public virtual SqlSugarRepository Change() + where T : class, new() + { + return App.GetService>(); + } + /// + /// 当前db + /// + public void CurrentBeginTran() + { + Ado.BeginTran(); + } + /// + /// 当前db + /// + public void CurrentCommitTran() + { + Ado.CommitTran(); + } + /// + /// 当前db + /// + public void CurrentRollbackTran() + { + Ado.RollbackTran(); + } + /// + /// 所有db + /// + public void BeginTran() + { + Context.BeginTran(); + } + /// + /// 所有db + /// + public void CommitTran() + { + Context.CommitTran(); + } + /// + /// 所有db + /// + public void RollbackTran() + { + Context.RollbackTran(); + } + #endregion +} diff --git a/Magic.Core/SqlSugar/SqlSugarSetup.cs b/Magic.Core/SqlSugar/SqlSugarSetup.cs new file mode 100644 index 0000000..bb4302a --- /dev/null +++ b/Magic.Core/SqlSugar/SqlSugarSetup.cs @@ -0,0 +1,460 @@ +using Furion; +using Furion.Logging.Extensions; +using Magic.Core.Entity; +using Microsoft.Extensions.DependencyInjection; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Linq.Dynamic.Core; +using System.Linq.Expressions; + +namespace Magic.Core; + +public static class SqlSugarSetup +{ + //public static void SqlSugarConfigure(this IServiceCollection services) + //{ + // #region 配置sqlsuagr + // List connectConfigList = new List(); + // //数据库序号从0开始,默认数据库为0 + // var config = App.GetOptions(); + // //默认数据库 + // connectConfigList.Add(new ConnectionConfig + // { + // ConnectionString = config.DefaultDbString, + // DbType = (DbType)Convert.ToInt32(Enum.Parse(typeof(DbType), config.DefaultDbType)), + // IsAutoCloseConnection = true, + // ConfigId = config.DefaultDbNumber, + // InitKeyType = InitKeyType.Attribute, + // MoreSettings = new ConnMoreSettings() + // { + // IsAutoRemoveDataCache = true//自动清理缓存 + + // }, + // ConfigureExternalServices = new ConfigureExternalServices() + // { + // EntityNameService = (type, entity) => + // { + // var attributes = type.GetCustomAttributes(true); + // if (attributes.Any(it => it is TableAttribute)) + // { + // entity.DbTableName = (attributes.First(it => it is TableAttribute) as TableAttribute).Name; + // } + // }, + // EntityService = (type, column) => + // { + // var attributes = type.GetCustomAttributes(true); + // if (attributes.Any(it => it is KeyAttribute))// by attribute set primarykey + // { + // column.IsPrimarykey = true; //有哪些特性可以看 1.2 特性明细 + // } + // if (attributes.Any(it => it is ColumnAttribute)) + // { + // column.DbColumnName = (attributes.First(it => it is ColumnAttribute) as ColumnAttribute).Name; + // } + // } + // } + + // }); + // if (config.DbConfigs == null) + // config.DbConfigs = new List(); + // //业务数据库集合 + // foreach (var item in config.DbConfigs) + // { + // //防止数据库重复,导致的事务异常 + // if (connectConfigList.Any(a => a.ConfigId == (dynamic)item.DbNumber || a.ConnectionString == item.DbString)) + //{ + // continue; + //} + // connectConfigList.Add(new ConnectionConfig + // { + // ConnectionString = item.DbString, + // DbType = (DbType)Convert.ToInt32(Enum.Parse(typeof(DbType), item.DbType)), + // IsAutoCloseConnection = true, + // ConfigId = item.DbNumber, + // InitKeyType = InitKeyType.Attribute, + // MoreSettings = new ConnMoreSettings() + // { + // IsAutoRemoveDataCache = true//自动清理缓存 + // } + // }); + // } + // List types = App.EffectiveTypes.Where(a => !a.IsAbstract && a.IsClass && a.GetCustomAttributes(typeof(SugarTable), true)?.FirstOrDefault() != null).ToList(); + // //sugar action + // Action configure = db => + // { + // connectConfigList.ForEach(config => { + // string temp = config.ConfigId; + // var _db = db.AsTenant().GetConnection(temp); + // _db.CurrentConnectionConfig.ConfigureExternalServices = new ConfigureExternalServices() + // { + // DataInfoCacheService = new SqlSugarCache()//配置我们创建的缓存类 + // }; + // //执行超时时间 + // _db.Ado.CommandTimeOut = 30; + // _db.Aop.OnLogExecuting = (sql, pars) => + // { + // if (sql.StartsWith("SELECT")) + // { + // Console.ForegroundColor = ConsoleColor.Green; + // } + // if (sql.StartsWith("UPDATE") || sql.StartsWith("INSERT")) + // { + // Console.ForegroundColor = ConsoleColor.White; + // } + // if (sql.StartsWith("DELETE")) + // { + // Console.ForegroundColor = ConsoleColor.Blue; + // } + // //App.PrintToMiniProfiler("SqlSugar", "Info", sql + "\r\n" + _db.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value))); + // Console.WriteLine("Sql:" + "\r\n\r\n" + UtilMethods.GetSqlString(db.CurrentConnectionConfig.DbType, sql, pars)); + // App.PrintToMiniProfiler("SqlSugar", "Info", UtilMethods.GetSqlString(db.CurrentConnectionConfig.DbType, sql, pars)); + // }; + + + // _db.Aop.DataExecuting = (oldValue, entityInfo) => + // { + // // 新增操作 + // if (entityInfo.OperationType == DataFilterType.InsertByObject) + // { + // // 主键(long)-赋值雪花Id + // if (entityInfo.EntityColumnInfo.IsPrimarykey && entityInfo.EntityColumnInfo.PropertyInfo.PropertyType == typeof(long)) { + // var id = ((dynamic)entityInfo.EntityValue).Id; + // if (id == null || id == 0) + // entityInfo.SetValue(Yitter.IdGenerator.YitIdHelper.NextId()); + // } + + + // if (entityInfo.PropertyName == "CreatedTime") + // entityInfo.SetValue(DateTime.Now); + // if (App.User != null) + // { + // if (entityInfo.PropertyName == "TenantId") + // { + // var tenantId = ((dynamic)entityInfo.EntityValue).TenantId; + // if (tenantId == null || tenantId == 0) + // entityInfo.SetValue(App.User.FindFirst(ClaimConst.TENANT_ID)?.Value); + // } + // if (entityInfo.PropertyName == "CreatedUserId") { + // var createUserId = ((dynamic)entityInfo.EntityValue).CreatedUserId; + // if (createUserId == null || createUserId == 0) + // entityInfo.SetValue(App.User.FindFirst(ClaimConst.CLAINM_USERID)?.Value); + // } + + // if (entityInfo.PropertyName == "CreatedUserName") + // entityInfo.SetValue(App.User.FindFirst(ClaimConst.CLAINM_NAME)?.Value); + // //if (entityInfo.PropertyName == "CreateOrgId") + // // entityInfo.SetValue(App.User.FindFirst(ClaimConst.OrgId)?.Value); + // } + // } + // // 更新操作 + // if (entityInfo.OperationType == DataFilterType.UpdateByObject) + // { + // if (entityInfo.PropertyName == "UpdatedTime") + // entityInfo.SetValue(DateTime.Now); + // if (entityInfo.PropertyName == "UpdatedUserId") + // entityInfo.SetValue(App.User?.FindFirst(ClaimConst.CLAINM_USERID)?.Value); + // if (entityInfo.PropertyName == "UpdatedUserName") + // entityInfo.SetValue(App.User?.FindFirst(ClaimConst.CLAINM_NAME)?.Value); + + // } + // }; + + // //全局过滤器 + // var superAdminViewAllData = Convert.ToBoolean(App.GetOptions().SuperAdminViewAllData); + // foreach (var entityType in types) + // { + // // 配置多租户全局过滤器 + // if (!entityType.GetProperty(ClaimConst.TENANT_ID).IsEmpty()) + // { //判断实体类中包含TenantId属性 + // //构建动态Lambda + // var lambda = DynamicExpressionParser.ParseLambda + // (new[] { Expression.Parameter(entityType, "it") }, + // typeof(bool), $"{nameof(DBEntityTenant.TenantId)} == @0 or (@1 and @2)", + // GetTenantId(), IsSuperAdmin(), superAdminViewAllData); + // _db.QueryFilter.Add(new TableFilterItem(entityType, lambda)); //将Lambda传入过滤器 + // } + // // 配置加删除全局过滤器 + // if (!entityType.GetProperty(CommonConst.DELETE_FIELD).IsEmpty()) + // { //判断实体类中包含IsDeleted属性 + // //构建动态Lambda + // var lambda = DynamicExpressionParser.ParseLambda + // (new[] { Expression.Parameter(entityType, "it") }, + // typeof(bool), $"{nameof(DEntityBase.IsDeleted)} == @0", + // false); + // _db.QueryFilter.Add(new TableFilterItem(entityType, lambda) + // { + // IsJoinQuery = true + // }); //将Lambda传入过滤器 + // } + // } + // }); + // }; + // services.AddSqlSugar(connectConfigList, configure); + // #endregion + //} + + + /// + /// SqlsugarScope的配置 + /// Scope必须用单例注入 + /// 不可以用Action委托注入 + /// + /// + public static void SqlSugarScopeConfigure(this IServiceCollection services) + { + //数据库序号从0开始,默认数据库为0 + var config = App.GetConfig("ConnectionStrings",true); + + //默认数据库 + List dbList = new List(); + DbConfig defaultdb = new DbConfig() + { + DbNumber = config.DefaultDbNumber, + DbString = config.DefaultDbString, + DbType = config.DefaultDbType + }; + dbList.Add(defaultdb); + //业务数据库集合 + foreach (var item in config.DbConfigs) + { + dbList.Add(item); + } + + List connectConfigList = new List(); + + foreach (var item in dbList) + { + //防止数据库重复,导致的事务异常 + if (connectConfigList.Any(a => a.ConfigId == (dynamic)item.DbNumber || a.ConnectionString == item.DbString)) + { + continue; + } + connectConfigList.Add(new ConnectionConfig() + { + ConnectionString = item.DbString, + DbType = (DbType)Convert.ToInt32(Enum.Parse(typeof(DbType), item.DbType)), + IsAutoCloseConnection = true, + ConfigId = item.DbNumber, + InitKeyType = InitKeyType.Attribute, + MoreSettings = new ConnMoreSettings() + { + IsAutoRemoveDataCache = true//自动清理缓存 + + }, + ConfigureExternalServices = new ConfigureExternalServices() + { + DataInfoCacheService = new SqlSugarCache(), + EntityNameService = (type, entity) => + { + var attributes = type.GetCustomAttributes(true); + if (attributes.Any(it => it is TableAttribute)) + { + entity.DbTableName = (attributes.First(it => it is TableAttribute) as TableAttribute).Name; + } + }, + EntityService = (type, column) => + { + var attributes = type.GetCustomAttributes(true); + if (attributes.Any(it => it is KeyAttribute))// by attribute set primarykey + { + column.IsPrimarykey = true; //有哪些特性可以看 1.2 特性明细 + } + if (attributes.Any(it => it is ColumnAttribute)) + { + column.DbColumnName = (attributes.First(it => it is ColumnAttribute) as ColumnAttribute).Name; + } + } + } + }); + } + + List types = App.EffectiveTypes.Where(a => !a.IsAbstract && a.IsClass && a.GetCustomAttributes(typeof(SugarTable), true)?.FirstOrDefault() != null).ToList(); + + SqlSugarScope sqlSugarScope = new SqlSugarScope(connectConfigList, + //全局上下文生效 + db => + { + /* + * 默认只会配置到第一个数据库,这里按照官方文档进行多数据库/多租户文档的说明进行循环配置 + */ + foreach (var c in connectConfigList) + { + var dbProvider = db.GetConnectionScope((string)c.ConfigId); + //执行超时时间 + dbProvider.Ado.CommandTimeOut = 30; + + dbProvider.Aop.OnLogExecuting = (sql, pars) => + { + if (sql.StartsWith("SELECT")) + { + Console.ForegroundColor = ConsoleColor.Green; + } + if (sql.StartsWith("UPDATE") || sql.StartsWith("INSERT")) + { + Console.ForegroundColor = ConsoleColor.White; + } + if (sql.StartsWith("DELETE")) + { + Console.ForegroundColor = ConsoleColor.Blue; + } + //Console.WriteLine("Sql:" + "\r\n\r\n" + UtilMethods.GetSqlString(c.DbType, sql, pars)); + App.PrintToMiniProfiler("SqlSugar", "Info", UtilMethods.GetSqlString(c.DbType, sql, pars)); + $"DB:{c.ConfigId}, Sql:\r\n\r\n { UtilMethods.GetSqlString(c.DbType, sql, pars)}".LogInformation(); + + + }; + + dbProvider.Aop.DataExecuting = (oldValue, entityInfo) => + { + // 新增操作 + if (entityInfo.OperationType == DataFilterType.InsertByObject) + { + // 主键(long)-赋值雪花Id + if (entityInfo.EntityColumnInfo.IsPrimarykey && entityInfo.EntityColumnInfo.PropertyInfo.PropertyType == typeof(long)) + { + var id = ((dynamic)entityInfo.EntityValue).Id; + if (id == null || id == 0) + entityInfo.SetValue(Yitter.IdGenerator.YitIdHelper.NextId()); + } + + + if (entityInfo.PropertyName == "CreatedTime") + entityInfo.SetValue(DateTime.Now); + if (App.User != null) + { + if (entityInfo.PropertyName == "TenantId") + { + var tenantId = ((dynamic)entityInfo.EntityValue).TenantId; + if (tenantId == null || tenantId == 0) + entityInfo.SetValue(App.User.FindFirst(ClaimConst.TENANT_ID)?.Value); + } + if (entityInfo.PropertyName == "CreatedUserId") + { + var createUserId = ((dynamic)entityInfo.EntityValue).CreatedUserId; + if (createUserId == null || createUserId == 0) + entityInfo.SetValue(App.User.FindFirst(ClaimConst.CLAINM_USERID)?.Value); + } + + if (entityInfo.PropertyName == "CreatedUserName") + entityInfo.SetValue(App.User.FindFirst(ClaimConst.CLAINM_NAME)?.Value); + } + } + // 更新操作 + if (entityInfo.OperationType == DataFilterType.UpdateByObject) + { + if (entityInfo.PropertyName == "UpdatedTime") + entityInfo.SetValue(DateTime.Now); + if (entityInfo.PropertyName == "UpdatedUserId") + entityInfo.SetValue(App.User?.FindFirst(ClaimConst.CLAINM_USERID)?.Value); + if (entityInfo.PropertyName == "UpdatedUserName") + entityInfo.SetValue(App.User?.FindFirst(ClaimConst.CLAINM_NAME)?.Value); + + } + }; + + /* + * 使用 SqlSugarScope 循环配置此项的时候会覆盖整个 ConfigureExternalServices, + * 移动到 New ConnectionConfig中配置 + */ + //db.CurrentConnectionConfig.ConfigureExternalServices = new ConfigureExternalServices() + //{ + // DataInfoCacheService = new SqlSugarCache()//配置我们创建的缓存类 + //}; + + //全局过滤器 + var superAdminViewAllData = Convert.ToBoolean(App.GetOptions().SuperAdminViewAllData); + foreach (var entityType in types) + { + // 配置多租户全局过滤器 + if (!entityType.GetProperty(ClaimConst.TENANT_ID).IsEmpty()) + { //判断实体类中包含TenantId属性 + //构建动态Lambda + var lambda = DynamicExpressionParser.ParseLambda + (new[] { Expression.Parameter(entityType, "it") }, + typeof(bool), $"{nameof(DBEntityTenant.TenantId)} == @0 or (@1 and @2)", + GetTenantId(), IsSuperAdmin(), superAdminViewAllData); + dbProvider.QueryFilter.Add(new TableFilterItem(entityType, lambda)); //将Lambda传入过滤器 + } + // 配置加删除全局过滤器 + if (!entityType.GetProperty(CommonConst.DELETE_FIELD).IsEmpty()) + { //判断实体类中包含IsDeleted属性 + //构建动态Lambda + var lambda = DynamicExpressionParser.ParseLambda + (new[] { Expression.Parameter(entityType, "it") }, + typeof(bool), $"{nameof(DEntityBase.IsDeleted)} == @0", + false); + dbProvider.QueryFilter.Add(new TableFilterItem(entityType, lambda) + { + IsJoinQuery = true + }); //将Lambda传入过滤器 + } + } + + } + }); + services.AddSingleton(sqlSugarScope); + // 注册 SqlSugar 仓储 + services.AddScoped(typeof(SqlSugarRepository<>)); + } + + + + /// + /// 获取当前租户id + /// + /// + private static object GetTenantId() + { + if (App.User == null) return null; + return App.User.FindFirst(ClaimConst.TENANT_ID)?.Value; + } + + /// + /// 判断是不是超级管理员 + /// + /// + private static bool IsSuperAdmin() + { + if (App.User == null) return false; + return App.User.FindFirst(ClaimConst.CLAINM_SUPERADMIN)?.Value == AdminType.SuperAdmin.GetHashCode().ToString(); + } + /// + /// 添加 SqlSugar 拓展 + /// + /// + /// + /// + /// + public static IServiceCollection AddSqlSugar(this IServiceCollection services, ConnectionConfig config, Action buildAction = default) + { + var list = new List(); + list.Add(config); + return services.AddSqlSugar(list, buildAction); + } + + /// + /// 添加 SqlSugar 拓展 + /// + /// + /// + /// + /// + public static IServiceCollection AddSqlSugar(this IServiceCollection services, List configs, Action buildAction = default) + { + // 注册 SqlSugar 客户端 + services.AddScoped(u => + { + var db = new SqlSugarClient(configs); + buildAction?.Invoke(db); + return db; + }); + + // 注册 SqlSugar 仓储 + services.AddScoped(typeof(SqlSugarRepository<>)); + return services; + } +} diff --git a/Magic.Core/Util/CodeGenUtil.cs b/Magic.Core/Util/CodeGenUtil.cs new file mode 100644 index 0000000..3b580b4 --- /dev/null +++ b/Magic.Core/Util/CodeGenUtil.cs @@ -0,0 +1,100 @@ +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace Magic.Core; + +/// +/// 代码生成帮助类 +/// +public static class CodeGenUtil +{ + public static string ConvertDataType(string dataType) + { + switch (dataType) + { + case "text": + case "varchar": + case "char": + case "nvarchar": + case "nchar": + case "timestamp": + return "string"; + + case "int": + return "int"; + + case "smallint": + return "Int16"; + + case "tinyint": + return "byte"; + + case "bigint": + case "integer"://sqlite数据库 + return "long"; + + case "bit": + return "bool"; + + case "money": + case "smallmoney": + case "numeric": + case "decimal": + return "decimal"; + + case "real": + return "Single"; + + case "datetime": + case "smalldatetime": + return "DateTime"; + + case "float": + return "double"; + + case "image": + case "binary": + case "varbinary": + return "byte[]"; + + case "uniqueidentifier": + return "Guid"; + + default: + return "object"; + } + } + + /// + /// 数据类型转显示类型 + /// + /// + /// + public static string DataTypeToEff(string dataType) + { + if (string.IsNullOrEmpty(dataType)) return ""; + return dataType switch + { + "string" => "input", + "int" => "inputnumber", + "long" => "input", + "float" => "input", + "double" => "input", + "decimal" => "input", + "bool" => "switch", + "Guid" => "input", + "DateTime" => "datepicker", + _ => "input", + }; + } + + // 是否通用字段 + public static bool IsCommonColumn(string columnName) + { + var columnList = new List() + { + "CreatedTime", "UpdatedTime", "CreatedUserId", "CreatedUserName", "UpdatedUserId", "UpdatedUserName", "IsDeleted" + }; + return columnList.Contains(columnName); + } +} diff --git a/Magic.Core/Util/Enum/EnumEntity.cs b/Magic.Core/Util/Enum/EnumEntity.cs new file mode 100644 index 0000000..180fd86 --- /dev/null +++ b/Magic.Core/Util/Enum/EnumEntity.cs @@ -0,0 +1,22 @@ +namespace Magic.Core; + +/// +/// 枚举的Entity类 +/// +public class EnumEntity +{ + /// + /// 枚举的描述 + /// + public string Describe { set; get; } + + /// + /// 枚举名称 + /// + public string Name { set; get; } + + /// + /// 枚举对象的值 + /// + public int Value { set; get; } +} diff --git a/Magic.Core/Util/Enum/EnumUtil.cs b/Magic.Core/Util/Enum/EnumUtil.cs new file mode 100644 index 0000000..22df491 --- /dev/null +++ b/Magic.Core/Util/Enum/EnumUtil.cs @@ -0,0 +1,203 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection; + +namespace Magic.Core; + +/// +/// 枚举工具类 +/// +public static class EnumUtil +{ + // 枚举显示字典缓存 + private static readonly ConcurrentDictionary> EnumDisplayValueDict = new(); + + // 枚举值字典缓存 + private static readonly ConcurrentDictionary> EnumNameValueDict = new(); + + // 枚举类型缓存 + private static ConcurrentDictionary _enumTypeDict; + + /// + /// 获取枚举对象Key与名称的字典(缓存) + /// + /// + /// + public static Dictionary GetEnumDictionary(this Type enumType) + { + if (!enumType.IsEnum) + throw new ArgumentException("Type '" + enumType.Name + "' is not an enum."); + + // 查询缓存 + var enumDic = EnumNameValueDict.ContainsKey(enumType) ? EnumNameValueDict[enumType] : new Dictionary(); + if (enumDic.Count != 0) + return enumDic; + // 取枚举类型的Key/Value字典集合 + enumDic = GetEnumDictionaryItems(enumType); + + // 缓存 + EnumNameValueDict[enumType] = enumDic; + + return enumDic; + } + + /// + /// 获取枚举对象Key与名称的字典 + /// + /// + /// + private static Dictionary GetEnumDictionaryItems(this Type enumType) + { + // 获取类型的字段,初始化一个有限长度的字典 + var enumFields = enumType.GetFields(BindingFlags.Public | BindingFlags.Static); + Dictionary enumDic = new(enumFields.Length); + + // 遍历字段数组获取key和name + foreach (var enumField in enumFields) + { + var intValue = (int)enumField.GetValue(enumType); + enumDic[intValue] = enumField.Name; + } + + return enumDic; + } + + /// + /// 获取枚举类型key与描述的字典(缓存) + /// + /// + /// + /// + public static Dictionary GetEnumDescDictionary(this Type enumType) + { + if (!enumType.IsEnum) + throw new ArgumentException("Type '" + enumType.Name + "' is not an enum."); + + // 查询缓存 + var enumDic = EnumDisplayValueDict.ContainsKey(enumType) + ? EnumDisplayValueDict[enumType] + : new Dictionary(); + if (enumDic.Count != 0) + return enumDic; + // 取枚举类型的Key/Value字典集合 + enumDic = GetEnumDescDictionaryItems(enumType); + + // 缓存 + EnumDisplayValueDict[enumType] = enumDic; + + return enumDic; + } + + /// + /// 获取枚举类型key与描述的字典(没有描述则获取name) + /// + /// + /// + /// + private static Dictionary GetEnumDescDictionaryItems(this Type enumType) + { + // 获取类型的字段,初始化一个有限长度的字典 + var enumFields = enumType.GetFields(BindingFlags.Public | BindingFlags.Static); + Dictionary enumDic = new(enumFields.Length); + + // 遍历字段数组获取key和name + foreach (var enumField in enumFields) + { + var intValue = (int)enumField.GetValue(enumType); + var desc = enumField.GetDescriptionValue(); + enumDic[intValue] = desc != null && !string.IsNullOrEmpty(desc.Description) ? desc.Description : enumField.Name; + } + + return enumDic; + } + + /// + /// 从程序集中查找指定枚举类型 + /// + /// + /// + /// + public static Type TryToGetEnumType(Assembly assembly, string typeName) + { + // 枚举缓存为空则重新加载枚举类型字典 + _enumTypeDict ??= LoadEnumTypeDict(assembly); + + // 按名称查找 + return _enumTypeDict.ContainsKey(typeName) ? _enumTypeDict[typeName] : null; + } + + /// + /// 从程序集中加载所有枚举类型 + /// + /// + /// + private static ConcurrentDictionary LoadEnumTypeDict(Assembly assembly) + { + // 取程序集中所有类型 + var typeArray = assembly.GetTypes(); + + // 过滤非枚举类型,转成字典格式并返回 + var dict = typeArray.Where(o => o.IsEnum).ToDictionary(o => o.Name, o => o); + ConcurrentDictionary enumTypeDict = new(dict); + return enumTypeDict; + } + + /// + /// 获取枚举的Description + /// + /// + /// + public static string GetDescription(this System.Enum value) + { + return value.GetType().GetMember(value.ToString()).FirstOrDefault()?.GetCustomAttribute() + ?.Description; + } + + /// + /// 获取枚举的Description + /// + /// + /// + public static string GetDescription(this object value) + { + return value.GetType().GetMember(value.ToString() ?? string.Empty).FirstOrDefault() + ?.GetCustomAttribute()?.Description; + } + + /// + /// 将枚举转成枚举信息集合 + /// + /// + /// + public static List EnumToList(this Type type) + { + if (!type.IsEnum) + throw new ArgumentException("Type '" + type.Name + "' is not an enum."); + var arr = System.Enum.GetNames(type); + return arr.Select(sl => + { + var item = System.Enum.Parse(type, sl); + return new EnumEntity + { + Name = item.ToString(), Describe = item.GetDescription(), Value = item.GetHashCode() + }; + }).ToList(); + } + + /// + /// 枚举ToList + /// + /// + /// + /// + public static List EnumToList(this Type type) + { + if (!type.IsEnum) + throw new ArgumentException("Type '" + type.Name + "' is not an enum."); + var arr = System.Enum.GetNames(type); + return arr.Select(name => (T)System.Enum.Parse(type, name)).ToList(); + } +} diff --git a/Magic.Core/Util/Extension/Extension.DateTime.cs b/Magic.Core/Util/Extension/Extension.DateTime.cs new file mode 100644 index 0000000..f11ec6b --- /dev/null +++ b/Magic.Core/Util/Extension/Extension.DateTime.cs @@ -0,0 +1,200 @@ +using System; +using System.Globalization; + +namespace Magic.Core; + +/// +/// DateTime扩展 +/// +public static partial class Extensions +{ + /// + /// 得到问好 + /// + /// + public static string GetSayHello(this DateTime dateTime) + { + var hour = DateTime.Now.Hour; + return hour switch + { + < 6 => "凌晨好!", + < 9 => "早上好!", + < 12 => "上午好!", + < 14 => "中午好!", + < 17 => "下午好!", + < 19 => "傍晚好!", + < 22 => "晚上好!", + _ => "夜里好!" + }; + } + + /// + /// 获取指定年月的第一天 + /// + /// + /// + /// + /// + public static DateTime GetCurMonthFirstDay(this DateTime dateTime, string year, string mon) + { + var AssemblyDate = Convert.ToDateTime(year + "-" + mon + "-" + "01"); // 组装当前指定月份 + var result = AssemblyDate.AddDays(1 - AssemblyDate.Day); // 返回指定当前月份的第一天 + return new DateTime(result.Year, result.Month, result.Day, 0, 0, 0); + } + + /// + /// 获取指定年月的第一天 + /// + /// + /// + /// + /// + public static DateTime GetCurMonthFirstDay(this DateTime dateTime, int year, int mon) + { + var AssemblyDate = Convert.ToDateTime(year + "-" + mon + "-" + "01"); // 组装当前指定月份 + var result = AssemblyDate.AddDays(1 - AssemblyDate.Day); // 返回指定当前月份的第一天 + return new DateTime(result.Year, result.Month, result.Day, 0, 0, 0); + } + + /// + /// 获取指定年月的最后一天 + /// + /// + /// + /// + /// + public static DateTime GetCurMonthLastDay(this DateTime dateTime, string year, string mon) + { + var AssemblyDate = Convert.ToDateTime(year + "-" + mon + "-" + "01"); // 组装当前指定月份 + var result = AssemblyDate.AddDays(1 - AssemblyDate.Day).AddMonths(1).AddDays(-1); // 返回指定当前月份的最后一天 + return new DateTime(result.Year, result.Month, result.Day, 23, 59, 59); + } + + /// + /// 获取指定年月的最后一天 + /// + /// + /// + /// + /// + public static DateTime GetCurMonthLastDay(this DateTime dateTime, int year, int mon) + { + var AssemblyDate = Convert.ToDateTime(year + "-" + mon + "-" + "01"); // 组装当前指定月份 + var result = AssemblyDate.AddDays(1 - AssemblyDate.Day).AddMonths(1).AddDays(-1); // 返回指定当前月份的最后一天 + return new DateTime(result.Year, result.Month, result.Day, 23, 59, 59); + } + + /// + /// 获取当前月的第一天 + /// + /// + /// + public static DateTime GetCurMonthFirstDay(this DateTime dateTime) + { + // 第一种写法 + //DateTime CurDate =Convert.ToDateTime(DateTime.Now.ToString()); // 组装当前指定月份 + //return CurDate.AddDays(1 - CurDate.Day); // 返回指定当前月份的第一天 + + // 第二种写法 + var nowDate = DateTime.Now; + return new DateTime(nowDate.Year, nowDate.Month, 1, 0, 0, 0); // 该方法可以指定,年、月、日 + } + + /// + /// 获取当前月的最后一天 + /// + /// + /// + public static DateTime GetCurMonthLastDay(this DateTime dateTime) + { + var CurDate = Convert.ToDateTime(DateTime.Now.ToString(CultureInfo.InvariantCulture)); // 组装当前指定月份 + var result = CurDate.AddDays(1 - CurDate.Day).AddMonths(1).AddDays(-1); // 返回指定当前月份的最后一天 + return new DateTime(result.Year, result.Month, result.Day, 23, 59, 59); + } + + /// + /// 获取上月的第一天 + /// + /// + /// + public static DateTime GetUpMonthFirstDay(this DateTime dateTime) + { + var nowDate = DateTime.Now.AddMonths(-1); + return new DateTime(nowDate.Year, nowDate.Month, 1, 0, 0, 0); // 该方法可以指定,年、月、日 + } + + /// + /// 获取上月的最后一天 + /// + /// + /// + public static DateTime GetUpMonthLastDay(this DateTime dateTime) + { + var CurDate = Convert.ToDateTime(DateTime.Now.ToString(CultureInfo.InvariantCulture)); // 组装当前指定月份 + var result = CurDate.AddDays(1 - CurDate.Day).AddDays(-1); // 返回指定上月份的最后一天 + return new DateTime(result.Year, result.Month, result.Day, 23, 59, 59); + } + + /// + /// 获取本周时间 + /// + /// + /// + public static (DateTime startTime, DateTime lastTime) GetCurWeekDay(this DateTime dateTime) + { + var startTime = DateTime.Now.AddDays(0 - Convert.ToInt16(DateTime.Now.DayOfWeek) + 1); + var lastTime = DateTime.Now.AddDays(6 - Convert.ToInt16(DateTime.Now.DayOfWeek) + 1); + return (new DateTime(startTime.Year, startTime.Month, startTime.Day, 0, 0, 0), + new DateTime(lastTime.Year, lastTime.Month, lastTime.Day, 23, 59, 59)); + } + + /// + /// 获取上周时间 + /// + /// + /// + public static (DateTime startTime, DateTime lastTime) GetUpWeekDay(this DateTime dateTime) + { + var startTime = DateTime.Now.AddDays(0 - Convert.ToInt16(DateTime.Now.DayOfWeek) - 6); + var lastTime = DateTime.Now.AddDays(6 - Convert.ToInt16(DateTime.Now.DayOfWeek) - 6); + return (new DateTime(startTime.Year, startTime.Month, startTime.Day, 0, 0, 0), + new DateTime(lastTime.Year, lastTime.Month, lastTime.Day, 23, 59, 59)); + } + + /// + /// 获取当天时间 + /// + /// + /// + public static (DateTime startTime, DateTime lastTime) GetCurDay(this DateTime dateTime) + { + var dt = DateTime.Now; + return (new DateTime(dt.Year, dt.Month, dt.Day, 0, 0, 0), new DateTime(dt.Year, dt.Month, dt.Day, 23, 59, 59)); + } + + /// + /// 获取昨天时间 + /// + /// + /// + public static (DateTime startTime, DateTime lastTime) GetUpDay(this DateTime dateTime) + { + var dt = DateTime.Now.AddDays(-1); + return (new DateTime(dt.Year, dt.Month, dt.Day, 0, 0, 0), new DateTime(dt.Year, dt.Month, dt.Day, 23, 59, 59)); + } + + /// + /// 计算两个时间的差 + /// + /// + /// + /// + /// + public static int DateDiff(this DateTime dateTime, DateTime startTime, DateTime lastTime) + { + var start = Convert.ToDateTime(startTime.ToShortDateString()); + var end = Convert.ToDateTime(lastTime.ToShortDateString()); + var sp = end.Subtract(start); + return sp.Days; + } +} diff --git a/Magic.Core/Util/Extension/Extension.Validate.cs b/Magic.Core/Util/Extension/Extension.Validate.cs new file mode 100644 index 0000000..173953b --- /dev/null +++ b/Magic.Core/Util/Extension/Extension.Validate.cs @@ -0,0 +1,45 @@ +using System; +using Microsoft.AspNetCore.Http; + +namespace Magic.Core; + +/// +/// 验证扩展类 +/// +public static partial class Extensions +{ + /// + /// 检查 Object 是否为 NULL + /// + /// + /// + public static bool IsEmpty(this object value) + { + return value == null || string.IsNullOrEmpty(value.ParseToString()); + } + + /// + /// 检查 Object 是否为 NULL 或者 0 + /// + /// + /// + public static bool IsNullOrZero(this object value) + { + return value == null || value.ParseToString().Trim() == "0"; + } + + /// + /// 检查是否为 AJAX 请求 + /// + /// + /// + public static bool IsAjaxRequest(this HttpRequest request) + { + if (request == null) + throw new ArgumentNullException(nameof(request)); + + if (request.Headers != null) + return request.Headers["X-Requested-With"] == "XMLHttpRequest"; + return false; + } +} diff --git a/Magic.Core/Util/Extension/Extensions.cs b/Magic.Core/Util/Extension/Extensions.cs new file mode 100644 index 0000000..3c1c4a1 --- /dev/null +++ b/Magic.Core/Util/Extension/Extensions.cs @@ -0,0 +1,465 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; + +namespace Magic.Core; + +/// +/// 转换扩展类 +/// +public static partial class Extensions +{ + #region 转换为long + + /// + /// 将object转换为long,若转换失败,则返回0。不抛出异常。 + /// + /// + /// + public static long ParseToLong(this object obj) + { + try + { + return long.Parse(obj.ToString() ?? string.Empty); + } + catch + { + return 0L; + } + } + + /// + /// 将object转换为long,若转换失败,则返回指定值。不抛出异常。 + /// + /// + /// + /// + public static long ParseToLong(this string str, long defaultValue) + { + try + { + return long.Parse(str); + } + catch + { + return defaultValue; + } + } + + #endregion + + #region 转换为int + + /// + /// 将object转换为int,若转换失败,则返回0。不抛出异常。 + /// + /// + /// + public static int ParseToInt(this object str) + { + try + { + return Convert.ToInt32(str); + } + catch + { + return 0; + } + } + + /// + /// 将object转换为int,若转换失败,则返回指定值。不抛出异常。 + /// null返回默认值 + /// + /// + /// + /// + public static int ParseToInt(this object str, int defaultValue) + { + if (str == null) + { + return defaultValue; + } + + try + { + return Convert.ToInt32(str); + } + catch + { + return defaultValue; + } + } + + #endregion + + #region 转换为short + + /// + /// 将object转换为short,若转换失败,则返回0。不抛出异常。 + /// + /// + /// + public static short ParseToShort(this object obj) + { + try + { + return short.Parse(obj.ToString() ?? string.Empty); + } + catch + { + return 0; + } + } + + /// + /// 将object转换为short,若转换失败,则返回指定值。不抛出异常。 + /// + /// + /// + /// + public static short ParseToShort(this object str, short defaultValue) + { + try + { + return short.Parse(str.ToString() ?? string.Empty); + } + catch + { + return defaultValue; + } + } + + #endregion + + #region 转换为demical + + /// + /// 将object转换为demical,若转换失败,则返回指定值。不抛出异常。 + /// + /// + /// + /// + public static decimal ParseToDecimal(this object str, decimal defaultValue) + { + try + { + return decimal.Parse(str.ToString() ?? string.Empty); + } + catch + { + return defaultValue; + } + } + + /// + /// 将object转换为demical,若转换失败,则返回0。不抛出异常。 + /// + /// + /// + public static decimal ParseToDecimal(this object str) + { + try + { + return decimal.Parse(str.ToString() ?? string.Empty); + } + catch + { + return 0; + } + } + + #endregion + + #region 转化为bool + + /// + /// 将object转换为bool,若转换失败,则返回false。不抛出异常。 + /// + /// + /// + public static bool ParseToBool(this object str) + { + try + { + return bool.Parse(str.ToString() ?? string.Empty); + } + catch + { + return false; + } + } + + /// + /// 将object转换为bool,若转换失败,则返回指定值。不抛出异常。 + /// + /// + /// + /// + public static bool ParseToBool(this object str, bool result) + { + try + { + return bool.Parse(str.ToString() ?? string.Empty); + } + catch + { + return result; + } + } + + #endregion + + #region 转换为float + + /// + /// 将object转换为float,若转换失败,则返回0。不抛出异常。 + /// + /// + /// + public static float ParseToFloat(this object str) + { + try + { + return float.Parse(str.ToString() ?? string.Empty); + } + catch + { + return 0; + } + } + + /// + /// 将object转换为float,若转换失败,则返回指定值。不抛出异常。 + /// + /// + /// + /// + public static float ParseToFloat(this object str, float result) + { + try + { + return float.Parse(str.ToString() ?? string.Empty); + } + catch + { + return result; + } + } + + #endregion + + #region 转换为Guid + + /// + /// 将string转换为Guid,若转换失败,则返回Guid.Empty。不抛出异常。 + /// + /// + /// + public static Guid ParseToGuid(this string str) + { + try + { + return new Guid(str); + } + catch + { + return Guid.Empty; + } + } + + #endregion + + #region 转换为DateTime + + /// + /// 将string转换为DateTime,若转换失败,则返回日期最小值。不抛出异常。 + /// + /// + /// + public static DateTime ParseToDateTime(this string str) + { + try + { + if (string.IsNullOrWhiteSpace(str)) + { + return DateTime.MinValue; + } + + if (str.Contains("-") || str.Contains("/")) + { + return DateTime.Parse(str); + } + + var length = str.Length; + return length switch + { + 4 => DateTime.ParseExact(str, "yyyy", CultureInfo.CurrentCulture), + 6 => DateTime.ParseExact(str, "yyyyMM", CultureInfo.CurrentCulture), + 8 => DateTime.ParseExact(str, "yyyyMMdd", CultureInfo.CurrentCulture), + 10 => DateTime.ParseExact(str, "yyyyMMddHH", CultureInfo.CurrentCulture), + 12 => DateTime.ParseExact(str, "yyyyMMddHHmm", CultureInfo.CurrentCulture), + // ReSharper disable once StringLiteralTypo + 14 => DateTime.ParseExact(str, "yyyyMMddHHmmss", CultureInfo.CurrentCulture), + // ReSharper disable once StringLiteralTypo + _ => DateTime.ParseExact(str, "yyyyMMddHHmmss", CultureInfo.CurrentCulture) + }; + } + catch + { + return DateTime.MinValue; + } + } + + /// + /// 将string转换为DateTime,若转换失败,则返回默认值。 + /// + /// + /// + /// + public static DateTime ParseToDateTime(this string str, DateTime? defaultValue) + { + try + { + if (string.IsNullOrWhiteSpace(str)) + { + return defaultValue.GetValueOrDefault(); + } + + if (str.Contains("-") || str.Contains("/")) + { + return DateTime.Parse(str); + } + + var length = str.Length; + return length switch + { + 4 => DateTime.ParseExact(str, "yyyy", CultureInfo.CurrentCulture), + 6 => DateTime.ParseExact(str, "yyyyMM", CultureInfo.CurrentCulture), + 8 => DateTime.ParseExact(str, "yyyyMMdd", CultureInfo.CurrentCulture), + 10 => DateTime.ParseExact(str, "yyyyMMddHH", CultureInfo.CurrentCulture), + 12 => DateTime.ParseExact(str, "yyyyMMddHHmm", CultureInfo.CurrentCulture), + // ReSharper disable once StringLiteralTypo + 14 => DateTime.ParseExact(str, "yyyyMMddHHmmss", CultureInfo.CurrentCulture), + // ReSharper disable once StringLiteralTypo + _ => DateTime.ParseExact(str, "yyyyMMddHHmmss", CultureInfo.CurrentCulture) + }; + } + catch + { + return defaultValue.GetValueOrDefault(); + } + } + + #endregion + + #region 转换为string + + /// + /// 将object转换为string,若转换失败,则返回""。不抛出异常。 + /// + /// + /// + public static string ParseToString(this object obj) + { + try + { + return obj == null ? string.Empty : obj.ToString(); + } + catch + { + return string.Empty; + } + } + + /// + /// + /// + /// + /// + /// + public static string ParseToStrings(this object obj) + { + try + { + if (obj is IEnumerable list) + { + return string.Join(",", list); + } + + return obj.ToString(); + } + catch + { + return string.Empty; + } + } + + #endregion + + #region 转换为double + + /// + /// 将object转换为double,若转换失败,则返回0。不抛出异常。 + /// + /// + /// + public static double ParseToDouble(this object obj) + { + try + { + return double.Parse(obj.ToString() ?? string.Empty); + } + catch + { + return 0; + } + } + + /// + /// 将object转换为double,若转换失败,则返回指定值。不抛出异常。 + /// + /// + /// + /// + public static double ParseToDouble(this object str, double defaultValue) + { + try + { + return double.Parse(str.ToString() ?? string.Empty); + } + catch + { + return defaultValue; + } + } + + #endregion + + #region 强制转换类型 + + /// + /// 强制转换类型 + /// + /// + /// + /// + public static IEnumerable CastSuper(this IEnumerable source) + { + return from object item in source select (TResult)Convert.ChangeType(item, typeof(TResult)); + } + + #endregion + + #region 转换为ToUnixTime + + public static long ParseToUnixTime(this DateTime nowTime) + { + var startTime = new DateTime(1970, 1, 1, 0, 0, 0, 0); + return (long)Math.Round((nowTime - startTime).TotalMilliseconds, MidpointRounding.AwayFromZero); + } + + #endregion +} diff --git a/Magic.Core/Util/Http/HttpNewUtil.cs b/Magic.Core/Util/Http/HttpNewUtil.cs new file mode 100644 index 0000000..fb3a2a0 --- /dev/null +++ b/Magic.Core/Util/Http/HttpNewUtil.cs @@ -0,0 +1,387 @@ +using System; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; +using System.Web; +using Furion; +using Furion.RemoteRequest.Extensions; +using UAParser; + +namespace Magic.Core; + +/// +/// HTTP网络工具 +/// +public static class HttpNewUtil +{ + /// + /// 客户端IP地址 + /// + public static string Ip + { + get + { + var result = string.Empty; + if (App.HttpContext != null) + { + result = GetWebClientIp(); + } + + if (string.IsNullOrEmpty(result)) + { + result = GetLanIp(); + } + + return result; + } + } + + /// + /// 得到客户端IP地址 + /// + /// + private static string GetWebClientIp() + { + var ip = GetWebRemoteIp(); + foreach (var hostAddress in Dns.GetHostAddresses(ip)) + { + if (hostAddress.AddressFamily == AddressFamily.InterNetwork) + { + return hostAddress.ToString(); + } + } + + return string.Empty; + } + + /// + /// 得到局域网IP地址 + /// + /// + public static string GetLanIp() + { + foreach (var hostAddress in Dns.GetHostAddresses(Dns.GetHostName())) + { + if (hostAddress.AddressFamily == AddressFamily.InterNetwork) + { + return hostAddress.ToString(); + } + } + + return string.Empty; + } + + /// + /// 得到远程Ip地址 + /// + /// + private static string GetWebRemoteIp() + { + if (App.HttpContext?.Connection?.RemoteIpAddress == null) + return string.Empty; + var ip = App.HttpContext?.Connection?.RemoteIpAddress.ToString(); + if (App.HttpContext == null) + return ip; + if (App.HttpContext.Request.Headers.ContainsKey("X-Real-IP")) + { + ip = App.HttpContext.Request.Headers["X-Real-IP"].ToString(); + } + + if (App.HttpContext.Request.Headers.ContainsKey("X-Forwarded-For")) + { + ip = App.HttpContext.Request.Headers["X-Forwarded-For"].ToString(); + } + + return ip; + } + + /// + /// 请求UserAgent信息 + /// + public static string UserAgent + { + get + { + string userAgent = App.HttpContext?.Request?.Headers["User-Agent"]; + + return userAgent; + } + } + + /// + /// 请求Url + /// + public static string Url + { + get + { + var url = new StringBuilder().Append(App.HttpContext?.Request?.Scheme).Append("://") + .Append(App.HttpContext?.Request?.Host).Append(App.HttpContext?.Request?.PathBase) + .Append(App.HttpContext?.Request?.Path).Append(App.HttpContext?.Request?.QueryString).ToString(); + return url; + } + } + + /// + /// 得到操作系统版本 + /// + /// + public static string GetOSVersion() + { + var osVersion = string.Empty; + var userAgent = UserAgent; + if (userAgent.Contains("NT 10")) + { + osVersion = "Windows 10"; + } + else if (userAgent.Contains("NT 6.3")) + { + osVersion = "Windows 8"; + } + else if (userAgent.Contains("NT 6.1")) + { + osVersion = "Windows 7"; + } + else if (userAgent.Contains("NT 6.0")) + { + osVersion = "Windows Vista/Server 2008"; + } + else if (userAgent.Contains("NT 5.2")) + { + osVersion = "Windows Server 2003"; + } + else if (userAgent.Contains("NT 5.1")) + { + osVersion = "Windows XP"; + } + else if (userAgent.Contains("NT 5")) + { + osVersion = "Windows 2000"; + } + else if (userAgent.Contains("NT 4")) + { + osVersion = "Windows NT4"; + } + else if (userAgent.Contains("Android")) + { + osVersion = "Android"; + } + else if (userAgent.Contains("Me")) + { + osVersion = "Windows Me"; + } + else if (userAgent.Contains("98")) + { + osVersion = "Windows 98"; + } + else if (userAgent.Contains("95")) + { + osVersion = "Windows 95"; + } + else if (userAgent.Contains("Mac")) + { + osVersion = "Mac"; + } + else if (userAgent.Contains("Unix")) + { + osVersion = "UNIX"; + } + else if (userAgent.Contains("Linux")) + { + osVersion = "Linux"; + } + else if (userAgent.Contains("SunOS")) + { + osVersion = "SunOS"; + } + + return osVersion; + } + + /// + /// 公网信息 + /// 慎用,如果不是直接请求接口,而是通过代理转发,拿到的是服务器的公网信息 + /// + /// + public static async Task WanInfo() + { + const string url = "http://whois.pconline.com.cn/ipJson.jsp"; + var resultStr = await url.GetAsStringAsync(); + resultStr = resultStr[(resultStr.IndexOf("IPCallBack(", StringComparison.Ordinal) + "IPCallBack(".Length)..] + .TrimEnd(); + resultStr = resultStr[..^3]; + var result = resultStr.ToObject(); + return result; + } + + /// + /// 根据IP地址获取公网信息 + /// + /// + public static async Task WanInfo(string ip) + { + var url = $"http://whois.pconline.com.cn/ipJson.jsp?ip={ip}"; + var resultStr = await url.GetAsStringAsync(); + resultStr = resultStr[(resultStr.IndexOf("IPCallBack(", StringComparison.Ordinal) + "IPCallBack(".Length)..] + .TrimEnd(); + resultStr = resultStr[..^3]; + var result = resultStr.ToObject(); + return result; + } + + /// + /// UserAgent信息 + /// + /// + public static UserAgentInfoModel UserAgentInfo() + { + var parser = Parser.GetDefault(); + var clientInfo = parser.Parse(UserAgent); + var result = new UserAgentInfoModel + { + PhoneModel = clientInfo.Device.ToString(), OS = clientInfo.OS.ToString(), Browser = clientInfo.UA.ToString() + }; + return result; + } + + private static readonly char[] reserveChar = { '/', '?', '*', ':', '|', '\\', '<', '>', '\"' }; + + /// + /// 远程路径Encode处理,会保证开头是/,结尾也是/ + /// + /// + /// + public static string EncodeRemotePath(string remotePath) + { + if (remotePath == "/") + { + return remotePath; + } + + var endWith = remotePath.EndsWith("/"); + var part = remotePath.Split('/'); + remotePath = ""; + foreach (var s in part) + { + if (s == "") + continue; + if (remotePath != "") + { + remotePath += "/"; + } + + remotePath += HttpUtility.UrlEncode(s).Replace("+", "%20"); + } + + remotePath = (remotePath.StartsWith("/") ? "" : "/") + remotePath + (endWith ? "/" : ""); + return remotePath; + } + + /// + /// 标准化远程目录路径,会保证开头是/,结尾也是/ ,如果命名不规范,存在保留字符,会返回空字符 + /// + /// 要标准化的远程路径 + /// + public static string StandardizationRemotePath(string remotePath) + { + if (string.IsNullOrEmpty(remotePath)) + { + return ""; + } + + if (!remotePath.StartsWith("/")) + { + remotePath = "/" + remotePath; + } + + if (!remotePath.EndsWith("/")) + { + remotePath = remotePath + "/"; + } + + var index1 = 1; + while (index1 < remotePath.Length) + { + var index2 = remotePath.IndexOf('/', index1); + if (index2 == index1) + { + return ""; + } + + var folderName = remotePath.Substring(index1, index2 - index1); + if (folderName.IndexOfAny(reserveChar) != -1) + { + return ""; + } + + index1 = index2 + 1; + } + + return remotePath; + } +} + +/// +/// 万网Ip信息Model类 +/// +public class WhoisIPInfoModel +{ + /// + /// Ip地址 + /// + public string Ip { get; set; } + + /// + /// 省份 + /// + public string Pro { get; set; } + + /// + /// 省份邮政编码 + /// + public string ProCode { get; set; } + + /// + /// 城市 + /// + public string City { get; set; } + + /// + /// 城市邮政编码 + /// + public string CityCode { get; set; } + + /// + /// 地理信息 + /// + [JsonPropertyName("addr")] + public string Address { get; set; } + + /// + /// 运营商 + /// + public string Operator => Address[(Pro.Length + City.Length)..].Trim(); +} + +/// +/// UserAgent 信息Model类 +/// +public class UserAgentInfoModel +{ + /// + /// 手机型号 + /// + public string PhoneModel { get; set; } + + /// + /// 操作系统(版本) + /// + public string OS { get; set; } + + /// + /// 浏览器(版本) + /// + public string Browser { get; set; } +} diff --git a/Magic.Core/Util/Http/WeatherUtil.cs b/Magic.Core/Util/Http/WeatherUtil.cs new file mode 100644 index 0000000..db15f4d --- /dev/null +++ b/Magic.Core/Util/Http/WeatherUtil.cs @@ -0,0 +1,118 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Furion.RemoteRequest.Extensions; + +namespace Magic.Core; + +/// +/// 天气预报工具类 +/// +public static class WeatherUtil +{ + private static readonly string _getWeatherUrl = "http://wthrcdn.etouch.cn/weather_mini"; + + public static async Task GetWeatherInfo(string cityName = "北京") + { + var weatherOutPut = await $"{_getWeatherUrl}?city={cityName}".SetClient("wthrcdn").GetAsAsync(); + if (weatherOutPut.Status != 1000 || weatherOutPut.Desc != "OK") + { + return new WeatherInfoOutPut { Success = false, Desc = weatherOutPut.Desc }; + } + + weatherOutPut.Data.Success = true; + + return weatherOutPut.Data; + } +} + +/// +/// 天气信息 +/// +public class WeatherInfo +{ + /// + /// 时间 + /// + public string Date { get; set; } + + /// + /// 最高温度 + /// + public string High { get; set; } + + /// + /// 风力 + /// + public string Fengli { get; set; } + + /// + /// 最低温度 + /// + public string Low { get; set; } + + /// + /// 分向 + /// + public string Fengxiang { get; set; } + + /// + /// 类型 + /// + public string Type { get; set; } +} + +public class WeatherInfoOutPut +{ + /// + /// 昨日天气 + /// + public WeatherInfo Yesterday { get; set; } + + /// + /// 城市 + /// + public string City { get; set; } + + /// + /// 未来五天天气 + /// + public List Forecast { get; set; } + + /// + /// 感冒 + /// + public string Ganmao { get; set; } + + /// + /// 温度 + /// + public string Wendu { get; set; } + + /// + /// 是否成功 + /// + public bool Success { get; set; } + + /// + /// 失败描述 + /// + public string Desc { get; set; } +} + +public class WeatherOutPut +{ + /// + /// 数据 + /// + public WeatherInfoOutPut Data { get; set; } + + /// + /// 状态 + /// + public int Status { get; set; } + + /// + /// 描述 + /// + public string Desc { get; set; } +} diff --git a/Magic.Core/Util/Image/ImageUtil.cs b/Magic.Core/Util/Image/ImageUtil.cs new file mode 100644 index 0000000..e840971 --- /dev/null +++ b/Magic.Core/Util/Image/ImageUtil.cs @@ -0,0 +1,192 @@ +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Furion.RemoteRequest.Extensions; + +namespace Magic.Core; + +/// +/// 图片工具类 +/// +public static class ImageUtil +{ + /// + /// 获取外网Url图片的二进制数组 + /// + /// + /// + public static async Task GetBytesFromUrl(this string url) + { + // 得到图片流 + var result = await url.GetAsStreamAsync(); + using var binaryReader = new BinaryReader(result.Stream); + // 读取二进制文件流 + var resultBytes = binaryReader.ReadBytes(result.Stream.Length.ParseToInt()); + binaryReader.Close(); + + return resultBytes; + } + + /// + /// 保存二进制流到文件 + /// + /// + /// + public static async Task WriteBytesToFile(byte[] content, string fileName) + { + // 检测文件夹是否存在 + if (!Directory.Exists(fileName[..fileName.LastIndexOf("/", StringComparison.Ordinal)])) + { + Directory.CreateDirectory(fileName[..fileName.LastIndexOf("/", StringComparison.Ordinal)]); + } + + // 检测文件是否存在 + if (!File.Exists(fileName)) + { + await File.WriteAllBytesAsync(fileName, content); + } + } + + /// + /// 保存外网Url到文件 + /// + /// 外网图片Url + /// 要保存的文件名称 + /// + public static async Task SaveFromUrlToFile(this string url, string fileName) + { + var bytes = await url.GetBytesFromUrl(); + await WriteBytesToFile(bytes, fileName); + } + + /// + /// 删除文件夹里面所有的文件 + /// + /// + /// + public static void DeleteFile(this string fileName) + { + foreach (var entry in Directory.GetFileSystemEntries(fileName)) + { + if (!File.Exists(entry)) + continue; + var name = Path.GetFileNameWithoutExtension(entry); + File.Delete(entry); + } + } + + /// + /// 无损压缩图片 + /// + /// 原图片地址 + /// 压缩后保存图片地址 + /// 压缩后宽度 + /// 压缩后高度 + /// 压缩质量(数字越小压缩率越高) + /// 压缩后图片的最大大小 + /// 是否为第一次调用 + /// + public static bool CompressImage(string sourceFile, string compressFile, int compressHeight = 750, + int compressWidth = 1334, int flag = 90, int size = 110, bool isFirst = true) + { + // 如果是第一次调用,原始图像的大小小于要压缩的大小,则直接复制文件,并且返回True + var firstFileInfo = new FileInfo(sourceFile); + if (isFirst && firstFileInfo.Length < size * 1024) + { + firstFileInfo.CopyTo(compressFile); + return true; + } + + var imageSource = Image.FromFile(sourceFile); + var imageFormat = imageSource.RawFormat; + var sourceWidth = 0; + var sourceHeight = 0; + + // 按比例缩放 + var temSize = new Size(imageSource.Width, imageSource.Height); + + // 处理大小,如果是0,原大小 + if (compressHeight.IsNullOrZero()) + { + compressHeight = temSize.Height; + } + + if (compressWidth.IsNullOrZero()) + { + compressWidth = temSize.Width; + } + + if (temSize.Width > compressHeight || temSize.Width > compressWidth) + { + if ((temSize.Width * compressHeight) > (temSize.Width * compressWidth)) + { + sourceWidth = compressWidth; + sourceHeight = (compressWidth * temSize.Height) / temSize.Width; + } + else + { + sourceWidth = compressHeight; + sourceHeight = (temSize.Height * compressHeight) / temSize.Height; + } + } + else + { + sourceWidth = temSize.Width; + sourceHeight = temSize.Height; + } + + + var bitmap = new Bitmap(compressWidth, compressHeight); + + var graphics = Graphics.FromImage(bitmap); + graphics.Clear(Color.Transparent); + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.DrawImage(imageSource, + new Rectangle((compressWidth - sourceWidth) / 2, (compressHeight - sourceHeight) / 2, sourceWidth, sourceHeight), + 0, 0, imageSource.Width, imageSource.Height, GraphicsUnit.Pixel); + graphics.Dispose(); + + // 设置压缩质量 + var encoderParameters = + new EncoderParameters {Param = {[0] = new EncoderParameter(Encoder.Quality, new long[] {flag})}}; + + try + { + // 找到系统中可用的图片编码器信息 + var imageCodecInfos = ImageCodecInfo.GetImageEncoders(); + var jpegIciInfo = imageCodecInfos.FirstOrDefault(t => t.FormatDescription.Equals("JPEG")); + + // 如果编码器存在的,可以压缩 + if (jpegIciInfo != null) + { + bitmap.Save(compressFile, jpegIciInfo, encoderParameters); + var fileInfo = new FileInfo(compressFile); + if (fileInfo.Length <= 1024 * size) + return true; + flag -= 10; + CompressImage(sourceFile, compressFile, compressHeight, compressWidth, flag, size, false); + } + else + { + bitmap.Save(compressFile, imageFormat); + } + + return true; + } + catch + { + return false; + } + finally + { + imageSource.Dispose(); + bitmap.Dispose(); + } + } +} diff --git a/Magic.Core/Util/JsonUtil.cs b/Magic.Core/Util/JsonUtil.cs new file mode 100644 index 0000000..bd97d9a --- /dev/null +++ b/Magic.Core/Util/JsonUtil.cs @@ -0,0 +1,114 @@ +using System.Collections.Generic; +using System.Linq; +using Furion.JsonSerialization; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Magic.Core; + +/// +/// Json序列化工具类 +/// +public static class JsonUtil +{ + /// + /// JSON 字符串转 Object + /// + /// + /// + /// + public static T ToObject(this string json) + { + json = json.Replace(" ", ""); + return json == null ? default(T) : JsonConvert.DeserializeObject(json); + } + /// + /// JSON 字符串转 Object + /// + /// + /// + public static object ToObject(this string Json) + { + return string.IsNullOrEmpty(Json) ? null : JsonConvert.DeserializeObject(Json); + } + /// + /// Object 转 JSON字符串 + /// + /// + /// + public static string ToJsonString(this object obj) + { + return obj == null ? string.Empty : JsonConvert.SerializeObject(obj); + } + + /// + /// JSON 字符串转 JObject + /// + /// + /// + public static JObject ToJObject(this string json) + { + return json == null ? JObject.Parse("{}") : JObject.Parse(json.Replace(" ", "")); + } + + /// + /// Dictionary 字符串转 Object + /// + /// + /// + /// + public static T ToObject(this IDictionary dictionary) + { + return dictionary.ToJsonString().ToObject(); + } + /// + /// 把数组转为逗号连接的字符串 + /// + /// + /// + /// + public static string ArrayToString(dynamic data, string Str) + { + string resStr = Str; + foreach (var item in data) + { + if (resStr != "") + { + resStr += ","; + } + + if (item is string) + { + resStr += item; + } + else + { + resStr += item.ToString(); + } + } + return resStr; + } + /// + /// 判断是否有交集 + /// + /// + /// + /// + /// + public static bool IsArrayIntersection(List list1, List list2) + { + List t = list1.Distinct().ToList(); + + var exceptArr = t.Except(list2).ToList(); + + if (exceptArr.Count < t.Count) + { + return true; + } + else + { + return false; + } + + } +} diff --git a/Magic.Core/Util/MachineUtil.cs b/Magic.Core/Util/MachineUtil.cs new file mode 100644 index 0000000..f46f0d7 --- /dev/null +++ b/Magic.Core/Util/MachineUtil.cs @@ -0,0 +1,322 @@ +using Furion.RemoteRequest.Extensions; +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.NetworkInformation; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Magic.Core; + +/// +/// 获取服务器信息 +/// +public static class MachineUtil +{ + /// + /// 获取资源使用信息 + /// + /// + public static dynamic GetMachineUseInfo() + { + var ramInfo = GetRamInfo(); + return new + { + TotalRam = Math.Ceiling(ramInfo.Total / 1024).ToString() + " GB", // 总内存 + RamRate = Math.Ceiling(100 * ramInfo.Used / ramInfo.Total), // 内存使用率 + CpuRate = Math.Ceiling(double.Parse(GetCPURate())), // cpu使用率 + RunTime = GetRunTime() + }; + } + + /// + /// 获取基本参数 + /// + /// + public static async Task GetMachineBaseInfo() + { + var assemblyName = typeof(Furion.App).Assembly.GetName(); + //var networkInfo = NetworkInfo.GetNetworkInfo(); + //var (Received, Send) = networkInfo.GetInternetSpeed(1000); + return new + { + WanIp = await GetWanIpFromPCOnline(), // 外网IP + SendAndReceived = "",// "上行" + Math.Round(networkInfo.SendLength / 1024.0 / 1024 / 1024, 2) + "GB 下行" + Math.Round(networkInfo.ReceivedLength / 1024.0 / 1024 / 1024, 2) + "GB", // 上下行流量统计 + LanIp = "",//networkInfo.AddressIpv4.ToString(), // 局域网IP + IpMac = "",//networkInfo.Mac, // Mac地址 + HostName = Environment.MachineName, // HostName + SystemOs = RuntimeInformation.OSDescription, // 系统名称 + OsArchitecture = Environment.OSVersion.Platform.ToString() + " " + RuntimeInformation.OSArchitecture.ToString(), // 系统架构 + ProcessorCount = Environment.ProcessorCount.ToString() + "核", // CPU核心数 + FrameworkDescription = RuntimeInformation.FrameworkDescription + " + " + assemblyName.Name.ToString() + assemblyName.Version.ToString(), // .NET和Furion版本 + NetworkSpeed = ""//"上行" + Send / 1024 + "kb/s 下行" + Received / 1024 + "kb/s" // 网络速度 + }; + } + + /// + /// 动态获取网络信息 + /// + /// + public static dynamic GetMachineNetWorkInfo() + { + //var networkInfo = NetworkInfo.GetNetworkInfo(); + //var (Received, Send) = networkInfo.GetInternetSpeed(1000); + ////int Send, Received; + ////while (true) + ////{ + //// var tmp = networkInfo.GetInternetSpeed(1000); + //// if (tmp.Send > 0 || tmp.Received > 0) + //// { + //// Send = tmp.Send; + //// Received = tmp.Received; + //// break; + //// } + //// Thread.Sleep(500); + ////} + + return new + { + SendAndReceived = "",// "上行" + Math.Round(networkInfo.SendLength / 1024.0 / 1024 / 1024, 2) + "GB 下行" + Math.Round(networkInfo.ReceivedLength / 1024.0 / 1024 / 1024, 2) + "GB", // 上下行流量统计 + NetworkSpeed = ""//"上行" + Send / 1024 + "kb/s 下行" + Received / 1024 + "kb/s" // 网络速度 + }; + } + + /// + /// 是否Linux + /// + /// + private static bool IsUnix() + { + return RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux); + } + + /// + /// 获取CPU使用率 + /// + /// + private static string GetCPURate() + { + string cpuRate; + if (IsUnix()) + { + var output = ShellUtil.Bash("top -b -n1 | grep \"Cpu(s)\" | awk '{print $2 + $4}'"); + cpuRate = output.Trim(); + } + else + { + var output = ShellUtil.Cmd("wmic", "cpu get LoadPercentage"); + cpuRate = output.Replace("LoadPercentage", string.Empty).Trim(); + if(string.IsNullOrWhiteSpace(cpuRate)){ + cpuRate = "0"; + } + } + return cpuRate; + } + + /// + /// 获取系统运行时间 + /// + /// + private static string GetRunTime() + { + return FormatTime((long)(DateTime.Now - Process.GetCurrentProcess().StartTime).TotalMilliseconds); + //return DateTimeUtil.FormatTime(Environment.TickCount); + } + + /// + /// 获取内存信息 + /// + /// + private static dynamic GetRamInfo() + { + if (IsUnix()) + { + var output = ShellUtil.Bash("free -m"); + var lines = output.Split("\n"); + var memory = lines[1].Split(" ", StringSplitOptions.RemoveEmptyEntries); + return new + { + Total = double.Parse(memory[1]), + Used = double.Parse(memory[2]), + Free = double.Parse(memory[3]) + }; + } + else + { + var output = ShellUtil.Cmd("wmic", "OS get FreePhysicalMemory,TotalVisibleMemorySize /Value"); + var lines = output.Trim().Split("\n"); + var freeMemoryParts = lines[0].Split("=", StringSplitOptions.RemoveEmptyEntries); + var totalMemoryParts = lines[1].Split("=", StringSplitOptions.RemoveEmptyEntries); + var total = Math.Round(double.Parse(totalMemoryParts[1]) / 1024, 2); + var free = Math.Round(double.Parse(freeMemoryParts[1]) / 1024, 2); + return new + { + Total = total, + Free = free, + Used = total - free + }; + } + } + + /// + /// 毫秒转天时分秒 + /// + /// + /// + private static string FormatTime(long ms) + { + int ss = 1000; + int mi = ss * 60; + int hh = mi * 60; + int dd = hh * 24; + + long day = ms / dd; + long hour = (ms - day * dd) / hh; + long minute = (ms - day * dd - hour * hh) / mi; + long second = (ms - day * dd - hour * hh - minute * mi) / ss; + //long milliSecond = ms - day * dd - hour * hh - minute * mi - second * ss; + + string sDay = day < 10 ? "0" + day : "" + day; //天 + string sHour = hour < 10 ? "0" + hour : "" + hour;//小时 + string sMinute = minute < 10 ? "0" + minute : "" + minute;//分钟 + string sSecond = second < 10 ? "0" + second : "" + second;//秒 + //string sMilliSecond = milliSecond < 10 ? "0" + milliSecond : "" + milliSecond;//毫秒 + //sMilliSecond = milliSecond < 100 ? "0" + sMilliSecond : "" + sMilliSecond; + return string.Format("{0} 天 {1} 小时 {2} 分 {3} 秒", sDay, sHour, sMinute, sSecond); + } + + /// + /// 获取外网IP和地理位置 + /// + /// + private static async Task GetWanIpFromPCOnline() + { + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + + var url = "http://whois.pconline.com.cn/ipJson.jsp"; + var result = await url.GetAsStreamAsync(); + var streamReader = new StreamReader(result.Stream, Encoding.GetEncoding("GBK")); + var html = streamReader.ReadToEnd(); + var tmp = html[(html.IndexOf("({") + 2)..].Split(","); + var ipAddr = tmp[0].Split(":")[1] + "【" + tmp[7].Split(":")[1] + "】"; + return ipAddr.Replace("\"", ""); + } +} + +/// +/// 系统Shell命令 +/// +public class ShellUtil +{ + /// + /// Bash命令 + /// + /// + /// + public static string Bash(string command) + { + var escapedArgs = command.Replace("\"", "\\\""); + var process = new Process() + { + StartInfo = new ProcessStartInfo + { + FileName = "/bin/bash", + Arguments = $"-c \"{escapedArgs}\"", + RedirectStandardOutput = true, + UseShellExecute = false, + CreateNoWindow = true, + } + }; + process.Start(); + string result = process.StandardOutput.ReadToEnd(); + process.WaitForExit(); + process.Dispose(); + return result; + } + + /// + /// cmd命令 + /// + /// + /// + /// + public static string Cmd(string fileName, string args) + { + string output = string.Empty; + var info = new ProcessStartInfo + { + FileName = fileName, + Arguments = args, + RedirectStandardOutput = true + }; + using (var process = Process.Start(info)) + { + output = process.StandardOutput.ReadToEnd(); + } + return output; + } +} + +/// +/// +/// +public class NetworkInfo +{ + private readonly NetworkInterface _instance; + public NetworkInterface NetworkInterface => _instance; + private readonly Lazy _statistics; + private readonly Lazy _addressIpv4; + + public IPAddress AddressIpv4 => _addressIpv4.Value; // IPv4 地址 + public string Mac => _instance?.GetPhysicalAddress().ToString(); // Mac地址 + public string Id => _instance?.Id; // 网络适配器的标识符 + public long ReceivedLength => _statistics.Value.BytesReceived; // 网络下载总量 + public long SendLength => _statistics.Value.BytesSent; // 网络上传总量 + + private NetworkInfo(NetworkInterface network) + { + _instance = network; + _statistics = new Lazy(() => _instance?.GetIPStatistics()); + //_Ipv4Statistics = new Lazy(() => _instance.GetIPv4Statistics()); + //_AddressIpv6 = new Lazy(() => _instance.GetIPProperties().UnicastAddresses + // .FirstOrDefault(x => x.IPv4Mask.ToString().Equals("0.0.0.0")).Address); + _addressIpv4 = new Lazy(() => _instance?.GetIPProperties().UnicastAddresses + .FirstOrDefault(x => !x.IPv4Mask.ToString().Equals("0.0.0.0")).Address); + } + + /// + /// 当前正在联网的网卡信息 + /// + /// + public static NetworkInfo GetNetworkInfo() + { + if (Environment.OSVersion.Platform == PlatformID.Unix) + return new NetworkInfo(NetworkInterface.GetAllNetworkInterfaces() + .FirstOrDefault(x => x.NetworkInterfaceType != NetworkInterfaceType.Loopback + && x.NetworkInterfaceType != NetworkInterfaceType.Ethernet)); + + return new NetworkInfo(NetworkInterface.GetAllNetworkInterfaces() + .FirstOrDefault(x => x.OperationalStatus == OperationalStatus.Up + && x.NetworkInterfaceType != NetworkInterfaceType.Loopback + && x.NetworkInterfaceType != NetworkInterfaceType.Ethernet)); + } + + /// + /// 获取当前网卡的网络速度 + /// + /// + /// + public (int Received, int Send) GetInternetSpeed(int Milliseconds) + { + var newNetwork = NetworkInterface.GetAllNetworkInterfaces().FirstOrDefault(x => x.Id == Id).GetIPStatistics(); + + long rec = ReceivedLength; + long send = SendLength; + Thread.Sleep(Milliseconds); + return ((int)(newNetwork.BytesReceived - rec), (int)(newNetwork.BytesSent - send)); + } +} diff --git a/Magic.Core/Util/MiniProgram/MiniProgramUtil.cs b/Magic.Core/Util/MiniProgram/MiniProgramUtil.cs new file mode 100644 index 0000000..3cc1c07 --- /dev/null +++ b/Magic.Core/Util/MiniProgram/MiniProgramUtil.cs @@ -0,0 +1,74 @@ +using System; +using System.Security.Cryptography; +using System.Text; +using System.Text.Json.Serialization; +using Furion.JsonSerialization; + +namespace Magic.Core; + +/// +/// 小程序工具类 +/// +public class MiniProgramUtil +{ + /// + /// 解密数据获取小程序用户信息 + /// + /// 包括敏感数据在内的完整用户信息的加密数据 + /// auth.code2Session获取的session_key + /// 加密算法的初始向量 + /// 如遇异常返回 "" + public static TelUserInfoModel AESDecrypt(string encryptedDataStr, string session_key, string iv) + { + var rlt = BasicAESDecrypt(encryptedDataStr, session_key, iv); + return !rlt.IsEmpty() ? JSON.Deserialize(rlt) : null; + } + + /// + /// 基础解析 + /// + /// 包括敏感数据在内的完整用户信息的加密数据 + /// auth.code2Session获取的session_key + /// 加密算法的初始向量 + /// + private static string BasicAESDecrypt(string encryptedDataStr, string session_key, string iv) + { + // 16进制转换成byte + var encryptedData = Convert.FromBase64String(encryptedDataStr); + var managed = new RijndaelManaged + { + Key = Convert.FromBase64String(session_key), + IV = Convert.FromBase64String(iv), + Mode = CipherMode.CBC, + Padding = PaddingMode.PKCS7 + }; + var transform = managed.CreateDecryptor(); + var finalBlock = transform.TransformFinalBlock(encryptedData, 0, encryptedData.Length); + var result = Encoding.Default.GetString(finalBlock); + return result; + } +} + +/// +/// 小程序登录解密后的用户信息Model +/// +public class TelUserInfoModel +{ + /// + /// 手机号 + /// + [JsonPropertyName("phoneNumber")] + public string PhoneNumber { get; set; } + + /// + /// 纯手机号 + /// + [JsonPropertyName("purePhoneNumber")] + public string PurePhoneNumber { get; set; } + + /// + /// 区号 + /// + [JsonPropertyName("countryCode")] + public string CountryCode { get; set; } +} diff --git a/Magic.Core/Util/OSSClientUtil.cs b/Magic.Core/Util/OSSClientUtil.cs new file mode 100644 index 0000000..5ad9ecb --- /dev/null +++ b/Magic.Core/Util/OSSClientUtil.cs @@ -0,0 +1,268 @@ +using Aliyun.OSS; +using Aliyun.OSS.Common; +using System; +using System.IO; +using System.Net; + +namespace Magic.Core; + +/// +/// 阿里云oss文件上传工具类 +/// +public class OSSClientUtil +{ + private static readonly string _accessKeyId = "accessKeyId"; + private static readonly string _accessKeySecret = "accessKeySecret"; + //const string endpoint = "oss-cn-huhehaote-internal.aliyuncs.com"; + private static readonly string _internalEndpoint = "internalEndpoint"; //内网传输连接 + private const string _endpoint = "oss-cn-beijing.aliyuncs.com"; //"oss-cn-beijing.aliyuncs.com";// "oss-cn-huhehaote-internal.aliyuncs.com";//"oss-cn-huhehaote.aliyuncs.com" ; + private static readonly string _bucketName = "bucketName"; + + public static OssClient GetClient() + { + return new OssClient(_endpoint, _accessKeyId, _accessKeySecret); + } + + public static OssClient GetClient_CND() + { + var conf = new ClientConfiguration + { + IsCname = true + }; + return new OssClient("cdnmedia.aliyuncs.com", _accessKeyId, _accessKeySecret, conf); + } + + public static OssClient GetClient_internal() + { + return new OssClient(_internalEndpoint, _accessKeyId, _accessKeySecret); + } + + /// + /// 上传本地文件(走阿里云内网传输) + /// + /// + /// + /// + public static bool PushMedia_internal(string objectName, string localFilename) + { + var client = GetClient_internal(); + return client.PutObject(_bucketName, objectName, localFilename).HttpStatusCode == System.Net.HttpStatusCode.OK; + } + + /// + /// 上传一个图片 + /// + /// 图片经过base64加密后的结果 + /// 文件名,例如:Emplyoee/dzzBack.jpg + public static bool PushImg(string base64Code, string fileName) + { + var client = GetClient(); + var stream = new MemoryStream(Convert.FromBase64String(base64Code)); + return client.PutObject(_bucketName, fileName, stream).HttpStatusCode == System.Net.HttpStatusCode.OK; + } + + public static bool PushMedia(Stream stream, string fileName) + { + var client = GetClient(); + return client.PutObject(_bucketName, fileName, stream).HttpStatusCode == System.Net.HttpStatusCode.OK; + } + + /// + /// 上传本地文件 + /// + /// + /// + /// 返回参数说明 1.本地文件不存在 2.文件oss上已存在 3.上传失败 4.上传成功 + /// + public static int PushMedia(string objectName, string localFilename) + { + if (!File.Exists(localFilename)) return 1; + if (DoesObjectExist(objectName)) return 2; // 存在文件 + try + { + var client = GetClient(); + //MemoryStream stream = new MemoryStream(Convert.FromBase64String(base64Code)); + //var metadata = new ObjectMetadata(); + //metadata.ContentType = TypeTo(contentType); + + if (localFilename.Contains("http")) + { + var webClient = new WebClient { Credentials = CredentialCache.DefaultCredentials }; + var stream = webClient.DownloadData(localFilename); + var ms = new MemoryStream(stream); + var c = client.PutObject(_bucketName, objectName, ms); + if (c.HttpStatusCode == System.Net.HttpStatusCode.OK) { return 4; } else { return 3; } + } + else + { + var c = client.PutObject(_bucketName, objectName, localFilename); + if (c.HttpStatusCode == System.Net.HttpStatusCode.OK) { return 4; } else { return 3; } + } + } + catch + { + return 3; + } + } + + /// + /// 上传一个图片 + /// + /// 图片字节 + /// 文件名,例如:Emplyoee/dzzBack.jpg + /// + public static bool PushImg(byte[] filebyte, string fileName, out string md5) + { + var client = GetClient(); + var stream = new MemoryStream(filebyte, 0, filebyte.Length); + var result = client.PutObject(_bucketName, fileName, stream); + md5 = result.ResponseMetadata["Content-MD5"]; + return result.HttpStatusCode == System.Net.HttpStatusCode.OK; + } + + /// + /// 获取鉴权后的URL,URL有效日期默认一小时 + /// + /// 文件名,例如:Emplyoee/dzzBack.jpg + /// + public static string GetImg(string fileName) + { + var client = GetClient(); + var key = fileName; + var req = new GeneratePresignedUriRequest(_bucketName, key, SignHttpMethod.Get) + { + Expiration = DateTime.Now.AddHours(1) + }; + return client.GeneratePresignedUri(req).ToString(); + } + + /// + /// 获取鉴权后的URL + /// + /// 文件名,例如:Emplyoee/dzzBack.jpg + /// URL有效日期,例如:DateTime.Now.AddHours(1) + /// + public static string GetImg(string fileName, DateTime expiration) + { + var client = GetClient(); + var key = fileName; + var req = new GeneratePresignedUriRequest(_bucketName, key, SignHttpMethod.Get) + { + Expiration = expiration + }; + return client.GeneratePresignedUri(req).ToString(); + } + + /// + /// 将文件转换成byte[] 数组 + /// + /// 文件路径文件名称 + /// byte[] + private byte[] AuthGetFileData(string fileUrl) + { + using (var fs = new FileStream(fileUrl, FileMode.OpenOrCreate, FileAccess.ReadWrite)) + { + byte[] buffur = new byte[fs.Length]; + using (BinaryWriter bw = new BinaryWriter(fs)) + { + bw.Write(buffur); + bw.Close(); + } + return buffur; + } + } + + /// + /// 删除文件 + /// + /// 文件id + /// 文件url + public static bool DeletefileCode(string fileCode) + { + if (string.IsNullOrEmpty(fileCode)) + return true; + + //检查fileCode磁盘中是否存在此文件 + if (File.Exists(fileCode)) + { + File.Delete(fileCode); + return true; + } + var client = GetClient(); + client.DeleteObject(_bucketName, fileCode); + return true; + } + + /// + /// 删除文件夹 + /// + /// 文件id + /// 文件url + public static bool DeleteFolder(string prefix) + { + if (string.IsNullOrEmpty(prefix)) + return true; + + var client = GetClient(); + var listObjectsRequest = new ListObjectsRequest(_bucketName); + listObjectsRequest.Prefix = prefix; + var result = client.ListObjects(listObjectsRequest); + + foreach (var summary in result.ObjectSummaries) + { + client.DeleteObject(_bucketName, summary.Key); + } + return false; + } + + /// + /// 判断文件是否存在 + /// + /// + /// + public static bool DoesObjectExist(string fileName) + { + var client = GetClient(); + // 判断文件是否存在。 + var exist = client.DoesObjectExist(_bucketName, fileName); + return exist; + } + + /// + /// 类型转换 + /// + /// + public static string TypeTo(string type) + { + type = type switch + { + "mp4" => "video/mp4", + "mp3" => "audio/mp3", + _ => "image/" + type, + }; + return type; + } + + public static OssObject DownLoad(String fileName) + { + //var client = GetClient(); + //DateTime expiration = new DateTime().AddHours(1); + //GeneratePresignedUriRequest request = new GeneratePresignedUriRequest(bucketName, fileName, SignHttpMethod.Get); + //// 设置过期时间。 + //request.Expiration=expiration; + //// 生成签名URL(HTTP GET请求)。 + //Uri signedUrl = client.GeneratePresignedUri(request); + + //// 添加GetObject请求头。 + ////customHeaders.put("Range", "bytes=100-1000"); + //OssObject result = client.GetObject(signedUrl); + + var client = GetClient(); + var key = fileName; + _ = new GeneratePresignedUriRequest(_bucketName, key, SignHttpMethod.Get) + { + Expiration = DateTime.Now.AddHours(1) + }; + return client.GetObject(_bucketName, key); + } +} diff --git a/Magic.Core/Util/ReflectionUtil.cs b/Magic.Core/Util/ReflectionUtil.cs new file mode 100644 index 0000000..a29ad75 --- /dev/null +++ b/Magic.Core/Util/ReflectionUtil.cs @@ -0,0 +1,25 @@ +using System; +using System.Reflection; + +namespace Magic.Core; + +/// +/// 反射工具 +/// +public static class ReflectionUtil +{ + /// + /// 获取字段特性 + /// + /// + /// + /// + public static T GetDescriptionValue(this FieldInfo field) where T : Attribute + { + // 获取字段的指定特性,不包含继承中的特性 + object[] customAttributes = field.GetCustomAttributes(typeof(T), false); + + // 如果没有数据返回null + return customAttributes.Length > 0 ? (T)customAttributes[0] : null; + } +} diff --git a/Magic.Core/Util/String/Base64Util.cs b/Magic.Core/Util/String/Base64Util.cs new file mode 100644 index 0000000..ead5458 --- /dev/null +++ b/Magic.Core/Util/String/Base64Util.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using Newtonsoft.Json; + +namespace Magic.Core; + +public static class Base64Util +{ + // 随机字符长度 + public const int RandomPrefixStrLength = 6; + + public const string RandomStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + + private static string GetRandomStr(string randomStr = RandomStr, int randomPrefixStrLength = RandomPrefixStrLength) + { + // ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/= + var result = ""; + var random = new Random(Convert.ToInt32($"{DateTime.Now:HHmmssfff}")); + + for (var i = 0; i < randomPrefixStrLength; i++) + { + var randomInt = random.Next(0, randomStr.Length); + var randomChar = randomStr[randomInt]; + result += randomChar; + } + + Thread.Sleep(1); // 休眠,以使随机数不重叠. + + return result; + } + + static readonly Encoding encoding = Encoding.UTF8; + + /// + /// 普通 字符串 转换为 base64 字符串 + /// + public static string ToBase64(this string str, int randomPrefixStrLength = RandomPrefixStrLength) + { + if (string.IsNullOrWhiteSpace(str)) + { + return ""; + } + + try + { + var randomPrefixStr = GetRandomStr(RandomStr, randomPrefixStrLength); + var buffer = encoding.GetBytes(str); + var base64Str = Convert.ToBase64String(buffer); + + base64Str = randomPrefixStrLength == 0 ? base64Str : InsertRandomStrToBase64Str(base64Str); + + return $"{randomPrefixStr}{base64Str}"; + } + catch (Exception ex) + { + Console.WriteLine($"Base64Utility.ToBase64: {ex}"); + } + + return string.Empty; + } + + /// + /// base64 字符串 转换为 普通 字符串 + /// + public static string Base64ToString(this string base64Str, int randomPrefixStrLength = RandomPrefixStrLength) + { + var result = base64Str.Trim(); + try + { + if (string.IsNullOrWhiteSpace(base64Str?.Trim())) + { + return ""; + } + + base64Str = base64Str?.Trim(); + var input = base64Str?.Substring(randomPrefixStrLength); + + input = randomPrefixStrLength == 0 ? input : RemoveBase64StrRandomStr(input); + var buffer = Convert.FromBase64String(input); + result = encoding.GetString(buffer); + } + catch (Exception ex) + { + Console.WriteLine($"Base64Utility.Base64ToString: {ex}"); + } + + return result; + } + + public struct PwdDic + { + [JsonProperty("version")] + public string Version { get; set; } + + [JsonProperty("item")] + public List Item { get; set; } + } + + public struct PwdDicItem + { + [JsonProperty("index")] + public int Index { get; set; } + + [JsonProperty("randomIndex")] + public int RandomIndex { get; set; } + } + + public static readonly PwdDic dic = new PwdDic + { + Version = "3", + Item = new List + { + // 100 以内字典 + new() {Index = 99, RandomIndex = 91}, + new() {Index = 77, RandomIndex = 66}, + new() {Index = 45, RandomIndex = 37}, + new() {Index = 22, RandomIndex = 12}, + new() {Index = 5, RandomIndex = 3} + // 这里的 RandomIndex 要比 Index 小,而且Index 和 RandomIndex 所有的Value都是唯一的,不能重复。 + // 由于这里开源,所以这个字典需要自行定义。 + } + }; + + private static string InsertRandomStrToBase64Str(string base64Str) + { + var strResult = $"{base64Str}"; + + dic.Item.ForEach(item => + { + if (item.Index < base64Str.Length) + { + var randomChar = base64Str[item.RandomIndex]; + strResult = strResult.Insert(item.Index, $"{randomChar}"); + } + }); + + return strResult; + } + + private static string RemoveBase64StrRandomStr(string input) + { + var items = dic.Item.OrderBy(x => x.Index).ToList(); + + var strResult = $"{input}"; + + items.ForEach(item => + { + if (item.Index < strResult.Length) + { + strResult = strResult.Remove(item.Index, 1); + } + }); + + return strResult; + } +} diff --git a/Magic.Core/Util/String/ValidatorUtil.cs b/Magic.Core/Util/String/ValidatorUtil.cs new file mode 100644 index 0000000..06ab6e2 --- /dev/null +++ b/Magic.Core/Util/String/ValidatorUtil.cs @@ -0,0 +1,397 @@ +using System; +using System.Linq; +using System.Text.RegularExpressions; + +namespace Magic.Core; + +/// +/// 字符串验证帮助类 +/// +public static class ValidatorUtil +{ + #region 验证输入字符串为数字(带小数) + + /// + /// 验证输入字符串为带小数点正数 + /// + /// 输入字符 + /// 返回一个bool类型的值 + public static bool IsNumber(this string str) + { + return Regex.IsMatch(str, "^([0]|([1-9]+\\d{0,}?))(.[\\d]+)?$"); + } + + /// + /// 验证输入字符串为带小数点正负数 + /// + /// 输入字符 + /// 返回一个bool类型的值 + public static bool IsNumberic(this string str) + { + return Regex.IsMatch(str, "^-?\\d+$|^(-?\\d+)(\\.\\d+)?$"); + } + + #endregion + + #region 验证中国电话格式是否有效,格式010-85849685 + + /// + /// 验证中国电话格式是否有效,格式010-85849685 + /// + /// 输入字符 + /// 返回一个bool类型的值 + public static bool IsTel(this string str) + { + return Regex.IsMatch(str, @"^(0[0-9]{2,3}\-)?([2-9][0-9]{6,7})+(\-[0-9]{1,4})?$", RegexOptions.IgnoreCase); + } + + #endregion + + #region 验证输入字符串为电话号码 + + /// + /// 验证输入字符串为电话号码 + /// + /// 输入字符 + /// 返回一个bool类型的值 + public static bool IsPhone(this string str) + { + return Regex.IsMatch(str, @"(^(\d{2,4}[-_-—]?)?\d{3,8}([-_-—]?\d{3,8})?([-_-—]?\d{1,7})?$)|(^0?1[35]\d{9}$)"); + //弱一点的验证: @"\d{3,4}-\d{7,8}" + } + + #endregion + + #region 验证是否是有效传真号码 + + /// + /// 验证是否是有效传真号码 + /// + /// 输入字符 + /// 返回一个bool类型的值 + public static bool IsFax(this string str) + { + return Regex.IsMatch(str, @"^[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+$"); + } + + #endregion + + #region 验证手机号是否合法 + + /// + /// 验证手机号是否合法 号段为13,14,15,16,17,18,19 0,86开头将自动识别 + /// + /// 输入字符 + /// 返回一个bool类型的值 + public static bool IsMobile(this string str) + { + if (!str.StartsWith("1")) + { + str = str.TrimStart('8', '6').TrimStart('0'); + } + + return Regex.IsMatch(str, @"^(13|14|15|16|17|18|19)\d{9}$"); + } + + #endregion + + #region 验证身份证是否有效 + + /// + /// 验证身份证是否有效 + /// + /// 输入字符 + /// 返回一个bool类型的值 + public static bool IsIdCard(this string str) + { + return str.Length switch + { + 18 => str.IsIdCard18(), + 15 => str.IsIdCard15(), + _ => false + }; + } + + /// + /// 验证输入字符串为18位的身份证号码 + /// + /// 输入字符 + /// 返回一个bool类型的值 + public static bool IsIdCard18(this string str) + { + if (long.TryParse(str.Remove(17), out var n) == false || n < Math.Pow(10, 16) || + long.TryParse(str.Replace('x', '0').Replace('X', '0'), out n) == false) + { + return false; //数字验证 + } + + const string address = + "11x22x35x44x53x12x23x36x45x54x13x31x37x46x61x14x32x41x50x62x15x33x42x51x63x21x34x43x52x64x65x71x81x82x91"; + if (address.IndexOf(str.Remove(2), StringComparison.Ordinal) == -1) + { + return false; //省份验证 + } + + var birth = str.Substring(6, 8).Insert(6, "-").Insert(4, "-"); + if (DateTime.TryParse(birth, out _) == false) + { + return false; //生日验证 + } + + var arrVarIfyCode = ("1,0,x,9,8,7,6,5,4,3,2").Split(','); + var wi = ("7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2").Split(','); + var ai = str.Remove(17).ToCharArray(); + var sum = 0; + for (var i = 0; i < 17; i++) + { + sum += int.Parse(wi[i]) * int.Parse(ai[i].ToString()); + } + + // ReSharper disable once UselessBinaryOperation + Math.DivRem(sum, 11, out var y); + return arrVarIfyCode[y] == str.Substring(17, 1).ToLower(); + } + + /// + /// 验证输入字符串为15位的身份证号码 + /// + /// 输入字符 + /// 返回一个bool类型的值 + public static bool IsIdCard15(this string str) + { + if (long.TryParse(str, out var n) == false || n < Math.Pow(10, 14)) + { + return false; //数字验证 + } + + const string address = + "11x22x35x44x53x12x23x36x45x54x13x31x37x46x61x14x32x41x50x62x15x33x42x51x63x21x34x43x52x64x65x71x81x82x91"; + if (address.IndexOf(str.Remove(2), StringComparison.Ordinal) == -1) + { + return false; //省份验证 + } + + var birth = str.Substring(6, 6).Insert(4, "-").Insert(2, "-"); + return DateTime.TryParse(birth, out _); + } + + #endregion + + #region 验证是否是有效邮箱地址 + + /// + /// 验证是否是有效邮箱地址 + /// + /// 输入字符 + /// 返回一个bool类型的值 + public static bool IsEmail(this string str) + { + return Regex.IsMatch(str, + @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$"); + } + + /// + /// 验证是否是有效QQ邮箱地址 + /// + /// 输入字符 + /// 返回一个bool类型的值 + public static bool IsQqEmail(this string str) + { + return Regex.IsMatch(str, @"[1-9]\d{4,10}@qq\.com"); + } + + #endregion + + #region 验证是否只含有汉字 + + /// + /// 验证是否只含有汉字 + /// + /// 输入字符 + /// + public static bool IsOnlyChinese(this string strLn) + { + return Regex.IsMatch(strLn, @"^[\u4e00-\u9fa5]+$"); + } + + #endregion + + #region 是否有多余的字符 防止SQL注入 + + /// + /// 是否有多余的字符 防止SQL注入 + /// + /// 输入字符 + /// + public static bool IsBadString(this string str) + { + if (string.IsNullOrEmpty(str)) + return false; + //列举一些特殊字符串 + const string badChars = + "@,*,#,$,!,+,',=,--,%,^,&,?,(,), <,>,[,],{,},/,\\,;,:,\",\"\",delete,update,drop,alert,select"; + var arraryBadChar = badChars.Split(','); + return arraryBadChar.Any(t => !str.Contains(t)); + } + + #endregion + + #region 是否由数字、26个英文字母或者下划线組成的字串 + + /// + /// 是否由数字、26个英文字母或者下划线組成的字串 + /// + /// 输入字符 + /// + public static bool IsNzx(this string str) + { + return Regex.Match(str, "^[0-9a-zA-Z_]+$").Success; + } + + #endregion + + #region 由数字、26个英文字母、汉字組成的字串 + + /// + /// 由数字、26个英文字母、汉字組成的字串 + /// + /// 输入字符 + /// + public static bool IsSzzmChinese(this string str) + { + return Regex.Match(str, @"^[0-9a-zA-Z\u4e00-\u9fa5]+$").Success; + } + + #endregion + + #region 由数字、26个英文字母組成的字串 + + /// + /// 是否由数字、26个英文字母組成的字串 + /// + /// 输入字符 + /// + public static bool IsSzzm(this string str) + { + return Regex.Match(str, @"^[0-9a-zA-Z]+$").Success; + } + + #endregion + + #region 验证输入字符串为邮政编码 + + /// + /// 验证输入字符串为邮政编码 + /// + /// 输入字符 + /// 返回一个bool类型的值 + public static bool IsPostCode(this string str) + { + return Regex.IsMatch(str, @"\d{6}"); + } + + #endregion + + #region 检查对象的输入长度 + + /// + /// 检查对象的输入长度 + /// + /// 输入字符 + /// 指定的长度 + /// false 太长,true -太短 + public static bool CheckLength(this string str, int length) + { + if (str.Length > length) + { + return false; //长度太长 + } + + return str.Length >= length; + } + + #endregion + + #region 判断用户输入是否为日期 + + /// + /// 判断用户输入是否为日期 + /// + /// 输入字符 + /// 返回一个bool类型的值 + /// + /// 可判断格式如下(其中-可替换为/,不影响验证) + /// YYYY | YYYY-MM | YYYY-MM-DD | YYYY-MM-DD HH:MM:SS | YYYY-MM-DD HH:MM:SS.FFF + /// + public static bool IsDateTime(this string str) + { + if (null == str) + { + return false; + } + + const string regexDate = + @"[1-2]{1}[0-9]{3}((-|\/|\.){1}(([0]?[1-9]{1})|(1[0-2]{1}))((-|\/|\.){1}((([0]?[1-9]{1})|([1-2]{1}[0-9]{1})|(3[0-1]{1})))( (([0-1]{1}[0-9]{1})|2[0-3]{1}):([0-5]{1}[0-9]{1}):([0-5]{1}[0-9]{1})(\.[0-9]{3})?)?)?)?$"; + if (!Regex.IsMatch(str, regexDate)) + return false; + //以下各月份日期验证,保证验证的完整性 + int indexY; + int indexM; + int indexD; + if (-1 != (indexY = str.IndexOf("-", StringComparison.Ordinal))) + { + indexM = str.IndexOf("-", indexY + 1, StringComparison.Ordinal); + indexD = str.IndexOf(":", StringComparison.Ordinal); + } + else + { + indexY = str.IndexOf("/", StringComparison.Ordinal); + indexM = str.IndexOf("/", indexY + 1, StringComparison.Ordinal); + indexD = str.IndexOf(":", StringComparison.Ordinal); + } + + //不包含日期部分,直接返回true + if (-1 == indexM) + return true; + if (-1 == indexD) + { + indexD = str.Length + 3; + } + + var iYear = Convert.ToInt32(str.Substring(0, indexY)); + var iMonth = Convert.ToInt32(str.Substring(indexY + 1, indexM - indexY - 1)); + var iDate = Convert.ToInt32(str.Substring(indexM + 1, indexD - indexM - 4)); + //判断月份日期 + if ((iMonth < 8 && 1 == iMonth % 2) || (iMonth > 8 && 0 == iMonth % 2)) + { + if (iDate < 32) + return true; + } + else + { + if (iMonth != 2) + { + if (iDate < 31) + return true; + } + else + { + //闰年 + if ((0 == iYear % 400) || (0 == iYear % 4 && 0 < iYear % 100)) + { + if (iDate < 30) + return true; + } + else + { + if (iDate < 29) + return true; + } + } + } + + return false; + } + + #endregion +} diff --git a/Magic.Core/Util/TreeBuildUtil.cs b/Magic.Core/Util/TreeBuildUtil.cs new file mode 100644 index 0000000..45ab72d --- /dev/null +++ b/Magic.Core/Util/TreeBuildUtil.cs @@ -0,0 +1,77 @@ +using System.Collections; +using System.Collections.Generic; + +namespace Magic.Core; + +/// +/// 树基类 +/// +public interface ITreeNode +{ + /// + /// 获取节点id + /// + /// + long GetId(); + + /// + /// 获取节点父id + /// + /// + long GetPid(); + + /// + /// 设置Children + /// + /// + void SetChildren(IList children); +} + +/// +/// 递归工具类,用于遍历有父子关系的节点,例如菜单树,字典树等等 +/// +/// +public class TreeBuildUtil where T : ITreeNode +{ + /// + /// 顶级节点的父节点Id(默认0) + /// + private readonly long _rootParentId = 0L; + + /// + /// 构造树节点 + /// + /// + /// + public List DoTreeBuild(List nodes) + { + nodes.ForEach(u => BuildChildNodes(nodes, u, new List())); + + var results = new List(); + nodes.ForEach(u => + { + if (_rootParentId == u.GetPid()) + results.Add(u); + }); + return results; + } + + /// + /// 构造子节点集合 + /// + /// + /// + /// + private void BuildChildNodes(List totalNodes, T node, List childNodeLists) + { + var nodeSubLists = new List(); + totalNodes.ForEach(u => + { + if (u.GetPid().Equals(node.GetId())) + nodeSubLists.Add(u); + }); + nodeSubLists.ForEach(u => BuildChildNodes(totalNodes, u, new List())); + childNodeLists.AddRange(nodeSubLists); + node.SetChildren(childNodeLists); + } +} diff --git a/Magic.Core/logo.png b/Magic.Core/logo.png new file mode 100644 index 0000000..5a014a8 Binary files /dev/null and b/Magic.Core/logo.png differ diff --git a/Magic.FlowCenter/Entity/FlcCustomForm.cs b/Magic.FlowCenter/Entity/FlcCustomForm.cs new file mode 100644 index 0000000..f80ae3a --- /dev/null +++ b/Magic.FlowCenter/Entity/FlcCustomForm.cs @@ -0,0 +1,42 @@ +using SqlSugar; +using System; + +namespace Magic.FlowCenter.Entity; + +/// +/// 自定义表单 +/// +[SugarTable("flc_customform")] +public class FlcCustomForm : FlcInstanceEntity +{ + /// + /// 名称 + /// + [SugarColumn(ColumnDescription = "名称")] + public string Name { get; set; } + /// + /// 排序 + /// + [SugarColumn(ColumnDescription = "排序")] + public int Sort { get; set; } + /// + /// 备注 + /// + [SugarColumn(ColumnDescription = "备注", IsNullable = true)] + public string Remark { get; set; } + /// + /// 创建时间 + /// + [SugarColumn(ColumnDescription = "创建时间")] + public virtual DateTime? CreatedTime { get; set; } + /// + /// 创建者Id + /// + [SugarColumn(ColumnDescription = "创建者Id")] + public virtual long? CreatedUserId { get; set; } + /// + /// 创建者名称 + /// + [SugarColumn(ColumnDescription = "创建者名称")] + public virtual string CreatedUserName { get; set; } +} diff --git a/Magic.FlowCenter/Entity/FlcDBEntityTenant.cs b/Magic.FlowCenter/Entity/FlcDBEntityTenant.cs new file mode 100644 index 0000000..9b39347 --- /dev/null +++ b/Magic.FlowCenter/Entity/FlcDBEntityTenant.cs @@ -0,0 +1,36 @@ +using SqlSugar; + +namespace Magic.FlowCenter.Entity; + +/// +/// 自定义租户基类实体 +/// +public abstract class FlcDBEntityTenant : FlcDEntityBase +{ + /// + /// 租户id + /// + [SugarColumn(ColumnDescription = "租户id")] + public virtual long? TenantId { get; set; } + + //public override void Create() { + // var userId = App.User.FindFirst(ClaimConst.CLAINM_USERID)?.Value; + // var userName = App.User.FindFirst(ClaimConst.CLAINM_ACCOUNT)?.Value; + // var tenantId = App.User.FindFirst(ClaimConst.TENANT_ID)?.Value; + // this.Id = YitIdHelper.NextId(); + // this.CreatedTime = DateTime.Now; + + // if (!string.IsNullOrEmpty(userId)) + // { + // this.CreatedUserId = long.Parse(userId); + // this.CreatedUserName = userName; + // } + // if (!string.IsNullOrWhiteSpace(tenantId)) { + // this.TenantId = long.Parse(tenantId); + // } + //} + + //public void CreateNotFillTenantInfo() { + // base.Create(); + //} +} diff --git a/Magic.FlowCenter/Entity/FlcDEntityBase.cs b/Magic.FlowCenter/Entity/FlcDEntityBase.cs new file mode 100644 index 0000000..18b5468 --- /dev/null +++ b/Magic.FlowCenter/Entity/FlcDEntityBase.cs @@ -0,0 +1,132 @@ +using SqlSugar; +using System; +using System.ComponentModel.DataAnnotations; + +namespace Magic.FlowCenter.Entity; + +/// +/// 自定义实体基类 +/// +[Tenant("1")] +public abstract class FlcDEntityBase : PrimaryKeyEntity +{ + /// + /// 创建时间 + /// + [SugarColumn(ColumnDescription = "创建时间")] + public virtual DateTime? CreatedTime { get; set; } + + /// + /// 更新时间 + /// + [SugarColumn(ColumnDescription = "更新时间", IsNullable = true)] + public virtual DateTime? UpdatedTime { get; set; } + + /// + /// 创建者Id + /// + [SugarColumn(ColumnDescription = "创建者Id")] + public virtual long? CreatedUserId { get; set; } + + /// + /// 创建者名称 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "创建者名称")] + public virtual string CreatedUserName { get; set; } + + /// + /// 修改者Id + /// + [SugarColumn(ColumnDescription = "修改者Id", IsNullable = true)] + public virtual long? UpdatedUserId { get; set; } + + /// + /// 修改者名称 + /// + [MaxLength(20)] + [SugarColumn(ColumnDescription = "修改者名称", IsNullable = true)] + public virtual string UpdatedUserName { get; set; } + + /// + /// 软删除 + /// + [SugarColumn(ColumnDescription = "软删除")] + public virtual bool IsDeleted { get; set; } = false; + + + //public virtual void Create() + //{ + // var userId = App.User.FindFirst(ClaimConst.CLAINM_USERID)?.Value; + // var userName = App.User.FindFirst(ClaimConst.CLAINM_ACCOUNT)?.Value; + // Id = YitIdHelper.NextId(); + // CreatedTime = DateTime.Now; + // if (!string.IsNullOrEmpty(userId)) + // { + // CreatedUserId = long.Parse(userId); + // CreatedUserName = userName; + // } + //} + + //public void Modify() + //{ + // var userId = App.User.FindFirst(ClaimConst.CLAINM_USERID)?.Value; + // var userName = App.User.FindFirst(ClaimConst.CLAINM_ACCOUNT)?.Value; + // UpdatedTime = DateTime.Now; + // if (!string.IsNullOrEmpty(userId)) + // { + // UpdatedUserId = long.Parse(userId); + // UpdatedUserName = userName; + // } + //} + + /// + /// 更新信息列 + /// + /// + public virtual string[] UpdateColumn() + { + var result = new[] {nameof(UpdatedUserId), nameof(UpdatedUserName), nameof(UpdatedTime)}; + return result; + } + + /// + /// 假删除的列,包含更新信息 + /// + /// + public virtual string[] FalseDeleteColumn() + { + var updateColumn = UpdateColumn(); + var deleteColumn = new[] {nameof(IsDeleted)}; + var result = new string [updateColumn.Length + deleteColumn.Length]; + deleteColumn.CopyTo(result, 0); + updateColumn.CopyTo(result, deleteColumn.Length); + return result; + } +} + +/// +/// 递增主键实体基类 +/// +public abstract class AutoIncrementEntity +{ + /// + /// 主键Id + /// + [SugarColumn(IsIdentity = true, ColumnDescription = "Id主键", IsPrimaryKey = true)] //通过特性设置主键和自增列 + // 注意是在这里定义你的公共实体 + public virtual int Id { get; set; } +} + +/// +/// 主键实体基类 +/// +public abstract class PrimaryKeyEntity +{ + /// + /// 主键Id + /// + [SugarColumn(ColumnDescription = "Id主键", IsPrimaryKey = true)] + // 注意是在这里定义你的公共实体 + public virtual long Id { get; set; } +} diff --git a/Magic.FlowCenter/Entity/FlcFlowInstanceOperationHistory.cs b/Magic.FlowCenter/Entity/FlcFlowInstanceOperationHistory.cs new file mode 100644 index 0000000..03a47a4 --- /dev/null +++ b/Magic.FlowCenter/Entity/FlcFlowInstanceOperationHistory.cs @@ -0,0 +1,38 @@ +using SqlSugar; +using System; + +namespace Magic.FlowCenter.Entity; + +/// +/// 工作流实例操作记录 +/// +[Tenant("1")] +[SugarTable("flc_flowinstanceinfo")] +public class FlcFlowInstanceOperationHistory : PrimaryKeyEntity +{ + /// + /// 实例进程Id + /// + [SugarColumn(IsNullable = false,ColumnDescription = "实例进程Id")] + public long InstanceId { get; set; } + /// + /// 操作内容 + /// + [SugarColumn(IsNullable = true,ColumnDescription = "操作内容")] + public string Content { get; set; } + /// + /// 创建时间 + /// + [SugarColumn(IsNullable = false,ColumnDescription = "类别名称")] + public DateTime? CreatedTime { get; set; } + /// + /// 创建用户主键 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "创建用户主键")] + public long CreatedUserId { get; set; } + /// + /// 创建用户 + /// + [SugarColumn(IsNullable = true,ColumnDescription = "创建用户")] + public string CreatedUserName { get; set; } +} diff --git a/Magic.FlowCenter/Entity/FlcFlowInstanceTransitionHistory.cs b/Magic.FlowCenter/Entity/FlcFlowInstanceTransitionHistory.cs new file mode 100644 index 0000000..71de6e0 --- /dev/null +++ b/Magic.FlowCenter/Entity/FlcFlowInstanceTransitionHistory.cs @@ -0,0 +1,74 @@ +using System; +using SqlSugar; + +namespace Magic.FlowCenter.Entity; + +/// +/// 工作流实例流转历史记录 +/// +[Tenant("1")] +[SugarTable("flc_flowinstancehis")] +public class FlcFlowInstanceTransitionHistory : PrimaryKeyEntity +{ + /// + /// 实例Id + /// + [SugarColumn(IsNullable = false,ColumnDescription = "实例Id")] + public long InstanceId { get; set; } + /// + /// 开始节点Id + /// + [SugarColumn(IsNullable = true, ColumnDescription = "开始节点Id")] + public string FromNodeId { get; set; } + /// + /// 开始节点类型 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "开始节点类型")] + public int? FromNodeType { get; set; } + /// + /// 开始节点名称 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "开始节点名称")] + public string FromNodeName { get; set; } + /// + /// 结束节点Id + /// + [SugarColumn(IsNullable = true, ColumnDescription = "结束节点Id")] + public string ToNodeId { get; set; } + /// + /// 结束节点类型 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "结束节点类型")] + public int? ToNodeType { get; set; } + /// + /// 结束节点名称 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "结束节点名称")] + public string ToNodeName { get; set; } + /// + /// 转化状态 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "转化状态")] + public bool TransitionSate { get; set; } + /// + /// 是否结束 + /// + [SugarColumn(IsNullable = false,ColumnDescription = "是否结束")] + public bool IsFinish { get; set; } + /// + /// 转化时间 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "转化时间")] + public DateTime CreatedTime { get; set; } + /// + /// 创建用户主键 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "创建用户主键")] + public long CreatedUserId { get; set; } + /// + /// 创建用户 + /// + [SugarColumn(IsNullable = true,ColumnDescription = "创建用户")] + public string CreatedUserName { get; set; } + +} diff --git a/Magic.FlowCenter/Entity/FlcFlowinstance.cs b/Magic.FlowCenter/Entity/FlcFlowinstance.cs new file mode 100644 index 0000000..823a913 --- /dev/null +++ b/Magic.FlowCenter/Entity/FlcFlowinstance.cs @@ -0,0 +1,176 @@ +using System.ComponentModel.DataAnnotations; +using Magic.Core; +using SqlSugar; + +namespace Magic.FlowCenter.Entity; + +/// +/// 创 建:超级管理员 +/// 日 期:2020-07-14 09:18 +/// 描 述:我的流程实体类 +/// +[SugarTable("flc_flowinstance")] +public class FlcFlowinstance: FlcDBEntityTenant +{ + /// + /// 流程实例模板Id + /// + /// + [SugarColumn(IsNullable = true, ColumnDescription = "流程实例模板Id")] + public long? InstanceSchemeId { get; set; } + /// + /// 实例编号 + /// + /// + [SugarColumn(IsNullable = false,ColumnDescription = "实例编号", UniqueGroupNameList = new string[] { "oms_flowinstance" })] + public string Code { get; set; } + /// + /// 自定义名称 + /// + /// + [SugarColumn(IsNullable = true, ColumnDescription = "自定义名称")] + public string CustomName { get; set; } + /// + /// 当前节点ID + /// + /// + [SugarColumn(IsNullable = true, ColumnDescription = "当前节点ID")] + public string ActivityId { get; set; } + /// + /// 当前节点类型(0会签节点) + /// + /// + [SugarColumn(IsNullable = true, ColumnDescription = "当前节点类型")] + public int? ActivityType { get; set; } + /// + /// 当前节点名称 + /// + /// + [SugarColumn(IsNullable = true, ColumnDescription = "当前节点名称")] + public string ActivityName { get; set; } + /// + /// 前一个ID + /// + /// + [SugarColumn(IsNullable = true,ColumnDescription = "前一个ID")] + public string PreviousId { get; set; } + /// + /// 流程模板内容 + /// + /// + [SugarColumn(IsNullable = true, ColumnDataType = "text", ColumnDescription = "流程模板内容")] + public string SchemeContent { get; set; } + /// + /// 流程模板ID + /// + /// + [Required(ErrorMessage = "模板不能为空")] + [SugarColumn(IsNullable = true,ColumnDescription = "流程模板ID")] + public long SchemeId { get; set; } + /// + /// 数据库名称 + /// + /// + [SugarColumn(IsNullable = false, ColumnDescription = "数据库名称")] + public string DbName { get; set; } + /// + /// 表单数据 + /// + /// + [SugarColumn(IsNullable = true, ColumnName = "FrmData", ColumnDataType = "text", ColumnDescription = "表单数据")] + public string FrmData { get; set; } + /// + /// 表单类型 + /// + /// + [SugarColumn(IsNullable = false, ColumnDescription = "表单类型")] + public FormType? FrmType { get; set; } + /// + /// 表单中的字段 + /// + /// + [SugarColumn(IsNullable = true, ColumnDataType = "text", ColumnDescription = "表单中的字段")] + public string FrmContentData { get; set; } + /// + /// 表单字段(冗余) + /// + /// + [SugarColumn(IsNullable = true, ColumnDataType = "text", ColumnDescription = "表单字段")] + public string FrmContentParse { get; set; } + /// + /// 表单参数 + /// + /// + [SugarColumn(IsNullable = true,ColumnDataType = "text", ColumnDescription = "表单参数")] + public string FrmContent { get; set; } + /// + /// 表单ID + /// + /// + [SugarColumn(IsNullable = true, ColumnDescription = "表单ID")] + public long? FrmId { get; set; } + /// + /// 流程类型 + /// + /// + [SugarColumn(IsNullable = true, ColumnDataType = "text", ColumnDescription = "流程类型")] + public string SchemeType { get; set; } + /// + /// 等级 + /// + /// + [SugarColumn(IsNullable = false, ColumnDescription = "等级")] + public int FlowLevel { get; set; } + /// + /// 是否完成 + /// + /// + [SugarColumn(IsNullable = false, ColumnDescription = "是否完成")] + public int IsFinish { get; set; } + /// + /// 执行人 + /// + /// + [SugarColumn(IsNullable = true, ColumnDataType = "text", ColumnDescription = "执行人")] + public string MakerList { get; set; } + /// + /// 所属部门 + /// + /// + [SugarColumn(IsNullable = true, ColumnDescription = "所属部门")] + public long? OrgId { get; set; } + /// + /// 状态标识 + /// + [SugarColumn(ColumnDescription = "状态")] + public CommonStatus? Status { get; set; } + /// + /// 如果下个执行节点是运行时指定执行者。需要传指定的类型 + /// 取值为RUNTIME_SPECIAL_ROLE、RUNTIME_SPECIAL_USER + /// + [SugarColumn(IsIgnore=true)] + public string NextNodeDesignateType { get; set; } + + /// + /// 如果下个执行节点是运行时指定执行者。该值表示具体的执行者 + /// 如果NodeDesignateType为RUNTIME_SPECIAL_ROLE,则该值为指定的角色 + /// 如果NodeDesignateType为RUNTIME_SPECIAL_USER,则该值为指定的用户 + /// + [SugarColumn(IsIgnore=true)] + public string[] NextNodeDesignates { get; set; } + /// + /// 下个节点执行人 + /// + [SugarColumn(IsIgnore=true)] + public string NextMakerName { get; set; } + /// + /// 当前节点执行人 + /// + [SugarColumn(IsIgnore=true)] + public string CurrentMakerName { get; set; } + /// + /// 当前节点执行类型 + /// + [SugarColumn(IsIgnore=true)] + public string CurrentNodeDesignateType { get; set; } +} diff --git a/Magic.FlowCenter/Entity/FlcFlowscheme.cs b/Magic.FlowCenter/Entity/FlcFlowscheme.cs new file mode 100644 index 0000000..1cd881e --- /dev/null +++ b/Magic.FlowCenter/Entity/FlcFlowscheme.cs @@ -0,0 +1,95 @@ +using Magic.Core; +using SqlSugar; +namespace Magic.FlowCenter.Entity; + +/// +/// 流程 +/// +[SugarTable("flc_flowscheme")] +public class FlcFlowscheme : FlcDEntityBase +{ + /// + /// 流程编号 + /// 默认值: + /// + [SugarColumn(ColumnDescription = "流程编号",IsNullable = true)] + public string SchemeCode { get; set; } + /// + /// 流程名称 + /// 默认值: + /// + [SugarColumn(ColumnDescription = "流程名称", IsNullable = true)] + public string SchemeName { get; set; } + /// + /// 流程类型 + /// 默认值: + /// + [SugarColumn(ColumnDescription = "流程类型",IsNullable = true)] + public string SchemeType { get; set; } + /// + /// 流程版本 + /// 默认值: + /// + [SugarColumn(ColumnDescription = "流程版本",IsNullable = true)] + public string SchemeVersion { get; set; } + /// + /// 流程使用人 + /// 默认值: + /// + [SugarColumn(ColumnDescription = "流程使用人", IsNullable = true)] + public string SchemeCanUser { get; set; } + /// + /// 流程内容 + /// 默认值: + /// + [SugarColumn(ColumnDescription = "流程内容", ColumnDataType = "text", IsNullable = true)] + public string SchemeContent { get; set; } + /// + /// 表单Id + /// 默认值: + /// + [SugarColumn( ColumnDescription = "表单Id", IsNullable = true)] + public long? FrmId { get; set; } + /// + /// 表单类型 + /// 默认值: + /// + [SugarColumn(ColumnDescription = "表单类型")] + public FormType? FrmType { get; set; } + /// + /// 权限类型 + /// 默认值: + /// + [SugarColumn(ColumnDescription = "权限类型")] + public int? AuthorizeType { get; set; } + /// + /// 组织Id + /// 默认值: + /// + [SugarColumn( ColumnDescription = "组织Id",IsNullable = true)] + public long? OrgId { get; set; } + /// + /// + /// 默认值: + /// + [SugarColumn(ColumnDescription = "")] + public string Active { get; set; } + /// + /// 状态 + /// 默认值: + /// + [SugarColumn(ColumnDescription = "状态")] + public CommonStatus? Status { get; set; } + /// + /// 排序 + /// 默认值: + /// + [SugarColumn(ColumnDescription = "排序")] + public int? Sort { get; set; } + /// + /// 备注 + /// 默认值: + /// + [SugarColumn(ColumnDescription = "备注", IsNullable = true)] + public string Remark { get; set; } +} diff --git a/Magic.FlowCenter/Entity/FlcForm.cs b/Magic.FlowCenter/Entity/FlcForm.cs new file mode 100644 index 0000000..a1bc1e3 --- /dev/null +++ b/Magic.FlowCenter/Entity/FlcForm.cs @@ -0,0 +1,89 @@ +using Magic.Core; +using SqlSugar; +namespace Magic.FlowCenter.Entity; + +/// +/// 表单 +/// +[SugarTable("flc_form")] +public class FlcForm: FlcDEntityBase +{ + /// + /// 表单名称 + /// 默认值: + /// + [SugarColumn(ColumnDescription= "表单名称", IsNullable = true)] + public string Name { get; set; } + /// + /// 表单类型 + /// 默认值: + /// + [SugarColumn(ColumnDescription = "表单类型", IsNullable = true)] + public FormType? FrmType { get; set; } + /// + /// 自定义表单 + /// 默认值: + /// + [SugarColumn(ColumnDescription= "自定义表单", IsNullable = true)] + public string WebId { get; set; } + /// + /// 字段数 + /// 默认值: + /// + [SugarColumn(ColumnDescription= "字段数",IsNullable = true)] + public int? Fields { get; set; } + /// + /// 字段 + /// 默认值: + /// + [SugarColumn(ColumnDescription= "字段", ColumnDataType = "text", IsNullable = true)] + public string ContentData { get; set; } + /// + /// 字段格式化 + /// 默认值: + /// + [SugarColumn(ColumnDescription= "字段格式化", ColumnDataType = "text", IsNullable = true)] + public string ContentParse { get; set; } + /// + /// 表单内容 + /// 默认值: + /// + [SugarColumn(ColumnDescription= "表单内容", ColumnDataType = "text", IsNullable = true)] + public string Content { get; set; } + /// + /// 数据库备用 + /// 默认值: + /// + [SugarColumn(ColumnDescription= "数据库备用",IsNullable = true)] + public string DbName { get; set; } + /// + /// 组织id + /// 默认值: + /// + [SugarColumn(ColumnDescription= "组织id", IsNullable = true)] + public long? OrgId { get; set; } + /// + /// + /// 默认值: + /// + [SugarColumn(ColumnName="Active",ColumnDescription="",IsNullable = true)] + public string Active { get; set; } + /// + /// 状态 + /// 默认值: + /// + [SugarColumn(ColumnDescription= "状态")] + public CommonStatus? Status { get; set; } + /// + /// 排序 + /// 默认值: + /// + [SugarColumn(ColumnDescription= "排序")] + public int? Sort { get; set; } + /// + /// 备注 + /// 默认值: + /// + [SugarColumn(ColumnDescription= "备注", IsNullable = true)] + public string Remark { get; set; } +} diff --git a/Magic.FlowCenter/Entity/FlcInstanceEntity.cs b/Magic.FlowCenter/Entity/FlcInstanceEntity.cs new file mode 100644 index 0000000..c4f9f23 --- /dev/null +++ b/Magic.FlowCenter/Entity/FlcInstanceEntity.cs @@ -0,0 +1,16 @@ +using SqlSugar; + +namespace Magic.FlowCenter.Entity; + +/// +/// 自定义表单实体 +/// +[Tenant("1")] +public class FlcInstanceEntity : PrimaryKeyEntity +{ + /// + /// 申请流程Id + /// + [SugarColumn(IsNullable = true)] + public long FlowInstanceId { get; set; } +} diff --git a/Magic.FlowCenter/Entity/Flow/Flow.cs b/Magic.FlowCenter/Entity/Flow/Flow.cs new file mode 100644 index 0000000..2e9e650 --- /dev/null +++ b/Magic.FlowCenter/Entity/Flow/Flow.cs @@ -0,0 +1,58 @@ +using System.Collections.Generic; + +namespace Magic.FlowCenter.Entity; + +/// +/// 流程 +/// + public class Flow +{ + /// + /// 流程配置 + /// + public FlowConfig config { get; set; } + /// + /// 参数 + /// + public Attr attr { get; set; } + /// + /// 状态 + /// + public string status { get; set; } + /// + /// 连线 + /// + public List linkList { get; set; } + /// + /// 节点 + /// + public List nodeList { get; set; } + /// + /// 泳道 + /// + public List areaList { get; set; } +} +/// +/// 流程配置 +/// +public class FlowConfig { + /// + /// 网格 + /// + public bool showGrid { get; set; } + /// + /// 文字 + /// + public string showGridText { get; set; } + /// + /// 图标 + /// + public string showGridIcon { get; set; } +} +/// +/// 参数 +/// +public class Attr +{ + public string id { get; set; } +} diff --git a/Magic.FlowCenter/Entity/Flow/FlowArea.cs b/Magic.FlowCenter/Entity/Flow/FlowArea.cs new file mode 100644 index 0000000..851f14e --- /dev/null +++ b/Magic.FlowCenter/Entity/Flow/FlowArea.cs @@ -0,0 +1,42 @@ +namespace Magic.FlowCenter.Entity; + +/// +/// 流程泳道 +/// + public class FlowArea +{ + public const string YLANE = "y-lane"; //y泳道 + public const string XLANE = "x-lane"; //x泳道 + /// + /// 泳道Id + /// + public string id { get; set; } + /// + /// 名称 + /// + public string name { get; set; } + /// + /// 类型 + /// + public string type { get; set; } + /// + /// 图标 + /// + public string icon { get; set; } + /// + /// x坐标 + /// + public int x { get; set; } + /// + /// y坐标 + /// + public int y { get; set; } + /// + /// 宽度 + /// + public int width { get; set; } + /// + /// 高度 + /// + public int height { get; set; } +} diff --git a/Magic.FlowCenter/Entity/Flow/FlowLine.cs b/Magic.FlowCenter/Entity/Flow/FlowLine.cs new file mode 100644 index 0000000..9d88aef --- /dev/null +++ b/Magic.FlowCenter/Entity/Flow/FlowLine.cs @@ -0,0 +1,302 @@ +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json.Linq; + +namespace Magic.FlowCenter.Entity; + +/// +/// 流程连线 +/// +public class FlowLine +{ + /// + /// 线Id + /// + public string id { get; set; } + /// + /// 显示 + /// + public string label { get; set; } + /// + /// 类型 + /// + public string type { get; set; } + /// + /// 源头节点 + /// + public string sourceId { get; set; } + /// + /// 目标节点 + /// + public string targetId { get; set; } + /// + /// 名称 + /// + public string name { get; set; } + /// + /// 连接样式 + /// + public LineStyle cls { get; set; } + + /// 分支条件 + public List Compares { get; set; } + /// + /// 连线比较 + /// + /// + /// + public bool Compare(JObject frmDataJson) + { + bool result = true; + foreach (var compare in Compares) + { + compare.FieldName = compare.FieldName.ToLower(); + compare.Value = compare.Value.ToLower(); + decimal value=0; //参考值 + decimal frmvalue=0; //表单中填写的值 + if (compare.Operation!= DataCompare.Equal&& compare.Operation != DataCompare.NotEqual) + { + value = decimal.Parse(compare.Value); + frmvalue = decimal.Parse(frmDataJson.GetValue(compare.FieldName.ToLower()).ToString()); //表单中填写的值 + } + bool res = false; + if (compare.Condition=="and") + { + switch (compare.Operation) + { + case DataCompare.Equal: + result &= compare.Value == frmDataJson.GetValue(compare.FieldName).ToString(); + break; + case DataCompare.NotEqual: + result &= compare.Value != frmDataJson.GetValue(compare.FieldName).ToString(); + break; + case DataCompare.Larger: + result &= frmvalue > value; + break; + case DataCompare.Less: + result &= frmvalue < value; + break; + case DataCompare.LargerEqual: + result &= frmvalue <= value; + break; + case DataCompare.LessEqual: + result &= frmvalue <= value; + break; + case DataCompare.In: + if (compare.FieldName == "申请人" || compare.FieldName == "所属部门") + { + var arr = compare.Value.Split(','); + foreach (var item in frmDataJson.GetValue(compare.FieldName).ToString().Split(',')) + { + if (arr.Contains(item)) + { + res = true; + break; + } + } + result &= res; + break; + } + else + { + var arr = compare.Value.Split(','); + if (arr.Contains(frmvalue.ToString())) + { + res = true; + break; + } + result &= res; + break; + } + case DataCompare.NotIn: + if (compare.FieldName == "申请人" || compare.FieldName == "所属部门") + { + var arr = compare.Value.Split(','); + foreach (var item in frmDataJson.GetValue(compare.FieldName).ToString().Split(',')) + { + if (arr.Contains(item)) + { + res = false; + break; + } + } + result &= res; + break; + } + else + { + var arr = compare.Value.Split(','); + if (arr.Contains(frmvalue.ToString())) + { + res = false; + break; + } + result &= res; + break; + } + } + } + else + { + switch (compare.Operation) + { + case DataCompare.Equal: + if (compare.FieldName == "申请人" || compare.FieldName == "所属部门") + { + var arr = compare.Value.Split(','); + foreach (var item in frmDataJson.GetValue(compare.FieldName).ToString().Split(',')) + { + if (arr.Contains(item)) + { + res = true; + break; + } + } + result |= res; + break; + } + result |= compare.Value == frmDataJson.GetValue(compare.FieldName).ToString(); + break; + case DataCompare.NotEqual: + if (compare.FieldName == "申请人" || compare.FieldName == "所属部门") + { + var arr = compare.Value.Split(','); + foreach (var item in frmDataJson.GetValue(compare.FieldName).ToString().Split(',')) + { + if (arr.Contains(item)) + { + res = false; + break; + } + } + result |= res; + break; + } + result |= compare.Value != frmDataJson.GetValue(compare.FieldName).ToString(); + break; + case DataCompare.Larger: + result |= frmvalue > value; + break; + case DataCompare.Less: + result |= frmvalue < value; + break; + case DataCompare.LargerEqual: + result |= frmvalue <= value; + break; + case DataCompare.LessEqual: + result |= frmvalue <= value; + break; + case DataCompare.In: + if (compare.FieldName == "申请人" || compare.FieldName == "所属部门") + { + var arr = compare.Value.Split(','); + foreach (var item in frmDataJson.GetValue(compare.FieldName).ToString().Split(',')) + { + if (arr.Contains(item)) + { + res = true; + break; + } + } + result |= res; + break; + } + else + { + var arr = compare.Value.Split(','); + if (arr.Contains(frmvalue.ToString())) + { + res = true; + } + result |= res; + break; + } + case DataCompare.NotIn: + if (compare.FieldName == "申请人" || compare.FieldName == "所属部门") + { + var arr = compare.Value.Split(','); + foreach (var item in frmDataJson.GetValue(compare.FieldName).ToString().Split(',')) + { + if (arr.Contains(item)) + { + res = false; + break; + } + } + result |= res; + break; + } + else + { + var arr = compare.Value.Split(','); + if (arr.Contains(frmvalue.ToString())) + { + res = false; + } + result |= res; + break; + } + } + } + } + + return result; + } +} + +/// +/// 分支条件 +/// +public class DataCompare +{ + public const string Larger = ">"; + public const string Less = "<"; + public const string LargerEqual = ">="; + public const string LessEqual = "<="; + public const string NotEqual = "!="; + public const string Equal = "="; + public const string In = "in"; + public const string NotIn = "not in"; + + /// 操作类型比如大于/等于/小于 + public string Operation { get; set; } + + /// form种的字段名称 + public string FieldName { get; set; } + + /// 字段类型:"form":为表单中的字段,后期扩展系统表等. + public string FieldType { get; set; } + + /// 实际的值 + public string Value { get; set; } + /// + /// 实际值的显示值 + /// + public string ValueName { get; set; } + /// + /// 显示值 + /// + public string Name { get; set; } + /// + /// 条件关系 + /// + public string Condition { get; set; } +} +/// +/// 连接样式 +/// +public class LineStyle +{ + /// + /// 连接类型 + /// + public string linkType { get; set; } + /// + /// 连接颜色 + /// + public string linkColor { get; set; } + /// + /// + /// + public int linkThickness { get; set; } +} diff --git a/Magic.FlowCenter/Entity/Flow/FlowNode.cs b/Magic.FlowCenter/Entity/Flow/FlowNode.cs new file mode 100644 index 0000000..d9de22c --- /dev/null +++ b/Magic.FlowCenter/Entity/Flow/FlowNode.cs @@ -0,0 +1,174 @@ +using System.Collections.Generic; + +namespace Magic.FlowCenter.Entity; + +/// +/// 流程节点 +/// +public class FlowNode +{ + public const string START = "start round mix"; + public const string END = "end round"; + public const string NODE = "node"; + public const string FORK = "fork"; //会签开始节点 + public const string JOIN = "join"; //会签结束节点 + /// + /// id + /// + public string id { get; set; } + /// + /// 名称 + /// + public string name { get; set; } + /// + /// 类型 + /// + public string type { get; set; } + /// + /// 图标 + /// + public string icon { get; set; } + /// + /// x坐标 + /// + public int x { get; set; } + /// + /// y左边 + /// + public int y { get; set; } + /// + /// 宽度 + /// + public int width { get; set; } + /// + /// 高度 + /// + public int height { get; set; } + + /// + /// 节点的附加数据项 + /// + /// The set information. + public Setinfo setInfo { get; set; } +} +/// +/// 节点详细 +/// +public class Setinfo +{ + public const string SPECIAL_USER = "SPECIAL_USER"; //指定用户 + public const string ALL_USER = "ALL_USER"; //所有用户 + public const string SPECIAL_ROLE = "SPECIAL_ROLE"; //指定角色 + public const string RUNTIME_SPECIAL_ROLE = "RUNTIME_SPECIAL_ROLE"; //运行时指定角色 + public const string RUNTIME_SPECIAL_USER = "RUNTIME_SPECIAL_USER"; //运行时指定用户 + + /// + /// 节点执行权限类型 + /// + public string NodeDesignate { get; set; } + /// + /// 选择值 + /// + public List NodeDesignateData { get; set; } + /// + /// 选择显示 + /// + public List NodeDesignateName { get; set; } + /// + /// 当前部门 + /// + public bool CurrentDepart { get; set; } = false; + /// + /// 节点编号 + /// + public string NodeCode { get; set; } + /// + /// 节点名称 + /// + public string NodeName { get; set; } + /// + /// 流程执行时,三方回调的URL地址 + /// + public string ThirdPartyUrl { get; set; } + + /// + /// 驳回节点0"前一步"1"第一步"2"某一步" 3"不处理" + /// + public string NodeRejectType { get; set; } = "1"; + /// + /// 节点状态 + /// + public int? Taged { get; set; } + /// + /// 用户名称 + /// + public string UserName { get; set; } + /// + /// 用户Id + /// + public long? UserId { get; set; } + /// + /// 描述 + /// + public string Description { get; set; } + /// + /// 节点时间 + /// + public string TagedTime { get; set; } + + /// + /// 节点会签方式,all/空:默认为全部通过,one :至少有一个通过 + /// + public string NodeConfluenceType { get; set; } = "all"; + + /// + /// 会签通过的个数 + /// + public int? ConfluenceOk { get; set; } + + /// + /// 会签拒绝的个数 + /// + public int? ConfluenceNo { get; set; } +} + +/// +/// 节点执行结果标签 +/// +public class Tag +{ + /// + /// 1: 通过 + /// 2:不通过 + /// 3:驳回 + /// + public int Taged { get; set; } + /// + /// 用户id + /// + public long? UserId { get; set; } + /// + /// 用户名 + /// + public string UserName { get; set; } + /// + /// 描述 + /// + public string Description { get; set; } + /// + /// 时间 + /// + public string TagedTime { get; set; } +} + +/// +/// 1: 通过 +/// 2:不通过 +/// 3:驳回 +/// +public enum TagState +{ + Ok = 1, + No = 2 , + Reject =3 +} diff --git a/Magic.FlowCenter/Entity/Flow/FlowRuntime.cs b/Magic.FlowCenter/Entity/Flow/FlowRuntime.cs new file mode 100644 index 0000000..e7989ed --- /dev/null +++ b/Magic.FlowCenter/Entity/Flow/FlowRuntime.cs @@ -0,0 +1,546 @@ +// +// 一个正在运行中的流程实例 +// +// *********************************************************************** + +using Magic.Core; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +namespace Magic.FlowCenter.Entity; + +/// +/// 流程运行类 +/// + public class FlowRuntime +{ + /// + /// 构造函数 + /// + public FlowRuntime(FlcFlowinstance instance) + { + var schemeContentJson = instance.SchemeContent.ToObject();//获取工作流模板内容的json对象; + InitFlow(schemeContentJson); + + currentNodeId = (string.IsNullOrEmpty(instance.ActivityId)? startNodeId : instance.ActivityId); + currentNodeType = GetNodeType(currentNodeId); + FrmData = instance.FrmData; + previousId = GetPreviousNodeId(currentNodeId); + flowInstanceId = instance.Id; + + //会签开始节点和流程结束节点没有下一步 + if (currentNodeType == 0 || currentNodeType == 4) + { + nextNodeId = "-1"; + nextNodeType = -1; + } + else + { + nextNodeId = GetNextNodeId();//下一个节点 + nextNodeType = GetNodeType(nextNodeId); + } + } + #region 私有方法 + + /// + /// 获取工作流信息 + /// + /// + /// + private void InitFlow(Flow schemeContentJson) + { + flow = schemeContentJson; + InitLines(schemeContentJson); + InitNodes(schemeContentJson); + } + /// + /// 获取工作流节点的字典列表:key节点id + /// + /// + /// + private void InitNodes(Flow schemeContentJson) + { + Nodes = new Dictionary(); + foreach (var item in schemeContentJson.nodeList) + { + var node = item; + if (!Nodes.ContainsKey(node.id)) + { + Nodes.Add(node.id, node); + } + if (node.type == FlowNode.START) + { + this.startNodeId = node.id; + } + } + } + + private void InitLines(Flow schemeContentJson) + { + Lines = new List(); + FromNodeLines = new Dictionary>(); + ToNodeLines = new Dictionary>(); + foreach (var item in schemeContentJson.linkList) + { + var line = item; + Lines.Add(line); + + if (!FromNodeLines.ContainsKey(line.sourceId)) + { + List d = new List { line }; + FromNodeLines.Add(line.sourceId, d); + } + else + { + FromNodeLines[line.sourceId].Add(line); + } + + if (!ToNodeLines.ContainsKey(line.targetId)) + { + List d = new List { line }; + ToNodeLines.Add(line.targetId, d); + } + else + { + ToNodeLines[line.targetId].Add(line); + } + } + } + + /// + /// 获取下一个节点 + /// + private string GetNextNodeId(string nodeId = null) + { + var lines = nodeId == null ? FromNodeLines[currentNodeId] : FromNodeLines[nodeId]; + if (lines.Count == 0) + { + throw new Exception("无法寻找到下一个节点"); + } + + if (string.IsNullOrEmpty(FrmData)) return lines[0].targetId; + + FrmData = FrmData.ToLower();//统一转小写 + var frmDataJson = FrmData.ToJObject();//获取数据内容 + + foreach (var l in lines) + { + if (l.Compares==null) + { + l.Compares = new List(); + } + if (l.Compares.Count>0 &&l.Compare(frmDataJson)) + { + return l.targetId; + } + } + + return lines[0].targetId; + } + /// + /// 获取上一个节点 + /// + private string GetPreviousNodeId(string nodeId = null) + { + try + { + var lines = nodeId == null ? ToNodeLines[currentNodeId] : ToNodeLines[nodeId]; + if (lines.Count == 0) + { + return string.Empty; + } + + if (FrmData == "") return lines[0].sourceId; + + FrmData = FrmData.ToLower();//统一转小写 + var frmDataJson = FrmData.ToJObject();//获取数据内容 + + foreach (var l in lines) + { + if (l.Compares == null) + { + l.Compares = new List(); + } + if (l.Compares.Count > 0 && l.Compare(frmDataJson)) + { + return l.sourceId; + } + } + + return lines[0].sourceId; + } + catch (Exception) + { + return string.Empty; + } + + } + #endregion 私有方法 + + #region 共有方法 + + /// + /// 获取下一个节点 + /// + /// + /// + public FlowNode GetNextNode(string nodeId = null) + { + return Nodes[GetNextNodeId(nodeId)]; + } + + /// + /// 获取实例接下来运行的状态 + /// + /// -1无法运行,0会签开始,1会签结束,2一般节点,4流程运行结束 + public int GetNextNodeType() + { + if (nextNodeId != "-1") + { + return GetNodeType(nextNodeId); + } + return -1; + } + + /// + /// 获取节点类型 0会签开始,1会签结束,2一般节点,开始节点,4流程运行结束 + /// + /// + /// + public int GetNodeType(string nodeId) + { + switch (Nodes[nodeId].type) + { + //会签开始节点 + case FlowNode.FORK: + return 0; + //会签结束节点 + case FlowNode.JOIN: + return 1; + //结束节点 + case FlowNode.END: + return 4; + //开始节点 + case FlowNode.START: + return 3; + + default: + return 2; + } + } + /// + /// 删除节点 + /// + /// + public void RemoveNode(string nodeId) + { + var node = Nodes[nodeId]; + if (node != null && node.setInfo != null) + { + node.setInfo.Taged = null; + node.setInfo.UserName = null; + node.setInfo.UserId = null; + node.setInfo.Description = null; + node.setInfo.TagedTime = null; + } + } + /// + /// 删除全部节点 + /// + public void RemoveNodes() + { + foreach (var item in Nodes) + { + var node = item.Value; + if (node != null && node.setInfo != null) + { + node.setInfo.Taged = null; + node.setInfo.UserName = null; + node.setInfo.UserId = null; + node.setInfo.Description = null; + node.setInfo.TagedTime = null; + } + } + } + + /// + /// 节点会签审核 + /// + /// 会签时,currentNodeId是会签开始节点。这个表示当前正在处理的节点 + /// + /// -1不通过,1等待,其它通过 + public string NodeConfluence(string nodeId, Tag tag) + { + var forkNode = Nodes[currentNodeId]; //会签开始节点 + FlowNode nextNode = GetNextNode(nodeId); //获取当前处理的下一个节点 + + int forkNumber = FromNodeLines[currentNodeId].Count; //直接与会签节点连接的点,即会签分支数目 + string res =string.Empty; //记录会签的结果,默认正在会签 + if (forkNode.setInfo.NodeConfluenceType == "one") //有一个步骤通过即可 + { + if (tag.Taged == (int) TagState.Ok) + { + if (nextNode.type == FlowNode.JOIN) //下一个节点是会签结束,则该线路结束 + { + res = GetNextNodeId(nextNode.id); + } + } + else if(tag.Taged ==(int) TagState.No) + { + if (forkNode.setInfo.ConfluenceNo == null) + { + forkNode.setInfo.ConfluenceNo = 1; + } + else if (forkNode.setInfo.ConfluenceNo == (forkNumber - 1)) + { + res = TagState.No.ToString("D"); + } + else + { + bool isFirst = true; //是不是从会签开始到现在第一个 + var preNode = GetPreNode(nodeId); + while (preNode.id != forkNode.id) //反向一直到会签开始节点 + { + if (preNode.setInfo != null && preNode.setInfo.Taged == (int) TagState.No) + { + isFirst = false; + break; + } + } + + if (isFirst) + { + forkNode.setInfo.ConfluenceNo++; + } + } + } + } + else //默认所有步骤通过 + { + if (tag.Taged == (int) TagState.No) //只要有一个不同意,那么流程就结束 + { + res = TagState.No.ToString("D"); + } + else if(tag.Taged == (int)TagState.Ok) + { + if (nextNode.type == FlowNode.JOIN) //这种模式下只有坚持到【会签结束】节点之前才有意义,是否需要判定这条线所有的节点都通过,不然直接执行这个节点?? + { + if (forkNode.setInfo.ConfluenceOk == null) + { + forkNode.setInfo.ConfluenceOk = 1; + } + else if (forkNode.setInfo.ConfluenceOk == (forkNumber - 1)) //会签成功 + { + res = GetNextNodeId(nextNode.id); + } + else + { + forkNode.setInfo.ConfluenceOk++; + } + } + } + } + + if (res == TagState.No.ToString("D")) + { + tag.Taged = (int) TagState.No; + MakeTagNode(nextNode.id, tag); + } + else if (!string.IsNullOrEmpty(res)) //会签结束,标记合流节点 + { + tag.Taged = (int) TagState.Ok; + MakeTagNode(nextNode.id, tag); + nextNodeId = res; + nextNodeType = GetNodeType(res); + } + else + { + nextNodeId = nextNode.id; + nextNodeType = GetNodeType(nextNode.id); + } + return res; + } + + /// + /// 获取上一个节点 + /// + /// + /// + /// + private FlowNode GetPreNode(string nodeId = null) + { + var lines = nodeId == null ? ToNodeLines[currentNodeId] : ToNodeLines[nodeId]; + if (lines.Count == 0) + { + throw new Exception("无法找到上一个点"); + } + return Nodes[lines[0].sourceId]; + } + + /// + /// 驳回 + /// + /// 驳回类型。null:使用节点配置的驳回类型/0:前一步/1:第一步/2:指定节点,使用NodeRejectStep + /// + public string RejectNode(string rejectType) + { + dynamic node = Nodes[currentNodeId]; + if (node.setInfo != null && string.IsNullOrEmpty(rejectType)) + { + rejectType = node.setInfo.NodeRejectType; + } + + if (rejectType == "0") + { + return previousId; + } + if (rejectType == "1") + { + return startNodeId; + } + return previousId; + } + + /// + /// 标记节点1通过,2不通过,3驳回 + /// + /// + public void MakeTagNode(string nodeId, Tag tag) + { + foreach (var item in Nodes) + { + if (item.Key == nodeId) + { + if (item.Value.setInfo == null) + { + item.Value.setInfo = new Setinfo(); + } + item.Value.setInfo.Taged = tag.Taged; + item.Value.setInfo.UserId = tag.UserId; + item.Value.setInfo.UserName = tag.UserName; + item.Value.setInfo.Description = tag.Description; + item.Value.setInfo.TagedTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm"); + break; + } + } + } + /// + /// 获取流程 + /// + /// + public Flow ToSchemeObj() + { + flow.linkList = Lines; + flow.nodeList = Nodes.Select(u => u.Value).ToList(); + return flow; + } + + /// + /// 通知三方系统,节点执行情况 + /// + public void NotifyThirdParty(HttpClient client, Tag tag) + { + if (currentNode.setInfo == null || string.IsNullOrEmpty(currentNode.setInfo.ThirdPartyUrl)) + { + return; + } + + var postData = new + { + flowInstanceId, + nodeName=currentNode.name, + nodeId = currentNodeId, + userId = tag.UserId, + userName = tag.UserName, + result=tag.Taged, //1:通过;2:不通过;3驳回 + description = tag.Description, + execTime = tag.TagedTime, + isFinish = currentNodeType == 4 + }; + HttpContent httpContent = new StringContent(postData.ToJsonString(), Encoding.UTF8); + httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); + client.PostAsync(currentNode.setInfo.ThirdPartyUrl, httpContent); + } + + #endregion 共有方法 + + #region 属性 + /// + /// 流程 + /// + public Flow flow { get; set; } + /// + /// 运行实例的Id + /// + public long flowInstanceId { get; set; } + + /// + /// 开始节点的ID + /// + public string startNodeId { get; set; } + + /// + /// 当前节点的ID + /// + public string currentNodeId { get; set; } + + /// + /// 当前节点类型 0会签开始,1会签结束,2一般节点,开始节点,4流程运行结束 + /// + public int currentNodeType { get; set; } + + /// + /// 当前节点的对象 + /// + public FlowNode currentNode => Nodes[currentNodeId]; + + /// + /// 下一个节点 + /// + public string nextNodeId { get; set; } + + /// + /// 下一个节点类型 -1无法运行,0会签开始,1会签结束,2一般节点,4流程运行结束 + /// + /// The type of the next node. + public int nextNodeType { get; set; } + + /// + /// 下一个节点对象 + /// + public FlowNode nextNode => Nodes[nextNodeId]; + + /// + /// 上一个节点 + /// + public string previousId { get; set; } + + /// + /// 实例节点集合 + /// + public Dictionary Nodes { get; set; } + + /// + /// 流程实例中所有的线段 + /// + public List Lines { get; set; } + + /// + /// 从节点发出的线段集合 + /// + public Dictionary> FromNodeLines { get; set; } + + /// + /// 到达节点的线段集合 + /// + public Dictionary> ToNodeLines { get; set; } + + /// + /// 表单数据 + /// + public string FrmData { get; set; } + + #endregion 属性 +} diff --git a/Magic.FlowCenter/Entity/Flow/FormUtil.cs b/Magic.FlowCenter/Entity/Flow/FormUtil.cs new file mode 100644 index 0000000..d10bf08 --- /dev/null +++ b/Magic.FlowCenter/Entity/Flow/FormUtil.cs @@ -0,0 +1,71 @@ +using Furion.JsonSerialization; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; + +namespace Magic.FlowCenter.Entity; + +/// +/// 表单工具 +/// + public class FormUtil { + /// + /// 获取值 + /// + /// + /// System.String. + public static List SetValue(string content) + { + List list = JSON.GetJsonSerializer().Deserialize>(content); + List temp = new List(); + SetFormValue(list, temp); + return temp; + } + /// + /// 表单赋值 + /// + /// + /// + /// + private static List SetFormValue(List list, List temp) + { + foreach (var item in list) + { + if (item.tag == "grid") + { + foreach (var column in item.columns) + { + SetFormValue(column.list, temp); + } + } + else + { + temp.Add(item.id); + } + } + return temp; + } + /// + /// 自定义表单设值 + /// + /// + /// + public static List SetValueByWeb(string webForm) + { + //首字母大写 + webForm = webForm.Substring(0, 1).ToUpper() + webForm.Substring(1); + var path = AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory; + var referencedAssemblies = Directory.GetFiles(path, "*.dll").Select(Assembly.LoadFrom).ToArray(); + var t = referencedAssemblies + .SelectMany(a => a.GetTypes().Where(t => t.FullName.Contains("Magic.FlowCenter"+"." + webForm))).First(); + List temp = new List(); + PropertyInfo[] pArray = t.GetProperties(); + Array.ForEach(pArray, p => + { + temp.Add(p.Name); + }); + return temp; + } +} diff --git a/Magic.FlowCenter/Entity/Flow/FormValue.cs b/Magic.FlowCenter/Entity/Flow/FormValue.cs new file mode 100644 index 0000000..c21419b --- /dev/null +++ b/Magic.FlowCenter/Entity/Flow/FormValue.cs @@ -0,0 +1,52 @@ +using System.Collections.Generic; + +namespace Magic.FlowCenter.Entity; + + /// + /// 表单设计类 + /// + public class FormValue +{ + /// + /// 表id + /// + public string id { get; set; } + /// + /// 说明 + /// + public string label { get; set; } + /// + /// 序号 + /// + public int index { get; set; } + /// + /// 标签 + /// + public string tag { get; set; } + /// + /// 跨度 + /// + public int span { get; set; } + /// + /// 表单 + /// + public List columns { get; set; } + /// + /// 名称 + /// + public string name { get; set; } +} +/// +/// 表单 +/// +public class FormEx +{ + /// + /// 跨度 + /// + public int span { get; set; } + /// + /// 表单设计列表 + /// + public List list { get; set; } +} diff --git a/Magic.FlowCenter/Entity/Flow/NodeDesignate.cs b/Magic.FlowCenter/Entity/Flow/NodeDesignate.cs new file mode 100644 index 0000000..167d3de --- /dev/null +++ b/Magic.FlowCenter/Entity/Flow/NodeDesignate.cs @@ -0,0 +1,20 @@ +namespace Magic.FlowCenter.Entity; + +/// +/// 节点执行类 +/// + public class NodeDesignate + { + /// + /// 如果下个执行节点是运行时指定执行者。需要传指定的类型 + /// 取值为RUNTIME_SPECIAL_ROLE、RUNTIME_SPECIAL_USER + /// + public string NodeDesignateType { get; set; } + + /// + /// 如果下个执行节点是运行时指定执行者。该值表示具体的执行者 + /// 如果NodeDesignateType为RUNTIME_SPECIAL_ROLE,则该值为指定的角色 + /// 如果NodeDesignateType为RUNTIME_SPECIAL_USER,则该值为指定的用户 + /// + public string[] NodeDesignates { get; set; } +} diff --git a/Magic.FlowCenter/Entity/Flow/Verification.cs b/Magic.FlowCenter/Entity/Flow/Verification.cs new file mode 100644 index 0000000..733fd04 --- /dev/null +++ b/Magic.FlowCenter/Entity/Flow/Verification.cs @@ -0,0 +1,31 @@ +namespace Magic.FlowCenter.Entity; + +/// +/// 流程审核类 +/// + public class Verification:NodeDesignate +{ + /// + /// 流程实例Id + /// + public long FlowInstanceId { get; set; } + /// + /// 1:同意;2:不同意;3:驳回 + /// + public string VerificationFinally { get; set; } + + /// + /// 审核意见 + /// + public string VerificationOpinion { get; set; } + + /// + /// 驳回的步骤,即驳回到的节点ID + /// + public string NodeRejectStep { get; set; } + + /// + /// 驳回类型。null:使用节点配置的驳回类型/0:前一步/1:第一步/2:指定节点,使用NodeRejectStep + /// + public string NodeRejectType { get; set; } +} diff --git a/Magic.FlowCenter/Enum/CommonFrmType.cs b/Magic.FlowCenter/Enum/CommonFrmType.cs new file mode 100644 index 0000000..dc6e82a --- /dev/null +++ b/Magic.FlowCenter/Enum/CommonFrmType.cs @@ -0,0 +1,21 @@ +using System.ComponentModel; + +namespace Magic.FlowCenter; + +/// +/// 表单类型 +/// +public enum FormType +{ + /// + /// 正常 + /// + [Description("动态表单")] + DESIGNFORM = 0, + + /// + /// 停用 + /// + [Description("自定义表单")] + CUSTOMFORM = 1, +} diff --git a/Magic.FlowCenter/Flowinstance/Dto/FlcFlowinstanceDto.cs b/Magic.FlowCenter/Flowinstance/Dto/FlcFlowinstanceDto.cs new file mode 100644 index 0000000..02ea8fe --- /dev/null +++ b/Magic.FlowCenter/Flowinstance/Dto/FlcFlowinstanceDto.cs @@ -0,0 +1,133 @@ +using System; +using Magic.Core; + +namespace Magic.FlowCenter.Service; + +/// +/// 工作流输出参数 +/// +public class FlcFlowinstanceDto +{ + /// + /// Id + /// + public long Id { get; set; } + + /// + /// InstanceSchemeId + /// + public long InstanceSchemeId { get; set; } + + /// + /// Code + /// + public string Code { get; set; } + + /// + /// CustomName + /// + public string CustomName { get; set; } + + /// + /// ActivityId + /// + public string ActivityId { get; set; } + + /// + /// ActivityType + /// + public long ActivityType { get; set; } + + /// + /// ActivityName + /// + public string ActivityName { get; set; } + + /// + /// PreviousId + /// + public string PreviousId { get; set; } + + /// + /// SchemeContent + /// + public string SchemeContent { get; set; } + + /// + /// SchemeId + /// + public long SchemeId { get; set; } + + /// + /// DbName + /// + public string DbName { get; set; } + + /// + /// FrmData + /// + public string FrmData { get; set; } + + /// + /// FrmType + /// + public FormType FrmType { get; set; } = FormType.CUSTOMFORM; + + /// + /// FrmContentData + /// + public string FrmContentData { get; set; } + + /// + /// FrmContentParse + /// + public string FrmContentParse { get; set; } + + /// + /// FrmId + /// + public long FrmId { get; set; } + + /// + /// SchemeType + /// + public string SchemeType { get; set; } + + /// + /// FlowLevel + /// + public long FlowLevel { get; set; } + + /// + /// IsFinish + /// + public bool IsFinish { get; set; } + + /// + /// FrmContent + /// + public string FrmContent { get; set; } + + /// + /// MakerList + /// + public string MakerList { get; set; } + + /// + /// OrgId + /// + public long OrgId { get; set; } + + /// + /// Active + /// + public string Active { get; set; } + + /// + /// Remark + /// + public string Remark { get; set; } + + public CommonStatus Status { get; set; } = CommonStatus.ENABLE; + +} diff --git a/Magic.FlowCenter/Flowinstance/Dto/FlcFlowinstanceInput.cs b/Magic.FlowCenter/Flowinstance/Dto/FlcFlowinstanceInput.cs new file mode 100644 index 0000000..934f8cc --- /dev/null +++ b/Magic.FlowCenter/Flowinstance/Dto/FlcFlowinstanceInput.cs @@ -0,0 +1,159 @@ +using Magic.Core; +using System; +using System.ComponentModel.DataAnnotations; + +namespace Magic.FlowCenter.Service; + +/// +/// 工作流输入参数 +/// +public class FlcFlowinstanceInput : PageInputBase +{ + /// + /// InstanceSchemeId + /// + public virtual long? InstanceSchemeId { get; set; } + + /// + /// Code + /// + public virtual string Code { get; set; } + + /// + /// CustomName + /// + public virtual string CustomName { get; set; } + + /// + /// ActivityId + /// + public virtual string ActivityId { get; set; } + + /// + /// ActivityType + /// + public virtual long? ActivityType { get; set; } + + /// + /// ActivityName + /// + public virtual string ActivityName { get; set; } + + /// + /// PreviousId + /// + public virtual string PreviousId { get; set; } + + /// + /// SchemeContent + /// + public virtual string SchemeContent { get; set; } + + /// + /// SchemeId + /// + public virtual long? SchemeId { get; set; } + + /// + /// DbName + /// + public virtual string DbName { get; set; } + + /// + /// FrmData + /// + public virtual string FrmData { get; set; } + + /// + /// FrmType + /// + public virtual FormType? FrmType { get; set; } + + /// + /// FrmContentData + /// + public virtual string FrmContentData { get; set; } + + /// + /// FrmContentParse + /// + public virtual string FrmContentParse { get; set; } + + /// + /// FrmId + /// + public virtual long? FrmId { get; set; } + + /// + /// SchemeType + /// + public virtual string SchemeType { get; set; } + + /// + /// FlowLevel + /// + public virtual long? FlowLevel { get; set; } + + /// + /// IsFinish + /// + public virtual long? IsFinish { get; set; } + + /// + /// FrmContent + /// + public virtual string FrmContent { get; set; } + + /// + /// MakerList + /// + public virtual string MakerList { get; set; } + + /// + /// OrgId + /// + public virtual long? OrgId { get; set; } + + /// + /// Active + /// + public virtual string Active { get; set; } + + /// + /// Remark + /// + public virtual string Remark { get; set; } + + public virtual CommonStatus Status { get; set; } = CommonStatus.ENABLE; + public virtual int LookType { get; set; } = 0; + +} + +public class AddFlcFlowinstanceInput : FlcFlowinstanceInput +{ +} + +public class DeleteFlcFlowinstanceInput +{ + /// + /// Id + /// + [Required(ErrorMessage = "Id不能为空")] + public long Id { get; set; } + +} + +public class UpdateFlcFlowinstanceInput : FlcFlowinstanceInput +{ + /// + /// Id + /// + [Required(ErrorMessage = "Id不能为空")] + public long Id { get; set; } + +} + +public class QueryeFlcFlowinstanceInput : DeleteFlcFlowinstanceInput +{ + +} diff --git a/Magic.FlowCenter/Flowinstance/Dto/FlcFlowinstanceOutput.cs b/Magic.FlowCenter/Flowinstance/Dto/FlcFlowinstanceOutput.cs new file mode 100644 index 0000000..a79f7f6 --- /dev/null +++ b/Magic.FlowCenter/Flowinstance/Dto/FlcFlowinstanceOutput.cs @@ -0,0 +1,15 @@ +using Magic.Core; +using Magic.FlowCenter.Entity; +using System.Collections.Generic; + +namespace Magic.FlowCenter.Service; + +/// +/// 工作流输出参数 +/// +public class FlcFlowinstanceOutput:FlcFlowinstance + { + public string WebId { get; set; } + public List hisList { get; set; } + + } diff --git a/Magic.FlowCenter/Flowinstance/FlcCustomFormService.cs b/Magic.FlowCenter/Flowinstance/FlcCustomFormService.cs new file mode 100644 index 0000000..32893d1 --- /dev/null +++ b/Magic.FlowCenter/Flowinstance/FlcCustomFormService.cs @@ -0,0 +1,55 @@ +using Furion.DependencyInjection; +using Magic.Core; +using Magic.FlowCenter.Entity; +using System; +using System.Threading.Tasks; +using Yitter.IdGenerator; + +namespace Magic.FlowCenter.Service; + +/// +/// 自定义表格服务 +/// +public class FlcCustomFormService : IFlcCustomFormService, ITransient +{ + private readonly SqlSugarRepository _rep; + + public FlcCustomFormService(SqlSugarRepository rep) + { + _rep = rep; + } + /// + /// 新增 + /// + /// + /// + /// + public async Task Add(long flowInstanceId, string frmData) + { + var req = frmData.ToObject(); + req.FlowInstanceId = flowInstanceId; + req.Id = YitIdHelper.NextId(); + req.CreatedUserId = UserManager.UserId; + req.CreatedUserName = UserManager.Name; + req.CreatedTime = DateTime.Now; + await _rep.InsertAsync(req); + } + /// + /// 编辑 + /// + /// + /// + /// + public async Task Edit(long flowInstanceId, string frmData) + { + var req = frmData.ToObject(); + req.FlowInstanceId = flowInstanceId; + await _rep.UpdateAsync(a => a.FlowInstanceId == req.FlowInstanceId, a => new FlcCustomForm + { + Remark = a.Remark, + Sort = a.Sort, + Name = a.Name + + }); + } +} diff --git a/Magic.FlowCenter/Flowinstance/FlcFlowinstanceService.cs b/Magic.FlowCenter/Flowinstance/FlcFlowinstanceService.cs new file mode 100644 index 0000000..fe401b0 --- /dev/null +++ b/Magic.FlowCenter/Flowinstance/FlcFlowinstanceService.cs @@ -0,0 +1,970 @@ +using Furion; +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Furion.FriendlyException; +using Magic.Core; +using Magic.Core.Entity; +using Magic.Core.Service; +using Magic.FlowCenter.Entity; +using Mapster; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; +using Yitter.IdGenerator; + +namespace Magic.FlowCenter.Service; + +/// +/// 工作流服务 +/// +[ApiDescriptionSettings("FlowCenter", Name = "Flowinstance", Order = 100)] +public class FlcFlowinstanceService : IFlcFlowinstanceService, IDynamicApiController, ITransient +{ + private readonly SqlSugarRepository _rep; + private readonly IHttpClientFactory _httpClientFactory; + private readonly ISysEmpService _sysEmpService; + public FlcFlowinstanceService(SqlSugarRepository rep, IHttpClientFactory httpClientFactory, ISysEmpService sysEmpService) + { + _rep = rep; + _httpClientFactory = httpClientFactory; + _sysEmpService = sysEmpService; + } + + /// + /// 分页查询工作流 + /// + /// + /// + [HttpGet("/flcFlowinstance/page")] + public async Task Page([FromQuery] FlcFlowinstanceInput input) + { + var userId = UserManager.UserId; + var query = _rep.AsQueryable() + .WhereIF(!string.IsNullOrWhiteSpace(input.Code), u => u.Code == input.Code) + .WhereIF(!string.IsNullOrWhiteSpace(input.CustomName), u => u.CustomName == input.CustomName) + .WhereIF(!string.IsNullOrWhiteSpace(input.ActivityId), u => u.ActivityId == input.ActivityId) + .WhereIF(!string.IsNullOrWhiteSpace(input.ActivityName), u => u.ActivityName == input.ActivityName) + .WhereIF(!string.IsNullOrWhiteSpace(input.PreviousId), u => u.PreviousId == input.PreviousId) + .Where(u => u.Status != CommonStatus.DELETED); + if (input.LookType == 1) //待办事项 + { + query = query.Where(a => (a.MakerList == "1" || a.MakerList.Contains(userId.ToString())) && (a.IsFinish == 0 || a.IsFinish == 4) && a.ActivityType < 3); + } + else if (input.LookType == 2) //已办事项(即我参与过的流程) + { + var instances = _rep.Change().Where(a => a.CreatedUserId == userId) + .Select(a => a.InstanceId).Distinct().ToList(); + query = query.Where(a => instances.Contains(a.Id)); + } + else //我的流程 + { + query = query.Where(a => a.CreatedUserId == userId); + } + var entities = await query.ToDataFilter().ToPagedListAsync(input.PageNo, input.PageSize); + return entities.XnPagedResult(); + } + + /// + /// 获取工作流 + /// + /// + /// + [NonAction] + public async Task Get(long id) + { + var data = await _rep.FirstOrDefaultAsync(u => u.Id == id); + var entity = data.Adapt(); + if (!entity.DbName.IsEmpty()) + { + entity.WebId = entity.DbName.Substring(0, 1).ToLower() + entity.DbName.Substring(1); + } + entity.hisList = await _rep.Change().Where(a => a.InstanceId == id).OrderBy(a => a.CreatedTime).ToListAsync(); + return entity; + } + + /// + /// 获取工作流列表 + /// + /// + /// Verification + [HttpGet("/flcFlowinstance/list")] + public async Task List([FromQuery] FlcFlowinstanceInput input) + { + return await _rep.AsQueryable() + .WhereIF(!string.IsNullOrWhiteSpace(input.Code), u => u.Code == input.Code) + .WhereIF(!string.IsNullOrWhiteSpace(input.CustomName), u => u.CustomName == input.CustomName) + .WhereIF(!string.IsNullOrWhiteSpace(input.ActivityId), u => u.ActivityId == input.ActivityId) + .WhereIF(!string.IsNullOrWhiteSpace(input.ActivityName), u => u.ActivityName == input.ActivityName) + .WhereIF(!string.IsNullOrWhiteSpace(input.PreviousId), u => u.PreviousId == input.PreviousId) + .Where(u => u.Status != CommonStatus.DELETED) + .ToListAsync(); + } + + /// + /// 获取历史 + /// + /// + /// + [HttpGet("/flcFlowinstance/histories")] + public async Task> QueryHistories([FromQuery] QueryeFlcFlowinstanceInput input) + { + return await _rep.Change().Where(u => u.InstanceId == input.Id).OrderBy(u => u.CreatedTime).ToListAsync(); + } + /// + /// 驳回 + /// 如果NodeRejectStep不为空,优先使用;否则按照NodeRejectType驳回 + /// + /// + [NonAction] + public async Task NodeReject(Verification reqest) + { + FlcFlowinstance flowInstance = await _rep.FirstOrDefaultAsync(u => u.Id == reqest.FlowInstanceId); + var flowCreator = flowInstance.CreatedUserId; + + FlowRuntime wfruntime = new FlowRuntime(flowInstance); + + string resnode = ""; + resnode = string.IsNullOrEmpty(reqest.NodeRejectStep) ? wfruntime.RejectNode(reqest.NodeRejectType) : reqest.NodeRejectStep; + + var tag = new Tag + { + Description = reqest.VerificationOpinion, + Taged = (int)TagState.Reject, + UserId = UserManager.UserId, + UserName = UserManager.Name + }; + + wfruntime.MakeTagNode(wfruntime.currentNodeId, tag); + flowInstance.IsFinish = 4;//4表示驳回(需要申请者重新提交表单) + _rep.CurrentBeginTran(); + if (resnode != "") + { + wfruntime.RemoveNode(resnode); + flowInstance.SchemeContent = wfruntime.ToSchemeObj().ToJsonString(); + flowInstance.ActivityId = resnode; + var prruntime = new FlowRuntime(flowInstance); + prruntime.MakeTagNode(prruntime.currentNodeId, tag); + flowInstance.PreviousId = prruntime.previousId; + flowInstance.ActivityType = prruntime.GetNodeType(resnode); + flowInstance.ActivityName = prruntime.Nodes[resnode].name; + if (resnode == wfruntime.startNodeId) + { + flowInstance.MakerList = flowInstance.CreatedUserId.ToString(); + } + else + { + flowInstance.MakerList = _rep.Change().Where(a => a.FromNodeId == resnode && a.ToNodeId == prruntime.nextNodeId).OrderBy(a => a.CreatedTime, OrderByType.Desc).Select(a => a.CreatedUserId).First().ToString();//当前节点可执行的人信息 + flowInstance.MakerList = flowInstance.MakerList == "1" ? null : flowInstance.MakerList; + } + await AddRejectTransHistory(wfruntime, prruntime); + await _rep.UpdateAsync(flowInstance); + } + await _rep.Change().InsertAsync(new FlcFlowInstanceOperationHistory + { + Id = YitIdHelper.NextId(), + InstanceId = reqest.FlowInstanceId, + CreatedUserId = UserManager.UserId, + CreatedUserName = UserManager.Name, + CreatedTime = DateTime.Now, + Content = "[" + + wfruntime.currentNode.name + + "][" + DateTime.Now.ToString("yyyy-MM-dd HH:mm") + "]驳回,备注:" + + reqest.VerificationOpinion + }); + _rep.CurrentCommitTran(); + + wfruntime.NotifyThirdParty(_httpClientFactory.CreateClient(), tag); + + return true; + } + /// + /// 节点审核 + /// + /// + /// + [NonAction] + public async Task NodeVerification(Verification request) + { + var instanceId = request.FlowInstanceId; + + var tag = new Tag + { + UserName = UserManager.Name, + UserId = UserManager.UserId, + Description = request.VerificationOpinion, + Taged = Int32.Parse(request.VerificationFinally) + }; + FlcFlowinstance flowInstance = await _rep.FirstOrDefaultAsync(u => u.Id == instanceId); + var flowCreator = flowInstance.CreatedUserId; + FlcFlowInstanceOperationHistory flowInstanceOperationHistory = new FlcFlowInstanceOperationHistory + { + Id = YitIdHelper.NextId(), + InstanceId = instanceId, + CreatedUserId = tag.UserId??0, + CreatedUserName = tag.UserName, + CreatedTime = DateTime.Now + };//操作记录 + FlowRuntime wfruntime = new FlowRuntime(flowInstance); + _rep.CurrentBeginTran(); + #region 会签 + if (flowInstance.ActivityType == 0)//当前节点是会签节点 + { + //会签时的[当前节点]一直是会签开始节点 + //TODO: 标记会签节点的状态,这个地方感觉怪怪的 + wfruntime.MakeTagNode(wfruntime.currentNodeId, tag); + + string canCheckId = ""; //寻找当前登录用户可审核的节点Id + foreach (string fromForkStartNodeId in wfruntime.FromNodeLines[wfruntime.currentNodeId].Select(u => u.targetId)) + { + var fromForkStartNode = wfruntime.Nodes[fromForkStartNodeId]; //与会前开始节点直接连接的节点 + canCheckId = await GetOneForkLineCanCheckNodeId(fromForkStartNode, wfruntime, tag, flowCreator??0); + if (!string.IsNullOrEmpty(canCheckId)) break; + } + + if (canCheckId == "") + { + throw Oops.Oh("审核异常,找不到审核节点"); + } + + flowInstanceOperationHistory.Content = "[" + wfruntime.Nodes[canCheckId].name + + "][" + DateTime.Now.ToString("yyyy-MM-dd HH:mm") + + "]" + (tag.Taged == 1 ? "同意" : "不同意") + ",备注:" + + tag.Description; + + wfruntime.MakeTagNode(canCheckId, tag); //标记审核节点状态 + string res = wfruntime.NodeConfluence(canCheckId, tag); + if (res == TagState.No.ToString("D")) + { + flowInstance.IsFinish = 3; + } + else if (!string.IsNullOrEmpty(res)) + { + flowInstance.PreviousId = flowInstance.ActivityId; + flowInstance.ActivityId = wfruntime.nextNodeId; + flowInstance.ActivityType = wfruntime.nextNodeType; + flowInstance.ActivityName = wfruntime.nextNode.name; + flowInstance.IsFinish = (wfruntime.nextNodeType == 4 ? 1 : 0); + flowInstance.MakerList = wfruntime.nextNodeType == 4 ? "" : await GetNextMakers(wfruntime, request, flowCreator??0); + await AddTransHistory(wfruntime); + } + else + { + //会签过程中,需要更新用户 + flowInstance.MakerList = await GetForkNodeMakers(wfruntime, wfruntime.currentNodeId, flowCreator??0); + await AddTransHistory(wfruntime); + } + + } + #endregion 会签 + + #region 一般审核 + else + { + wfruntime.MakeTagNode(wfruntime.currentNodeId, tag); + if (tag.Taged == (int)TagState.Ok) + { + flowInstance.PreviousId = flowInstance.ActivityId; + flowInstance.ActivityId = wfruntime.nextNodeId; + flowInstance.ActivityType = wfruntime.nextNodeType; + flowInstance.ActivityName = wfruntime.nextNode.name; + flowInstance.MakerList = (wfruntime.GetNextNodeType() != 4 ? await GetNextMakers(wfruntime, request, flowCreator??0) : ""); + flowInstance.IsFinish = (wfruntime.nextNodeType == 4 ? 1 : 0); + await AddTransHistory(wfruntime); + } + else + { + flowInstance.IsFinish = 3; //表示该节点不同意 + } + flowInstanceOperationHistory.Content = "[" + wfruntime.currentNode.name + + "][" + DateTime.Now.ToString("yyyy-MM-dd HH:mm") + + "]" + (tag.Taged == 1 ? "同意" : "不同意") + ",备注:" + + tag.Description; + } + #endregion 一般审核 + + wfruntime.RemoveNode(wfruntime.nextNodeId); + flowInstance.SchemeContent = wfruntime.ToSchemeObj().ToJsonString(); + await _rep.AsUpdateable(flowInstance).IgnoreColumns(ignoreAllNullColumns:true).ExecuteCommandAsync(); + await _rep.Change().InsertAsync(flowInstanceOperationHistory); + _rep.CurrentCommitTran(); + //通知信息 + wfruntime.NotifyThirdParty(_httpClientFactory.CreateClient(), tag); + return true; + } + //会签时,获取一条会签分支上面是否有用户可审核的节点 + [NonAction] + private async Task GetOneForkLineCanCheckNodeId(FlowNode fromForkStartNode, FlowRuntime wfruntime, Tag tag,long flowCreator) + { + string canCheckId = ""; + var node = fromForkStartNode; + do //沿一条分支线路执行,直到遇到会签结束节点 + { + var makerList = await GetNodeMarkers(node, flowCreator); + + if (node.setInfo.Taged == null && !string.IsNullOrEmpty(makerList) && makerList.Split(',').Any(one => tag.UserId == long.Parse(one))) + { + canCheckId = node.id; + break; + } + + node = wfruntime.GetNextNode(node.id); + } while (node.type != FlowNode.JOIN); + + return canCheckId; + } + /// + /// 寻找下一步的执行人 + /// 一般用于本节点审核完成后,修改流程实例的当前执行人,可以做到通知等功能 + /// + /// + [NonAction] + private async Task GetNextMakers(FlowRuntime wfruntime, NodeDesignate request, long flowCreator) + { + string makerList = ""; + if (wfruntime.nextNodeId == "-1") + { + throw Oops.Oh("无法寻找到下一个节点"); + } + if (wfruntime.nextNodeType == 0)//如果是会签节点 + { + makerList = await GetForkNodeMakers(wfruntime, wfruntime.nextNodeId, flowCreator); + } + else if (wfruntime.nextNode.setInfo.NodeDesignate == Setinfo.RUNTIME_SPECIAL_ROLE) + { //如果是运行时指定角色 + if (wfruntime.nextNode.setInfo.NodeDesignate != request.NodeDesignateType) + { + throw Oops.Oh("前端提交的节点权限类型异常,请检查流程"); + } + var users = new List(); + foreach (var item in request.NodeDesignates) + { + var temps = _rep.Change().Where(a => a.SysRoleId == long.Parse(item)).Select(a => a.SysUserId.ToString()).ToList(); + if (temps != null && temps.Count > 0) + { + users.AddRange(temps); + } + } + makerList = JsonUtil.ArrayToString(users.Distinct().ToList(), makerList); + } + else if (wfruntime.nextNode.setInfo.NodeDesignate == Setinfo.RUNTIME_SPECIAL_USER) + { //如果是运行时指定用户 + if (wfruntime.nextNode.setInfo.NodeDesignate != request.NodeDesignateType) + { + throw Oops.Oh("前端提交的节点权限类型异常,请检查流程"); + } + makerList = JsonUtil.ArrayToString(request.NodeDesignates, makerList); + } + else + { + makerList = await GetNodeMarkers(wfruntime.nextNode, flowCreator); + if (string.IsNullOrEmpty(makerList)) + { + throw (new Exception("无法寻找到节点的审核者,请查看流程设计是否有问题!")); + } + } + + return makerList; + } + + /// + /// 获取会签开始节点的所有可执行者 + /// + /// + /// + /// + /// + [NonAction] + private async Task GetForkNodeMakers(FlowRuntime wfruntime, string forkNodeId, long flowCreator) + { + string makerList = ""; + foreach (string fromForkStartNodeId in wfruntime.FromNodeLines[forkNodeId].Select(u => u.targetId)) + { + var fromForkStartNode = wfruntime.Nodes[fromForkStartNodeId]; //与会前开始节点直接连接的节点 + if (makerList != "") + { + makerList += ","; + } + + makerList += await GetOneForkLineMakers(fromForkStartNode, wfruntime, flowCreator); + } + + return makerList; + } + + //获取会签一条线上的审核者,该审核者应该是已审核过的节点的下一个人 + [NonAction] + private async Task GetOneForkLineMakers(FlowNode fromForkStartNode, FlowRuntime wfruntime,long flowCreator) + { + string markers = ""; + var node = fromForkStartNode; + do //沿一条分支线路执行,直到遇到第一个没有审核的节点 + { + if (node.setInfo != null && node.setInfo.Taged != null) + { + if (node.type != FlowNode.FORK && node.setInfo.Taged != (int)TagState.Ok) //如果节点是不同意或驳回,则不用再找了 + { + break; + } + node = wfruntime.GetNextNode(node.id); //下一个节点 + continue; + } + var marker = await GetNodeMarkers(node, flowCreator); + if (marker == "") + { + throw (new Exception($"节点{node.name}没有审核者,请检查!")); + } + if (marker == "1") + { + throw (new Exception($"节点{node.name}是会签节点,不能用所有人,请检查!")); + } + + if (markers != "") + { + markers += ","; + } + markers += marker; + break; + } while (node.type != FlowNode.JOIN); + + return markers; + } + + /// + /// 寻找该节点执行人 + /// + /// + /// + /// + [NonAction] + private async Task GetNodeMarkers(FlowNode node,long flowCreator) + { + string makerList = ""; + + if (node.setInfo != null) + { + if (node.setInfo.NodeDesignate == Setinfo.ALL_USER)//所有成员 + { + makerList = "1"; + } + else if (node.setInfo.NodeDesignate == Setinfo.SPECIAL_USER)//指定成员 + { + makerList = JsonUtil.ArrayToString(node.setInfo.NodeDesignateData, makerList); + } + else if (node.setInfo.NodeDesignate == Setinfo.SPECIAL_ROLE) //指定角色 + { + List list = new List(); + List users = new List(); + foreach (var item in node.setInfo.NodeDesignateData) + { + var temp = _rep.Change().AsQueryable().InnerJoin((a,b)=>a.Id==b.SysUserId && b.SysRoleId == long.Parse(item)).Select((a,b)=>a).Distinct().ToList(); + var tempList = new List(); + if (node.setInfo.CurrentDepart) + { + var currentDepartment = new List(); + var empInfo= await _sysEmpService.GetEmpInfo(flowCreator); + if (empInfo != null) + { + currentDepartment.Add(long.Parse(empInfo.OrgId)); + if (empInfo.ExtOrgPos!=null&&empInfo.ExtOrgPos.Count>0) + currentDepartment.AddRange(empInfo.ExtOrgPos.Select(a=>a.OrgId)); + } + foreach (var user in temp) + { + var nextCurrentDepartment = new List(); + var empTempInfo = await _sysEmpService.GetEmpInfo(user.Id); + if (empTempInfo != null) + { + nextCurrentDepartment.Add(long.Parse(empTempInfo.OrgId)); + if (empInfo.ExtOrgPos != null && empTempInfo.ExtOrgPos.Count > 0) + nextCurrentDepartment.AddRange(empTempInfo.ExtOrgPos.Select(a => a.OrgId)); + } + if (JsonUtil.IsArrayIntersection(currentDepartment, nextCurrentDepartment)) + { + tempList.Add(user); + } + } + } + else + { + tempList = temp; + } + var tempFinal = tempList.Select(a => a.Id).ToList(); + users.AddRange(tempFinal); + } + users = users.Distinct().ToList(); + makerList = JsonUtil.ArrayToString(users, makerList); + } + else if (node.setInfo.NodeDesignate == Setinfo.RUNTIME_SPECIAL_ROLE || node.setInfo.NodeDesignate == Setinfo.RUNTIME_SPECIAL_USER) + { + //如果是运行时选定的用户,则暂不处理。由上个节点审批时选定 + } + } + else //如果没有设置节点信息,默认所有人都可以审核 + { + makerList = "1"; + } + return makerList; + } + + /// + /// 判定节点需要选择执行人或执行角色 + /// + /// + /// + [NonAction] + private void CheckNodeDesignate(NodeDesignate request) + { + if ((request.NodeDesignateType == Setinfo.RUNTIME_SPECIAL_ROLE + || request.NodeDesignateType == Setinfo.RUNTIME_SPECIAL_USER) && request.NodeDesignates.Length == 0) + { + throw Oops.Oh("下个节点需要选择执行人或执行角色"); + } + } + /// + /// 返回用于处理流程节点 + /// + /// + /// + [HttpGet("/flcFlowinstance/detail")] + public async Task GetForVerification([FromQuery] QueryeFlcFlowinstanceInput input) + { + var flowinstance = await Get(input.Id); + var runtime = new FlowRuntime(flowinstance); + if (runtime.nextNodeType != -1 && runtime.nextNode != null && runtime.nextNode.setInfo != null && runtime.nextNodeType != 4) + { + flowinstance.NextNodeDesignateType = runtime.nextNode.setInfo.NodeDesignate; + if (flowinstance.NextNodeDesignateType == Setinfo.SPECIAL_USER) + { + flowinstance.NextNodeDesignates = runtime.nextNode.setInfo.NodeDesignateData.ToArray(); + flowinstance.NextMakerName = string.Join(',', _rep.Change().Where(a => flowinstance.NextNodeDesignates.Contains(a.Id.ToString())).Select(a => a.Name).ToList()); + } + else if (flowinstance.NextNodeDesignateType == Setinfo.SPECIAL_ROLE) + { + flowinstance.NextNodeDesignates = runtime.nextNode.setInfo.NodeDesignateData.ToArray(); + List list = new List(); + List users = new List(); + foreach (var item in flowinstance.NextNodeDesignates) + { + var temp = _rep.Change().AsQueryable().InnerJoin((a, b) => a.Id == b.SysUserId && b.SysRoleId == long.Parse(item)).Select((a, b) => a).ToList(); + var tempList = new List(); + if (runtime.nextNode.setInfo.CurrentDepart) + { + var currentDepartment = new List(); + var empInfo = await _sysEmpService.GetEmpInfo(flowinstance.CreatedUserId??0); + if (empInfo != null) + { + currentDepartment.Add(long.Parse(empInfo.OrgId)); + if (empInfo.ExtOrgPos != null && empInfo.ExtOrgPos.Count > 0) + currentDepartment.AddRange(empInfo.ExtOrgPos.Select(a => a.OrgId)); + } + foreach (var user in temp) + { + var nextCurrentDepartment = new List(); + var empTempInfo = await _sysEmpService.GetEmpInfo(user.Id); + if (empTempInfo != null) + { + nextCurrentDepartment.Add(long.Parse(empTempInfo.OrgId)); + if (empInfo.ExtOrgPos != null && empTempInfo.ExtOrgPos.Count > 0) + nextCurrentDepartment.AddRange(empTempInfo.ExtOrgPos.Select(a => a.OrgId)); + } + if (JsonUtil.IsArrayIntersection(currentDepartment, nextCurrentDepartment)) + { + tempList.Add(user); + } + } + } + else + { + tempList = temp; + } + var tempFinal = tempList.Select(a => a.Id).ToList(); + users.AddRange(tempFinal); + } + users = users.Distinct().ToList(); + flowinstance.NextMakerName = string.Join(',', _rep.Change().Where(a => users.Contains(a.Id)).Select(a => a.Name).ToList()); + } + } + if (runtime.currentNode != null && runtime.currentNode.setInfo != null && runtime.currentNodeType != 4) + { + flowinstance.CurrentNodeDesignateType = runtime.currentNode.setInfo.NodeDesignate; + if (flowinstance.MakerList != "1" && !string.IsNullOrEmpty(flowinstance.MakerList)) + { + var temps = flowinstance.MakerList.Split(','); + flowinstance.CurrentMakerName = string.Join(',', _rep.Change().Where(a => temps.Contains(a.Id.ToString())).Select(a => a.Name).ToList()); + } + else + { + flowinstance.CurrentMakerName = "所有人"; + } + } + return flowinstance; + } + + /// + /// 添加扭转记录 + /// + [NonAction] + private async Task AddTransHistory(FlowRuntime wfruntime) + { + await _rep.Change().InsertAsync(new FlcFlowInstanceTransitionHistory + { + Id = YitIdHelper.NextId(), + InstanceId = wfruntime.flowInstanceId, + CreatedUserId = UserManager.UserId, + CreatedTime = DateTime.Now, + CreatedUserName = UserManager.Name, + FromNodeId = wfruntime.currentNodeId, + FromNodeName = wfruntime.currentNode.name, + FromNodeType = wfruntime.currentNodeType, + ToNodeId = wfruntime.nextNodeId, + ToNodeName = wfruntime.nextNode.name, + ToNodeType = wfruntime.nextNodeType, + IsFinish = wfruntime.nextNodeType == 4 ? true : false, + TransitionSate = false + }); + } + /// + /// 添加扭转记录 + /// + [NonAction] + private async Task AddRejectTransHistory(FlowRuntime wfruntime, FlowRuntime prruntime) + { + await _rep.Change().InsertAsync(new FlcFlowInstanceTransitionHistory + { + Id = YitIdHelper.NextId(), + InstanceId = wfruntime.flowInstanceId, + CreatedUserId = UserManager.UserId, + CreatedTime = DateTime.Now, + CreatedUserName = UserManager.Name, + FromNodeId = wfruntime.currentNodeId, + FromNodeName = wfruntime.currentNode.name, + FromNodeType = wfruntime.currentNodeType, + ToNodeId = prruntime.currentNodeId, + ToNodeName = prruntime.currentNode.name, + ToNodeType = prruntime.currentNodeType, + IsFinish = false, + TransitionSate = false + }); + } + + /// + /// 节点处理 + /// + /// + /// + [HttpPost("/flcFlowinstance/verification")] + public async Task Verification(Verification input) + { + bool isReject = TagState.Reject.Equals((TagState)Int32.Parse(input.VerificationFinally)); + if (isReject) //驳回 + { + await NodeReject(input); + } + else + { + await NodeVerification(input); + } + } + + /// + /// 新增流程实例 + /// + /// + /// + /// + [HttpPost("/flcFlowinstance/add")] + public async Task Add(FlcFlowinstance entity) + { + var nodeDesignate = new NodeDesignate(); + nodeDesignate.NodeDesignates = entity.NextNodeDesignates; + nodeDesignate.NodeDesignateType = entity.NextNodeDesignateType; + CheckNodeDesignate(nodeDesignate); + FlcFlowscheme scheme = null; + if (entity.SchemeId!=0) + { + scheme = await _rep.Change().AsQueryable().InSingleAsync(entity.SchemeId); + } + if (scheme == null) + { + throw Oops.Oh("该流程模板已不存在,请重新设计流程"); + } + entity.SchemeContent = scheme.SchemeContent; + var form = await _rep.Change().AsQueryable().InSingleAsync(scheme.FrmId); + if (form == null) + { + throw Oops.Oh("该流程模板对应的表单已不存在,请重新设计流程"); + } + entity.CustomName = scheme.SchemeName + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); + var startTime = DateTime.Parse("1970-01-01"); + entity.Code = ((long)(DateTime.Now - startTime).TotalSeconds).ToString(); + entity.FrmContentData = form.ContentData; + entity.FrmContent = form.Content; + entity.FrmContentParse = form.ContentParse; + entity.FrmType = form.FrmType; + entity.FrmId = form.Id; + entity.Status = CommonStatus.ENABLE; + var flowCreator = entity.CreatedUserId; + Dictionary dic = JsonUtil.ToObject>(entity.FrmData); + if (!dic.ContainsKey("CreatedUserId")) + { + dic.Add("CreatedUserId", UserManager.UserId.ToString()); + + } + if (!dic.ContainsKey("CreatedOrgId")) + { + var currentDepartment = new List(); + var empInfo = await _sysEmpService.GetEmpInfo(flowCreator??0); + if (empInfo != null&& (empInfo.OrgId!=null ||(empInfo.ExtOrgPos != null && empInfo.ExtOrgPos.Count > 0))) + { + currentDepartment.Add(long.Parse(empInfo.OrgId)); + if (empInfo.ExtOrgPos != null && empInfo.ExtOrgPos.Count > 0) + currentDepartment.AddRange(empInfo.ExtOrgPos.Select(a => a.OrgId)); + } + dic.Add("CreatedOrgId", String.Join(',', currentDepartment)); + } + entity.FrmData = dic.ToJsonString(); + if(!form.WebId.IsEmpty()) + { + entity.DbName = form.WebId.Substring(0, 1).ToUpper() + form.WebId.Substring(1); + } + entity.FlowLevel = 0; + //创建运行实例 + var wfruntime = new FlowRuntime(entity); + + #region 根据运行实例改变当前节点状态 + entity.ActivityId = wfruntime.nextNodeId; + entity.ActivityType = wfruntime.GetNextNodeType(); + entity.ActivityName = wfruntime.nextNode.name; + entity.PreviousId = wfruntime.currentNodeId; + entity.CreatedUserName = UserManager.Name; + entity.MakerList = (wfruntime.GetNextNodeType() != 4 ? await GetNextMakers(wfruntime, nodeDesignate, flowCreator??0) : ""); + entity.IsFinish = (wfruntime.GetNextNodeType() == 4 ? 1 : 0); + _rep.CurrentBeginTran(); + await _rep.InsertAsync(entity); + + wfruntime.flowInstanceId = entity.Id; + //复杂表单提交 + if (entity.FrmType == FormType.CUSTOMFORM) + { + var t = App.Assemblies + .SelectMany(a => a.GetTypes().Where(t => t.FullName.Contains("Magic.FlowCenter.") && t.FullName.Contains("." + entity.DbName + "Service"))).First(); + IFlcCustomFormService icf = (IFlcCustomFormService)App.GetService(t); + await icf.Add(entity.Id, entity.FrmData); + } + + #endregion + + #region 流程操作记录 + + FlcFlowInstanceOperationHistory processOperationHistoryEntity = new FlcFlowInstanceOperationHistory + { + Id = YitIdHelper.NextId(), + InstanceId = entity.Id, + CreatedUserId = entity.CreatedUserId??0, + CreatedUserName = entity.CreatedUserName, + CreatedTime = entity.CreatedTime, + Content = "[创建]" + + entity.CreatedUserName + + "创建了一个流程[" + + entity.Code + "/" + + entity.CustomName + "]" + }; + await _rep.Change().InsertAsync(processOperationHistoryEntity); + + #endregion 流程操作记录 + + await AddTransHistory(wfruntime); + + _rep.CurrentCommitTran(); + } + + /// + /// 编辑流程实例 + /// + /// + /// + /// + [HttpPost("/flcFlowinstance/edit")] + public async Task Update(FlcFlowinstance entity) + { + var nodeDesignate = new NodeDesignate(); + nodeDesignate.NodeDesignates = entity.NextNodeDesignates; + nodeDesignate.NodeDesignateType = entity.NextNodeDesignateType; + CheckNodeDesignate(nodeDesignate); + FlcFlowscheme scheme = null; + if (entity.SchemeId != 0) + { + scheme = await _rep.Change().AsQueryable().InSingleAsync(entity.SchemeId); + } + if (scheme == null) + { + throw Oops.Oh("该流程模板已不存在,请重新设计流程"); + } + entity.SchemeContent = scheme.SchemeContent; + var form = await _rep.Change().AsQueryable().InSingleAsync(scheme.FrmId); + if (form == null) + { + throw Oops.Oh("该流程模板对应的表单已不存在,请重新设计流程"); + } + Dictionary dic = JsonUtil.ToObject>(entity.FrmData); + if (!dic.ContainsKey("CreatedUserId")) + { + dic.Add("CreatedUserId", UserManager.UserId.ToString()); + + } + var flowCreator = UserManager.UserId; + if (!dic.ContainsKey("CreatedOrgId")) + { + var currentDepartment = new List(); + var empInfo = await _sysEmpService.GetEmpInfo(flowCreator); + if (empInfo != null && (empInfo.OrgId != null || (empInfo.ExtOrgPos != null && empInfo.ExtOrgPos.Count > 0))) + { + currentDepartment.Add(long.Parse(empInfo.OrgId)); + if (empInfo.ExtOrgPos != null && empInfo.ExtOrgPos.Count > 0) + currentDepartment.AddRange(empInfo.ExtOrgPos.Select(a => a.OrgId)); + } + dic.Add("CreatedOrgId", String.Join(',', currentDepartment)); + } + entity.FrmData = dic.ToJsonString(); + var wfruntime = new FlowRuntime(await _rep.FirstOrDefaultAsync(u => u.Id == entity.Id)); + entity.FrmContentData = form.ContentData; + entity.FrmContentParse = form.ContentParse; + entity.FrmType = form.FrmType; + entity.FrmId = form.Id; + if (!form.WebId.IsEmpty()) + { + entity.DbName = form.WebId.Substring(0, 1).ToUpper() + form.WebId.Substring(1); + } + entity.FlowLevel = 0; + //创建运行实例 + wfruntime = new FlowRuntime(entity); + + + #region 根据运行实例改变当前节点状态 + entity.ActivityId = wfruntime.nextNodeId; + entity.ActivityType = wfruntime.GetNextNodeType(); + entity.ActivityName = wfruntime.nextNode.name; + entity.PreviousId = wfruntime.currentNodeId; + entity.CreatedUserName = UserManager.Name; + entity.MakerList = (wfruntime.GetNextNodeType() != 4 ? await GetNextMakers(wfruntime, nodeDesignate, flowCreator) : ""); + entity.IsFinish = (wfruntime.GetNextNodeType() == 4 ? 1 : 0); + _rep.CurrentBeginTran(); + await _rep.AsUpdateable(entity) + .IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync(); + wfruntime.flowInstanceId = entity.Id; + //复杂表单提交 + if (entity.FrmType == FormType.CUSTOMFORM) + { + var t = App.Assemblies + .SelectMany(a => a.GetTypes().Where(t => t.FullName.Contains("Magic.FlowCenter.") && t.FullName.Contains("." + entity.DbName + "Service"))).First(); + IFlcCustomFormService icf = (IFlcCustomFormService)App.GetService(t); + await icf.Edit(entity.Id, entity.FrmData); + + } + #endregion + + #region 流程操作记录 + FlcFlowInstanceOperationHistory processOperationHistoryEntity = new FlcFlowInstanceOperationHistory + { + Id = YitIdHelper.NextId(), + InstanceId = entity.Id, + CreatedUserId = UserManager.UserId, + CreatedUserName = entity.CreatedUserName, + CreatedTime = DateTime.Now, + Content = "[修改]" + + entity.CreatedUserName + + "修改了一个流程[" + + entity.Code + "/" + + entity.CustomName + "]" + }; + await _rep.Change().InsertAsync(processOperationHistoryEntity); + #endregion + + await AddTransHistory(wfruntime); + _rep.CurrentCommitTran(); + } + /// + /// 删除流程实例 + /// + /// + /// + [HttpPost("/flcFlowinstance/delete")] + public async Task Delete(DeleteFlcFlowinstanceInput input) + { + FlcFlowinstance flowInstance = await _rep.FirstOrDefaultAsync(u => u.Id == input.Id); + if (flowInstance != null && flowInstance.IsFinish != 4 && flowInstance.IsFinish != 2) + { + throw Oops.Oh("流程已在执行中,不能删除"); + } + // 直接删除用户 + await _rep.AsUpdateable(new FlcFlowinstance { IsDeleted = true }) + .UpdateColumns(flowInstance.FalseDeleteColumn()).Where(wh => wh.Id == flowInstance.Id).ExecuteCommandAsync(); + } + + /// + /// 撤销流程实例 + /// + /// + /// + [HttpPost("/flcFlowinstance/cancel")] + public async Task Cancel(DeleteFlcFlowinstanceInput input) + { + FlcFlowinstance flowInstance = await _rep.FirstOrDefaultAsync(u => u.Id == input.Id); + var flowCreator = flowInstance.CreatedUserId; + FlowRuntime wfruntime = new FlowRuntime(flowInstance); + + string resnode = ""; + resnode = wfruntime.RejectNode("1"); + + var tag = new Tag + { + Description = "流程撤回", + Taged = (int)TagState.Reject, + UserId = UserManager.UserId, + UserName = UserManager.Name + }; + + wfruntime.MakeTagNode(wfruntime.currentNodeId, tag); + flowInstance.IsFinish = 2;//2表示撤回(需要申请者重新提交表单) + _rep.CurrentBeginTran(); + if (resnode != "") + { + wfruntime.RemoveNode(resnode); + flowInstance.SchemeContent = wfruntime.ToSchemeObj().ToJsonString(); + flowInstance.ActivityId = resnode; + var prruntime = new FlowRuntime(flowInstance); + prruntime.MakeTagNode(prruntime.currentNodeId, tag); + flowInstance.PreviousId = prruntime.previousId; + flowInstance.ActivityType = prruntime.GetNodeType(resnode); + flowInstance.ActivityName = prruntime.Nodes[resnode].name; + if (resnode == wfruntime.startNodeId) + { + flowInstance.MakerList = flowInstance.CreatedUserId.ToString(); + } + else + { + flowInstance.MakerList = _rep.Change().Where(a => a.FromNodeId == resnode && a.ToNodeId == prruntime.nextNodeId).OrderBy(a => a.CreatedTime, OrderByType.Desc).Select(a => a.CreatedUserId).First().ToString();//当前节点可执行的人信息 + flowInstance.MakerList = flowInstance.MakerList == "1" ? null: flowInstance.MakerList; + } + await AddRejectTransHistory(wfruntime, prruntime); + await _rep.UpdateAsync(flowInstance); + } + await _rep.Change().InsertAsync(new FlcFlowInstanceOperationHistory + { + Id = YitIdHelper.NextId(), + InstanceId = input.Id, + CreatedUserId = UserManager.UserId, + CreatedUserName = UserManager.Name, + CreatedTime = DateTime.Now, + Content = "[" + + wfruntime.currentNode.name + + "][" + DateTime.Now.ToString("yyyy-MM-dd HH:mm") + "]撤回,备注:流程撤回" + }); + _rep.CurrentCommitTran(); + wfruntime.NotifyThirdParty(_httpClientFactory.CreateClient(), tag); + } +} diff --git a/Magic.FlowCenter/Flowinstance/IFlcCustomFormService.cs b/Magic.FlowCenter/Flowinstance/IFlcCustomFormService.cs new file mode 100644 index 0000000..389de44 --- /dev/null +++ b/Magic.FlowCenter/Flowinstance/IFlcCustomFormService.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace Magic.FlowCenter.Service; + +public interface IFlcCustomFormService +{ + Task Add(long flowInstanceId, string frmData); + Task Edit(long flowInstanceId, string frmData); +} diff --git a/Magic.FlowCenter/Flowinstance/IFlcFlowinstanceService.cs b/Magic.FlowCenter/Flowinstance/IFlcFlowinstanceService.cs new file mode 100644 index 0000000..112e53e --- /dev/null +++ b/Magic.FlowCenter/Flowinstance/IFlcFlowinstanceService.cs @@ -0,0 +1,18 @@ +using Magic.FlowCenter.Entity; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Threading.Tasks; +namespace Magic.FlowCenter.Service; + + public interface IFlcFlowinstanceService +{ + Task Add(FlcFlowinstance input); + Task Delete(DeleteFlcFlowinstanceInput input); + Task Cancel(DeleteFlcFlowinstanceInput input); + Task Verification(Verification input); + Task List([FromQuery] FlcFlowinstanceInput input); + Task Page([FromQuery] FlcFlowinstanceInput input); + Task Update(FlcFlowinstance input); + Task> QueryHistories([FromQuery] QueryeFlcFlowinstanceInput input); + Task GetForVerification([FromQuery] QueryeFlcFlowinstanceInput input); +} diff --git a/Magic.FlowCenter/Flowscheme/Dto/FlcFlowschemeInput.cs b/Magic.FlowCenter/Flowscheme/Dto/FlcFlowschemeInput.cs new file mode 100644 index 0000000..e92a5f4 --- /dev/null +++ b/Magic.FlowCenter/Flowscheme/Dto/FlcFlowschemeInput.cs @@ -0,0 +1,49 @@ +using Magic.Core; +using System; +using System.ComponentModel.DataAnnotations; + +namespace Magic.FlowCenter.Service; + +/// +/// 流程管理输入参数 +/// +public class FlcFlowschemeInput : InputBase +{ + public string SchemeCode { get; set; } + public string SchemeName { get; set; } + public string SchemeType { get; set; } + public string SchemeVersion { get; set; } + public string SchemeCanUser { get; set; } + public string SchemeContent { get; set; } + public string FrmId { get; set; } + public FormType? FrmType { get; set; } + public int? AuthorizeType { get; set; } + public string OrgId { get; set; } + public string Active { get; set; } + public CommonStatus? Status { get; set; } + public int? Sort { get; set; } + public string Remark { get; set; } +} + +public class AddFlcFlowschemeInput: FlcFlowschemeInput +{ +} + +public class DeleteFlcFlowschemeInput +{ + public string Id { get; set; } +} + +public class UpdateFlcFlowschemeInput : FlcFlowschemeInput +{ + /// + /// 流程Id + /// + [Required(ErrorMessage = "流程Id不能为空")] + public string Id { get; set; } +} + +public class PageFlcFlowschemeInput : FlcFlowschemeInput +{ + public string Id { get; set; } +} diff --git a/Magic.FlowCenter/Flowscheme/Dto/FlcFlowschemeOutput.cs b/Magic.FlowCenter/Flowscheme/Dto/FlcFlowschemeOutput.cs new file mode 100644 index 0000000..ec8c7ab --- /dev/null +++ b/Magic.FlowCenter/Flowscheme/Dto/FlcFlowschemeOutput.cs @@ -0,0 +1,33 @@ +using System; + +namespace Magic.FlowCenter.Service; + +/// +/// 流程管理输出参数 +/// +public class FlcFlowschemeOutput:FlcFlowschemeInput +{ + /// + /// 流程Id + /// + public string Id { get; set; } + public int? Fields { get; set; } + public string Name { get; set; } + public string WebId { get; set; } + public string ContentData { get; set; } + public string ContentParse { get; set; } + public string Content { get; set; } + /// + /// 如果下个执行节点是运行时指定执行者。需要传指定的类型 + /// 取值为RUNTIME_SPECIAL_ROLE、RUNTIME_SPECIAL_USER + /// + public string NextNodeDesignateType { get; set; } + + /// + /// 如果下个执行节点是运行时指定执行者。该值表示具体的执行者 + /// 如果NodeDesignateType为RUNTIME_SPECIAL_ROLE,则该值为指定的角色 + /// 如果NodeDesignateType为RUNTIME_SPECIAL_USER,则该值为指定的用户 + /// + public string[] NextNodeDesignates { get; set; } + public string NextMakerName { get; set; } +} diff --git a/Magic.FlowCenter/Flowscheme/FlcFlowschemeService.cs b/Magic.FlowCenter/Flowscheme/FlcFlowschemeService.cs new file mode 100644 index 0000000..c954666 --- /dev/null +++ b/Magic.FlowCenter/Flowscheme/FlcFlowschemeService.cs @@ -0,0 +1,270 @@ +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Furion.FriendlyException; +using Magic.Core; +using Magic.Core.Entity; +using Magic.Core.Service; +using Magic.FlowCenter.Entity; +using Mapster; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Magic.FlowCenter.Service; + +/// +/// 流程管理服务 +/// +[ApiDescriptionSettings("FlowCenter", Name = "Flowscheme", Order = 100)] +public class FlcFlowschemeService : IFlcFlowschemeService, IDynamicApiController, ITransient +{ + private readonly SqlSugarRepository _rep; + private readonly IFlcFormManageService _flcFormService; + private readonly ISysEmpService _sysEmpService; + + public FlcFlowschemeService(SqlSugarRepository flcFormRep, + IFlcFormManageService flcFormService, + ISysEmpService sysEmpService) + { + _rep = flcFormRep; + _flcFormService = flcFormService; + _sysEmpService = sysEmpService; + } + + /// + /// 分页查询流程管理 + /// + /// + /// + [HttpGet("/flcFlowscheme/page")] + public async Task Page([FromQuery] PageFlcFlowschemeInput input) + { + var entities = await _rep.AsQueryable() + .LeftJoin((u,b)=>u.FrmId==b.Id) + .WhereIF(!string.IsNullOrWhiteSpace(input.SchemeName), u => u.SchemeName.Contains(input.SchemeName.Trim())) + .WhereIF(!string.IsNullOrWhiteSpace(input.Id), u => u.Id == long.Parse(input.Id.Trim())) + .WhereIF(!string.IsNullOrWhiteSpace(input.OrgId), u => u.OrgId == long.Parse(input.OrgId) || u.OrgId == null || u.OrgId == 0) + .WhereIF(input.Status != null, u => u.Status == input.Status) + .Where(u => u.Status != CommonStatus.DELETED) + .OrderBy(u => u.Sort) + .Select((u,b)=>new FlcFlowschemeOutput { + Id=u.Id.ToString(), + Active=u.Active, + AuthorizeType=u.AuthorizeType, + FrmId=u.FrmId.ToString(), + Name=b.Name, + WebId = b.WebId, + FrmType =u.FrmType, + OrgId=u.OrgId.ToString(), + Remark=u.Remark, + SchemeCanUser=u.SchemeCanUser, + SchemeCode=u.SchemeCode, + SchemeContent=u.SchemeContent, + SchemeName=u.SchemeName, + SchemeType=u.SchemeType, + SchemeVersion=u.SchemeVersion, + Sort=u.Sort, + Status=u.Status, + Content=b.Content, + ContentData=b.ContentData, + ContentParse=b.ContentParse, + Fields=b.Fields + }) + .ToPagedListAsync(input.PageNo, input.PageSize); + return entities.XnPagedResult(); + } + + /// + /// 增加流程管理 + /// + /// + /// + [HttpPost("/flcFlowscheme/add")] + public async Task Add(AddFlcFlowschemeInput input) + { + var isExist = await _rep.AnyAsync(u => u.SchemeName == input.SchemeName); + if (isExist) + throw Oops.Oh(ErrorCode.D2002); + var formEntity = await _flcFormService.GetForm(new QueryFlcFormInput { Id = input.FrmId }); + if (formEntity == null) + throw Oops.Oh(ErrorCode.F1000); + input.Status = CommonStatus.DISABLE; + var entity = input.Adapt(); + entity.FrmType = formEntity.FrmType; + await _rep.InsertAsync(entity); + } + + /// + /// 删除流程管理 + /// + /// + /// + [HttpPost("/flcFlowscheme/delete")] + public async Task Delete(DeleteFlcFlowschemeInput input) + { + var flow = await _rep.FirstOrDefaultAsync(u => u.Id == long.Parse(input.Id)); + + // 检测数据范围能不能操作这个表单 + (flow.CreatedUserId ?? 0).CheckDataScope(); + //假删除 + await _rep.UpdateAsync(a => a.Id == long.Parse(input.Id),a => new FlcFlowscheme + { + Status = CommonStatus.DELETED, + IsDeleted = true, + }); + } + + /// + /// 更新流程管理 + /// + /// + /// + [HttpPost("/flcFlowscheme/edit")] + public async Task Update(UpdateFlcFlowschemeInput input) + { + if (input.Id != "0" && !string.IsNullOrEmpty(input.Id)) + { + var org = await _rep.FirstOrDefaultAsync(u => u.Id == long.Parse(input.Id)); + _ = org ?? throw Oops.Oh(ErrorCode.D2000); + } + + var flcFlow = await _rep.FirstOrDefaultAsync(u => u.Id == long.Parse(input.Id)); + + // 检测数据范围能不能操作这个表单 + (flcFlow.CreatedUserId ?? 0).CheckDataScope(); + + var isExist = await _rep.AnyAsync(u => (u.SchemeName == input.SchemeName) && u.Id != flcFlow.Id); + if (isExist) + throw Oops.Oh(ErrorCode.D2002); + var entity = input.Adapt(); + var formEntity = await _flcFormService.GetForm(new QueryFlcFormInput { Id = flcFlow.FrmId.ToString() }); + if (formEntity == null) + throw Oops.Oh(ErrorCode.F1000); + entity.FrmType=formEntity.FrmType; + await _rep.AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns:true).ExecuteCommandAsync(); + } + + /// + /// 获取流程管理 + /// + /// + /// + [HttpGet("/flcFlowscheme/detail")] + public async Task Get([FromQuery] DeleteFlcFlowschemeInput input) + { + var cachedata = await _rep.FirstOrDefaultAsync(u => u.Id == long.Parse(input.Id)); + var temp = cachedata.Adapt(); + var form = await _rep.Change().AsQueryable().InSingleAsync(cachedata.FrmId); + temp.WebId = form.WebId; + temp.ContentData = form.ContentData; + temp.Content = form.Content; + //创建运行实例 + var flowinstance = new FlcFlowinstance(); + flowinstance.SchemeContent = temp.SchemeContent; + if (flowinstance.SchemeContent.IsEmpty()) + { + return temp; + } + var runtime = new FlowRuntime(flowinstance); + if (runtime.nextNodeType != -1 && runtime.nextNode != null && runtime.nextNode.setInfo != null && runtime.nextNodeType != 4) + { + temp.NextNodeDesignateType = runtime.nextNode.setInfo.NodeDesignate; + if (temp.NextNodeDesignateType == Setinfo.SPECIAL_USER) + { + temp.NextNodeDesignates = runtime.nextNode.setInfo.NodeDesignateData.ToArray(); + temp.NextMakerName = string.Join(',', _rep.Change().Where(a => temp.NextNodeDesignates.Contains(a.Id.ToString())).Select(a => a.Name).ToList()); + } + else if (temp.NextNodeDesignateType == Setinfo.SPECIAL_ROLE) + { + temp.NextNodeDesignates = runtime.nextNode.setInfo.NodeDesignateData.ToArray(); + List list = new List(); + List users = new List(); + foreach (var item in temp.NextNodeDesignates) + { + var usertemp = _rep.Change().AsQueryable().LeftJoin((a, b) => a.Id == b.SysUserId && b.SysRoleId == long.Parse(item)).Select((a, b) => a).Distinct().ToList(); + var tempList = new List(); + if (runtime.nextNode.setInfo.CurrentDepart) + { + var currentDepartment = new List(); + var empInfo = await _sysEmpService.GetEmpInfo(UserManager.UserId); + if (empInfo != null) + { + currentDepartment.Add(long.Parse(empInfo.OrgId)); + if (empInfo.ExtOrgPos != null && empInfo.ExtOrgPos.Count > 0) + currentDepartment.AddRange(empInfo.ExtOrgPos.Select(a => a.OrgId)); + } + foreach (var user in usertemp) + { + var nextCurrentDepartment = new List(); + var empTempInfo = await _sysEmpService.GetEmpInfo(UserManager.UserId); + if (empTempInfo != null) + { + nextCurrentDepartment.Add(long.Parse(empTempInfo.OrgId)); + if (empInfo.ExtOrgPos != null && empTempInfo.ExtOrgPos.Count > 0) + nextCurrentDepartment.AddRange(empTempInfo.ExtOrgPos.Select(a => a.OrgId)); + } + if (JsonUtil.IsArrayIntersection(currentDepartment, nextCurrentDepartment)) + { + tempList.Add(user); + } + } + } + else + { + tempList = usertemp; + } + var tempFinal = tempList.Select(a => a.Id).ToList(); + users.AddRange(tempFinal); + } + users = users.Distinct().ToList(); + temp.NextMakerName = string.Join(',', _rep.Change().Where(a => users.Contains(a.Id)).Select(a => a.Name).ToList()); + } + } + return temp; + } + + /// + /// 获取流程管理列表 + /// + /// + /// + [HttpGet("/flcFlowscheme/list")] + public async Task> List([FromQuery] FlcFlowschemeInput input) + { + var dataScopeList = await DataFilterExtensions.GetDataScopeIdList(FilterType.Org); + var flows = await _rep.AsQueryable() + .LeftJoin((u, b) => u.FrmId == b.Id) + .WhereIF(!string.IsNullOrWhiteSpace(input.OrgId), u => u.OrgId == long.Parse(input.OrgId) || u.OrgId == null || u.OrgId == 0) + .WhereIF(dataScopeList.Any(), u => dataScopeList.Contains(u.OrgId ?? 0)) + .Where(u => u.Status != CommonStatus.DELETED) + .OrderBy(u => u.Sort) + .Select((u, b) => new FlcFlowschemeOutput + { + Id = u.Id.ToString(), + Active = u.Active, + AuthorizeType = u.AuthorizeType, + FrmId = u.FrmId.ToString(), + FrmType = u.FrmType, + OrgId = u.OrgId.ToString(), + Name = b.Name, + WebId=b.WebId, + Remark = u.Remark, + SchemeCanUser = u.SchemeCanUser, + SchemeCode = u.SchemeCode, + SchemeContent = u.SchemeContent, + SchemeName = u.SchemeName, + SchemeType = u.SchemeType, + SchemeVersion = u.SchemeVersion, + Sort = u.Sort, + Status = u.Status, + Content = b.Content, + ContentData = b.ContentData, + ContentParse = b.ContentParse, + Fields = b.Fields + }) + .ToListAsync(); + return flows; + } +} diff --git a/Magic.FlowCenter/Flowscheme/IFlcFlowschemeService.cs b/Magic.FlowCenter/Flowscheme/IFlcFlowschemeService.cs new file mode 100644 index 0000000..273f9b5 --- /dev/null +++ b/Magic.FlowCenter/Flowscheme/IFlcFlowschemeService.cs @@ -0,0 +1,14 @@ +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Threading.Tasks; +namespace Magic.FlowCenter.Service; + + public interface IFlcFlowschemeService +{ + Task Add(AddFlcFlowschemeInput input); + Task Delete(DeleteFlcFlowschemeInput input); + Task Get([FromQuery] DeleteFlcFlowschemeInput input); + Task> List([FromQuery] FlcFlowschemeInput input); + Task Page([FromQuery] PageFlcFlowschemeInput input); + Task Update(UpdateFlcFlowschemeInput input); +} diff --git a/Magic.FlowCenter/FormManage/Dto/FlcFormInput.cs b/Magic.FlowCenter/FormManage/Dto/FlcFormInput.cs new file mode 100644 index 0000000..4d8e674 --- /dev/null +++ b/Magic.FlowCenter/FormManage/Dto/FlcFormInput.cs @@ -0,0 +1,78 @@ +using Magic.Core; +using System.ComponentModel.DataAnnotations; + +namespace Magic.FlowCenter.Service; + +/// +/// 组织机构参数 +/// +public class FlcFormInput : InputBase +{ + /// + /// 组织Id + /// + public string OrgId { get; set; } + + /// + /// 名称 + /// + public virtual string Name { get; set; } + + /// + /// 排序 + /// + public int? Sort { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } + + /// + /// 状态(字典 0正常 1停用 2删除) + /// + public CommonStatus? Status { get; set; } + public string ContentData { get; set; } + public string ContentParse { get; set; } + public string Content { get; set; } + public int? Fields { get; set; } + public string WebId { get; set; } + public FormType? FrmType { get; set; } +} + + public class AddFlcFormInput : FlcFormInput +{ + /// + /// 名称 + /// + [Required(ErrorMessage = "表单名称不能为空")] + public override string Name { get; set; } +} + +public class DeleteFlcFormInput +{ + /// + /// 机构Id + /// + [Required(ErrorMessage = "表单Id不能为空")] + public string Id { get; set; } +} + +public class UpdateFlcFormInput : FlcFormInput +{ + /// + /// 机构Id + /// + [Required(ErrorMessage = "表单Id不能为空")] + public string Id { get; set; } +} + +public class QueryFlcFormInput : DeleteFlcFormInput +{ + +} + +public class PageFlcFormInput : FlcFormInput +{ + public string Id { get; set; } +} diff --git a/Magic.FlowCenter/FormManage/Dto/FlcFormOutput.cs b/Magic.FlowCenter/FormManage/Dto/FlcFormOutput.cs new file mode 100644 index 0000000..0c5280b --- /dev/null +++ b/Magic.FlowCenter/FormManage/Dto/FlcFormOutput.cs @@ -0,0 +1,12 @@ +namespace Magic.FlowCenter.Service; + +/// +/// 组织机构参数 +/// +public class FlcFormOutput : FlcFormInput +{ + /// + /// 表单Id + /// + public string Id { get; set; } +} diff --git a/Magic.FlowCenter/FormManage/FlcFormManageService.cs b/Magic.FlowCenter/FormManage/FlcFormManageService.cs new file mode 100644 index 0000000..bdbb275 --- /dev/null +++ b/Magic.FlowCenter/FormManage/FlcFormManageService.cs @@ -0,0 +1,181 @@ +using Furion; +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Furion.FriendlyException; +using Magic.Core; +using Magic.FlowCenter.Entity; +using Mapster; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; + +namespace Magic.FlowCenter.Service; + +/// +/// 表单管理 +/// +[ApiDescriptionSettings("FlowCenter", Name = "FormManage", Order = 100)] +public class FlcFormManageService : IFlcFormManageService, IDynamicApiController, ITransient +{ + private readonly SqlSugarRepository _flcFormRep; + + public FlcFormManageService(SqlSugarRepository flcFormRep) + { + _flcFormRep = flcFormRep; + } + + /// + /// 分页查询表单 + /// + /// + /// + [HttpGet("/flcForm/page")] + public async Task QueryFormPageList([FromQuery] PageFlcFormInput input) + { + var orgs = await _flcFormRep.AsQueryable() + .WhereIF(!string.IsNullOrWhiteSpace(input.Name), u => u.Name.Contains(input.Name.Trim())) + .WhereIF(!string.IsNullOrWhiteSpace(input.Id), u => u.Id == long.Parse(input.Id.Trim())) + .WhereIF(!string.IsNullOrWhiteSpace(input.OrgId), u => u.OrgId == long.Parse(input.OrgId) || u.OrgId == null || u.OrgId == 0) + .Where(u => u.Status != CommonStatus.DELETED) + .OrderBy(u => u.Sort) + .Select() + .ToPagedListAsync(input.PageNo, input.PageSize); + return orgs.XnPagedResult(); + } + + /// + /// 获取表单列表 + /// + /// + /// + [HttpGet("/flcForm/list")] + public async Task> GetFormList([FromQuery] FlcFormInput input) + { + var dataScopeList = await DataFilterExtensions.GetDataScopeIdList(FilterType.Org); + var forms = await _flcFormRep.AsQueryable() + .WhereIF(!string.IsNullOrWhiteSpace(input.OrgId), u => u.OrgId == long.Parse(input.OrgId) || u.OrgId == null || u.OrgId == 0) + .WhereIF(dataScopeList.Any(), u => dataScopeList.Contains(u.OrgId??0)|| u.OrgId == null || u.OrgId == 0) + .Where(u => u.Status == CommonStatus.ENABLE) + .OrderBy(u => u.Sort) + .ToListAsync(); + return forms.Adapt>(); + } + + /// + /// 增加表单 + /// + /// + /// + [HttpPost("/flcForm/add")] + public async Task AddForm(AddFlcFormInput input) + { + var isExist = await _flcFormRep.AnyAsync(u => u.Name == input.Name); + if (isExist) + throw Oops.Oh(ErrorCode.D2002); + + var flcForm = input.Adapt(); + flcForm.Status = CommonStatus.ENABLE; + //反射获取这个表单的所有参数和备注,排除主键 + if (flcForm.FrmType == FormType.CUSTOMFORM) + { + var dataname = input.WebId.Substring(0, 1).ToUpper() + input.WebId.Substring(1); + var t = App.Assemblies + .SelectMany(a => a.GetTypes().Where(t => t.FullName.Contains("Magic.FlowCenter.Entity") && t.FullName.Contains("." + dataname))).First(); + List list = new List(); + List parses = new List(); + dynamic obj = Activator.CreateInstance(t); + foreach (PropertyInfo info in obj.GetType().GetProperties()) + { + if (info.Name != "Id") + { + list.Add(info.Name); + parses.Add(new { id = info.Name, name = info.Name }); + } + } + flcForm.ContentData = string.Join(',', list); + flcForm.Fields = list.Count(); + flcForm.ContentParse = parses.ToJsonString(); + } + await _flcFormRep.InsertAsync(flcForm); + } + + /// + /// 删除表单 + /// + /// + /// + [HttpPost("/flcForm/delete")] + public async Task DeleteForm(DeleteFlcFormInput input) + { + var flcForm = await _flcFormRep.FirstOrDefaultAsync(u => u.Id == long.Parse(input.Id)); + + (flcForm.CreatedUserId ?? 0).CheckDataScope(); + //假删除 + await _flcFormRep.Change().UpdateAsync(u => u.Id == long.Parse(input.Id),a => new FlcForm + { + Status = CommonStatus.DELETED, + IsDeleted = true, + }); + } + + /// + /// 更新表单 + /// + /// + /// + [HttpPost("/flcForm/edit")] + public async Task UpdateForm(UpdateFlcFormInput input) + { + if (input.Id != "0" && !string.IsNullOrEmpty(input.Id)) + { + var org = await _flcFormRep.FirstOrDefaultAsync(u => u.Id == long.Parse(input.Id)); + _ = org ?? throw Oops.Oh(ErrorCode.D2000); + } + + var flcForm = await _flcFormRep.FirstOrDefaultAsync(u => u.Id == long.Parse(input.Id)); + // 检测数据范围能不能操作这个表单 + (flcForm.CreatedUserId ?? 0).CheckDataScope(); + + var isExist = await _flcFormRep.AnyAsync(u => (u.Name == input.Name) && u.Id != flcForm.Id); + if (isExist) + throw Oops.Oh(ErrorCode.D2002); + flcForm = input.Adapt(); + //反射获取这个表单的所有参数和备注,排除主键 + if (flcForm.FrmType == FormType.CUSTOMFORM) + { + var dataname = input.WebId.Substring(0, 1).ToUpper() + input.WebId.Substring(1); + var t = App.Assemblies + .SelectMany(a => a.GetTypes().Where(t => t.FullName.Contains("Magic.FlowCenter.Entity") && t.FullName.Contains("." + dataname))).First(); + List list = new List(); + List parses = new List(); + dynamic obj = Activator.CreateInstance(t); + foreach (PropertyInfo info in obj.GetType().GetProperties()) + { + if (info.Name != "Id") + { + list.Add(info.Name); + parses.Add(new { id = info.Name, name = info.Name }); + } + } + flcForm.ContentData = string.Join(',', list); + flcForm.Fields = list.Count(); + flcForm.ContentParse = parses.ToJsonString(); + } + await _flcFormRep.AsUpdateable(flcForm).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync(); + } + + /// + /// 获取表单信息 + /// + /// + /// + [HttpGet("/flcForm/detail")] + public async Task GetForm([FromQuery] QueryFlcFormInput input) + { + return await _flcFormRep.FirstOrDefaultAsync(u => u.Id == long.Parse(input.Id)); + } +} diff --git a/Magic.FlowCenter/FormManage/IFlcFormManageService.cs b/Magic.FlowCenter/FormManage/IFlcFormManageService.cs new file mode 100644 index 0000000..a34e741 --- /dev/null +++ b/Magic.FlowCenter/FormManage/IFlcFormManageService.cs @@ -0,0 +1,15 @@ +using Magic.FlowCenter.Entity; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Magic.FlowCenter.Service; + + public interface IFlcFormManageService +{ + Task AddForm(AddFlcFormInput input); + Task DeleteForm(DeleteFlcFormInput input); + Task GetForm([FromQuery] QueryFlcFormInput input); + Task> GetFormList([FromQuery] FlcFormInput input); + Task QueryFormPageList([FromQuery] PageFlcFormInput input); +} diff --git a/Magic.FlowCenter/Magic.FlowCenter.csproj b/Magic.FlowCenter/Magic.FlowCenter.csproj new file mode 100644 index 0000000..25d47cc --- /dev/null +++ b/Magic.FlowCenter/Magic.FlowCenter.csproj @@ -0,0 +1,13 @@ + + + + net7.0 + True + Magic.FlowCenter.xml + + + + + + + diff --git a/Magic.FlowCenter/Magic.FlowCenter.xml b/Magic.FlowCenter/Magic.FlowCenter.xml new file mode 100644 index 0000000..58fbb50 --- /dev/null +++ b/Magic.FlowCenter/Magic.FlowCenter.xml @@ -0,0 +1,1871 @@ + + + + Magic.FlowCenter + + + + + 自定义表单 + + + + + 名称 + + + + + 排序 + + + + + 备注 + + + + + 创建时间 + + + + + 创建者Id + + + + + 创建者名称 + + + + + 自定义租户基类实体 + + + + + 租户id + + + + + 自定义实体基类 + + + + + 创建时间 + + + + + 更新时间 + + + + + 创建者Id + + + + + 创建者名称 + + + + + 修改者Id + + + + + 修改者名称 + + + + + 软删除 + + + + + 更新信息列 + + + + + + 假删除的列,包含更新信息 + + + + + + 递增主键实体基类 + + + + + 主键Id + + + + + 主键实体基类 + + + + + 主键Id + + + + + 创 建:超级管理员 + 日 期:2020-07-14 09:18 + 描 述:我的流程实体类 + + + + + 流程实例模板Id + + + + + + 实例编号 + + + + + + 自定义名称 + + + + + + 当前节点ID + + + + + + 当前节点类型(0会签节点) + + + + + + 当前节点名称 + + + + + + 前一个ID + + + + + + 流程模板内容 + + + + + + 流程模板ID + + + + + + 数据库名称 + + + + + + 表单数据 + + + + + + 表单类型 + + + + + + 表单中的字段 + + + + + + 表单字段(冗余) + + + + + + 表单参数 + + + + + + 表单ID + + + + + + 流程类型 + + + + + + 等级 + + + + + + 是否完成 + + + + + + 执行人 + + + + + + 所属部门 + + + + + + 状态标识 + + + + + 如果下个执行节点是运行时指定执行者。需要传指定的类型 + 取值为RUNTIME_SPECIAL_ROLE、RUNTIME_SPECIAL_USER + + + + + 如果下个执行节点是运行时指定执行者。该值表示具体的执行者 + 如果NodeDesignateType为RUNTIME_SPECIAL_ROLE,则该值为指定的角色 + 如果NodeDesignateType为RUNTIME_SPECIAL_USER,则该值为指定的用户 + + + + + 下个节点执行人 + + + + + 当前节点执行人 + + + + + 当前节点执行类型 + + + + + 工作流实例操作记录 + + + + + 实例进程Id + + + + + 操作内容 + + + + + 创建时间 + + + + + 创建用户主键 + + + + + 创建用户 + + + + + 工作流实例流转历史记录 + + + + + 实例Id + + + + + 开始节点Id + + + + + 开始节点类型 + + + + + 开始节点名称 + + + + + 结束节点Id + + + + + 结束节点类型 + + + + + 结束节点名称 + + + + + 转化状态 + + + + + 是否结束 + + + + + 转化时间 + + + + + 创建用户主键 + + + + + 创建用户 + + + + + 流程 + + + + + 流程编号 + 默认值: + + + + + 流程名称 + 默认值: + + + + + 流程类型 + 默认值: + + + + + 流程版本 + 默认值: + + + + + 流程使用人 + 默认值: + + + + + 流程内容 + 默认值: + + + + + 表单Id + 默认值: + + + + + 表单类型 + 默认值: + + + + + 权限类型 + 默认值: + + + + + 组织Id + 默认值: + + + + + + 默认值: + + + + + 状态 + 默认值: + + + + + 排序 + 默认值: + + + + + 备注 + 默认值: + + + + + 表单 + + + + + 表单名称 + 默认值: + + + + + 表单类型 + 默认值: + + + + + 自定义表单 + 默认值: + + + + + 字段数 + 默认值: + + + + + 字段 + 默认值: + + + + + 字段格式化 + 默认值: + + + + + 表单内容 + 默认值: + + + + + 数据库备用 + 默认值: + + + + + 组织id + 默认值: + + + + + + 默认值: + + + + + 状态 + 默认值: + + + + + 排序 + 默认值: + + + + + 备注 + 默认值: + + + + + 自定义表单实体 + + + + + 申请流程Id + + + + + 流程 + + + + + 流程配置 + + + + + 参数 + + + + + 状态 + + + + + 连线 + + + + + 节点 + + + + + 泳道 + + + + + 流程配置 + + + + + 网格 + + + + + 文字 + + + + + 图标 + + + + + 参数 + + + + + 流程泳道 + + + + + 泳道Id + + + + + 名称 + + + + + 类型 + + + + + 图标 + + + + + x坐标 + + + + + y坐标 + + + + + 宽度 + + + + + 高度 + + + + + 流程连线 + + + + + 线Id + + + + + 显示 + + + + + 类型 + + + + + 源头节点 + + + + + 目标节点 + + + + + 名称 + + + + + 连接样式 + + + + 分支条件 + + + + 连线比较 + + + + + + + 分支条件 + + + + 操作类型比如大于/等于/小于 + + + form种的字段名称 + + + 字段类型:"form":为表单中的字段,后期扩展系统表等. + + + 实际的值 + + + + 实际值的显示值 + + + + + 显示值 + + + + + 条件关系 + + + + + 连接样式 + + + + + 连接类型 + + + + + 连接颜色 + + + + + + + + + + 流程节点 + + + + + id + + + + + 名称 + + + + + 类型 + + + + + 图标 + + + + + x坐标 + + + + + y左边 + + + + + 宽度 + + + + + 高度 + + + + + 节点的附加数据项 + + The set information. + + + + 节点详细 + + + + + 节点执行权限类型 + + + + + 选择值 + + + + + 选择显示 + + + + + 当前部门 + + + + + 节点编号 + + + + + 节点名称 + + + + + 流程执行时,三方回调的URL地址 + + + + + 驳回节点0"前一步"1"第一步"2"某一步" 3"不处理" + + + + + 节点状态 + + + + + 用户名称 + + + + + 用户Id + + + + + 描述 + + + + + 节点时间 + + + + + 节点会签方式,all/空:默认为全部通过,one :至少有一个通过 + + + + + 会签通过的个数 + + + + + 会签拒绝的个数 + + + + + 节点执行结果标签 + + + + + 1: 通过 + 2:不通过 + 3:驳回 + + + + + 用户id + + + + + 用户名 + + + + + 描述 + + + + + 时间 + + + + + 1: 通过 + 2:不通过 + 3:驳回 + + + + + 流程运行类 + + + + + 构造函数 + + + + + 获取工作流信息 + + + + + + + 获取工作流节点的字典列表:key节点id + + + + + + + 获取下一个节点 + + + + + 获取上一个节点 + + + + + 获取下一个节点 + + + + + + + 获取实例接下来运行的状态 + + -1无法运行,0会签开始,1会签结束,2一般节点,4流程运行结束 + + + + 获取节点类型 0会签开始,1会签结束,2一般节点,开始节点,4流程运行结束 + + + + + + + 删除节点 + + + + + + 删除全部节点 + + + + + 节点会签审核 + + 会签时,currentNodeId是会签开始节点。这个表示当前正在处理的节点 + + -1不通过,1等待,其它通过 + + + + 获取上一个节点 + + + + + + + + 驳回 + + 驳回类型。null:使用节点配置的驳回类型/0:前一步/1:第一步/2:指定节点,使用NodeRejectStep + + + + + 标记节点1通过,2不通过,3驳回 + + + + + + 获取流程 + + + + + + 通知三方系统,节点执行情况 + + + + + 流程 + + + + + 运行实例的Id + + + + + 开始节点的ID + + + + + 当前节点的ID + + + + + 当前节点类型 0会签开始,1会签结束,2一般节点,开始节点,4流程运行结束 + + + + + 当前节点的对象 + + + + + 下一个节点 + + + + + 下一个节点类型 -1无法运行,0会签开始,1会签结束,2一般节点,4流程运行结束 + + The type of the next node. + + + + 下一个节点对象 + + + + + 上一个节点 + + + + + 实例节点集合 + + + + + 流程实例中所有的线段 + + + + + 从节点发出的线段集合 + + + + + 到达节点的线段集合 + + + + + 表单数据 + + + + + 表单工具 + + + + + 获取值 + + + System.String. + + + + 表单赋值 + + + + + + + + 自定义表单设值 + + + + + + + 表单设计类 + + + + + 表id + + + + + 说明 + + + + + 序号 + + + + + 标签 + + + + + 跨度 + + + + + 表单 + + + + + 名称 + + + + + 表单 + + + + + 跨度 + + + + + 表单设计列表 + + + + + 节点执行类 + + + + + 如果下个执行节点是运行时指定执行者。需要传指定的类型 + 取值为RUNTIME_SPECIAL_ROLE、RUNTIME_SPECIAL_USER + + + + + 如果下个执行节点是运行时指定执行者。该值表示具体的执行者 + 如果NodeDesignateType为RUNTIME_SPECIAL_ROLE,则该值为指定的角色 + 如果NodeDesignateType为RUNTIME_SPECIAL_USER,则该值为指定的用户 + + + + + 流程审核类 + + + + + 流程实例Id + + + + + 1:同意;2:不同意;3:驳回 + + + + + 审核意见 + + + + + 驳回的步骤,即驳回到的节点ID + + + + + 驳回类型。null:使用节点配置的驳回类型/0:前一步/1:第一步/2:指定节点,使用NodeRejectStep + + + + + 表单类型 + + + + + 正常 + + + + + 停用 + + + + + 工作流输出参数 + + + + + Id + + + + + InstanceSchemeId + + + + + Code + + + + + CustomName + + + + + ActivityId + + + + + ActivityType + + + + + ActivityName + + + + + PreviousId + + + + + SchemeContent + + + + + SchemeId + + + + + DbName + + + + + FrmData + + + + + FrmType + + + + + FrmContentData + + + + + FrmContentParse + + + + + FrmId + + + + + SchemeType + + + + + FlowLevel + + + + + IsFinish + + + + + FrmContent + + + + + MakerList + + + + + OrgId + + + + + Active + + + + + Remark + + + + + 工作流输入参数 + + + + + InstanceSchemeId + + + + + Code + + + + + CustomName + + + + + ActivityId + + + + + ActivityType + + + + + ActivityName + + + + + PreviousId + + + + + SchemeContent + + + + + SchemeId + + + + + DbName + + + + + FrmData + + + + + FrmType + + + + + FrmContentData + + + + + FrmContentParse + + + + + FrmId + + + + + SchemeType + + + + + FlowLevel + + + + + IsFinish + + + + + FrmContent + + + + + MakerList + + + + + OrgId + + + + + Active + + + + + Remark + + + + + Id + + + + + Id + + + + + 工作流输出参数 + + + + + 自定义表格服务 + + + + + 新增 + + + + + + + + 编辑 + + + + + + + + 工作流服务 + + + + + 分页查询工作流 + + + + + + + 获取工作流 + + + + + + + 获取工作流列表 + + + Verification + + + + 获取历史 + + + + + + + 驳回 + 如果NodeRejectStep不为空,优先使用;否则按照NodeRejectType驳回 + + + + + + 节点审核 + + + + + + + 寻找下一步的执行人 + 一般用于本节点审核完成后,修改流程实例的当前执行人,可以做到通知等功能 + + + + + + 获取会签开始节点的所有可执行者 + + + + + + + + + 寻找该节点执行人 + + + + + + + + 判定节点需要选择执行人或执行角色 + + + + + + + 返回用于处理流程节点 + + + + + + + 添加扭转记录 + + + + + 添加扭转记录 + + + + + 节点处理 + + + + + + + 新增流程实例 + + + + + + + + 编辑流程实例 + + + + + + + + 删除流程实例 + + + + + + + 撤销流程实例 + + + + + + + 流程管理输入参数 + + + + + 流程Id + + + + + 流程管理输出参数 + + + + + 流程Id + + + + + 如果下个执行节点是运行时指定执行者。需要传指定的类型 + 取值为RUNTIME_SPECIAL_ROLE、RUNTIME_SPECIAL_USER + + + + + 如果下个执行节点是运行时指定执行者。该值表示具体的执行者 + 如果NodeDesignateType为RUNTIME_SPECIAL_ROLE,则该值为指定的角色 + 如果NodeDesignateType为RUNTIME_SPECIAL_USER,则该值为指定的用户 + + + + + 流程管理服务 + + + + + 分页查询流程管理 + + + + + + + 增加流程管理 + + + + + + + 删除流程管理 + + + + + + + 更新流程管理 + + + + + + + 获取流程管理 + + + + + + + 获取流程管理列表 + + + + + + + 组织机构参数 + + + + + 组织Id + + + + + 名称 + + + + + 排序 + + + + + 备注 + + + + + 状态(字典 0正常 1停用 2删除) + + + + + 名称 + + + + + 机构Id + + + + + 机构Id + + + + + 组织机构参数 + + + + + 表单Id + + + + + 表单管理 + + + + + 分页查询表单 + + + + + + + 获取表单列表 + + + + + + + 增加表单 + + + + + + + 删除表单 + + + + + + + 更新表单 + + + + + + + 获取表单信息 + + + + + + diff --git a/Magic.FlowCenter/Startup.cs b/Magic.FlowCenter/Startup.cs new file mode 100644 index 0000000..b9f12ce --- /dev/null +++ b/Magic.FlowCenter/Startup.cs @@ -0,0 +1,14 @@ +using Furion; +using Microsoft.Extensions.DependencyInjection; +using SqlSugar; +using System.Linq; + +namespace Magic.FlowCenter; + +public class Startup : AppStartup +{ + public void ConfigureServices(IServiceCollection services) + { + + } +} diff --git a/Magic.Web.Core/Handlers/JwtHandler.cs b/Magic.Web.Core/Handlers/JwtHandler.cs new file mode 100644 index 0000000..28364e0 --- /dev/null +++ b/Magic.Web.Core/Handlers/JwtHandler.cs @@ -0,0 +1,67 @@ +using Furion; +using Furion.Authorization; +using Furion.DataEncryption; +using Magic.Core; +using Magic.Core.Service; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using System.Threading.Tasks; + +namespace Magic.Web.Core; + +public class JwtHandler : AppAuthorizeHandler +{ + /// + /// 重写 Handler 添加自动刷新 + /// + /// + /// + public override async Task HandleAsync(AuthorizationHandlerContext context) + { + // 自动刷新Token + if (JWTEncryption.AutoRefreshToken(context, context.GetCurrentHttpContext())) + { + await AuthorizeHandleAsync(context); + } + else context.Fail(); // 授权失败 + } + + /// + /// 授权判断逻辑,授权通过返回 true,否则返回 false + /// + /// + /// + /// + public override async Task PipelineAsync(AuthorizationHandlerContext context, DefaultHttpContext httpContext) + { + // 此处已经自动验证 Jwt Token的有效性了,无需手动验证 + return await CheckAuthorzieAsync(httpContext); + } + + /// + /// 检查权限 + /// + /// + /// + private static async Task CheckAuthorzieAsync(DefaultHttpContext httpContext) + { + // 管理员跳过判断 + if (UserManager.IsSuperAdmin) return true; + + // 路由名称 + var routeName = httpContext.Request.Path.Value.Substring(1).Replace("/", ":"); + + var allPermission = await App.GetService().GetAllPermission(); + + if (!allPermission.Contains(routeName)) + { + return true; + } + + // 获取用户权限集合(按钮或API接口) + var permissionList = await App.GetService().GetLoginPermissionList(UserManager.UserId); + + // 检查授权 + return permissionList.Contains(routeName); + } +} diff --git a/Magic.Web.Core/Magic.Web.Core.csproj b/Magic.Web.Core/Magic.Web.Core.csproj new file mode 100644 index 0000000..a3daf0f --- /dev/null +++ b/Magic.Web.Core/Magic.Web.Core.csproj @@ -0,0 +1,32 @@ + + + + net7.0 + 1701;1702;1591 + Magic.Web.Core.xml + Magic.Web.Core + + + + + + + + + + + + + + + + + + PreserveNewest + + + Always + + + + diff --git a/Magic.Web.Core/Magic.Web.Core.xml b/Magic.Web.Core/Magic.Web.Core.xml new file mode 100644 index 0000000..eecef91 --- /dev/null +++ b/Magic.Web.Core/Magic.Web.Core.xml @@ -0,0 +1,30 @@ + + + + Magic.Web.Core + + + + + 重写 Handler 添加自动刷新 + + + + + + + 授权判断逻辑,授权通过返回 true,否则返回 false + + + + + + + + 检查权限 + + + + + + diff --git a/Magic.Web.Core/Startup.cs b/Magic.Web.Core/Startup.cs new file mode 100644 index 0000000..65a6f12 --- /dev/null +++ b/Magic.Web.Core/Startup.cs @@ -0,0 +1,150 @@ +using Furion; +using Magic.Core; +using Magic.Core.Service; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using System; +using System.Net; +using System.Net.Http; +using System.Text.Encodings.Web; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Text.Unicode; +using Yitter.IdGenerator; +using Furion.Templates; +using Furion.Logging; +using System.Collections.Generic; +using Newtonsoft.Json.Serialization; +using Newtonsoft.Json; + +namespace Magic.Web.Core; + +[AppStartup(9)] +public class Startup : AppStartup +{ + public void ConfigureServices(IServiceCollection services) + { + services.AddBStyle(m => m.UseDefault()); + services.AddConfigurableOptions(); + services.AddConfigurableOptions(); + services.AddConfigurableOptions(); + services.AddConfigurableOptions(); + services.AddConfigurableOptions(); + services.AddConfigurableOptions(); + services.AddConfigurableOptions(); + + #region 上传文件大小限制 + long maxRequestBodySize = Convert.ToInt64(App.Configuration["MaxRequestBodySize"]); + services.Configure(options => + { + options.Limits.MaxRequestBodySize = maxRequestBodySize; + }); + services.Configure(options => + { + options.MaxRequestBodySize = maxRequestBodySize; + }); + + services.Configure(o => + { + o.MultipartBodyLengthLimit = maxRequestBodySize; + }); + #endregion + + services.AddResponseCompression(); + + services.SqlSugarScopeConfigure(); + + services.AddJwt(enableGlobalAuthorize: true); + + services.AddCorsAccessor(); + + // 配置远程请求 + services.AddRemoteRequest(option => + { + // 配置天气预报GZIP + option.AddHttpClient("wthrcdn", c => + { + c.BaseAddress = new Uri("http://wthrcdn.etouch.cn/"); + }).ConfigurePrimaryHttpMessageHandler(_ => + new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip }); + }); + services.AddControllersWithViews() + .AddMvcFilter() + .AddInjectWithUnifyResult() + .AddNewtonsoftJson(options => + { + // 首字母小写(驼峰样式) + options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); + // 时间格式化 + options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; + // 忽略循环引用 + options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; + // 忽略空值 + options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; + }); + + services.AddViewEngine(); + services.AddSignalR(); + + // 设置雪花id的workerId,确保每个实例workerId都应不同 + var workerId = ushort.Parse(App.GetConfig("SnowId").WorkerId); + YitIdHelper.SetIdGenerator(new IdGeneratorOptions { WorkerId = workerId }); + + // 开启自启动定时任务 + services.AddTaskScheduler(); + //App.GetService().StartTimerJob(); + + // 注册EventBus服务 + services.AddEventBus(builder => + { + // 注册 Log 日志订阅者 + builder.AddSubscriber(); + }); + } + + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + else + { + app.UseExceptionHandler("/Home/Error"); + app.UseHsts(); + } + + // 添加状态码拦截中间件 + app.UseUnifyResultStatusCodes(); + + app.UseHttpsRedirection(); // 强制https + app.UseStaticFiles(); + + app.UseRouting(); + + app.UseCorsAccessor(); + + app.UseAuthentication(); + app.UseAuthorization(); + + app.UseResponseCompression(); + + app.UseInject(string.Empty); + + app.UseEndpoints(endpoints => + { + endpoints.MapHub("/hubs/chathub"); + endpoints.MapControllerRoute( + name: "default", + pattern: "{controller=Home}/{action=Index}/{id?}"); + }); + + } + + +} diff --git a/Magic.Web.Core/applicationconfig.json b/Magic.Web.Core/applicationconfig.json new file mode 100644 index 0000000..895f266 --- /dev/null +++ b/Magic.Web.Core/applicationconfig.json @@ -0,0 +1,106 @@ +{ + //如果前端不代理的话,又是axios请求的话,需要添加以下代码 + "CorsAccessorSettings": { + "WithExposedHeaders": [ "Content-Disposition" ] + }, + //动态api配置 + //"DynamicApiControllerSettings": { + // "DefaultRoutePrefix": "api666" //默认路由前缀,默认api,但是如果action上面写死route的话 就无效了特性的优先级最高 + //}, + "SystemSettings": { + "SuperAdminViewAllData": false, //超管是否可以查看所有租户的数据 + "IsGlobalRequestLog": false //是否开启全局请求日志 + }, + "AppSettings": { + "InjectSpecificationDocument": true //是否开启swagger + }, + "SpecificationDocumentSettings": { + "DocumentTitle": "Magic", + "DocExpansionState": "None", + "GroupOpenApiInfos": [ + { + "Group": "Default", + "Title": "Magic.NET通用权限管理平台", + "Description": "前后端分离架构,开箱即用,紧随前沿技术。
作者By 蛋蛋,QQ群901868674
https://gitee.com/zhengguojing/admin-net-sqlsugar", + "Version": "1.0.0" + }, + { + "Group": "FlowCenter", + "Title": "流程中心", + "Description": "流程中心模块或插件。
作者By MonsterUncle,QQ295228902", + "Version": "1.0.0" + }, + { + //rm -rf + "Group": "Application", + "Title": "业务模块", + "Description": "独立业务模块", + "Version": "1.0.0" + } + ] + }, + "JWTSettings": { + "ValidateIssuerSigningKey": true, // 是否验证密钥,bool 类型,默认true + "IssuerSigningKey": "3c1cbc3f546eda35168c3aa3cb91780fbe703f0996c6d123ea96dc85c70bbc0a", // 密钥,string 类型,必须是复杂密钥,长度大于16 + "ValidateIssuer": true, // 是否验证签发方,bool 类型,默认true + "ValidIssuer": "magic", // 签发方,string 类型 + "ValidateAudience": true, // 是否验证签收方,bool 类型,默认true + "ValidAudience": "magic", // 签收方,string 类型 + "ValidateLifetime": true, // 是否验证过期时间,bool 类型,默认true,建议true + "ExpiredTime": 1440, // 过期时间,long 类型,单位分钟,默认20分钟 + "ClockSkew": 5 // 过期时间容错值,long 类型,单位秒,默认5秒 + }, + "Cache": { + "CacheType": "MemoryCache", // RedisCache + "RedisConnectionString": "127.0.0.1:6379,password=,defaultDatabase=2" + }, + "SnowId": { + "WorkerId": "1" // 取值范围0~63,默认1 + }, + "OAuth": { + "Wechat": { + "app_id": "wx2959fdd3abc05362", + "app_key": "829f65b2be0652bcd50ea8cb820fd7fa", + "redirect_uri": "http://127.0.0.1:56868/oauth/wechatcallback", + "scope": "snsapi_userinfo" + } + }, + "UploadFile": { + // 阿里云OSS配置 + "Aliyun": { + "path": "Magic/Upload", + "maxSize": 1048576, + "contentType": [ "image/jpg", "image/png", "image/jpeg", "image/gif", "image/bmp", "text/plain", "application/pdf", "application/msword", "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.presentationml.presentation" ] + }, + // 头像 + "Avatar": { + "path": "Upload/Avatar", + "maxSize": 1048576, + "contentType": [ "image/jpg", "image/png", "image/jpeg", "image/gif" ] + }, + // 文档 + "Document": { + "path": "Upload/Document", + "maxSize": 1048576, + "contentType": [ "image/jpg", "image/png", "image/jpeg", "image/gif", "image/bmp", "text/plain", "application/pdf", "application/msword", "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.presentationml.presentation" ] + }, + // 商店 + "Shop": { + "path": "Upload/Shop", + "maxSize": 1048576, + "contentType": [ "image/jpg", "image/png", "image/jpeg", "image/gif" ] + }, + // 富文本 + "Editor": { + "path": "Upload/Editor", + "maxSize": 1048576, + "contentType": [ "image/jpg", "image/png", "image/jpeg", "image/gif" ] + }, + // 默认 + "Default": { + "path": "Upload/Default", + "maxSize": 41943040, + "contentType": [ "image/jpg", "image/png", "image/jpeg", "image/gif", "image/bmp", "text/plain", "application/pdf", "application/msword", "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.presentationml.presentation" ] + } + } +} \ No newline at end of file diff --git a/Magic.Web.Core/dbsettings.json b/Magic.Web.Core/dbsettings.json new file mode 100644 index 0000000..002e9bd --- /dev/null +++ b/Magic.Web.Core/dbsettings.json @@ -0,0 +1,22 @@ +{ + "ConnectionStrings": { + "DefaultDbNumber": "0", + //"DefaultDbType": "Sqlite", + //"DefaultDbString": "Data Source=./Magic.db", + //"DefaultDbType": "SqlServer", + //"DefaultDbString": "Server=.;Database=MagicCodeFirst;User=sa;Password=123456;MultipleActiveResultSets=True;", + "DefaultDbType": "MySql", + "DefaultDbString": "Data Source=127.0.0.1;Database=magic;User ID=root;Password=zhongzhi2022;pooling=true;port=3306;sslmode=none;CharSet=utf8;Convert Zero Datetime=True;Allow Zero Datetime=True;", + "DbConfigs": [ + { + "DbNumber": "1", + "DbType": "Sqlite", + "DbString": "Data Source=./flow.db" + } + ] + } + //"Sqlite": "Data Source=./Magic.db" + //"SqlServer": "Server=.;Database=Magic;User=sa;Password=123456;MultipleActiveResultSets=True;", + //"MySql": "Data Source=localhost;Database=Magic;User ID=root;Password=123456;pooling=true;port=3306;sslmode=none;CharSet=utf8;Convert Zero Datetime=True;Allow Zero Datetime=True;" + +} \ No newline at end of file diff --git a/Magic.Web.Entry/.config/dotnet-tools.json b/Magic.Web.Entry/.config/dotnet-tools.json new file mode 100644 index 0000000..aaaa036 --- /dev/null +++ b/Magic.Web.Entry/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-ef": { + "version": "5.0.3", + "commands": [ + "dotnet-ef" + ] + } + } +} \ No newline at end of file diff --git a/Magic.Web.Entry/Controllers/ValuesController.cs b/Magic.Web.Entry/Controllers/ValuesController.cs new file mode 100644 index 0000000..0659f1f --- /dev/null +++ b/Magic.Web.Entry/Controllers/ValuesController.cs @@ -0,0 +1,13 @@ +using Microsoft.AspNetCore.Mvc; + +namespace Magic.Web.Entry.Controllers; + +[Route("api/[controller]")] +[ApiController] +public class ValuesController : ControllerBase +{ + [HttpGet] + public string GetName() { + return nameof(Furion); + } +} diff --git a/Magic.Web.Entry/Dockerfile b/Magic.Web.Entry/Dockerfile new file mode 100644 index 0000000..2217956 --- /dev/null +++ b/Magic.Web.Entry/Dockerfile @@ -0,0 +1,17 @@ +#FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base +#WORKDIR /app +#EXPOSE 80 +#EXPOSE 443 +# +#COPY . . +##拷贝字体 +#COPY /wwwroot/Captcha/Font/zkkht.ttf /usr/share/fonts/zkkht.ttf +##安装libgdiplus +#RUN apt-get update -y && apt-get install -y libgdiplus && apt-get clean && ln -s /usr/lib/libgdiplus.so /usr/lib/gdiplus.dll +#ENTRYPOINT ["dotnet", "Magic.Web.Entry.dll"] + +FROM mcr.microsoft.com/dotnet/aspnet:7.0 +WORKDIR /app +EXPOSE 80 +COPY publish/ . +ENTRYPOINT ["dotnet", "Magic.Web.Entry.dll","--urls","http://*:5000"] \ No newline at end of file diff --git a/Magic.Web.Entry/Magic.Web.Entry.csproj b/Magic.Web.Entry/Magic.Web.Entry.csproj new file mode 100644 index 0000000..970e66f --- /dev/null +++ b/Magic.Web.Entry/Magic.Web.Entry.csproj @@ -0,0 +1,92 @@ + + + + net7.0 + enable + aa1cd362-1bdb-4ac9-ad5c-461b3b5b1003 + en-US + Magic.Web.Entry + true + + + + + + + + + + + + + + + + + + PreserveNewest + + + Always + + + Always + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + + + + + + + + + diff --git a/Magic.Web.Entry/Magic.db b/Magic.Web.Entry/Magic.db new file mode 100644 index 0000000..5d21e43 Binary files /dev/null and b/Magic.Web.Entry/Magic.db differ diff --git a/Magic.Web.Entry/Program.cs b/Magic.Web.Entry/Program.cs new file mode 100644 index 0000000..2498402 --- /dev/null +++ b/Magic.Web.Entry/Program.cs @@ -0,0 +1,7 @@ + +using Magic.Core; + +Serve.Run(RunOptions.Default.ConfigureBuilder(builder => { + builder.UseLoggingFile(); +})); + diff --git a/Magic.Web.Entry/Properties/launchSettings.json b/Magic.Web.Entry/Properties/launchSettings.json new file mode 100644 index 0000000..15b3871 --- /dev/null +++ b/Magic.Web.Entry/Properties/launchSettings.json @@ -0,0 +1,28 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:5566", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Magic.Web.Entry": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": "true", + "applicationUrl": "http://localhost:5566" + } + } +} \ No newline at end of file diff --git a/Magic.Web.Entry/SingleFilePublish.cs b/Magic.Web.Entry/SingleFilePublish.cs new file mode 100644 index 0000000..fde3591 --- /dev/null +++ b/Magic.Web.Entry/SingleFilePublish.cs @@ -0,0 +1,38 @@ +using Furion; +using System.Reflection; + +namespace Magic.Web.Entry; + +/// +/// 解决单文件发布问题 +/// +public class SingleFilePublish : ISingleFilePublish +{ + /// + /// 解决单文件不能扫描的程序集 + /// + /// 可同时配置 + /// + public Assembly[] IncludeAssemblies() + { + // 需要 Furion 框架扫描哪些程序集就写上去即可 + return Array.Empty(); + } + + /// + /// 解决单文件不能扫描的程序集名称 + /// + /// 可同时配置 + /// + public string[] IncludeAssemblyNames() + { + // 需要 Furion 框架扫描哪些程序集就写上去即可 + return new[] + { + "Magic.Application", + "Magic.Core", + "Magic.FlowCenter", + "Magic.Web.Core" + }; + } +} \ No newline at end of file diff --git a/Magic.Web.Entry/appsettings.Development.json b/Magic.Web.Entry/appsettings.Development.json new file mode 100644 index 0000000..7fd9ccb --- /dev/null +++ b/Magic.Web.Entry/appsettings.Development.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information", + "Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information" + } + } +} diff --git a/Magic.Web.Entry/appsettings.json b/Magic.Web.Entry/appsettings.json new file mode 100644 index 0000000..bd75b94 --- /dev/null +++ b/Magic.Web.Entry/appsettings.json @@ -0,0 +1,40 @@ +{ + "MaxRequestBodySize": 41943040, //单位是字节(byte) 1kb=1024byte,此处限制40M + //"Serilog": { + // "MinimumLevel": { + // "Default": "Information", + // "Override": { + // "System": "Warning", + // "Microsoft": "Warning", + // "Microsoft.Hosting.Lifetime": "Information", + // "Microsoft.EntityFrameworkCore": "Information" + // } + // }, + // "WriteTo": [ + // { + // "Name": "Console", + // "Args": { + // "outputTemplate": "【时间】{Timestamp:yyyy-MM-dd HH:mm:ss,fff}{NewLine}【等级】{Level:u3}{NewLine}【消息】{Message:lj}{NewLine}{NewLine}" + // } + // }, + // { + // "Name": "File", + // "Args": { + // "path": "logs/.log", + // "rollingInterval": "Day", + // "outputTemplate": "【时间】{Timestamp:yyyy-MM-dd HH:mm:ss,fff}{NewLine}【等级】{Level:u3}{NewLine}【消息】{Message:lj}{NewLine}{NewLine}" + // } + // } + // ] + //}, + + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information", + "Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information" + } + }, + "AllowedHosts": "*" +} \ No newline at end of file diff --git a/Magic.Web.Entry/flow.db b/Magic.Web.Entry/flow.db new file mode 100644 index 0000000..d5e4921 Binary files /dev/null and b/Magic.Web.Entry/flow.db differ diff --git a/Magic.Web.Entry/jenkins-docker.sh b/Magic.Web.Entry/jenkins-docker.sh new file mode 100644 index 0000000..31acee9 --- /dev/null +++ b/Magic.Web.Entry/jenkins-docker.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +##版本号 +_tag=1.0 +##镜像名称 +_imageName=magix-service + +#停止容器 +cid=$(docker ps -a | grep ${_imageName} | awk '{print $1}') +if [ -n "$cid" ] + then + docker stop ${cid} +fi + +#删除容器 +cid=$(docker ps -a | grep ${_imageName} | grep "Exited" | awk '{print $1}') +if [ -n "$cid" ] + then + docker rm ${cid} +fi + +#删除镜像 +tags=`docker images | awk -v iname=${_imageName} '($1 ~ iname) {print $1":"$2}'` +if [ -n "${tags}" ] +then + for tag in ${tags} + do + docker rmi ${tag} + done +fi + +#删除空镜像 +cid=$(docker images | grep "none" | awk '{print $3}') +if [ -n "$cid" ] + then + docker rmi ${cid} +fi + +#编译代码 +dotnet publish -r linux-x64 -f net7.0 -o ./publish --self-contained false + +if [ $? -ne 0 ] + then + echo "compilation fails" + exit 1 +fi +#生成镜像 +docker build -t ${_imageName}:${_tag} . +if [ $? -ne 0 ] + then + echo "docker build fails" + exit 1 +fi + +##启动镜像 +echo '=====================run container===================' +docker run -p 5000:5000 \ +-v /data/magic-service/logs:/app/Logs \ +--restart=always \ +--name ${_imageName} -d ${_imageName}:${_tag} diff --git a/Magic.Web.Entry/templates/~0db08c10b01555b1d888f11248a2cc64.dll b/Magic.Web.Entry/templates/~0db08c10b01555b1d888f11248a2cc64.dll new file mode 100644 index 0000000..e5cb946 Binary files /dev/null and b/Magic.Web.Entry/templates/~0db08c10b01555b1d888f11248a2cc64.dll differ diff --git a/Magic.Web.Entry/templates/~159c422bcf43edda31a9bd75256b79f1.dll b/Magic.Web.Entry/templates/~159c422bcf43edda31a9bd75256b79f1.dll new file mode 100644 index 0000000..304b581 Binary files /dev/null and b/Magic.Web.Entry/templates/~159c422bcf43edda31a9bd75256b79f1.dll differ diff --git a/Magic.Web.Entry/templates/~19108359356e5efe42dcdf645a2eebfc.dll b/Magic.Web.Entry/templates/~19108359356e5efe42dcdf645a2eebfc.dll new file mode 100644 index 0000000..2dfb581 Binary files /dev/null and b/Magic.Web.Entry/templates/~19108359356e5efe42dcdf645a2eebfc.dll differ diff --git a/Magic.Web.Entry/templates/~2651e0999c391a0b5aba580191e2d6c6.dll b/Magic.Web.Entry/templates/~2651e0999c391a0b5aba580191e2d6c6.dll new file mode 100644 index 0000000..882a19d Binary files /dev/null and b/Magic.Web.Entry/templates/~2651e0999c391a0b5aba580191e2d6c6.dll differ diff --git a/Magic.Web.Entry/templates/~4a6ee469d4d39086077630dd2bed9f1e.dll b/Magic.Web.Entry/templates/~4a6ee469d4d39086077630dd2bed9f1e.dll new file mode 100644 index 0000000..57fd1c2 Binary files /dev/null and b/Magic.Web.Entry/templates/~4a6ee469d4d39086077630dd2bed9f1e.dll differ diff --git a/Magic.Web.Entry/templates/~59a6eeb9747854ce8e0b0de6194ab0fa.dll b/Magic.Web.Entry/templates/~59a6eeb9747854ce8e0b0de6194ab0fa.dll new file mode 100644 index 0000000..e578f51 Binary files /dev/null and b/Magic.Web.Entry/templates/~59a6eeb9747854ce8e0b0de6194ab0fa.dll differ diff --git a/Magic.Web.Entry/templates/~5d908a873d5ce8cd99e004db7bfaaf6c.dll b/Magic.Web.Entry/templates/~5d908a873d5ce8cd99e004db7bfaaf6c.dll new file mode 100644 index 0000000..0979270 Binary files /dev/null and b/Magic.Web.Entry/templates/~5d908a873d5ce8cd99e004db7bfaaf6c.dll differ diff --git a/Magic.Web.Entry/templates/~9e972f810c110f86c9fe70c0e0a4c1fc.dll b/Magic.Web.Entry/templates/~9e972f810c110f86c9fe70c0e0a4c1fc.dll new file mode 100644 index 0000000..ceb321d Binary files /dev/null and b/Magic.Web.Entry/templates/~9e972f810c110f86c9fe70c0e0a4c1fc.dll differ diff --git a/Magic.Web.Entry/templates/~bc7b58f116bac34d7af4bef34a87f620.dll b/Magic.Web.Entry/templates/~bc7b58f116bac34d7af4bef34a87f620.dll new file mode 100644 index 0000000..edbfdb6 Binary files /dev/null and b/Magic.Web.Entry/templates/~bc7b58f116bac34d7af4bef34a87f620.dll differ diff --git a/Magic.Web.Entry/templates/~c55ba40db5a21a311a7ab81fad6917a9.dll b/Magic.Web.Entry/templates/~c55ba40db5a21a311a7ab81fad6917a9.dll new file mode 100644 index 0000000..95af411 Binary files /dev/null and b/Magic.Web.Entry/templates/~c55ba40db5a21a311a7ab81fad6917a9.dll differ diff --git a/Magic.Web.Entry/templates/~dd0b7d0d8022b1fbe3eae0c827b159cf.dll b/Magic.Web.Entry/templates/~dd0b7d0d8022b1fbe3eae0c827b159cf.dll new file mode 100644 index 0000000..07b54d0 Binary files /dev/null and b/Magic.Web.Entry/templates/~dd0b7d0d8022b1fbe3eae0c827b159cf.dll differ diff --git a/Magic.Web.Entry/templates/~f322dcae78db006b53da5f26e21dba3b.dll b/Magic.Web.Entry/templates/~f322dcae78db006b53da5f26e21dba3b.dll new file mode 100644 index 0000000..41d6e6b Binary files /dev/null and b/Magic.Web.Entry/templates/~f322dcae78db006b53da5f26e21dba3b.dll differ diff --git a/Magic.Web.Entry/templates/~faa2e001498506525726c745a81c3bef.dll b/Magic.Web.Entry/templates/~faa2e001498506525726c745a81c3bef.dll new file mode 100644 index 0000000..03213fc Binary files /dev/null and b/Magic.Web.Entry/templates/~faa2e001498506525726c745a81c3bef.dll differ diff --git a/Magic.Web.Entry/templates/~fb1a575125f1424c84f5d49478aad029.dll b/Magic.Web.Entry/templates/~fb1a575125f1424c84f5d49478aad029.dll new file mode 100644 index 0000000..49ddf08 Binary files /dev/null and b/Magic.Web.Entry/templates/~fb1a575125f1424c84f5d49478aad029.dll differ diff --git a/Magic.Web.Entry/templates/~fe0c69bed93ec0b64ba42ef010e76497.dll b/Magic.Web.Entry/templates/~fe0c69bed93ec0b64ba42ef010e76497.dll new file mode 100644 index 0000000..9681a0a Binary files /dev/null and b/Magic.Web.Entry/templates/~fe0c69bed93ec0b64ba42ef010e76497.dll differ diff --git a/Magic.Web.Entry/wwwroot/Captcha/Font/zkkht.ttf b/Magic.Web.Entry/wwwroot/Captcha/Font/zkkht.ttf new file mode 100644 index 0000000..8d2a1d7 Binary files /dev/null and b/Magic.Web.Entry/wwwroot/Captcha/Font/zkkht.ttf differ diff --git a/Magic.Web.Entry/wwwroot/Captcha/Image/1.jpg b/Magic.Web.Entry/wwwroot/Captcha/Image/1.jpg new file mode 100644 index 0000000..e77f91e Binary files /dev/null and b/Magic.Web.Entry/wwwroot/Captcha/Image/1.jpg differ diff --git a/Magic.Web.Entry/wwwroot/Captcha/Image/2.jpg b/Magic.Web.Entry/wwwroot/Captcha/Image/2.jpg new file mode 100644 index 0000000..f5c9116 Binary files /dev/null and b/Magic.Web.Entry/wwwroot/Captcha/Image/2.jpg differ diff --git a/Magic.Web.Entry/wwwroot/Captcha/Image/3.jpg b/Magic.Web.Entry/wwwroot/Captcha/Image/3.jpg new file mode 100644 index 0000000..851c312 Binary files /dev/null and b/Magic.Web.Entry/wwwroot/Captcha/Image/3.jpg differ diff --git a/Magic.Web.Entry/wwwroot/Captcha/Image/4.jpg b/Magic.Web.Entry/wwwroot/Captcha/Image/4.jpg new file mode 100644 index 0000000..688e74f Binary files /dev/null and b/Magic.Web.Entry/wwwroot/Captcha/Image/4.jpg differ diff --git a/Magic.Web.Entry/wwwroot/Captcha/Image/5.jpg b/Magic.Web.Entry/wwwroot/Captcha/Image/5.jpg new file mode 100644 index 0000000..07bbdbd Binary files /dev/null and b/Magic.Web.Entry/wwwroot/Captcha/Image/5.jpg differ diff --git a/Magic.Web.Entry/wwwroot/Captcha/Image/6.jpg b/Magic.Web.Entry/wwwroot/Captcha/Image/6.jpg new file mode 100644 index 0000000..1acf701 Binary files /dev/null and b/Magic.Web.Entry/wwwroot/Captcha/Image/6.jpg differ diff --git a/Magic.Web.Entry/wwwroot/Captcha/Image/7.jpg b/Magic.Web.Entry/wwwroot/Captcha/Image/7.jpg new file mode 100644 index 0000000..9906864 Binary files /dev/null and b/Magic.Web.Entry/wwwroot/Captcha/Image/7.jpg differ diff --git a/Magic.Web.Entry/wwwroot/Captcha/Image/8.jpg b/Magic.Web.Entry/wwwroot/Captcha/Image/8.jpg new file mode 100644 index 0000000..def81ae Binary files /dev/null and b/Magic.Web.Entry/wwwroot/Captcha/Image/8.jpg differ diff --git a/Magic.Web.Entry/wwwroot/Template/Dto.cs.vm b/Magic.Web.Entry/wwwroot/Template/Dto.cs.vm new file mode 100644 index 0000000..8f705cd --- /dev/null +++ b/Magic.Web.Entry/wwwroot/Template/Dto.cs.vm @@ -0,0 +1,28 @@ +using System; +using Magic.Core; + +namespace @Model.NameSpace +{ + /// + /// @(@Model.BusName)输出参数 + /// + public class @(@Model.ClassName)Dto + { +@foreach (var column in Model.TableField){ +if(@column.EffectType == "fk" && @column.FkEntityName != "" && @column.FkColumnName != ""){ + @:/// + @:/// @column.ColumnComment + @:/// + @:public @(@column.FkColumnNetType) @(@column.FkEntityName)@(@column.FkColumnName) { get; set; } + @: +} +} +@foreach (var column in Model.TableField){ + @:/// + @:/// @column.ColumnComment + @:/// + @:public @column.NetType @column.ColumnName { get; set; } + @: +} + } +} diff --git a/Magic.Web.Entry/wwwroot/Template/Entity.cs.vm b/Magic.Web.Entry/wwwroot/Template/Entity.cs.vm new file mode 100644 index 0000000..98cadcd --- /dev/null +++ b/Magic.Web.Entry/wwwroot/Template/Entity.cs.vm @@ -0,0 +1,43 @@ +using System; +using SqlSugar; +using System.ComponentModel; +using Magic.Core.Entity; +namespace Magic.Application.Entity +{ + /// + /// @(@Model.Description) + /// + [SugarTable("@(@Model.TableName)")] + [Description("@(@Model.Description)")] + public class @(@Model.EntityName) @Model.BaseClassName + { + @foreach (var column in Model.TableField){ + if(@Model.BaseClassName=="" && @column.IsPrimarykey){ + @:/// + @:/// @column.ColumnDescription + @:/// + @:[SugarColumn(IsIdentity = @column.IsIdentity.ToString().ToLower(), ColumnDescription = "@column.ColumnDescription", IsPrimaryKey = true)] + @:public @column.DataType @column.DbColumnName { get; set; } + } + else if(@Model.BaseClassName=="" && !@column.IsPrimarykey){ + @:/// + @:/// @column.ColumnDescription + @:/// + @:public @column.DataType @column.DbColumnName { get; set; } + } + else if(@Model.BaseClassName!="" && @column.IsPrimarykey && @column.DbColumnName.ToLower()!="id"){ + @:/// + @:/// @column.ColumnDescription + @:/// + @:[SugarColumn(IsIdentity = @column.IsIdentity.ToString().ToLower(), ColumnDescription = "@column.ColumnDescription", IsPrimaryKey = true)] + @:public @column.DataType @column.DbColumnName { get; set; } + } + else if(@Model.BaseClassName!="" && !@column.IsPrimarykey && @column.DbColumnName.ToLower()!="id"){ + @:/// + @:/// @column.ColumnDescription + @:/// + @:public @column.DataType @column.DbColumnName { get; set; } + } + } + } +} \ No newline at end of file diff --git a/Magic.Web.Entry/wwwroot/Template/IService.cs.vm b/Magic.Web.Entry/wwwroot/Template/IService.cs.vm new file mode 100644 index 0000000..63b0caa --- /dev/null +++ b/Magic.Web.Entry/wwwroot/Template/IService.cs.vm @@ -0,0 +1,16 @@ +using Magic.Core; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Magic.Application.Entity; +namespace @Model.NameSpace +{ + public interface I@(@Model.ClassName)Service + { + Task Add(Add@(@Model.ClassName)Input input); + Task Delete(Delete@(@Model.ClassName)Input input); + Task<@(@Model.ClassName)> Get([FromQuery] Querye@(@Model.ClassName)Input input); + Task List([FromQuery] @(@Model.ClassName)Input input); + Task Page([FromQuery] @(@Model.ClassName)Input input); + Task Update(Update@(@Model.ClassName)Input input); + } +} \ No newline at end of file diff --git a/Magic.Web.Entry/wwwroot/Template/Input.cs.vm b/Magic.Web.Entry/wwwroot/Template/Input.cs.vm new file mode 100644 index 0000000..e323180 --- /dev/null +++ b/Magic.Web.Entry/wwwroot/Template/Input.cs.vm @@ -0,0 +1,69 @@ +using Magic.Core; +using System; +using System.ComponentModel.DataAnnotations; + +namespace @Model.NameSpace +{ + /// + /// @(@Model.BusName)输入参数 + /// + public class @(@Model.ClassName)Input : PageInputBase + { +@foreach (var column in Model.TableField){ +if (@column.ColumnKey != "True"){ + @:/// + @:/// @column.ColumnComment + @:/// + @:public virtual @column.NetType @column.ColumnName { get; set; } + @: +} +} + } + + public class Add@(@Model.ClassName)Input : @(@Model.ClassName)Input + { +@foreach (var column in Model.TableField){ +if (@column.WhetherRequired == "Y"){ + @:/// + @:/// @column.ColumnComment + @:/// + @:[Required(ErrorMessage = "@(@column.ColumnComment)不能为空")] + @:public override @column.NetType @column.ColumnName { get; set; } + @: +} +} + } + + public class Delete@(@Model.ClassName)Input + { +@foreach (var column in Model.TableField){ +if (@column.ColumnKey == "True"){ + @:/// + @:/// @column.ColumnComment + @:/// + @:[Required(ErrorMessage = "@(@column.ColumnComment)不能为空")] + @:public @column.NetType @column.ColumnName { get; set; } + @: +} +} + } + + public class Update@(@Model.ClassName)Input : @(@Model.ClassName)Input + { +@foreach (var column in Model.TableField){ +if (@column.ColumnKey == "True"){ + @:/// + @:/// @column.ColumnComment + @:/// + @:[Required(ErrorMessage = "@(@column.ColumnComment)不能为空")] + @:public @column.NetType @column.ColumnName { get; set; } + @: +} +} + } + + public class Querye@(@Model.ClassName)Input : Delete@(@Model.ClassName)Input + { + + } +} diff --git a/Magic.Web.Entry/wwwroot/Template/Manage.js.vm b/Magic.Web.Entry/wwwroot/Template/Manage.js.vm new file mode 100644 index 0000000..80fbeca --- /dev/null +++ b/Magic.Web.Entry/wwwroot/Template/Manage.js.vm @@ -0,0 +1,81 @@ +import { axios } from '@@/utils/request' + +/** + * 查询@(@Model.BusName) + * + * @@author @Model.AuthorName + */ +export function @(@Model.ClassName)Page (parameter) { + return axios({ + url: '/@Model.ClassName/page', + method: 'get', + params: parameter + }) +} + +/** + * @(@Model.BusName)列表 + * + * @@author @Model.AuthorName + */ +export function @(@Model.ClassName)List (parameter) { + return axios({ + url: '/@Model.ClassName/list', + method: 'get', + params: parameter + }) +} + +/** + * 添加@(@Model.BusName) + * + * @@author @Model.AuthorName + */ +export function @(@Model.ClassName)Add (parameter) { + return axios({ + url: '/@Model.ClassName/add', + method: 'post', + data: parameter + }) +} + +/** + * 编辑@(@Model.BusName) + * + * @@author @Model.AuthorName + */ +export function @(@Model.ClassName)Edit (parameter) { + return axios({ + url: '/@Model.ClassName/edit', + method: 'post', + data: parameter + }) +} + +/** + * 删除@(@Model.BusName) + * + * @@author @Model.AuthorName + */ +export function @(@Model.ClassName)Delete (parameter) { + return axios({ + url: '/@Model.ClassName/delete', + method: 'post', + data: parameter + }) +} +@foreach (var column in Model.TableField){ +if(@column.EffectType == "fk" && @column.FkEntityName != "" && @column.FkColumnName != ""){ +@: +@:/** +@:* 获取@(@column.FkEntityName)列表 +@:* @@author @Model.AuthorName +@:*/ +@:export function @(@Model.ClassName)Fk@(@column.FkEntityName)List() { +@: return axios({ +@: url: '/@Model.ClassName/fk@(@column.FkEntityName)', +@: method: 'get' +@: }) +@:} +} +} diff --git a/Magic.Web.Entry/wwwroot/Template/Output.cs.vm b/Magic.Web.Entry/wwwroot/Template/Output.cs.vm new file mode 100644 index 0000000..6a1d40b --- /dev/null +++ b/Magic.Web.Entry/wwwroot/Template/Output.cs.vm @@ -0,0 +1,18 @@ +using System; + +namespace @Model.NameSpace +{ + /// + /// @(@Model.BusName)输出参数 + /// + public class @(@Model.ClassName)Output + { +@foreach (var column in Model.TableField){ + @:/// + @:/// @column.ColumnComment + @:/// + @:public @column.NetType @column.ColumnName { get; set; } + @: +} + } +} diff --git a/Magic.Web.Entry/wwwroot/Template/Service.cs.vm b/Magic.Web.Entry/wwwroot/Template/Service.cs.vm new file mode 100644 index 0000000..032b48e --- /dev/null +++ b/Magic.Web.Entry/wwwroot/Template/Service.cs.vm @@ -0,0 +1,115 @@ +using Magic.Core; +using Furion.DependencyInjection; +using Furion.DynamicApiController; +using Mapster; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using System.Linq; +using System.Threading.Tasks; +using Magic.Application.Entity; +namespace @Model.NameSpace +{ + /// + /// @(@Model.BusName)服务 + /// + [ApiDescriptionSettings("Application",Name = "@Model.ClassName", Order = 1)] + public class @(@Model.ClassName)Service : I@(@Model.ClassName)Service, IDynamicApiController, ITransient + { + private readonly SqlSugarRepository<@(@Model.ClassName)> _rep; + + public @(@Model.ClassName)Service(SqlSugarRepository<@(@Model.ClassName)> rep) + { + _rep = rep; + } + + /// + /// 分页查询@(@Model.BusName) + /// + /// + /// + [HttpGet("/@Model.ClassName/page")] + public async Task Page([FromQuery] @(@Model.ClassName)Input input) + { + var entities = await _rep.AsQueryable() +@foreach (var column in Model.TableField){ +if (@column.QueryWhether == "Y"){ +if (@column.NetType == "string"){ +if(@column.QueryType == "like"){ + @:.WhereIF(!string.IsNullOrWhiteSpace(input.@column.ColumnName), u => u.@(@column.ColumnName).Contains(input.@(@column.ColumnName).Trim())) +}else{ + @:.WhereIF(!string.IsNullOrWhiteSpace(input.@column.ColumnName), u => u.@(@column.ColumnName) @column.QueryType input.@(@column.ColumnName)) +} +} +} +} + .ToPagedListAsync(input.PageNo, input.PageSize); + return entities.XnPagedResult(); + } + + /// + /// 增加@(@Model.BusName) + /// + /// + /// + [HttpPost("/@Model.ClassName/add")] + public async Task Add(Add@(@Model.ClassName)Input input) + { + var entity = input.Adapt<@(@Model.ClassName)>(); + await _rep.InsertAsync(entity); + } + + /// + /// 删除@(@Model.BusName) + /// + /// + /// + [HttpPost("/@Model.ClassName/delete")] + public async Task Delete(Delete@(@Model.ClassName)Input input) + { +@foreach (var column in Model.TableField){ +if (@column.ColumnKey == "True"){ + @:var entity = await _rep.FirstOrDefaultAsync(u => u.@(@column.ColumnName) == input.@(@column.ColumnName)); +} +} + await _rep.DeleteAsync(entity); + } + + /// + /// 更新@(@Model.BusName) + /// + /// + /// + [HttpPost("/@Model.ClassName/edit")] + public async Task Update(Update@(@Model.ClassName)Input input) + { + var entity = input.Adapt<@(@Model.ClassName)>(); + await _rep.AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns:true).ExecuteCommandAsync(); + } + + /// + /// 获取@(@Model.BusName) + /// + /// + /// + [HttpGet("/@Model.ClassName/detail")] + public async Task<@(@Model.ClassName)> Get([FromQuery] Querye@(@Model.ClassName)Input input) + { +@foreach (var column in Model.TableField){ +if (@column.ColumnKey == "True"){ + @:return await _rep.FirstOrDefaultAsync(u => u.@(@column.ColumnName) == input.@(@column.ColumnName)); +} +} + } + + /// + /// 获取@(@Model.BusName)列表 + /// + /// + /// + [HttpGet("/@Model.ClassName/list")] + public async Task List([FromQuery] @(@Model.ClassName)Input input) + { + return await _rep.ToListAsync(); + } + } +} diff --git a/Magic.Web.Entry/wwwroot/Template/addForm.vue.vm b/Magic.Web.Entry/wwwroot/Template/addForm.vue.vm new file mode 100644 index 0000000..57fdf8d --- /dev/null +++ b/Magic.Web.Entry/wwwroot/Template/addForm.vue.vm @@ -0,0 +1,243 @@ + + + diff --git a/Magic.Web.Entry/wwwroot/Template/editForm.vue.vm b/Magic.Web.Entry/wwwroot/Template/editForm.vue.vm new file mode 100644 index 0000000..2902061 --- /dev/null +++ b/Magic.Web.Entry/wwwroot/Template/editForm.vue.vm @@ -0,0 +1,305 @@ + + + diff --git a/Magic.Web.Entry/wwwroot/Template/index.vue.vm b/Magic.Web.Entry/wwwroot/Template/index.vue.vm new file mode 100644 index 0000000..6e2fb01 --- /dev/null +++ b/Magic.Web.Entry/wwwroot/Template/index.vue.vm @@ -0,0 +1,333 @@ + + + diff --git a/Magic.Web.Entry/wwwroot/Upload/Avatar/167456009080901.png b/Magic.Web.Entry/wwwroot/Upload/Avatar/167456009080901.png new file mode 100644 index 0000000..fe6060f Binary files /dev/null and b/Magic.Web.Entry/wwwroot/Upload/Avatar/167456009080901.png differ diff --git a/Magic.Web.Entry/wwwroot/Upload/Avatar/167456254419013.png b/Magic.Web.Entry/wwwroot/Upload/Avatar/167456254419013.png new file mode 100644 index 0000000..979a692 Binary files /dev/null and b/Magic.Web.Entry/wwwroot/Upload/Avatar/167456254419013.png differ diff --git a/Magic.Web.Entry/wwwroot/Upload/Avatar/175614800654405.jpeg b/Magic.Web.Entry/wwwroot/Upload/Avatar/175614800654405.jpeg new file mode 100644 index 0000000..ab13ef2 Binary files /dev/null and b/Magic.Web.Entry/wwwroot/Upload/Avatar/175614800654405.jpeg differ diff --git a/Magic.Web.Entry/wwwroot/Upload/Avatar/188632919339077.png b/Magic.Web.Entry/wwwroot/Upload/Avatar/188632919339077.png new file mode 100644 index 0000000..668794d Binary files /dev/null and b/Magic.Web.Entry/wwwroot/Upload/Avatar/188632919339077.png differ diff --git a/Magic.Web.Entry/wwwroot/Upload/Avatar/263006401138757.jpg b/Magic.Web.Entry/wwwroot/Upload/Avatar/263006401138757.jpg new file mode 100644 index 0000000..51598bc Binary files /dev/null and b/Magic.Web.Entry/wwwroot/Upload/Avatar/263006401138757.jpg differ diff --git a/Magic.Web.Entry/wwwroot/Upload/Document/2022/4/27/282067842687045.png b/Magic.Web.Entry/wwwroot/Upload/Document/2022/4/27/282067842687045.png new file mode 100644 index 0000000..5a014a8 Binary files /dev/null and b/Magic.Web.Entry/wwwroot/Upload/Document/2022/4/27/282067842687045.png differ diff --git a/Magic.Web.Entry/wwwroot/Upload/Document/2022/4/27/282118658961477.png b/Magic.Web.Entry/wwwroot/Upload/Document/2022/4/27/282118658961477.png new file mode 100644 index 0000000..5a014a8 Binary files /dev/null and b/Magic.Web.Entry/wwwroot/Upload/Document/2022/4/27/282118658961477.png differ diff --git a/Magic.sln b/Magic.sln new file mode 100644 index 0000000..be696d4 --- /dev/null +++ b/Magic.sln @@ -0,0 +1,55 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.32112.339 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Magic.Web.Core", "Magic.Web.Core\Magic.Web.Core.csproj", "{9D14BB78-DA2A-4040-B9DB-5A515B599181}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Magic.Core", "Magic.Core\Magic.Core.csproj", "{4FB30091-15C7-4FD9-AB7D-266814F360F5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Magic.Web.Entry", "Magic.Web.Entry\Magic.Web.Entry.csproj", "{9826E365-EEE9-4721-A738-B02AB64D47E5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Magic.Application", "Magic.Application\Magic.Application.csproj", "{3B7EE94A-0620-43AD-8A01-18A7771FDEEA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Magic.FlowCenter", "Magic.FlowCenter\Magic.FlowCenter.csproj", "{79C7E074-1029-4E65-B8AB-8ED26B4426AF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Magic.CodeFirst", "Magic.CodeFirst\Magic.CodeFirst.csproj", "{E75A7323-4369-4EC5-A8BE-5E127C0AC38E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9D14BB78-DA2A-4040-B9DB-5A515B599181}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9D14BB78-DA2A-4040-B9DB-5A515B599181}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9D14BB78-DA2A-4040-B9DB-5A515B599181}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9D14BB78-DA2A-4040-B9DB-5A515B599181}.Release|Any CPU.Build.0 = Release|Any CPU + {4FB30091-15C7-4FD9-AB7D-266814F360F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4FB30091-15C7-4FD9-AB7D-266814F360F5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4FB30091-15C7-4FD9-AB7D-266814F360F5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4FB30091-15C7-4FD9-AB7D-266814F360F5}.Release|Any CPU.Build.0 = Release|Any CPU + {9826E365-EEE9-4721-A738-B02AB64D47E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9826E365-EEE9-4721-A738-B02AB64D47E5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9826E365-EEE9-4721-A738-B02AB64D47E5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9826E365-EEE9-4721-A738-B02AB64D47E5}.Release|Any CPU.Build.0 = Release|Any CPU + {3B7EE94A-0620-43AD-8A01-18A7771FDEEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3B7EE94A-0620-43AD-8A01-18A7771FDEEA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3B7EE94A-0620-43AD-8A01-18A7771FDEEA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3B7EE94A-0620-43AD-8A01-18A7771FDEEA}.Release|Any CPU.Build.0 = Release|Any CPU + {79C7E074-1029-4E65-B8AB-8ED26B4426AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {79C7E074-1029-4E65-B8AB-8ED26B4426AF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {79C7E074-1029-4E65-B8AB-8ED26B4426AF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {79C7E074-1029-4E65-B8AB-8ED26B4426AF}.Release|Any CPU.Build.0 = Release|Any CPU + {E75A7323-4369-4EC5-A8BE-5E127C0AC38E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E75A7323-4369-4EC5-A8BE-5E127C0AC38E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E75A7323-4369-4EC5-A8BE-5E127C0AC38E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E75A7323-4369-4EC5-A8BE-5E127C0AC38E}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B2073C2C-0FD3-452B-8047-8134D68E12CE} + EndGlobalSection +EndGlobal