添加项目文件。

This commit is contained in:
fuenmao
2025-09-29 13:48:36 +08:00
parent f61e922f0c
commit 5dc1780ef1
407 changed files with 63703 additions and 0 deletions
@@ -0,0 +1,32 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 前端表格特性
/// </summary>
public class AntTableAttribute : Attribute
{
/// <summary>
/// 是否是日期格式
/// </summary>
public bool IsDate { get; set; }
/// <summary>
/// 是否自动省略
/// </summary>
public bool Ellipsis { get; set; } = false;
/// <summary>
/// 宽度
/// </summary>
public int Width { get; set; } = 100;
}
@@ -0,0 +1,18 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 批量更新
/// </summary>
public class BatchEditAttribute : Attribute
{
}
@@ -0,0 +1,65 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 验证值是否在字典中,大数据慎用
/// </summary>
public class InDictAttribute : ValidationAttribute
{
public InDictAttribute(string dictValue)
{
DictValue = dictValue;
}
/// <summary>
/// 字典值
/// </summary>
public string DictValue { get; set; }
/// <summary>
/// 获取错误信息
/// </summary>
/// <param name="value">值</param>
/// <returns></returns>
public string GetErrorMessage(string value)
{
if (string.IsNullOrEmpty(ErrorMessage))
{
switch (DictValue)
{
case SysDictConst.GENDER:
return "性别只能是男和女";
case SysDictConst.NATION:
return "不存在的民族";
default:
return $"字典中不存在{value}";
}
}
return ErrorMessage;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (value != null)
{
var dictService = App.GetService<IDictService>();
var values = dictService.GetValuesByDictValue(DictValue).Result;
if (!values.Contains(value))
{
return new ValidationResult(GetErrorMessage(value.ToString()), new[] { validationContext.MemberName });
}
}
return ValidationResult.Success;
}
}
+266
View File
@@ -0,0 +1,266 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 分类常量
/// </summary>
public class CateGoryConst
{
#region 系统配置
/// <summary>
/// 系统基础
/// </summary>
public const string CONFIG_SYS_BASE = "SYS_BASE";
/// <summary>
/// 登录策略
/// </summary>
public const string CONFIG_LOGIN_POLICY = "LOGIN_POLICY";
/// <summary>
/// 密码策略
/// </summary>
public const string CONFIG_PWD_POLICY = "PWD_POLICY";
/// <summary>
/// 业务定义
/// </summary>
public const string CONFIG_BIZ_DEFINE = "BIZ_DEFINE";
/// <summary>
/// 文件-本地
/// </summary>
public const string CONFIG_FILE_LOCAL = "FILE_LOCAL";
/// <summary>
/// 文件-MINIO
/// </summary>
public const string CONFIG_FILE_MINIO = "FILE_MINIO";
#endregion 系统配置
#region Mqtt配置
/// <summary>
/// MQTT配置
/// </summary>
public const string CONFIG_MQTT_BASE = "MQTT_BASE";
#endregion Mqtt配置
#region 关系表
/// <summary>
/// 用户有哪些角色
/// </summary>
public const string RELATION_SYS_USER_HAS_ROLE = "SYS_USER_HAS_ROLE";
/// <summary>
/// 角色有哪些资源
/// </summary>
public const string RELATION_SYS_ROLE_HAS_RESOURCE = "SYS_ROLE_HAS_RESOURCE";
/// <summary>
/// 角色有哪些模块
/// </summary>
public const string RELATION_SYS_ROLE_HAS_MODULE = "SYS_ROLE_HAS_MODULE";
/// <summary>
/// 用户有哪些模块
/// </summary>
public const string RELATION_SYS_USER_HAS_MODULE = "SYS_USER_HAS_MODULE";
/// <summary>
///用户有哪些资源
/// </summary>
public const string RELATION_SYS_USER_HAS_RESOURCE = "SYS_USER_HAS_RESOURCE";
/// <summary>
/// 角色有哪些权限
/// </summary>
public const string RELATION_SYS_ROLE_HAS_PERMISSION = "SYS_ROLE_HAS_PERMISSION";
/// <summary>
/// 用户有哪些权限
/// </summary>
public const string RELATION_SYS_USER_HAS_PERMISSION = "SYS_USER_HAS_PERMISSION";
/// <summary>
/// 用户工作台数据
/// </summary>
public const string RELATION_SYS_USER_WORKBENCH_DATA = "SYS_USER_WORKBENCH_DATA";
/// <summary>
/// 用户日程数据
/// </summary>
public const string RELATION_SYS_USER_SCHEDULE_DATA = "SYS_USER_SCHEDULE_DATA";
/// <summary>
/// 站内信与接收用户
/// </summary>
public const string RELATION_MSG_TO_USER = "MSG_TO_USER";
#endregion 关系表
#region 数据范围
/// <summary>
/// 本人
/// </summary>
public const string SCOPE_SELF = "SCOPE_SELF";
/// <summary>
/// 所有
/// </summary>
public const string SCOPE_ALL = "SCOPE_ALL";
/// <summary>
/// 仅所属组织
/// </summary>
public const string SCOPE_ORG = "SCOPE_ORG";
/// <summary>
/// 所属组织及以下
/// </summary>
public const string SCOPE_ORG_CHILD = "SCOPE_ORG_CHILD";
/// <summary>
/// 自定义
/// </summary>
public const string SCOPE_ORG_DEFINE = "SCOPE_ORG_DEFINE";
#endregion 数据范围
#region 资源表
/// <summary>
/// 模块
/// </summary>
public const string RESOURCE_MODULE = "MODULE";
/// <summary>
/// 菜单
/// </summary>
public const string RESOURCE_MENU = "MENU";
/// <summary>
/// 单页
/// </summary>
public const string RESOURCE_SPA = "SPA";
/// <summary>
/// 按钮
/// </summary>
public const string RESOURCE_BUTTON = "BUTTON";
#endregion 资源表
#region 日志表
/// <summary>
/// 登录
/// </summary>
public const string LOG_LOGIN = "LOGIN";
/// <summary>
/// 登出
/// </summary>
public const string LOG_LOGOUT = "LOGOUT";
/// <summary>
/// 操作
/// </summary>
public const string LOG_OPERATE = "OPERATE";
/// <summary>
/// 异常
/// </summary>
public const string LOG_EXCEPTION = "EXCEPTION";
#endregion 日志表
#region 字典表
/// <summary>
/// 框架
/// </summary>
public const string DICT_FRM = "FRM";
/// <summary>
/// 业务
/// </summary>
public const string DICT_BIZ = "BIZ";
#endregion 字典表
#region 组织表
/// <summary>
/// 部门
/// </summary>
public const string ORG_DEPT = "DEPT";
/// <summary>
/// 公司
/// </summary>
public const string ORG_COMPANY = "COMPANY";
#endregion 组织表
#region 职位表
/// <summary>
/// 高层
/// </summary>
public const string POSITION_HIGH = "HIGH";
/// <summary>
/// 中层
/// </summary>
public const string POSITION_MIDDLE = "MIDDLE";
/// <summary>
/// 基层
/// </summary>
public const string POSITION_LOW = "LOW";
#endregion 职位表
#region 角色表
/// <summary>
/// 全局
/// </summary>
public const string ROLE_GLOBAL = "GLOBAL";
/// <summary>
/// 机构
/// </summary>
public const string ROLE_ORG = "ORG";
#endregion 角色表
#region 站内信表
/// <summary>
/// 通知
/// </summary>
public const string MESSAGE_INFORM = "INFORM";
/// <summary>
/// 公告
/// </summary>
public const string MESSAGE_NOTICE = "NOTICE";
#endregion 站内信表
}
+53
View File
@@ -0,0 +1,53 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
public class GenConst
{
#region 是否
/// <summary>
/// 是
/// </summary>
public const string Yes = "Y";
/// <summary>
/// 否
/// </summary>
public const string No = "N";
#endregion 是否
/// <summary>
/// 压缩包
/// </summary>
public const string Zip = "ZIP";
/// <summary>
/// 项目中
/// </summary>
public const string Pro = "PRO";
/// <summary>
/// 全部
/// </summary>
public const string ExecAll = "ALL";
/// <summary>
/// 前端
/// </summary>
public const string ExecFrontend = "FRONTEND";
/// <summary>
/// 后端
/// </summary>
public const string ExecBackend = "BACKEND";
}
+200
View File
@@ -0,0 +1,200 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 系统配置常量
/// </summary>
public class SysConfigConst
{
#region MyRegion
/// <summary>
/// 系统名称
/// </summary>
public const string SYS_NAME = "SYS_NAME";
/// <summary>
/// ico图标
/// </summary>
public const string SYS_ICO = "SYS_ICO";
/// <summary>
/// 网站开启访问
/// </summary>
public const string SYS_WEB_STATUS = "SYS_WEB_STATUS";
/// <summary>
/// 网站关闭提示
/// </summary>
public const string SYS_WEB_CLOSE_PROMPT = "SYS_WEB_CLOSE_PROMPT";
/// <summary>
/// 系统logo
/// </summary>
public const string SYS_LOGO = "SYS_LOGO";
/// <summary>
/// 系统版本
/// </summary>
public const string SYS_VERSION = "SYS_VERSION";
/// <summary>
/// 多租户开关
/// </summary>
public const string SYS_TENANT_OPTIONS = "SYS_TENANT_OPTIONS";
/// <summary>
/// 系统默认工作台
/// </summary>
public const string SYS_DEFAULT_WORKBENCH_DATA = "SYS_DEFAULT_WORKBENCH_DATA";
#endregion
#region 登录策略
/// <summary>
/// 登录验证码开关
/// </summary>
public const string LOGIN_CAPTCHA_OPEN = "LOGIN_CAPTCHA_OPEN";
/// <summary>
/// 登录验证码开关
/// </summary>
public const string LOGIN_CAPTCHA_TYPE = "LOGIN_CAPTCHA_TYPE";
/// <summary>
/// 单用户登录开关
/// </summary>
public const string LOGIN_SINGLE_OPEN = "LOGIN_SINGLE_OPEN";
/// <summary>
/// 登录错误锁定时长
/// </summary>
public const string LOGIN_ERROR_LOCK = "LOGIN_ERROR_LOCK";
/// <summary>
/// 登录错误锁定时长
/// </summary>
public const string LOGIN_ERROR_RESET_TIME = "LOGIN_ERROR_RESET_TIME";
/// <summary>
/// 登录错误次数
/// </summary>
public const string LOGIN_ERROR_COUNT = "LOGIN_ERROR_COUNT";
#endregion 登录策略
#region 密码策略
/// <summary>
/// 默认用户密码
/// </summary>
public const string PWD_DEFAULT_PASSWORD = "PWD_DEFAULT_PASSWORD";
/// <summary>
/// 密码定期提醒更新
/// </summary>
public const string PWD_REMIND = "PWD_REMIND";
/// <summary>
/// 密码定期提醒更新时间
/// </summary>
public const string PWD_REMIND_DAY = "PWD_REMIND_DAY";
/// <summary>
/// 修改初始密码提醒
/// </summary>
public const string PWD_UPDATE_DEFAULT = "PWD_UPDATE_DEFAULT";
/// <summary>
/// 密码最小长度
/// </summary>
public const string PWD_MIN_LENGTH = "PWD_MIN_LENGTH";
/// <summary>
/// 包含数字
/// </summary>
public const string PWD_CONTAIN_NUM = "PWD_CONTAIN_NUM";
/// <summary>
/// 包含小写字母
/// </summary>
public const string PWD_CONTAIN_LOWER = "PWD_CONTAIN_LOWER";
/// <summary>
/// 包含大写字母
/// </summary>
public const string PWD_CONTAIN_UPPER = "PWD_CONTAIN_UPPER";
/// <summary>
/// 包含特殊字符
/// </summary>
public const string PWD_CONTAIN_CHARACTER = "PWD_CONTAIN_UPPER";
#endregion 密码策略
#region 存储引擎
/// <summary>
/// windows系统本地目录
/// </summary>
public const string FILE_LOCAL_FOLDER_FOR_WINDOWS = "FILE_LOCAL_FOLDER_FOR_WINDOWS";
/// <summary>
/// Unix系统本地目录
/// </summary>
public const string FILE_LOCAL_FOLDER_FOR_UNIX = "FILE_LOCAL_FOLDER_FOR_UNIX";
/// <summary>
/// MINIO文件AccessKey
/// </summary>
public const string FILE_MINIO_ACCESS_KEY = "FILE_MINIO_ACCESS_KEY";
/// <summary>
/// MINIO文件SecretKey
/// </summary>
public const string FILE_MINIO_SECRET_KEY = "FILE_MINIO_SECRET_KEY";
/// <summary>
/// MINIO文件EndPoint
/// </summary>
public const string FILE_MINIO_END_POINT = "FILE_MINIO_END_POINT";
/// <summary>
/// MINIO文件默认存储桶
/// </summary>
public const string FILE_MINIO_DEFAULT_BUCKET_NAME = "FILE_MINIO_DEFAULT_BUCKET_NAME";
#endregion 存储引擎
#region MQTT
/// <summary>
/// mqtt连接地址
/// </summary>
public const string MQTT_PARAM_URL = "MQTT_PARAM_URL";
/// <summary>
/// mqtt连接用户名
/// </summary>
public const string MQTT_PARAM_USERNAME = "MQTT_PARAM_USERNAME";
/// <summary>
/// mqtt连接密码
/// </summary>
public const string MQTT_PARAM_PASSWORD = "MQTT_PARAM_PASSWORD";
#endregion
}
+166
View File
@@ -0,0 +1,166 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 字典常量
/// </summary>
public class SysDictConst
{
#region 系统字典
/// <summary>
/// 性别
/// </summary>
public const string GENDER = "GENDER";
/// <summary>
/// 名族
/// </summary>
public const string NATION = "NATION";
/// <summary>
/// 用户证件类型
/// </summary>
public const string ID_CARD_TYPE = "ID_CARD_TYPE";
/// <summary>
/// 通用文化程度
/// </summary>
public const string CULTURE_LEVEL = "CULTURE_LEVEL";
/// <summary>
/// 系统职位分类
/// </summary>
public const string POSITION_CATEGORY = "POSITION_CATEGORY";
#region 在线用户状态
/// <summary>
/// 在线
/// </summary>
public const string ONLINE_STATUS_ONLINE = "ONLINE";
/// <summary>
/// 离线
/// </summary>
public const string ONLINE_STATUS_OFFLINE = "OFFLINE";
#endregion 在线用户状态
#region 上传文件引擎
/// <summary>
/// 本地
/// </summary>
public const string FILE_ENGINE_LOCAL = "LOCAL";
/// <summary>
/// MINIO
/// </summary>
public const string FILE_ENGINE_MINIO = "MINIO";
#endregion 上传文件引擎
#region 系统字典分类
/// <summary>
/// 系统
/// </summary>
public const string DICT_CATEGORY_FRM = "FRM";
/// <summary>
/// 业务
/// </summary>
public const string DICT_CATEGORY_BIZ = "BIZ";
#endregion 系统字典分类
#region 多租户选项
/// <summary>
/// 关闭
/// </summary>
public const string TENANT_OPTIONS_CLOSE = "CLOSE";
/// <summary>
/// 手动选择
/// </summary>
public const string TENANT_OPTIONS_CHOSE = "CHOSE";
/// <summary>
/// 根据域名
/// </summary>
public const string TENANT_OPTIONS_DOMAIN = "DOMAIN";
#endregion
#region 站内信
/// <summary>
/// 消息分类
/// </summary>
public const string MESSAGE_CATEGORY = "MESSAGE_CATEGORY";
/// <summary>
/// 接受者类型
/// </summary>
public const string RECEIVER_TYPE = "RECEIVER_TYPE";
/// <summary>
/// 发送方式
/// </summary>
public const string MESSAGE_WAY = "MESSAGE_WAY";
/// <summary>
/// 立即发送
/// </summary>
public const string SEND_WAY_NOW = "NOW";
/// <summary>
/// 延迟发送
/// </summary>
public const string SEND_WAY_DELAY = "DELAY";
/// <summary>
/// 指定时间
/// </summary>
public const string SEND_WAY_SCHEDULE = "SCHEDULE";
/// <summary>
/// 待发送
/// </summary>
public const string MESSAGE_STATUS_READY = "READY";
/// <summary>
/// 已发送
/// </summary>
public const string MESSAGE_STATUS_ALREADY = "ALREADY";
/// <summary>
/// 所有
/// </summary>
public const string RECEIVER_TYPE_ALL = "ALL";
/// <summary>
/// 角色
/// </summary>
public const string RECEIVER_TYPE_ROLE = "ROLE";
/// <summary>
/// 指定
/// </summary>
public const string RECEIVER_TYPE_APPOINT = "APPOINT";
#endregion
#endregion 系统字典
}
+27
View File
@@ -0,0 +1,27 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 日志常量
/// </summary>
public class SysLogConst
{
/// <summary>
/// 成功
/// </summary>
public const string SUCCESS = "SUCCESS";
/// <summary>
/// 成功
/// </summary>
public const string FAIL = "FAIL";
}
@@ -0,0 +1,52 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 资源表常量
/// </summary>
public class SysResourceConst
{
/// <summary>
/// 目录
/// </summary>
public const string CATALOG = "CATALOG";
/// <summary>
/// 菜单
/// </summary>
public const string MENU = "MENU";
/// <summary>
/// 内链
/// </summary>
public const string IFRAME = "IFRAME";
/// <summary>
/// 子页
/// </summary>
public const string SUBSET = "SUBSET";
/// <summary>
/// 外链
/// </summary>
public const string LINK = "LINK";
/// <summary>
/// 单页
/// </summary>
public const string SPA = "SPA";
/// <summary>
/// 系统内置单页面编码
/// </summary>
public const string SYSTEM = "system";
}
+27
View File
@@ -0,0 +1,27 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 角色常量
/// </summary>
public class SysRoleConst
{
/// <summary>
/// 超级管理员
/// </summary>
public const string SUPER_ADMIN = "superAdmin";
/// <summary>
/// 业务管理员
/// </summary>
public const string BIZ_ADMIN = "bizAdmin";
}
+145
View File
@@ -0,0 +1,145 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 系统层常量
/// </summary>
public class SystemConst
{
/// <summary>
/// 系统配置表缓存Key
/// </summary>
public const string CACHE_DEV_CONFIG = CacheConst.CACHE_PREFIX_WEB + "SysConfig:";
/// <summary>
/// 登录验证码缓存Key
/// </summary>
public const string CACHE_CAPTCHA = CacheConst.CACHE_PREFIX_WEB + "Captcha:";
/// <summary>
/// 用户表缓存Key
/// </summary>
public const string CACHE_SYS_USER = CacheConst.CACHE_PREFIX_WEB + "SysUser";
/// <summary>
/// 用户头像缓存关系Key
/// </summary>
public const string CACHE_SYS_USER_AVATAR = CacheConst.CACHE_PREFIX_WEB + "SysUserAvatar";
/// <summary>
/// 用户手机号关系缓存Key
/// </summary>
public const string CACHE_SYS_USER_PHONE = CacheConst.CACHE_PREFIX_WEB + "SysUserPhone";
/// <summary>
/// 用户手机号关系缓存Key
/// </summary>
public const string CACHE_SYS_USER_ACCOUNT = CacheConst.CACHE_PREFIX_WEB + "SysUserAccount";
/// <summary>
/// 资源表缓存Key
/// </summary>
public const string CACHE_SYS_RESOURCE = CacheConst.CACHE_PREFIX_WEB + "SysResource:";
/// <summary>
/// 字典表缓存Key
/// </summary>
public const string CACHE_DEV_DICT = CacheConst.CACHE_PREFIX_WEB + "SysDict";
/// <summary>
/// 关系表缓存Key
/// </summary>
public const string CACHE_SYS_RELATION = CacheConst.CACHE_PREFIX_WEB + "SysRelation:";
/// <summary>
/// 机构表缓存Key
/// </summary>
public const string CACHE_SYS_ORG = CacheConst.CACHE_PREFIX_WEB + "SysOrg";
/// <summary>
/// 机构对应租户关系缓存Key
/// </summary>
public const string CACHE_SYS_ORG_TENANT = CacheConst.CACHE_PREFIX_WEB + "SysOrgTenant";
/// <summary>
/// 租户列表缓存
/// </summary>
public const string CACHE_SYS_TENANT = CacheConst.CACHE_PREFIX_WEB + "Tenant";
/// <summary>
/// 角色表缓存Key
/// </summary>
public const string CACHE_SYS_ROLE = CacheConst.CACHE_PREFIX_WEB + "SysRole";
/// <summary>
/// 职位表缓存Key
/// </summary>
public const string CACHE_SYS_POSITION = CacheConst.CACHE_PREFIX_WEB + "SysPosition";
#region 登录错误次数
/// <summary>
/// 登录错误次数缓存Key
/// </summary>
public const string CACHE_LOGIN_ERROR_COUNT = CacheConst.CACHE_PREFIX_WEB + "LoginErrorCount:";
#endregion 登录错误次数
#region 操作
/// <summary>
/// 添加操作
/// </summary>
public const string ADD = "添加";
/// <summary>
/// 编辑操作
/// </summary>
public const string EDIT = "编辑";
/// <summary>
/// 启用操作
/// </summary>
public const string ENABLE = "启用";
/// <summary>
/// 禁用操作
/// </summary>
public const string DISABLE = "禁用";
/// <summary>
/// 重置密码操作
/// </summary>
public const string RESET_PWD = "重置密码";
/// <summary>
/// 用户授权操作
/// </summary>
public const string GRANT_ROLE = "授权";
#endregion 操作
#region 别称
/// <summary>
/// 组织
/// </summary>
public const string SYS_ORG = "组织";
/// <summary>
/// 职位
/// </summary>
public const string SYS_POS = "职位";
#endregion 别称
}
+50
View File
@@ -0,0 +1,50 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 批量修改
///</summary>
[SugarTable("batch_edit", TableDescription = "批量修改")]
[Tenant(SqlSugarConst.DB_DEFAULT)]
[CodeGen]
public class BatchEdit : PrimaryKeyEntity
{
/// <summary>
/// 唯一编码
///</summary>
[SugarColumn(ColumnName = "Code", ColumnDescription = "唯一编码", Length = 100, IsNullable = false)]
public string Code { get; set; }
/// <summary>
/// 所属库
///</summary>
[SugarColumn(ColumnName = "ConfigId", ColumnDescription = "所属库", Length = 100, IsNullable = false)]
public string ConfigId { get; set; }
/// <summary>
/// 实体名
///</summary>
[SugarColumn(ColumnName = "EntityName", ColumnDescription = "实体名", Length = 100, IsNullable = false)]
public string EntityName { get; set; }
/// <summary>
/// 表名
///</summary>
[SugarColumn(ColumnName = "TableName", ColumnDescription = "表名", Length = 100, IsNullable = false)]
public string TableName { get; set; }
/// <summary>
/// 表描述
///</summary>
[SugarColumn(ColumnName = "TableDescription", ColumnDescription = "表描述", Length = 100, IsNullable = false)]
public string TableDescription { get; set; }
}
@@ -0,0 +1,85 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 批量修改配置表
///</summary>
[SugarTable("batch_edit_config", TableDescription = "批量修改配置表")]
[Tenant(SqlSugarConst.DB_DEFAULT)]
public class BatchEditConfig : PrimaryKeyEntity
{
/// <summary>
/// 批量配置Id
///</summary>
[SugarColumn(ColumnName = "UId", ColumnDescription = "批量配置Id", IsNullable = false)]
public long UId { get; set; }
/// <summary>
/// 字段名
///</summary>
[SugarColumn(ColumnName = "ColumnName", ColumnDescription = "字段名", Length = 100, IsNullable = false)]
public string ColumnName { get; set; }
/// <summary>
/// 字段描述
///</summary>
[SugarColumn(ColumnName = "ColumnComment", ColumnDescription = "字段描述", Length = 100, IsNullable = false)]
public string ColumnComment { get; set; }
/// <summary>
/// 作用类型
///</summary>
[SugarColumn(ColumnName = "DataType", ColumnDescription = "作用类型", Length = 100, IsNullable = false)]
public string DataType { get; set; }
/// <summary>
/// 字典值
///</summary>
[SugarColumn(ColumnName = "DictTypeCode", ColumnDescription = "字典值", Length = 100, IsNullable = true)]
public string DictTypeCode { get; set; }
/// <summary>
/// 数据库类型
///</summary>
[SugarColumn(ColumnName = "NetType", ColumnDescription = "数据库类型", Length = 100, IsNullable = true)]
public string NetType { get; set; }
/// <summary>
/// 接口名称
/// </summary>
[SugarColumn(ColumnName = "RequestUrl", ColumnDescription = "接口名称", Length = 100, IsNullable = true)]
public string RequestUrl { get; set; }
/// <summary>
/// 接口类型
/// </summary>
[SugarColumn(ColumnName = "RequestType", ColumnDescription = "接口类型", Length = 100, IsNullable = true)]
public string RequestType { get; set; }
/// <summary>
/// 接口结果标签
/// </summary>
[SugarColumn(ColumnName = "RequestLabel", ColumnDescription = "接口结果标签", Length = 100, IsNullable = true)]
public string RequestLabel { get; set; }
/// <summary>
/// 接口结果值
/// </summary>
[SugarColumn(ColumnName = "RequestValue", ColumnDescription = "接口结果值", Length = 100, IsNullable = true)]
public string RequestValue { get; set; }
/// <summary>
/// 启用状态
/// </summary>
[SugarColumn(ColumnName = "Status", ColumnDescription = "状态", Length = 100, IsNullable = false)]
public string Status { get; set; }
}
@@ -0,0 +1,37 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.Core.Entity.System;
/// <summary>
/// C端用户关系
/// </summary>
[SugarTable("client_relation", TableDescription = "关系")]
[Tenant(SqlSugarConst.DB_DEFAULT)]
public class ClientRelation : PrimaryKeyEntity
{
/// <summary>
/// 对象ID
///</summary>
[SugarColumn(ColumnName = "ObjectId", ColumnDescription = "对象ID", IsNullable = false)]
public long ObjectId { get; set; }
/// <summary>
/// 目标ID
///</summary>
[SugarColumn(ColumnName = "TargetId", ColumnDescription = "目标ID", IsNullable = true)]
public string TargetId { get; set; }
/// <summary>
/// 分类
///</summary>
[SugarColumn(ColumnName = "Category", ColumnDescription = "分类", Length = 200, IsNullable = true)]
public string Category { get; set; }
}
+289
View File
@@ -0,0 +1,289 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// C端用户
///</summary>
[SugarTable("client_user", TableDescription = "C端用户")]
[Tenant(SqlSugarConst.DB_DEFAULT)]
public class ClientUser : DataEntityBase
{
/// <summary>
/// 头像
///</summary>
[SugarColumn(ColumnName = "Avatar", ColumnDescription = "头像", ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)]
public string Avatar { get; set; }
/// <summary>
/// 签名
///</summary>
[SugarColumn(ColumnName = "Signature", ColumnDescription = "签名", ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)]
public string Signature { get; set; }
/// <summary>
/// 账号
///</summary>
[SugarColumn(ColumnName = "Account", ColumnDescription = "账号", Length = 200, IsNullable = false)]
public string Account { get; set; }
/// <summary>
/// 密码
///</summary>
[SugarColumn(ColumnName = "Password", ColumnDescription = "密码", Length = 200, IsNullable = false)]
public string Password { get; set; }
/// <summary>
/// 姓名
///</summary>
[SugarColumn(ColumnName = "Name", ColumnDescription = "姓名", Length = 200, IsNullable = true)]
public string Name { get; set; }
/// <summary>
/// 昵称
///</summary>
[SugarColumn(ColumnName = "Nickname", ColumnDescription = "昵称", Length = 200, IsNullable = true)]
public string Nickname { get; set; }
/// <summary>
/// 性别
///</summary>
[SugarColumn(ColumnName = "Gender", ColumnDescription = "性别", Length = 200, IsNullable = true)]
public string Gender { get; set; }
/// <summary>
/// 年龄
///</summary>
[SugarColumn(ColumnName = "Age", ColumnDescription = "年龄", Length = 200, IsNullable = true)]
public string Age { get; set; }
/// <summary>
/// 出生日期
///</summary>
[SugarColumn(ColumnName = "Birthday", ColumnDescription = "出生日期", Length = 200, IsNullable = true)]
public string Birthday { get; set; }
/// <summary>
/// 民族
///</summary>
[SugarColumn(ColumnName = "Nation", ColumnDescription = "民族", Length = 200, IsNullable = true)]
public string Nation { get; set; }
/// <summary>
/// 籍贯
///</summary>
[SugarColumn(ColumnName = "NativePlace", ColumnDescription = "籍贯", Length = 200, IsNullable = true)]
public string NativePlace { get; set; }
/// <summary>
/// 家庭住址
///</summary>
[SugarColumn(ColumnName = "HomeAddress", ColumnDescription = "家庭住址", IsNullable = true)]
public string HomeAddress { get; set; }
/// <summary>
/// 通信地址
///</summary>
[SugarColumn(ColumnName = "MailingAddress", ColumnDescription = "通信地址", IsNullable = true)]
public string MailingAddress { get; set; }
/// <summary>
/// 证件类型
///</summary>
[SugarColumn(ColumnName = "IdCardType", ColumnDescription = "证件类型", Length = 200, IsNullable = true)]
public string IdCardType { get; set; }
/// <summary>
/// 证件号码
///</summary>
[SugarColumn(ColumnName = "IdCardNumber", ColumnDescription = "证件号码", Length = 200, IsNullable = true)]
public string IdCardNumber { get; set; }
/// <summary>
/// 文化程度
///</summary>
[SugarColumn(ColumnName = "CultureLevel", ColumnDescription = "文化程度", Length = 200, IsNullable = true)]
public string CultureLevel { get; set; }
/// <summary>
/// 政治面貌
///</summary>
[SugarColumn(ColumnName = "PoliticalOutlook", ColumnDescription = "政治面貌", Length = 200, IsNullable = true)]
public string PoliticalOutlook { get; set; }
/// <summary>
/// 毕业院校
///</summary>
[SugarColumn(ColumnName = "College", ColumnDescription = "毕业院校", Length = 200, IsNullable = true)]
public string College { get; set; }
/// <summary>
/// 学历
///</summary>
[SugarColumn(ColumnName = "Education", ColumnDescription = "学历", Length = 200, IsNullable = true)]
public string Education { get; set; }
/// <summary>
/// 学制
///</summary>
[SugarColumn(ColumnName = "EduLength", ColumnDescription = "学制", Length = 200, IsNullable = true)]
public string EduLength { get; set; }
/// <summary>
/// 学位
///</summary>
[SugarColumn(ColumnName = "Degree", ColumnDescription = "学位", Length = 200, IsNullable = true)]
public string Degree { get; set; }
/// <summary>
/// 手机
///</summary>
[SugarColumn(ColumnName = "Phone", ColumnDescription = "手机", Length = 200, IsNullable = true)]
public string Phone { get; set; }
/// <summary>
/// 邮箱
///</summary>
[SugarColumn(ColumnName = "Email", ColumnDescription = "邮箱", Length = 200, IsNullable = true)]
public string Email { get; set; }
/// <summary>
/// 家庭电话
///</summary>
[SugarColumn(ColumnName = "HomeTel", ColumnDescription = "家庭电话", Length = 200, IsNullable = true)]
public string HomeTel { get; set; }
/// <summary>
/// 办公电话
///</summary>
[SugarColumn(ColumnName = "OfficeTel", ColumnDescription = "办公电话", Length = 200, IsNullable = true)]
public string OfficeTel { get; set; }
/// <summary>
/// 紧急联系人
///</summary>
[SugarColumn(ColumnName = "EmergencyContact", ColumnDescription = "紧急联系人", Length = 200, IsNullable = true)]
public string EmergencyContact { get; set; }
/// <summary>
/// 紧急联系人电话
///</summary>
[SugarColumn(ColumnName = "EmergencyPhone", ColumnDescription = "紧急联系人电话", Length = 200, IsNullable = true)]
public string EmergencyPhone { get; set; }
/// <summary>
/// 紧急联系人地址
///</summary>
[SugarColumn(ColumnName = "EmergencyAddress", ColumnDescription = "紧急联系人地址", IsNullable = true)]
public string EmergencyAddress { get; set; }
/// <summary>
/// 员工编号
///</summary>
[SugarColumn(ColumnName = "EmpNo", ColumnDescription = "员工编号", Length = 200, IsNullable = true)]
public string EmpNo { get; set; }
/// <summary>
/// 入职日期
///</summary>
[SugarColumn(ColumnName = "EntryDate", ColumnDescription = "入职日期", Length = 200, IsNullable = true)]
public string EntryDate { get; set; }
/// <summary>
/// 机构id
///</summary>
[SugarColumn(ColumnName = "OrgId", ColumnDescription = "机构id")]
public long OrgId { get; set; }
/// <summary>
/// 职位id
///</summary>
[SugarColumn(ColumnName = "PositionId", ColumnDescription = "职位id")]
public long PositionId { get; set; }
/// <summary>
/// 职级
///</summary>
[SugarColumn(ColumnName = "PositionLevel", ColumnDescription = "职级", Length = 200, IsNullable = true)]
public string PositionLevel { get; set; }
/// <summary>
/// 主管id
///</summary>
[SugarColumn(ColumnName = "DirectorId", ColumnDescription = "主管id", IsNullable = true)]
public long DirectorId { get; set; }
/// <summary>
/// 兼任信息
///</summary>
[SugarColumn(ColumnName = "PositionJson", ColumnDescription = "兼任信息", Length = 100, IsNullable = true)]
public string PositionJson { get; set; }
/// <summary>
/// 上次登录ip
///</summary>
[SugarColumn(ColumnName = "LastLoginIp", ColumnDescription = "上次登录ip", Length = 200, IsNullable = true)]
public string LastLoginIp { get; set; }
/// <summary>
/// 上次登录地点
///</summary>
[SugarColumn(ColumnName = "LastLoginAddress", ColumnDescription = "上次登录地点", Length = 200, IsNullable = true)]
public string LastLoginAddress { get; set; }
/// <summary>
/// 上次登录时间
///</summary>
[SugarColumn(ColumnName = "LastLoginTime", ColumnDescription = "上次登录时间", IsNullable = true)]
public DateTime? LastLoginTime { get; set; }
/// <summary>
/// 上次登录设备
///</summary>
[SugarColumn(ColumnName = "LastLoginDevice", ColumnDescription = "上次登录设备", IsNullable = true)]
public string LastLoginDevice { get; set; }
/// <summary>
/// 最新登录ip
///</summary>
[SugarColumn(ColumnName = "LatestLoginIp", ColumnDescription = "最新登录ip", Length = 200, IsNullable = true)]
public string LatestLoginIp { get; set; }
/// <summary>
/// 最新登录地点
///</summary>
[SugarColumn(ColumnName = "LatestLoginAddress", ColumnDescription = "最新登录地点", Length = 200, IsNullable = true)]
public string LatestLoginAddress { get; set; }
/// <summary>
/// 最新登录时间
///</summary>
[SugarColumn(ColumnName = "LatestLoginTime", ColumnDescription = "最新登录时间", IsNullable = true)]
public DateTime? LatestLoginTime { get; set; }
/// <summary>
/// 最新登录设备
///</summary>
[SugarColumn(ColumnName = "LatestLoginDevice", ColumnDescription = "最新登录设备", IsNullable = true)]
public string LatestLoginDevice { get; set; }
/// <summary>
/// 用户状态
///</summary>
[SugarColumn(ColumnName = "Status", ColumnDescription = "用户状态", Length = 200, IsNullable = true)]
public string Status { get; set; }
/// <summary>
/// 排序码
///</summary>
[SugarColumn(ColumnName = "SortCode", ColumnDescription = "排序码", IsNullable = true)]
public int? SortCode { get; set; }
}
+202
View File
@@ -0,0 +1,202 @@
namespace SimpleAdmin.System;
/// <summary>
/// 代码生成基础
///</summary>
[SugarTable("gen_basic", TableDescription = "代码生成基础")]
[Tenant(SqlSugarConst.DB_DEFAULT)]
public class GenBasic : BaseEntity
{
/// <summary>
/// 所属库
///</summary>
[SugarColumn(ColumnName = "ConfigId", ColumnDescription = "库名", Length = 200)]
public virtual string ConfigId { get; set; }
/// <summary>
/// 主表
///</summary>
[SugarColumn(ColumnName = "DbTable", ColumnDescription = "主表", Length = 200)]
public virtual string DbTable { get; set; }
/// <summary>
/// 表实体名称
/// </summary>
[SugarColumn(ColumnName = "EntityName", ColumnDescription = "表实体名称", Length = 200)]
public virtual string EntityName { get; set; }
/// <summary>
/// 功能列表
///</summary>
[SugarColumn(ColumnName = "Functions", ColumnDescription = "功能列表", Length = 200, IsNullable = false)]
public virtual string Functions { get; set; }
/// <summary>
/// 数据权限
///</summary>
[SugarColumn(ColumnName = "DataPermission", ColumnDescription = "数据权限", Length = 200, IsNullable = false)]
public virtual string DataPermission { get; set; }
/// <summary>
/// 生成模版
///</summary>
[SugarColumn(ColumnName = "ModuleType", ColumnDescription = "生成模版", Length = 200, IsNullable = false)]
public virtual string ModuleType { get; set; }
/// <summary>
/// 树Id字段
///</summary>
[SugarColumn(ColumnName = "TreeId", ColumnDescription = "树Id字段", Length = 200, IsNullable = true)]
public virtual string TreeId { get; set; }
/// <summary>
/// 树父Id字段
///</summary>
[SugarColumn(ColumnName = "TreePid", ColumnDescription = "树父Id字段", Length = 200, IsNullable = true)]
public virtual string TreePid { get; set; }
/// <summary>
/// 树名称字段
///</summary>
[SugarColumn(ColumnName = "TreeName", ColumnDescription = "树名称字段", Length = 200, IsNullable = true)]
public virtual string TreeName { get; set; }
/// <summary>
/// 关联子表名
///</summary>
[SugarColumn(ColumnName = "ChildTable", ColumnDescription = "关联子表名", Length = 200, IsNullable = true)]
public virtual string ChildTable { get; set; }
/// <summary>
/// 关联子表外键
///</summary>
[SugarColumn(ColumnName = "ChildFk", ColumnDescription = "关联子表外键", Length = 200, IsNullable = true)]
public virtual string ChildFk { get; set; }
/// <summary>
/// 移除表前缀
///</summary>
[SugarColumn(ColumnName = "TablePrefix", ColumnDescription = "移除表前缀", Length = 200)]
public virtual string TablePrefix { get; set; }
/// <summary>
/// 生成方式
///</summary>
[SugarColumn(ColumnName = "GenerateType", ColumnDescription = "生成方式", Length = 200)]
public virtual string GenerateType { get; set; }
/// <summary>
/// 所属模块
///</summary>
[SugarColumn(ColumnName = "Module", ColumnDescription = "所属模块")]
public virtual long Module { get; set; }
/// <summary>
/// 上级目录
///</summary>
[SugarColumn(ColumnName = "MenuPid", ColumnDescription = "上级目录")]
public virtual long MenuPid { get; set; }
/// <summary>
/// 业务名
///</summary>
[SugarColumn(ColumnName = "RouteName", ColumnDescription = "路由名", Length = 200)]
public virtual string RouteName { get; set; }
/// <summary>
/// 图标
///</summary>
[SugarColumn(ColumnName = "Icon", ColumnDescription = "图标", Length = 200)]
public virtual string Icon { get; set; }
/// <summary>
/// 功能名
///</summary>
[SugarColumn(ColumnName = "FunctionName", ColumnDescription = "功能名", Length = 200)]
public virtual string FunctionName { get; set; }
/// <summary>
/// 功能名后缀
///</summary>
[SugarColumn(ColumnName = "FunctionNameSuffix", ColumnDescription = "功能名后缀", Length = 200, IsNullable = true)]
public virtual string FunctionNameSuffix { get; set; }
/// <summary>
/// 业务名
///</summary>
[SugarColumn(ColumnName = "BusName", ColumnDescription = "业务名", Length = 200)]
public virtual string BusName { get; set; }
/// <summary>
/// 类名
///</summary>
[SugarColumn(ColumnName = "ClassName", ColumnDescription = "类名", Length = 200)]
public virtual string ClassName { get; set; }
/// <summary>
/// 表单布局
///</summary>
[SugarColumn(ColumnName = "FormLayout", ColumnDescription = "表单布局", Length = 200)]
public virtual string FormLayout { get; set; }
/// <summary>
/// 使用栅格
///</summary>
[SugarColumn(ColumnName = "GridWhether", ColumnDescription = "使用栅格", Length = 200)]
public virtual string GridWhether { get; set; }
/// <summary>
/// 左侧树
///</summary>
[SugarColumn(ColumnName = "LeftTree", ColumnDescription = "使用左侧树", Length = 200)]
public virtual string LeftTree { get; set; }
/// <summary>
/// 前端项目路径
///</summary>
[SugarColumn(ColumnName = "FrontedPath", ColumnDescription = "前端项目路径", IsNullable = true, Length = 200)]
public virtual string FrontedPath { get; set; }
/// <summary>
/// 服务代码存放项目
///</summary>
[SugarColumn(ColumnName = "ServicePosition", ColumnDescription = "服务代码存放项目", IsNullable = true, Length = 200)]
public virtual string ServicePosition { get; set; }
/// <summary>
/// 服务代码存放文件夹
///</summary>
[SugarColumn(ColumnName = "ServiceDictionary", ColumnDescription = "服务代码存放文件夹", IsNullable = true, Length = 200)]
public virtual string ServiceDictionary { get; set; }
/// <summary>
/// 控制器代码存放位置
///</summary>
[SugarColumn(ColumnName = "ControllerPosition", ColumnDescription = "控制器代码存放位置", IsNullable = true, Length = 200)]
public virtual string ControllerPosition { get; set; }
/// <summary>
/// 控制器代码存放文件夹
///</summary>
[SugarColumn(ColumnName = "ControllerDictionary", ColumnDescription = "控制器代码存放文件夹", IsNullable = true, Length = 200)]
public virtual string ControllerDictionary { get; set; }
/// <summary>
/// 作者
///</summary>
[SugarColumn(ColumnName = "AuthorName", ColumnDescription = "作者", Length = 200)]
public virtual string AuthorName { get; set; }
/// <summary>
/// 排序
///</summary>
[SugarColumn(ColumnName = "SortCode", ColumnDescription = "排序")]
public virtual int SortCode { get; set; }
/// <summary>
/// 功能列表
///</summary>
[SugarColumn(IsIgnore = true)]
public virtual List<string> FuncList { get; set; }
}
+154
View File
@@ -0,0 +1,154 @@
namespace SimpleAdmin.System;
/// <summary>
/// 代码生成配置
///</summary>
[SugarTable("gen_config", TableDescription = "代码生成配置")]
[Tenant(SqlSugarConst.DB_DEFAULT)]
public class GenConfig : BaseEntity
{
/// <summary>
/// 基础ID
///</summary>
[SugarColumn(ColumnName = "BasicId", ColumnDescription = "基础配置ID")]
public long BasicId { get; set; }
/// <summary>
/// 字段排序
/// </summary>
[SugarColumn(ColumnName = "FieldIndex", ColumnDescription = "字段排序", IsNullable = true)]
public int FieldIndex { get; set; }
/// <summary>
/// 是否主键
///</summary>
[SugarColumn(ColumnName = "IsPrimaryKey", ColumnDescription = "是否主键", Length = 200)]
public string IsPrimaryKey { get; set; }
/// <summary>
/// 字段
///</summary>
[SugarColumn(ColumnName = "FieldName", ColumnDescription = "字段", Length = 200)]
public string FieldName { get; set; }
/// <summary>
/// 名称
///</summary>
[SugarColumn(ColumnName = "FieldRemark", ColumnDescription = "名称", Length = 200)]
public string FieldRemark { get; set; }
/// <summary>
/// 类型
///</summary>
[SugarColumn(ColumnName = "FieldType", ColumnDescription = "类型", Length = 200)]
public string FieldType { get; set; }
/// <summary>
/// 实体类型
///</summary>
[SugarColumn(ColumnName = "FieldNetType", ColumnDescription = "实体类型", Length = 200)]
public string FieldNetType { get; set; }
/// <summary>
/// 作用类型
///</summary>
[SugarColumn(ColumnName = "EffectType", ColumnDescription = "作用类型", Length = 200)]
public string EffectType { get; set; }
/// <summary>
/// 外键显示字段
/// </summary>
[SugarColumn(ColumnName = "FkEntityName", ColumnDescription = "外键实体名称", Length = 200, IsNullable = true)]
public string FkEntityName { get; set; }
/// <summary>
/// 外键ID
/// </summary>
[SugarColumn(ColumnName = "FkColumnId", ColumnDescription = "外键ID", Length = 200, IsNullable = true)]
public string FkColumnId { get; set; }
/// <summary>
/// 外键显示字段
/// </summary>
[SugarColumn(ColumnName = "FkColumnName", ColumnDescription = "外键显示字段", Length = 200, IsNullable = true)]
public string FkColumnName { get; set; }
/// <summary>
/// 字典
///</summary>
[SugarColumn(ColumnName = "DictTypeCode", ColumnDescription = "字典", Length = 200, IsNullable = true)]
public string DictTypeCode { get; set; }
/// <summary>
/// 列宽度
///</summary>
[SugarColumn(ColumnName = "Width", ColumnDescription = "列宽度")]
public int Width { get; set; }
/// <summary>
/// 列表显示
///</summary>
[SugarColumn(ColumnName = "WhetherTable", ColumnDescription = "列表显示", Length = 200)]
public string WhetherTable { get; set; }
/// <summary>
/// 列省略
///</summary>
[SugarColumn(ColumnName = "WhetherRetract", ColumnDescription = "列省略", Length = 200)]
public string WhetherRetract { get; set; }
/// <summary>
/// 可伸缩列
///</summary>
[SugarColumn(ColumnName = "WhetherResizable", ColumnDescription = "可伸缩列", Length = 200)]
public string WhetherResizable { get; set; }
/// <summary>
/// 是否增改
///</summary>
[SugarColumn(ColumnName = "WhetherAddUpdate", ColumnDescription = "是否增改", Length = 200)]
public string WhetherAddUpdate { get; set; }
/// <summary>
/// 是否导入导出
///</summary>
[SugarColumn(ColumnName = "WhetherImportExport", ColumnDescription = "是否导入导出", Length = 200)]
public string WhetherImportExport { get; set; }
/// <summary>
/// 必填
///</summary>
[SugarColumn(ColumnName = "WhetherRequired", ColumnDescription = "必填", Length = 200)]
public string WhetherRequired { get; set; }
/// <summary>
/// 查询
///</summary>
[SugarColumn(ColumnName = "QueryWhether", ColumnDescription = "查询", Length = 200)]
public string QueryWhether { get; set; }
/// <summary>
/// 查询方式
///</summary>
[SugarColumn(ColumnName = "QueryType", ColumnDescription = "查询方式", Length = 200, IsNullable = true)]
public string QueryType { get; set; }
/// <summary>
/// 排序
///</summary>
[SugarColumn(ColumnName = "SortCode", ColumnDescription = "排序")]
public int SortCode { get; set; }
/// <summary>
/// 字段名首字母小写
/// </summary>
[SugarColumn(IsIgnore = true)]
public string FieldNameFirstLower { get; set; }
/// <summary>
/// 字段名首字母大写
/// </summary>
[SugarColumn(IsIgnore = true)]
public string FieldNameFirstUpper { get; set; }
}
+49
View File
@@ -0,0 +1,49 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 配置
///</summary>
[SugarTable("sys_config", TableDescription = "配置")]
[Tenant(SqlSugarConst.DB_DEFAULT)]
public class SysConfig : BaseEntity
{
/// <summary>
/// 配置键
///</summary>
[SugarColumn(ColumnName = "ConfigKey", ColumnDescription = "配置键", Length = 200)]
public virtual string ConfigKey { get; set; }
/// <summary>
/// 配置值
///</summary>
[SugarColumn(ColumnName = "ConfigValue", ColumnDescription = "配置值", ColumnDataType = StaticConfig.CodeFirst_BigString)]
public virtual string ConfigValue { get; set; }
/// <summary>
/// 分类
///</summary>
[SugarColumn(ColumnName = "Category", ColumnDescription = "分类", Length = 200)]
public string Category { get; set; }
/// <summary>
/// 备注
///</summary>
[SugarColumn(ColumnName = "Remark", ColumnDescription = "备注", Length = 200, IsNullable = true)]
public string Remark { get; set; }
/// <summary>
/// 排序码
///</summary>
[SugarColumn(ColumnName = "SortCode", ColumnDescription = "排序码", IsNullable = true)]
public int SortCode { get; set; }
}
+56
View File
@@ -0,0 +1,56 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 字典
///</summary>
[SugarTable("sys_dict", TableDescription = "字典表")]
[Tenant(SqlSugarConst.DB_DEFAULT)]
public class SysDict : BaseEntity
{
/// <summary>
/// 父id
///</summary>
[SugarColumn(ColumnName = "ParentId", ColumnDescription = "父id")]
public virtual long ParentId { get; set; }
/// <summary>
/// 字典文字
///</summary>
[SugarColumn(ColumnName = "DictLabel", ColumnDescription = "字典文字", Length = 200)]
public virtual string DictLabel { get; set; }
/// <summary>
/// 字典值
///</summary>
[SugarColumn(ColumnName = "DictValue", ColumnDescription = "字典值", Length = 200)]
public virtual string DictValue { get; set; }
/// <summary>
/// 分类
///</summary>
[SugarColumn(ColumnName = "Category", ColumnDescription = "分类", Length = 200)]
public virtual string Category { get; set; }
/// <summary>
/// 排序码
///</summary>
[SugarColumn(ColumnName = "SortCode", ColumnDescription = "排序码")]
public int SortCode { get; set; }
/// <summary>
/// 子节点
/// </summary>
[SugarColumn(IsIgnore = true)]
public List<SysDict> Children { get; set; }
}
+79
View File
@@ -0,0 +1,79 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 文件表
///</summary>
[SugarTable("sys_file", TableDescription = "文件表")]
[Tenant(SqlSugarConst.DB_DEFAULT)]
public class SysFile : DataEntityBase
{
/// <summary>
/// 存储引擎
///</summary>
[SugarColumn(ColumnName = "Engine", ColumnDescription = "存储引擎", Length = 200)]
public string Engine { get; set; }
/// <summary>
/// 存储桶
///</summary>
[SugarColumn(ColumnName = "Bucket", ColumnDescription = "存储桶", Length = 200)]
public string Bucket { get; set; }
/// <summary>
/// 文件名称
///</summary>
[SugarColumn(ColumnName = "Name", ColumnDescription = "文件名称")]
public string Name { get; set; }
/// <summary>
/// 文件后缀
///</summary>
[SugarColumn(ColumnName = "Suffix", ColumnDescription = "文件后缀", Length = 200)]
public string Suffix { get; set; }
/// <summary>
/// 文件大小kb
///</summary>
[SugarColumn(ColumnName = "SizeKb", ColumnDescription = "文件大小kb")]
public long SizeKb { get; set; }
/// <summary>
/// 文件大小(格式化后)
///</summary>
[SugarColumn(ColumnName = "SizeInfo", ColumnDescription = "文件大小(格式化后)", Length = 200)]
public string SizeInfo { get; set; }
/// <summary>
/// 文件的对象名(唯一名称)
///</summary>
[SugarColumn(ColumnName = "ObjName", ColumnDescription = "文件的对象名(唯一名称)")]
public string ObjName { get; set; }
/// <summary>
/// 文件存储路径
///</summary>
[SugarColumn(ColumnName = "StoragePath", ColumnDescription = "文件存储路径")]
public string StoragePath { get; set; }
/// <summary>
/// 文件下载路径
///</summary>
[SugarColumn(ColumnName = "DownloadPath", ColumnDescription = "文件下载路径", IsNullable = true)]
public string DownloadPath { get; set; }
/// <summary>
/// 图片缩略图
///</summary>
[SugarColumn(ColumnName = "Thumbnail", ColumnDescription = "图片缩略图", IsNullable = true, ColumnDataType = StaticConfig.CodeFirst_BigString)]
public string Thumbnail { get; set; }
}
@@ -0,0 +1,61 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 操作日志表
///</summary>
[SugarTable("sys_log_operate_{year}{month}{day}", TableDescription = "操作日志表")]
[Tenant(SqlSugarConst.DB_DEFAULT)]
public class SysLogOperate : SysLogVisit
{
/// <summary>
/// 具体消息
///</summary>
[SugarColumn(ColumnName = "ExeMessage", ColumnDescription = "具体消息", ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)]
public string ExeMessage { get; set; }
/// <summary>
/// 类名称
///</summary>
[SugarColumn(ColumnName = "ClassName", ColumnDescription = "类名称", Length = 200)]
public string ClassName { get; set; }
/// <summary>
/// 方法名称
///</summary>
[SugarColumn(ColumnName = "MethodName", ColumnDescription = "方法名称", Length = 200)]
public string MethodName { get; set; }
/// <summary>
/// 请求方式
///</summary>
[SugarColumn(ColumnName = "ReqMethod", ColumnDescription = "请求方式", Length = 200, IsNullable = true)]
public string ReqMethod { get; set; }
/// <summary>
/// 请求地址
///</summary>
[SugarColumn(ColumnName = "ReqUrl", ColumnDescription = "请求地址", ColumnDataType = StaticConfig.CodeFirst_BigString)]
public string ReqUrl { get; set; }
/// <summary>
/// 请求参数
///</summary>
[SugarColumn(ColumnName = "ParamJson", ColumnDescription = "请求参数", ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)]
public string ParamJson { get; set; }
/// <summary>
/// 返回结果
///</summary>
[SugarColumn(ColumnName = "ResultJson", ColumnDescription = "返回结果", ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)]
public string ResultJson { get; set; }
}
+81
View File
@@ -0,0 +1,81 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 访问日志表
///</summary>
[SugarTable("sys_log_visit_{year}{month}{day}", TableDescription = "访问日志表")]
[SplitTable(SplitType.Year)]//按年分表 (自带分表支持 年、季、月、周、日)
[Tenant(SqlSugarConst.DB_DEFAULT)]
public class SysLogVisit : BaseEntity
{
/// <summary>
/// 日志分类
///</summary>
[SugarColumn(ColumnName = "Category", ColumnDescription = "日志分类", Length = 200)]
public string Category { get; set; }
/// <summary>
/// 日志名称
///</summary>
[SugarColumn(ColumnName = "Name", ColumnDescription = "日志名称", Length = 200)]
public string Name { get; set; }
/// <summary>
/// 执行状态
///</summary>
[SugarColumn(ColumnName = "ExeStatus", ColumnDescription = "执行状态", Length = 200)]
public string ExeStatus { get; set; }
/// <summary>
/// 操作ip
///</summary>
[SugarColumn(ColumnName = "OpIp", ColumnDescription = "操作ip", Length = 200)]
public string OpIp { get; set; }
/// <summary>
/// 操作地址
///</summary>
[SugarColumn(ColumnName = "OpAddress", ColumnDescription = "操作地址", Length = 200)]
public string OpAddress { get; set; }
/// <summary>
/// 操作浏览器
///</summary>
[SugarColumn(ColumnName = "OpBrowser", ColumnDescription = "操作浏览器", Length = 200)]
public string OpBrowser { get; set; }
/// <summary>
/// 操作系统
///</summary>
[SugarColumn(ColumnName = "OpOs", ColumnDescription = "操作系统", Length = 200)]
public string OpOs { get; set; }
/// <summary>
/// 操作时间
///</summary>
[SugarColumn(ColumnName = "OpTime", ColumnDescription = "操作时间")]
[SplitField]//分表字段 在插入的时候会根据这个字段插入哪个表,在更新删除的时候用这个字段找出相关表
public DateTime OpTime { get; set; }
/// <summary>
/// 操作人姓名
///</summary>
[SugarColumn(ColumnName = "OpUser", ColumnDescription = "操作人姓名", Length = 200, IsNullable = true)]
public string OpUser { get; set; }
/// <summary>
/// 操作人姓名
///</summary>
[SugarColumn(ColumnName = "OpAccount", ColumnDescription = "操作人账号", Length = 200, IsNullable = true)]
public string OpAccount { get; set; }
}
+123
View File
@@ -0,0 +1,123 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 站内信
///</summary>
[SugarTable("sys_message", TableDescription = "站内信")]
[Tenant(SqlSugarConst.DB_DEFAULT)]
public class SysMessage : BaseEntity
{
/// <summary>
/// 分类
///</summary>
[SugarColumn(ColumnName = "Category", ColumnDescription = "分类", Length = 200)]
public virtual string Category { get; set; }
/// <summary>
/// 主题
///</summary>
[SugarColumn(ColumnName = "Subject", ColumnDescription = "主题")]
public virtual string Subject { get; set; }
/// <summary>
/// 接收人类型
/// </summary>
[SugarColumn(ColumnName = "ReceiverType", ColumnDescription = "接收人类型")]
public virtual string ReceiverType { get; set; }
/// <summary>
/// 接收人列表
/// </summary>
[SugarColumn(ColumnName = "ReceiverInfo", ColumnDescription = "接收人列表", IsJson = true)]
public virtual List<ReceiverInfo> ReceiverInfo { get; set; }
/// <summary>
/// 发送方式
/// </summary>
[SugarColumn(ColumnName = "SendWay", ColumnDescription = "发送方式")]
public virtual string SendWay { get; set; }
/// <summary>
/// 发送时间
/// </summary>
[SugarColumn(ColumnDescription = "发送时间")]
public virtual DateTime SendTime { get; set; }
/// <summary>
/// 正文
///</summary>
[SugarColumn(ColumnName = "Content", ColumnDescription = "正文", ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)]
public virtual string Content { get; set; }
/// <summary>
/// 延迟时间(秒)
/// </summary>
[SugarColumn(IsIgnore = true)]
public int DelayTime { get; set; }
/// <summary>
/// 已读情况
/// </summary>
[SugarColumn(IsIgnore = true)]
public List<ReceiverDetail> ReceiverDetail { get; set; } = new List<ReceiverDetail>();
/// <summary>
/// 发送时间格式化
/// </summary>
[SugarColumn(IsIgnore = true)]
public string SendTimeFormat { get; set; }
/// <summary>
/// 分组查询用
/// </summary>
[SugarColumn(IsIgnore = true)]
public int Index2 { get; set; }
/// <summary>
/// 是否已读
/// </summary>
[SugarColumn(IsIgnore = true)]
public bool Read { get; set; }
}
public class ReceiverInfo
{
/// <summary>
/// ID
/// </summary>
public long Id { get; set; }
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
}
public class ReceiverDetail
{
/// <summary>
/// ID
/// </summary>
public long Id { get; set; }
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 是否已读
/// </summary>
public bool Read { get; set; }
}
@@ -0,0 +1,37 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 用户消息表
///</summary>
[SugarTable("sys_message_user", TableDescription = "用户消息表")]
[Tenant(SqlSugarConst.DB_DEFAULT)]
public class SysMessageUser : BaseEntity
{
/// <summary>
/// 消息Id
///</summary>
[SugarColumn(ColumnName = "MessageId", ColumnDescription = "消息Id", IsNullable = false)]
public long MessageId { get; set; }
/// <summary>
/// 用户Id
///</summary>
[SugarColumn(ColumnName = "UserId", ColumnDescription = "用户Id", IsNullable = false)]
public long UserId { get; set; }
/// <summary>
/// 已读未读
///</summary>
[SugarColumn(ColumnName = "Read", ColumnDescription = "已读未读", IsNullable = false)]
public bool Read { get; set; }
}
+83
View File
@@ -0,0 +1,83 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 组织
///</summary>
[SugarTable("sys_org", TableDescription = "组织")]
[Tenant(SqlSugarConst.DB_DEFAULT)]
[CodeGen]
public class SysOrg : BaseEntity
{
/// <summary>
/// 父id
///</summary>
[SugarColumn(ColumnName = "ParentId", ColumnDescription = "父id")]
public long ParentId { get; set; }
[SugarColumn(ColumnName = "ParentIdList", ColumnDescription = "父id列表", IsNullable = true, IsJson = true)]
public List<long> ParentIdList { get; set; } = new List<long>();
/// <summary>
/// 主管ID
///</summary>
[SugarColumn(ColumnName = "DirectorId", ColumnDescription = "主管ID", IsNullable = true)]
public long? DirectorId { get; set; }
/// <summary>
/// 名称
///</summary>
[SugarColumn(ColumnName = "Name", ColumnDescription = "名称", Length = 200)]
public string Name { get; set; }
/// <summary>
/// 全称
///</summary>
[SugarColumn(ColumnName = "Names", ColumnDescription = "全称", Length = 500)]
public string Names { get; set; }
/// <summary>
/// 编码
///</summary>
[SugarColumn(ColumnName = "Code", ColumnDescription = "编码", Length = 200)]
public string Code { get; set; }
/// <summary>
/// 分类
///</summary>
[SugarColumn(ColumnName = "Category", ColumnDescription = "分类", Length = 200)]
public string Category { get; set; }
/// <summary>
/// 排序码
///</summary>
[SugarColumn(ColumnName = "SortCode", ColumnDescription = "排序码", IsNullable = true)]
public int? SortCode { get; set; }
/// <summary>
/// 主管信息
/// </summary>
[SugarColumn(IsIgnore = true)]
public UserSelectorOutPut DirectorInfo { get; set; }
/// <summary>
/// 子节点
/// </summary>
[SugarColumn(IsIgnore = true)]
public List<SysOrg> Children { get; set; }
/// <summary>
/// 设置为叶子节点(设置了loadData时有效)
/// </summary>
[SugarColumn(IsIgnore = true)]
public bool? Leaf { get; set; }
}
+50
View File
@@ -0,0 +1,50 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 职位表
///</summary>
[SugarTable("sys_position", TableDescription = "职位表")]
[Tenant(SqlSugarConst.DB_DEFAULT)]
[CodeGen]
public class SysPosition : DataEntityBase
{
/// <summary>
/// 组织id
///</summary>
[SugarColumn(ColumnName = "OrgId", ColumnDescription = "组织id")]
public virtual long OrgId { get; set; }
/// <summary>
/// 名称
///</summary>
[SugarColumn(ColumnName = "Name", ColumnDescription = "名称", Length = 200)]
public virtual string Name { get; set; }
/// <summary>
/// 编码
///</summary>
[SugarColumn(ColumnName = "Code", ColumnDescription = "编码", Length = 200)]
public string Code { get; set; }
/// <summary>
/// 分类
///</summary>
[SugarColumn(ColumnName = "Category", ColumnDescription = "分类", Length = 200)]
public virtual string Category { get; set; }
/// <summary>
/// 排序码
///</summary>
[SugarColumn(ColumnName = "SortCode", ColumnDescription = "排序码", IsNullable = true)]
public int? SortCode { get; set; }
}
+37
View File
@@ -0,0 +1,37 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 系统关系表
///</summary>
[SugarTable("sys_relation", TableDescription = "系统关系表")]
[Tenant(SqlSugarConst.DB_DEFAULT)]
public class SysRelation : PrimaryKeyEntity
{
/// <summary>
/// 对象ID
///</summary>
[SugarColumn(ColumnName = "ObjectId", ColumnDescription = "对象ID", IsNullable = false)]
public long ObjectId { get; set; }
/// <summary>
/// 目标ID
///</summary>
[SugarColumn(ColumnName = "TargetId", ColumnDescription = "目标ID", IsNullable = true)]
public string TargetId { get; set; }
/// <summary>
/// 分类
///</summary>
[SugarColumn(ColumnName = "Category", ColumnDescription = "分类", Length = 200, IsNullable = false)]
public string Category { get; set; }
}
+191
View File
@@ -0,0 +1,191 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 资源
///</summary>
[SugarTable("sys_resource", TableDescription = "资源")]
[Tenant(SqlSugarConst.DB_DEFAULT)]
public class SysResource : BaseEntity
{
/// <summary>
/// 父id
///</summary>
[SugarColumn(ColumnName = "ParentId", ColumnDescription = "父id", IsNullable = true)]
public virtual long? ParentId { get; set; }
/// <summary>
/// 标题
///</summary>
[SugarColumn(ColumnName = "Title", ColumnDescription = "标题", Length = 200)]
public virtual string Title { get; set; }
/// <summary>
/// 别名
///</summary>
[SugarColumn(ColumnName = "Name", ColumnDescription = "别名", Length = 200, IsNullable = true)]
public string Name { get; set; }
/// <summary>
/// 描述
///</summary>
[SugarColumn(ColumnName = "Description", ColumnDescription = "描述", Length = 200, IsNullable = true)]
public string Description { get; set; }
/// <summary>
/// 编码
///</summary>
[SugarColumn(ColumnName = "Code", ColumnDescription = "编码", Length = 200, IsNullable = true)]
public virtual string Code { get; set; }
/// <summary>
/// 分类
///</summary>
[SugarColumn(ColumnName = "Category", ColumnDescription = "分类", Length = 200)]
public string Category { get; set; }
/// <summary>
/// 模块
///</summary>
[SugarColumn(ColumnName = "Module", ColumnDescription = "所属模块Id", IsNullable = true)]
public virtual long? Module { get; set; }
/// <summary>
/// 菜单类型
///</summary>
[SugarColumn(ColumnName = "MenuType", ColumnDescription = "菜单类型", Length = 200, IsNullable = true)]
public virtual string MenuType { get; set; }
/// <summary>
/// 路径
///</summary>
[SugarColumn(ColumnName = "Path", ColumnDescription = "路径", IsNullable = true)]
public virtual string Path { get; set; }
/// <summary>
/// 组件
///</summary>
[SugarColumn(ColumnName = "Component", ColumnDescription = "组件", Length = 200, IsNullable = true)]
public string Component { get; set; }
/// <summary>
/// 图标
///</summary>
[SugarColumn(ColumnName = "Icon", ColumnDescription = "图标", Length = 200, IsNullable = true)]
public virtual string Icon { get; set; }
/// <summary>
/// 是否在菜单中隐藏, 需要高亮的 path (通常用作详情页高亮父级菜单)
///</summary>
[SugarColumn(ColumnName = "ActiveMenu", ColumnDescription = "需要高亮的 path (通常用作详情页高亮父级菜单)", Length = 200, IsNullable = true)]
public string ActiveMenu { get; set; }
/// <summary>
/// 是否在菜单中隐藏 (通常列表详情页需要隐藏)
///</summary>
[SugarColumn(ColumnName = "IsHide", ColumnDescription = "是否在菜单中隐藏 (通常列表详情页需要隐藏) ", IsNullable = true)]
public bool IsHide { get; set; }
/// <summary>
/// 是否在菜单中隐藏 (通常列表详情页需要隐藏)
///</summary>
[SugarColumn(ColumnName = "IsFull", ColumnDescription = "菜单是否全屏 (示例:数据大屏页面)", IsNullable = true)]
public bool IsFull { get; set; }
/// <summary>
/// 菜单是否固定在标签页中 (首页通常是固定项)
///</summary>
[SugarColumn(ColumnName = "IsAffix", ColumnDescription = "菜单是否固定在标签页中 (首页通常是固定项)", IsNullable = true)]
public bool IsAffix { get; set; }
/// <summary>
/// 菜单是否固定在标签页中 (首页通常是固定项)
///</summary>
[SugarColumn(ColumnName = "IsKeepAlive", ColumnDescription = " 当前路由是否缓存", IsNullable = true)]
public bool IsKeepAlive { get; set; }
/// <summary>
/// 是否为首页
///</summary>
[SugarColumn(ColumnName = "IsHome", ColumnDescription = " 是否为首页", IsNullable = true)]
public bool IsHome { get; set; }
/// <summary>
/// 排序码
///</summary>
[SugarColumn(ColumnName = "SortCode", ColumnDescription = "排序码", IsNullable = true)]
public int? SortCode { get; set; }
/// <summary>
/// 外链地址
///</summary>
[SugarColumn(ColumnName = "IsLink", ColumnDescription = "外链地址", IsNullable = true)]
public string IsLink { get; set; }
/// <summary>
/// 菜单元标签
/// </summary>
[SugarColumn(IsIgnore = true)]
public Meta Meta { get; set; }
/// <summary>
/// 子节点
/// </summary>
[SugarColumn(IsIgnore = true)]
public List<SysResource> Children { get; set; }
}
/// <summary>
/// 菜单元标签
/// </summary>
public class Meta
{
/// <summary>
/// 图标
/// </summary>
public string Icon { get; set; }
/// <summary>
/// 标题
/// </summary>
public string Title { get; set; }
/// <summary>
/// 是否在菜单中隐藏, 需要高亮的 path (通常用作详情页高亮父级菜单)
///</summary>
public string ActiveMenu { get; set; }
/// <summary>
/// 是否在菜单中隐藏 (通常列表详情页需要隐藏)
///</summary>
public bool IsHide { get; set; }
/// <summary>
/// 路由外链时填写的访问地址
/// </summary>
public string IsLink { get; set; } = "";
/// <summary>
/// 是否在菜单中隐藏 (通常列表详情页需要隐藏)
///</summary>
public bool IsFull { get; set; }
/// <summary>
/// 菜单是否固定在标签页中 (首页通常是固定项)
///</summary>
public bool IsAffix { get; set; }
/// <summary>
/// 菜单是否固定在标签页中 (首页通常是固定项)
///</summary>
public bool IsKeepAlive { get; set; }
}
+83
View File
@@ -0,0 +1,83 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 角色
///</summary>
[SugarTable("sys_role", TableDescription = "角色")]
[Tenant(SqlSugarConst.DB_DEFAULT)]
public class SysRole : DataEntityBase
{
/// <summary>
/// 组织id
///</summary>
[SugarColumn(ColumnName = "OrgId", ColumnDescription = "组织id", IsNullable = true)]
public long? OrgId { get; set; }
/// <summary>
/// 名称
///</summary>
[SugarColumn(ColumnName = "Name", ColumnDescription = "名称", Length = 200, IsNullable = false)]
public virtual string Name { get; set; }
/// <summary>
/// 编码
///</summary>
[SugarColumn(ColumnName = "Code", ColumnDescription = "编码", Length = 200, IsNullable = false)]
public string Code { get; set; }
/// <summary>
/// 分类
///</summary>
[SugarColumn(ColumnName = "Category", ColumnDescription = "分类", Length = 200, IsNullable = false)]
public virtual string Category { get; set; }
/// <summary>
/// 默认数据范围
///</summary>
[SugarColumn(ColumnName = "DefaultDataScope", ColumnDescription = "默认数据范围", IsJson = true, ColumnDataType = StaticConfig.CodeFirst_BigString,
IsNullable = false)]
public virtual DefaultDataScope DefaultDataScope { get; set; }
/// <summary>
/// 排序码
///</summary>
[SugarColumn(ColumnName = "SortCode", ColumnDescription = "排序码", IsNullable = true)]
public int? SortCode { get; set; }
/// <summary>
/// 用户列表
/// </summary>
[SugarColumn(IsIgnore = true)]
public List<UserSelectorOutPut> UserList { get; set; } = new List<UserSelectorOutPut>();
}
/// <summary>
/// 默认数据范围
/// </summary>
public class DefaultDataScope
{
/// <summary>
/// 数据范围等级
/// </summary>
public int Level { get; set; }
/// <summary>
/// 数据范围
/// </summary>
public string ScopeCategory { get; set; }
/// <summary>
/// 自定义机构范围列表
/// </summary>
public List<long> ScopeDefineOrgIdList { get; set; } = new List<long>();
}
+393
View File
@@ -0,0 +1,393 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 用户信息表
///</summary>
[SugarTable("sys_user", TableDescription = "用户信息表")]
[Tenant(SqlSugarConst.DB_DEFAULT)]
[BatchEdit]
[CodeGen]
public class SysUser : BaseEntity
{
/// <summary>
/// 头像
///</summary>
[SugarColumn(ColumnName = "Avatar", ColumnDescription = "头像", ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)]
public virtual string Avatar { get; set; }
/// <summary>
/// 签名
///</summary>
[SugarColumn(ColumnName = "Signature", ColumnDescription = "签名", ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)]
public string Signature { get; set; }
/// <summary>
/// 账号
///</summary>
[SugarColumn(ColumnName = "Account", ColumnDescription = "账号", Length = 200, IsNullable = false)]
public virtual string Account { get; set; }
/// <summary>
/// 密码
///</summary>
[SugarColumn(ColumnName = "Password", ColumnDescription = "密码", Length = 200, IsNullable = false)]
public string Password { get; set; }
/// <summary>
/// 姓名
///</summary>
[SugarColumn(ColumnName = "Name", ColumnDescription = "姓名", Length = 200, IsNullable = true)]
public virtual string Name { get; set; }
/// <summary>
/// 昵称
///</summary>
[SugarColumn(ColumnName = "Nickname", ColumnDescription = "昵称", Length = 200, IsNullable = true)]
public string Nickname { get; set; }
/// <summary>
/// 性别
///</summary>
[SugarColumn(ColumnName = "Gender", ColumnDescription = "性别", Length = 200, IsNullable = true)]
public string Gender { get; set; }
/// <summary>
/// 出生日期
///</summary>
[SugarColumn(ColumnName = "Birthday", ColumnDescription = "出生日期", Length = 200, IsNullable = true)]
public string Birthday { get; set; }
/// <summary>
/// 民族
///</summary>
[SugarColumn(ColumnName = "Nation", ColumnDescription = "民族", Length = 200, IsNullable = true)]
public string Nation { get; set; }
/// <summary>
/// 籍贯
///</summary>
[SugarColumn(ColumnName = "NativePlace", ColumnDescription = "籍贯", Length = 200, IsNullable = true)]
public string NativePlace { get; set; }
/// <summary>
/// 家庭住址
///</summary>
[SugarColumn(ColumnName = "HomeAddress", ColumnDescription = "家庭住址", IsNullable = true)]
public string HomeAddress { get; set; }
/// <summary>
/// 通信地址
///</summary>
[SugarColumn(ColumnName = "MailingAddress", ColumnDescription = "通信地址", IsNullable = true)]
public string MailingAddress { get; set; }
/// <summary>
/// 证件类型
///</summary>
[SugarColumn(ColumnName = "IdCardType", ColumnDescription = "证件类型", Length = 200, IsNullable = true)]
public string IdCardType { get; set; }
/// <summary>
/// 证件号码
///</summary>
[SugarColumn(ColumnName = "IdCardNumber", ColumnDescription = "证件号码", Length = 200, IsNullable = true)]
public string IdCardNumber { get; set; }
/// <summary>
/// 文化程度
///</summary>
[SugarColumn(ColumnName = "CultureLevel", ColumnDescription = "文化程度", Length = 200, IsNullable = true)]
public string CultureLevel { get; set; }
/// <summary>
/// 政治面貌
///</summary>
[SugarColumn(ColumnName = "PoliticalOutlook", ColumnDescription = "政治面貌", Length = 200, IsNullable = true)]
public string PoliticalOutlook { get; set; }
/// <summary>
/// 毕业院校
///</summary>
[SugarColumn(ColumnName = "College", ColumnDescription = "毕业院校", Length = 200, IsNullable = true)]
public string College { get; set; }
/// <summary>
/// 学历
///</summary>
[SugarColumn(ColumnName = "Education", ColumnDescription = "学历", Length = 200, IsNullable = true)]
public string Education { get; set; }
/// <summary>
/// 学制
///</summary>
[SugarColumn(ColumnName = "EduLength", ColumnDescription = "学制", Length = 200, IsNullable = true)]
public string EduLength { get; set; }
/// <summary>
/// 学位
///</summary>
[SugarColumn(ColumnName = "Degree", ColumnDescription = "学位", Length = 200, IsNullable = true)]
public string Degree { get; set; }
/// <summary>
/// 手机
/// 这里使用了SM4自动加密解密
///</summary>
[SugarColumn(ColumnName = "Phone", ColumnDescription = "手机", Length = 200, IsNullable = true)]
public string Phone { get; set; }
/// <summary>
/// 邮箱
///</summary>
[SugarColumn(ColumnName = "Email", ColumnDescription = "邮箱", Length = 200, IsNullable = true)]
public string Email { get; set; }
/// <summary>
/// 家庭电话
///</summary>
[SugarColumn(ColumnName = "HomeTel", ColumnDescription = "家庭电话", Length = 200, IsNullable = true)]
public string HomeTel { get; set; }
/// <summary>
/// 办公电话
///</summary>
[SugarColumn(ColumnName = "OfficeTel", ColumnDescription = "办公电话", Length = 200, IsNullable = true)]
public string OfficeTel { get; set; }
/// <summary>
/// 紧急联系人
///</summary>
[SugarColumn(ColumnName = "EmergencyContact", ColumnDescription = "紧急联系人", Length = 200, IsNullable = true)]
public string EmergencyContact { get; set; }
/// <summary>
/// 紧急联系人电话
///</summary>
[SugarColumn(ColumnName = "EmergencyPhone", ColumnDescription = "紧急联系人电话", Length = 200, IsNullable = true)]
public string EmergencyPhone { get; set; }
/// <summary>
/// 紧急联系人地址
///</summary>
[SugarColumn(ColumnName = "EmergencyAddress", ColumnDescription = "紧急联系人地址", IsNullable = true)]
public string EmergencyAddress { get; set; }
/// <summary>
/// 员工编号
///</summary>
[SugarColumn(ColumnName = "EmpNo", ColumnDescription = "员工编号", Length = 200, IsNullable = true)]
public string EmpNo { get; set; }
/// <summary>
/// 入职日期
///</summary>
[SugarColumn(ColumnName = "EntryDate", ColumnDescription = "入职日期", Length = 200, IsNullable = true)]
public string EntryDate { get; set; }
/// <summary>
/// 机构id
///</summary>
[SugarColumn(ColumnName = "OrgId", ColumnDescription = "机构id", IsNullable = false)]
public virtual long OrgId { get; set; }
/// <summary>
/// 职位id
///</summary>
[SugarColumn(ColumnName = "PositionId", ColumnDescription = "职位id", IsNullable = false)]
public virtual long PositionId { get; set; }
/// <summary>
/// 职级
///</summary>
[SugarColumn(ColumnName = "PositionLevel", ColumnDescription = "职级", Length = 200, IsNullable = true)]
public string PositionLevel { get; set; }
/// <summary>
/// 主管id
///</summary>
[SugarColumn(ColumnName = "DirectorId", ColumnDescription = "主管id", IsNullable = true)]
public long? DirectorId { get; set; }
/// <summary>
/// 上次修改密码时间
///</summary>
[SugarColumn(ColumnName = "PwdRemindUpdateTime", ColumnDescription = "密码提醒修改时间", IsNullable = true)]
public DateTime? PwdRemindUpdateTime { get; set; }
/// <summary>
/// 上次登录ip
///</summary>
[SugarColumn(ColumnName = "LastLoginIp", ColumnDescription = "上次登录ip", Length = 200, IsNullable = true)]
public string LastLoginIp { get; set; }
/// <summary>
/// 上次登录地点
///</summary>
[SugarColumn(ColumnName = "LastLoginAddress", ColumnDescription = "上次登录地点", Length = 200, IsNullable = true)]
public string LastLoginAddress { get; set; }
/// <summary>
/// 上次登录时间
///</summary>
[SugarColumn(ColumnName = "LastLoginTime", ColumnDescription = "上次登录时间", IsNullable = true)]
public DateTime? LastLoginTime { get; set; }
/// <summary>
/// 上次登录设备
///</summary>
[SugarColumn(ColumnName = "LastLoginDevice", ColumnDescription = "上次登录设备", IsNullable = true)]
public string LastLoginDevice { get; set; }
/// <summary>
/// 最新登录ip
///</summary>
[SugarColumn(ColumnName = "LatestLoginIp", ColumnDescription = "最新登录ip", Length = 200, IsNullable = true)]
public string LatestLoginIp { get; set; }
/// <summary>
/// 最新登录地点
///</summary>
[SugarColumn(ColumnName = "LatestLoginAddress", ColumnDescription = "最新登录地点", Length = 200, IsNullable = true)]
public string LatestLoginAddress { get; set; }
/// <summary>
/// 最新登录时间
///</summary>
[SugarColumn(ColumnName = "LatestLoginTime", ColumnDescription = "最新登录时间", IsNullable = true)]
public DateTime? LatestLoginTime { get; set; }
/// <summary>
/// 最新登录设备
///</summary>
[SugarColumn(ColumnName = "LatestLoginDevice", ColumnDescription = "最新登录设备", IsNullable = true)]
public string LatestLoginDevice { get; set; }
/// <summary>
/// 排序码
///</summary>
[SugarColumn(ColumnName = "SortCode", ColumnDescription = "排序码", IsNullable = true)]
public int? SortCode { get; set; }
/// <summary>
/// 默认模块
///</summary>
[SugarColumn(ColumnName = "DefaultModule", ColumnDescription = "默认模块", IsNullable = true)]
public long? DefaultModule { get; set; }
/// <summary>
/// 机构信息
/// </summary>
[SugarColumn(IsIgnore = true)]
public string OrgName { get; set; }
/// <summary>
/// 机构信息全称
/// </summary>
[SugarColumn(IsIgnore = true)]
public string OrgNames { get; set; }
/// <summary>
/// 职位信息
/// </summary>
[SugarColumn(IsIgnore = true)]
public string PositionName { get; set; }
/// <summary>
/// 组织和机构ID列表,组织ID从上到下最后是职位
/// </summary>
[SugarColumn(IsIgnore = true, IsJson = true)]
public List<long> OrgAndPosIdList { get; set; } = new List<long>();
/// <summary>
/// 主管信息
/// </summary>
[SugarColumn(IsIgnore = true)]
public UserSelectorOutPut DirectorInfo { get; set; }
/// <summary>
/// 按钮码集合
/// </summary>
[SugarColumn(IsIgnore = true)]
public List<string> ButtonCodeList { get; set; }
/// <summary>
/// 权限码集合
/// </summary>
[SugarColumn(IsIgnore = true)]
public List<string> PermissionCodeList { get; set; }
/// <summary>
/// 角色码集合
/// </summary>
[SugarColumn(IsIgnore = true)]
public List<string> RoleCodeList { get; set; }
/// <summary>
/// 角色ID集合
/// </summary>
[SugarColumn(IsIgnore = true)]
public List<long> RoleIdList { get; set; }
/// <summary>
/// 数据范围集合
/// </summary>
[SugarColumn(IsIgnore = true)]
public List<DataScope> DataScopeList { get; set; }
/// <summary>
/// 默认数据范围
/// </summary>
[SugarColumn(IsIgnore = true)]
public DefaultDataScope DefaultDataScope { get; set; }
/// <summary>
/// 机构及以下机构ID集合
/// </summary>
[SugarColumn(IsIgnore = true)]
public List<long> ScopeOrgChildList { get; set; }
/// <summary>
/// 机构及以下机构ID集合
/// </summary>
[SugarColumn(IsIgnore = true)]
public List<SysResource> ModuleList { get; set; } = new List<SysResource>();
/// <summary>
/// 租户Id
/// </summary>
[SugarColumn(IsIgnore = true)]
public long? TenantId { get; set; }
}
/// <summary>
/// 数据范围类
/// </summary>
public class DataScope
{
/// <summary>
/// API接口
/// </summary>
public string ApiUrl { get; set; }
/// <summary>
/// 数据范围分类
/// </summary>
public string ScopeCategory { get; set; }
/// <summary>
/// 数据范围的机构ID列表
/// </summary>
public List<long>? DataScopes { get; set; }
}
@@ -0,0 +1,169 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
using IP2Region.Net.Abstractions;
namespace SimpleAdmin.System;
/// <summary>
/// 认证模块事件总线
/// </summary>
public class AuthEventSubscriber : IEventSubscriber, ISingleton
{
private readonly ISimpleCacheService _simpleCacheService;
private readonly ISearcher _searcher;
public IServiceProvider Services { get; }
private readonly SqlSugarScope _db;
public AuthEventSubscriber(ISimpleCacheService simpleCacheService, IServiceProvider services, ISearcher searcher)
{
_db = DbContext.DB;
_simpleCacheService = simpleCacheService;
_searcher = searcher;
Services = services;
}
/// <summary>
/// 登录事件
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
[EventSubscribe(EventSubscriberConst.LOGIN_B)]
public async Task Login(EventHandlerExecutingContext context)
{
var loginEvent = (LoginEvent)context.Source.Payload;//获取参数
var loginAddress = GetLoginAddress(loginEvent.Ip);
var sysUser = loginEvent.SysUser;
#region 登录/密码策略
var key = SystemConst.CACHE_LOGIN_ERROR_COUNT + sysUser.Account;//获取登录错误次数Key值
_simpleCacheService.Remove(key);//移除登录错误次数
// 创建新的作用域
using var scope = Services.CreateScope();
// 解析服务
var configService = scope.ServiceProvider.GetRequiredService<IConfigService>();
var messageService = scope.ServiceProvider.GetRequiredService<IMessageService>();
var pwdRemindUpdateTime = sysUser.PwdRemindUpdateTime;//获取上次提醒修改密码时间
var loginPolicy = await configService.GetConfigsByCategory(CateGoryConst.CONFIG_PWD_POLICY);//获取密码策略
//获取用户token列表
var tokenInfos = _simpleCacheService.HashGetOne<List<TokenInfo>>(CacheConst.CACHE_USER_TOKEN, sysUser.Id.ToString());
var userToken = tokenInfos.Where(it => it.Token == loginEvent.Token).FirstOrDefault();
if (userToken != null)
{
var subject = "请及时修改密码";
//如果上次修改密码时间为空
if (pwdRemindUpdateTime == null)
{
var pwdUpdateDefault = loginPolicy.First(x => x.ConfigKey == SysConfigConst.PWD_UPDATE_DEFAULT).ConfigValue.ToBoolean();//获取初始化提醒
//如果密码初始化提醒为true
if (pwdUpdateDefault)
{
await messageService.Add(new MessageSendInput
{
Subject = subject,
Content = "请及时修改初始密码",
Category = CateGoryConst.MESSAGE_INFORM,
ReceiverIdList = new List<long> { sysUser.Id },
SendWay = SysDictConst.SEND_WAY_NOW,
ReceiverType = SysDictConst.RECEIVER_TYPE_APPOINT,
ReceiverInfo = new List<ReceiverInfo> { new ReceiverInfo { Id = sysUser.Id, Name = sysUser.Name } }
});
}
sysUser.PwdRemindUpdateTime = DateTime.Now;//设置提醒时密码时间为当前时间
}
else
{
var pwdRemind = loginPolicy.First(x => x.ConfigKey == SysConfigConst.PWD_REMIND).ConfigValue.ToBoolean();//获取密码提醒天数
if (pwdRemind)
{
var pwdRemindDay = loginPolicy.First(x => x.ConfigKey == SysConfigConst.PWD_REMIND_DAY).ConfigValue.ToInt();//获取密码提醒时间
if (DateTime.Now - pwdRemindUpdateTime > TimeSpan.FromDays(pwdRemindDay))
{
await messageService.Add(new MessageSendInput
{
Subject = subject,
Content = $"已超过{pwdRemindDay}天未修改密码,请及时修改密码",
Category = CateGoryConst.MESSAGE_INFORM,
SendWay = SysDictConst.SEND_WAY_NOW,
ReceiverType = SysDictConst.RECEIVER_TYPE_APPOINT,
ReceiverInfo = new List<ReceiverInfo> { new ReceiverInfo { Id = sysUser.Id, Name = sysUser.Name } }
});
}
sysUser.PwdRemindUpdateTime = DateTime.Now;//设置提醒时密码时间为当前时间,避免重复提醒
}
}
}
#endregion 登录/密码策略
#region 重新赋值属性,设置本次登录信息为最新的信息
sysUser.LastLoginAddress = sysUser.LatestLoginAddress;
sysUser.LastLoginDevice = sysUser.LatestLoginDevice;
sysUser.LastLoginIp = sysUser.LatestLoginIp;
sysUser.LastLoginTime = sysUser.LatestLoginTime;
sysUser.LatestLoginAddress = loginAddress;
sysUser.LatestLoginDevice = loginEvent.Device.ToString();
sysUser.LatestLoginIp = loginEvent.Ip;
sysUser.LatestLoginTime = loginEvent.DateTime;
#endregion 重新赋值属性,设置本次登录信息为最新的信息
//更新用户登录信息
if (await _db.UpdateableWithAttr(sysUser).UpdateColumns(it => new
{
it.LastLoginAddress,
it.LastLoginDevice,
it.LastLoginIp,
it.LastLoginTime,
it.LatestLoginAddress,
it.LatestLoginDevice,
it.LatestLoginIp,
it.LatestLoginTime,
LastUpdatePwdTime = it.PwdRemindUpdateTime
}).ExecuteCommandAsync() > 0)
_simpleCacheService.HashAdd(SystemConst.CACHE_SYS_USER, sysUser.Id.ToString(), sysUser);//更新Redis信息
await Task.CompletedTask;
}
/// <summary>
/// 登出事件
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
[EventSubscribe(EventSubscriberConst.LOGIN_OUT_B)]
public async Task LoginOut(EventHandlerExecutingContext context)
{
_ = (LoginEvent)context.Source.Payload;//获取参数
}
/// <summary>
/// 解析IP地址
/// </summary>
/// <param name="ip">ip地址</param>
/// <returns></returns>
private string GetLoginAddress(string ip)
{
try
{
var ipInfo = _searcher.Search(ip).Replace("0|", "");//解析ip并格式化
return ipInfo;
}
catch
{
return "未知";
}
}
}
@@ -0,0 +1,64 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 事件总线常量
/// </summary>
public class EventSubscriberConst
{
#region AuthEventSubscriber
/// <summary>
/// B端登录
/// </summary>
public const string LOGIN_B = "B端登录";
/// <summary>
/// B端登录
/// </summary>
public const string LOGIN_OUT_B = "B端登出";
#endregion AuthEventSubscriber
#region UserEventSubscriber
/// <summary>
/// 清除用户缓存
/// </summary>
public const string CLEAR_USER_CACHE = "清除用户缓存";
/// <summary>
/// 清除组织下用户Token
/// </summary>
public const string CLEAR_ORG_TOKEN = "清除组织下用户Token";
/// <summary>
/// 清除模块下用户Token
/// </summary>
public const string CLEAR_MODULE_TOKEN = "清除模块下用户Token";
#endregion UserEventSubscriber
#region NoticeEventSubscriber
/// <summary>
/// 通知用户下线
/// </summary>
public const string USER_LOGIN_OUT = "通知用户下线";
/// <summary>
/// 新消息
/// </summary>
public const string NEW_MESSAGE = "新消息";
#endregion NoticeEventSubscriber
}
@@ -0,0 +1,54 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
using UAParser;
namespace SimpleAdmin.System;
/// <summary>
/// 登录事件参数
/// </summary>
public class LoginEvent
{
/// <summary>
/// 请求上下文
/// </summary>
public ClientInfo ClientInfo { get; set; }
/// <summary>
/// 用户信息
/// </summary>
public SysUser SysUser { get; set; }
/// <summary>
/// Ip地址
/// </summary>
public string Ip { get; set; }
/// <summary>
/// 登录设备
/// </summary>
public AuthDeviceTypeEnum Device { get; set; }
/// <summary>
/// Tokens
/// </summary>
public string Token { get; set; }
/// <summary>
/// 过期时间
/// </summary>
public int Expire { get; set; }
/// <summary>
/// 时间
/// </summary>
public DateTime DateTime = DateTime.Now;
}
@@ -0,0 +1,54 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 用户登出事件
/// </summary>
public class UserLoginOutEvent
{
/// <summary>
/// 用户Id
/// </summary>
public string UserId { get; set; }
/// <summary>
/// token信息
/// </summary>
public List<TokenInfo> TokenInfos { get; set; }
/// <summary>
/// 内容
/// </summary>
public string Message { get; set; }
}
/// <summary>
/// 新消息事件
/// </summary>
public class NewMessageEvent
{
/// <summary>
/// 消息Id
/// </summary>
public long Id { get; set; }
/// <summary>
/// 发送方式
/// </summary>
public string SendWay { get; set; }
/// <summary>
/// 发送时间
/// </summary>
public DateTime SendTime { get; set; }
}
@@ -0,0 +1,110 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
using Microsoft.Extensions.Options;
namespace SimpleAdmin.System;
/// <summary>
/// 通知事件总线
/// </summary>
public class NoticeEventSubscriber : IEventSubscriber, ISingleton
{
private readonly ISimpleCacheService _simpleCacheService;
private readonly IServiceScopeFactory _scopeFactory;
private readonly bool _useMessageCenter;
private readonly SqlSugarScope _db;
public NoticeEventSubscriber(ISimpleCacheService simpleCacheService, IServiceScopeFactory scopeFactory,
IOptionsMonitor<SystemSettingsOptions> options)
{
_db = DbContext.DB;
_simpleCacheService = simpleCacheService;
_scopeFactory = scopeFactory;
_useMessageCenter = options.CurrentValue.UseMessageCenter;
}
/// <summary>
/// 通知用户下线事件
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
[EventSubscribe(EventSubscriberConst.USER_LOGIN_OUT)]
public async Task UserLoginOut(EventHandlerExecutingContext context)
{
var loginEvent = (UserLoginOutEvent)context.Source.Payload;//获取参数
//客户端ID列表
var clientIds = new List<string>();
//遍历token列表获取客户端ID列表
loginEvent.TokenInfos.ForEach(it =>
{
clientIds.AddRange(it.ClientIds);
});
}
/// <summary>
/// 有新的消息
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
[EventSubscribe(EventSubscriberConst.NEW_MESSAGE)]
public async Task NewMessage(EventHandlerExecutingContext context)
{
var newMessageEvent = (NewMessageEvent)context.Source.Payload;//获取参数
var messageId = newMessageEvent.Id;
//如果启用了通知中心
if (_useMessageCenter)
{
if (newMessageEvent.SendWay == SysDictConst.SEND_WAY_NOW)
{
//立即发送
await SendMessage(messageId);
}
else
{
//延迟发送
var sendTime = newMessageEvent.SendTime;
//计算延迟时间
var delay = (int)(sendTime - DateTime.Now).TotalSeconds;
if (delay > 0)
{
await SendMessage(messageId, delay);
}
else
{
await SendMessage(messageId);
}
}
}
}
/// <summary>
/// 发送消息
/// </summary>
/// <param name="messageId">消息id</param>
/// <param name="delay">延迟</param>
private async Task SendMessage(long messageId, int delay = 0)
{
_simpleCacheService.AddDelayQueue(CacheConst.CACHE_NOTIFICATION, messageId, delay);
}
/// <summary>
/// 获取服务
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
private T GetService<T>() where T : class, new()
{
// 创建新的作用域
using var scope = _scopeFactory.CreateScope();
return scope.ServiceProvider.GetRequiredService<T>();
}
}
@@ -0,0 +1,108 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
using NetTaste;
using SimpleRedis;
namespace SimpleAdmin.System;
/// <summary>
/// 用户模块事件总线
/// </summary>
public class UserEventSubscriber : IEventSubscriber, ISingleton
{
private readonly IServiceProvider _services;
private readonly ISimpleCacheService _simpleCacheService;
public UserEventSubscriber(IServiceProvider services, ISimpleCacheService simpleCacheService)
{
_services = services;
_simpleCacheService = simpleCacheService;
}
/// <summary>
/// 根据角色ID列表清除用户缓存
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
[EventSubscribe(EventSubscriberConst.CLEAR_USER_CACHE)]
public async Task DeleteUserCacheByRoleIds(EventHandlerExecutingContext context)
{
var roleIds = (List<long>)context.Source.Payload;//获取角色ID
// 创建新的作用域
using var scope = _services.CreateScope();
// 解析角色服务
var relationService = scope.ServiceProvider.GetRequiredService<IRelationService>();
//获取用户和角色关系
var relations = await relationService.GetRelationListByTargetIdListAndCategory(roleIds.Select(it => it.ToString()).ToList(),
CateGoryConst.RELATION_SYS_USER_HAS_ROLE);
if (relations.Count > 0)
{
var userIds = relations.Select(it => it.ObjectId).ToList();//用户ID列表
if (userIds.Count > 0)
{
// 解析用户服务
var userService = scope.ServiceProvider.GetRequiredService<ISysUserService>();
//从redis中删除
userService.DeleteUserFromRedis(userIds);
}
}
}
/// <summary>
/// 根据机构ID列表清除用户token
/// </summary>
/// <param name="context"></param>
[EventSubscribe(EventSubscriberConst.CLEAR_ORG_TOKEN)]
public async Task DeleteUserTokenByOrgIds(EventHandlerExecutingContext context)
{
var orgIds = (List<long>)context.Source.Payload;//获取机构ID
// 创建新的作用域
using var scope = _services.CreateScope();
// 获取用户ID列表
var userIds = await DbContext.DB.QueryableWithAttr<SysUser>().Where(it => orgIds.Contains(it.OrgId)).Select(it => it.Id).ToListAsync();
//从redis中删除所属机构的用户token
_simpleCacheService.HashDel<List<Token>>(CacheConst.CACHE_USER_TOKEN, userIds.Select(it => it.ToString()).ToArray());
}
/// <summary>
/// 根据模块ID列表清除用户token
/// </summary>
/// <param name="context"></param>
[EventSubscribe(EventSubscriberConst.CLEAR_MODULE_TOKEN)]
public async Task DeleteUserTokenByModuleId(EventHandlerExecutingContext context)
{
var moduleId = (long)context.Source.Payload;//获取机构ID
// 创建新的作用域
using var scope = _services.CreateScope();
// 解析关系服务
var relationService = scope.ServiceProvider.GetRequiredService<IRelationService>();
var roleModuleRelations =
await relationService.GetRelationListByTargetIdAndCategory(moduleId.ToString(), CateGoryConst.RELATION_SYS_ROLE_HAS_MODULE);//角色模块关系
var userModuleRelations =
await relationService.GetRelationListByTargetIdAndCategory(moduleId.ToString(), CateGoryConst.RELATION_SYS_USER_HAS_MODULE);//用户模块关系
var userIds = userModuleRelations.Select(it => it.ObjectId).ToList();//用户ID列表
var roleIds = roleModuleRelations.Select(it => it.ObjectId).ToList();//角色ID列表
var userRoleRelations = await relationService.GetRelationListByTargetIdListAndCategory(roleIds.Select(it => it.ToString()).ToList(),
CateGoryConst.RELATION_SYS_USER_HAS_ROLE);//用户角色关系
userIds.AddRange(userRoleRelations.Select(it => it.ObjectId).ToList());//添加用户ID列表
// 解析用户服务
var userService = scope.ServiceProvider.GetRequiredService<ISysUserService>();
if (userIds.Count > 0)
{
//从redis中删除用户信息
userService.DeleteUserFromRedis(userIds);
//从redis中删除用户token
_simpleCacheService.HashDel<List<Token>>(CacheConst.CACHE_USER_TOKEN, userIds.Select(it => it.ToString()).ToArray());
}
}
}
@@ -0,0 +1,23 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 站内信与接收用户拓展
/// MSG_TO_USER
/// </summary>
public class RelationMsgUser
{
/// <summary>
/// 是否已读
/// </summary>
public bool Read { get; set; } = false;
}
@@ -0,0 +1,33 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// SYS_ROLE_HAS_PERMISSION
/// 角色权限关系扩展
/// </summary>
public class RelationRolePermission
{
/// <summary>
/// 数据范围
/// </summary>
public string ScopeCategory { get; set; }
/// <summary>
/// 自定义机构范围列表
/// </summary>
public List<long> ScopeDefineOrgIdList { get; set; } = new List<long>();
/// <summary>
/// 接口Url
/// </summary>
public string ApiUrl { get; set; }
}
@@ -0,0 +1,28 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// SYS_ROLE_HAS_RESOURCE
/// 角色有哪些资源扩展
/// </summary>
public class RelationRoleResource
{
/// <summary>
/// 菜单ID
/// </summary>
public long MenuId { get; set; }
/// <summary>
/// 按钮信息
/// </summary>
public List<long> ButtonInfo { get; set; } = new List<long>();
}
@@ -0,0 +1,43 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// SYS_USER_SCHEDULE_DATA
/// 用户日程扩展
/// </summary>
public class RelationUserSchedule
{
/// <summary>
/// 日程日期
/// </summary>
public virtual string ScheduleDate { get; set; }
/// <summary>
/// 日程时间
/// </summary>
public virtual string ScheduleTime { get; set; }
/// <summary>
/// 日程内容
/// </summary>
public virtual string ScheduleContent { get; set; }
/// <summary>
/// 用户id
/// </summary>
public long ScheduleUserId { get; set; }
/// <summary>
/// 用户姓名
/// </summary>
public string ScheduleUserName { get; set; }
}
@@ -0,0 +1,49 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// SYS_USER_WORKBENCH_DATA
/// 用户工作台扩展
/// </summary>
public class RelationUserWorkBench
{
/// <summary>
/// 快捷方式列表
/// </summary>
public List<WorkBenchShortcut> Shortcut { get; set; }
}
/// <summary>
/// 工作台快捷方式信息
/// </summary>
public class WorkBenchShortcut
{
/// <summary>
/// id
/// </summary>
public long Id { get; set; }
/// <summary>
/// 标题
/// </summary>
public string Title { get; set; }
/// <summary>
/// 图标
/// </summary>
public string Icon { get; set; }
/// <summary>
/// 路由地址
/// </summary>
public string Path { get; set; }
}
+43
View File
@@ -0,0 +1,43 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
global using MoYu;
global using MoYu.DataEncryption;
global using MoYu.DependencyInjection;
global using MoYu.EventBus;
global using MoYu.FriendlyException;
global using MoYu.ViewEngine;
global using Magicodes.ExporterAndImporter.Core;
global using Magicodes.ExporterAndImporter.Core.Models;
global using Magicodes.ExporterAndImporter.Excel;
global using Mapster;
global using Masuit.Tools;
global using Microsoft.AspNetCore.Http;
global using Microsoft.AspNetCore.Mvc;
global using Microsoft.Extensions.DependencyInjection;
global using Microsoft.Extensions.Logging;
global using NewLife.Serialization;
global using OfficeOpenXml.Table;
global using SimpleAdmin.Cache;
global using SimpleAdmin.Core;
global using SimpleAdmin.Core.Utils;
global using SimpleAdmin.SqlSugar;
global using SimpleTool;
global using SqlSugar;
global using System.ComponentModel.DataAnnotations;
global using System.Reflection;
global using System.Text;
global using System.Web;
global using SkiaSharp;
global using System.Runtime.InteropServices;
global using Microsoft.AspNetCore.Builder;
global using Microsoft.AspNetCore.Hosting;
global using Newtonsoft.Json.Linq;
global using NewLife;
+21
View File
@@ -0,0 +1,21 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 对象映射
/// </summary>
public class Mapper : IRegister
{
public void Register(TypeAdapterConfig config)
{
}
}
@@ -0,0 +1,29 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
using MoYu.ConfigurableOptions;
namespace SimpleAdmin.System;
/// <summary>
/// 系统配置
/// </summary>
public class SystemSettingsOptions : BaseOptions, IConfigurableOptions
{
/// <summary>
/// 超级管理员可以看到全部数据
/// </summary>
public bool SuperAdminViewAllData { get; set; }
/// <summary>
/// 启用通知中心
/// </summary>
public bool UseMessageCenter { get; set; }
}
+128
View File
@@ -0,0 +1,128 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
using Minio;
using Minio.Exceptions;
namespace SimpleAdmin.System;
/// <summary>
/// Minio功能类
/// </summary>
public class MinioUtils : ITransient
{
public MinioClient MinioClient;
private string _defaultBucketName;
private string _defaultEndPoint;
private string _defaultPrefix = "http://";
private readonly IConfigService _configService;
public MinioUtils(IConfigService configService)
{
_configService = configService;
InitClient();
}
/// <summary>
/// 初始化操作
/// </summary>
/// <returns></returns>
private async void InitClient()
{
var configs = await _configService.GetConfigsByCategory(CateGoryConst.CONFIG_FILE_MINIO);//获取minio配置
var accessKey = configs.Where(it => it.ConfigKey == SysConfigConst.FILE_MINIO_ACCESS_KEY).FirstOrDefault();//MINIO文件AccessKey
var secretKey = configs.Where(it => it.ConfigKey == SysConfigConst.FILE_MINIO_SECRET_KEY).FirstOrDefault();//MINIO文件SecretKey
var endPoint = configs.Where(it => it.ConfigKey == SysConfigConst.FILE_MINIO_END_POINT).FirstOrDefault();//MINIO文件EndPoint
var bucketName = configs.Where(it => it.ConfigKey == SysConfigConst.FILE_MINIO_DEFAULT_BUCKET_NAME).FirstOrDefault();//MINIO文件默认存储桶
if (accessKey == null || secretKey == null || endPoint == null || bucketName == null)
{
throw Oops.Oh("MINIO客户端未正确配置");
}
try
{
//默认值赋值
_defaultBucketName = bucketName.ConfigValue;
_defaultEndPoint = endPoint.ConfigValue;
if (_defaultEndPoint.ToLower().StartsWith("http"))
{
var point = _defaultEndPoint.Split("//").ToList();//分割、
_defaultPrefix = $"{point[0]}//";
_defaultEndPoint = point[1];
}
MinioClient = new MinioClient().WithEndpoint(_defaultEndPoint).WithCredentials(accessKey.ConfigValue, secretKey.ConfigValue)
.Build();//初始化minio对象
MinioClient.WithTimeout(5000);//超时时间
}
catch (Exception ex)
{
throw Oops.Oh("MINIO客户端启动失败", ex);
}
}
/// <summary>
/// 上传文件 - 返回Minio文件完整Url
/// </summary>
/// <param name="objectName">存储桶里的对象名称,例:/mnt/photos/island.jpg</param>
/// <param name="file">文件</param>
/// <param name="contentType">文件的Content type,默认是"application/octet-stream"</param>
/// <returns></returns>
public async Task<string> PutObjectAsync(string objectName, IFormFile file, string contentType = "application/octet-stream")
{
try
{
using var fileStream = file.OpenReadStream();//获取文件流
var putObjectArgs = new PutObjectArgs().WithBucket(_defaultBucketName).WithObject(objectName).WithStreamData(fileStream)
.WithObjectSize(file.Length).WithContentType(contentType);
await MinioClient.PutObjectAsync(putObjectArgs);
return $"{_defaultPrefix}{_defaultEndPoint}/{_defaultBucketName}/{objectName}";//默认http
}
catch (MinioException e)
{
throw Oops.Oh("上传文件失败!", e);
}
catch (Exception e)
{
throw Oops.Oh("上传文件失败!", e);
}
}
/// <summary>
/// 下载文件
/// </summary>
/// <param name="objectName"></param>
/// <returns></returns>
public async Task<MemoryStream> DownloadFileAsync(string objectName)
{
var stream = new MemoryStream();
try
{
var getObjectArgs = new GetObjectArgs().WithBucket(_defaultBucketName).WithObject(objectName).WithCallbackStream(cb =>
{
cb.CopyTo(stream);
});
await MinioClient.GetObjectAsync(getObjectArgs);
//UserCenter.InvalidOperationException: Response Content-Length mismatch: too few bytes written (0 of 30788)
if (stream.CanSeek)
{
stream.Seek(0, SeekOrigin.Begin);
}
return stream;
}
catch (MinioException e)
{
throw Oops.Oh("下载文件失败!", e);
}
catch (Exception e)
{
throw Oops.Oh("下载文件失败!", e);
}
}
}
@@ -0,0 +1,12 @@
namespace SimpleAdmin.System;
/// <summary>
/// 系统配置种子数据
/// </summary>
public class GenBaseSeedData : ISqlSugarEntitySeedData<GenBasic>
{
public IEnumerable<GenBasic> SeedData()
{
return SeedDataUtil.GetSeedData<GenBasic>("seed_gen_basic.json");
}
}
@@ -0,0 +1,12 @@
namespace SimpleAdmin.System;
/// <summary>
/// 系统配置种子数据
/// </summary>
public class GenConfigSeedData : ISqlSugarEntitySeedData<GenConfig>
{
public IEnumerable<GenConfig> SeedData()
{
return SeedDataUtil.GetSeedData<GenConfig>("seed_gen_config.json");
}
}
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,764 @@
{
"RECORDS": [
{
"Id": "252885263003720",
"ParentId": "0",
"DirectorId": "212725263002001",
"Name": "果冻科技有限公司",
"Names": "果冻科技有限公司",
"Code": "4fuFapeKGy",
"Category": "COMPANY",
"SortCode": "1",
"CreateTime": "2023-8-14 16:19:29.15",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "",
"UpdateUserId": "212725263002001",
"CreateUser": "",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[]"
},
{
"Id": "252885263003721",
"ParentId": "252885263003720",
"DirectorId": "",
"Name": "科技部",
"Names": "果冻科技有限公司/科技部",
"Code": "5JOEG44G62",
"Category": "DEPT",
"SortCode": "2",
"CreateTime": "2023-8-14 16:19:29.15",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "",
"UpdateUserId": "212725263002001",
"CreateUser": "",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[252885263003720]"
},
{
"Id": "252885263003722",
"ParentId": "252885263003720",
"DirectorId": "359177888051269",
"Name": "生产部",
"Names": "果冻科技有限公司/生产部",
"Code": "aln9y4tno6",
"Category": "DEPT",
"SortCode": "3",
"CreateTime": "2023-8-14 16:19:29.15",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "",
"UpdateUserId": "212725263002001",
"CreateUser": "",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[252885263003720]"
},
{
"Id": "359569393872965",
"ParentId": "0",
"DirectorId": "",
"Name": "萝卜科技有限公司",
"Names": "萝卜科技有限公司",
"Code": "l77v30V3yG",
"Category": "COMPANY",
"SortCode": "1",
"CreateTime": "2023-8-14 16:19:29.153",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[]"
},
{
"Id": "360642028625989",
"ParentId": "252885263003720",
"DirectorId": "",
"Name": "销售部",
"Names": "果冻科技有限公司/销售部",
"Code": "dihhtLuWG1",
"Category": "DEPT",
"SortCode": "4",
"CreateTime": "2023-8-14 16:19:29.153",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[252885263003720]"
},
{
"Id": "361404296994885",
"ParentId": "359569393872965",
"DirectorId": "",
"Name": "研发部",
"Names": "萝卜科技有限公司/研发部",
"Code": "fLOhh7s091",
"Category": "DEPT",
"SortCode": "99",
"CreateTime": "2023-8-14 16:19:29.153",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[359569393872965]"
},
{
"Id": "361404346445893",
"ParentId": "359569393872965",
"DirectorId": "",
"Name": "财务部",
"Names": "萝卜科技有限公司/财务部",
"Code": "tmDWFRfXuQ",
"Category": "DEPT",
"SortCode": "99",
"CreateTime": "2023-8-14 16:19:29.153",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[359569393872965]"
},
{
"Id": "464837351616581",
"ParentId": "252885263003721",
"DirectorId": "",
"Name": "科技一部",
"Names": "果冻科技有限公司/科技部/科技一部",
"Code": "Mzv2sj1MEo",
"Category": "DEPT",
"SortCode": "99",
"CreateTime": "2023-9-25 22:08:03.567",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[252885263003720,252885263003721]"
},
{
"Id": "464837557956677",
"ParentId": "464837351616581",
"DirectorId": "",
"Name": "科技一部1组",
"Names": "果冻科技有限公司/科技部/科技一部/科技一部1组",
"Code": "g6R7zuMMk4",
"Category": "DEPT",
"SortCode": "99",
"CreateTime": "2023-9-25 22:08:53.943",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[252885263003720,252885263003721,464837351616581]"
},
{
"Id": "479974472933445",
"ParentId": "359569393872965",
"DirectorId": "",
"Name": "销售部",
"Names": "萝卜科技有限公司/销售部",
"Code": "jjQ1i8btel",
"Category": "DEPT",
"SortCode": "4",
"CreateTime": "2023-11-7 16:41:09.83",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[359569393872965]"
},
{
"Id": "485978445475909",
"ParentId": "252885263003722",
"DirectorId": "",
"Name": "生产一部",
"Names": "果冻科技有限公司/生产部/生产一部",
"Code": "fHsgj48J0D",
"Category": "DEPT",
"SortCode": "99",
"CreateTime": "2023-11-24 15:51:23.437",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[252885263003720,252885263003722]"
},
{
"Id": "487320043610181",
"ParentId": "359569393872965",
"DirectorId": "",
"Name": "科技部",
"Names": "萝卜科技有限公司/科技部",
"Code": "1QWox5893Q",
"Category": "DEPT",
"SortCode": "2",
"CreateTime": "2023-11-28 10:50:49.177",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[359569393872965]"
},
{
"Id": "487320070803525",
"ParentId": "487320043610181",
"DirectorId": "",
"Name": "科技一部",
"Names": "萝卜科技有限公司/科技部/科技一部",
"Code": "fIaBZ15osx",
"Category": "DEPT",
"SortCode": "99",
"CreateTime": "2023-11-28 10:50:49.18",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[359569393872965,487320043610181]"
},
{
"Id": "510752889880645",
"ParentId": "0",
"DirectorId": "",
"Name": "旺仔科技有限公司",
"Names": "旺仔科技有限公司",
"Code": "wz",
"Category": "COMPANY",
"SortCode": "99",
"CreateTime": "2024-2-2 15:58:51.777",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[]"
},
{
"Id": "510753093025861",
"ParentId": "0",
"DirectorId": "",
"Name": "达达科技有限公司",
"Names": "达达科技有限公司",
"Code": "dd",
"Category": "COMPANY",
"SortCode": "99",
"CreateTime": "2024-2-2 15:59:41.373",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[]"
},
{
"Id": "510753219502149",
"ParentId": "0",
"DirectorId": "",
"Name": "杰尼科技有限公司",
"Names": "杰尼科技有限公司",
"Code": "jn",
"Category": "DEPT",
"SortCode": "99",
"CreateTime": "2024-2-2 16:00:12.25",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[]"
},
{
"Id": "510753479417925",
"ParentId": "510752889880645",
"DirectorId": "",
"Name": "科技部",
"Names": "旺仔科技有限公司/科技部",
"Code": "oNSxenwpqn",
"Category": "DEPT",
"SortCode": "2",
"CreateTime": "2024-2-2 16:01:15.713",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[510752889880645]"
},
{
"Id": "510753479422021",
"ParentId": "510753479417925",
"DirectorId": "",
"Name": "科技一部",
"Names": "旺仔科技有限公司/科技部/科技一部",
"Code": "j83kVrfVD0",
"Category": "DEPT",
"SortCode": "99",
"CreateTime": "2024-2-2 16:01:15.713",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[510752889880645,510753479417925]"
},
{
"Id": "510753479422022",
"ParentId": "510753479422021",
"DirectorId": "",
"Name": "科技一部1组",
"Names": "旺仔科技有限公司/科技部/科技一部/科技一部1组",
"Code": "93BGNo5HXE",
"Category": "DEPT",
"SortCode": "99",
"CreateTime": "2024-2-2 16:01:15.713",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[510752889880645,510753479417925,510753479422021]"
},
{
"Id": "510753479422023",
"ParentId": "510752889880645",
"DirectorId": "359177888051269",
"Name": "生产部",
"Names": "旺仔科技有限公司/生产部",
"Code": "2l3276Q5Tg",
"Category": "DEPT",
"SortCode": "3",
"CreateTime": "2024-2-2 16:01:15.713",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[510752889880645]"
},
{
"Id": "510753479426117",
"ParentId": "510753479422023",
"DirectorId": "",
"Name": "生产一部",
"Names": "旺仔科技有限公司/生产部/生产一部",
"Code": "298gdc2Oy6",
"Category": "DEPT",
"SortCode": "99",
"CreateTime": "2024-2-2 16:01:15.713",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[510752889880645,510753479422023]"
},
{
"Id": "510753479430213",
"ParentId": "510752889880645",
"DirectorId": "",
"Name": "销售部",
"Names": "旺仔科技有限公司/销售部",
"Code": "qEB7a8wtP3",
"Category": "DEPT",
"SortCode": "4",
"CreateTime": "2024-2-2 16:01:15.713",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[510752889880645]"
},
{
"Id": "510753515745349",
"ParentId": "510753093025861",
"DirectorId": "",
"Name": "科技部",
"Names": "达达科技有限公司/科技部",
"Code": "LMB0GjrOM8",
"Category": "DEPT",
"SortCode": "2",
"CreateTime": "2024-2-2 16:01:24.577",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[510753093025861]"
},
{
"Id": "510753515745350",
"ParentId": "510753515745349",
"DirectorId": "",
"Name": "科技一部",
"Names": "达达科技有限公司/科技部/科技一部",
"Code": "mgd2SJ35jH",
"Category": "DEPT",
"SortCode": "99",
"CreateTime": "2024-2-2 16:01:24.577",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[510753093025861,510753515745349]"
},
{
"Id": "510753515745351",
"ParentId": "510753515745350",
"DirectorId": "",
"Name": "科技一部1组",
"Names": "达达科技有限公司/科技部/科技一部/科技一部1组",
"Code": "jQ5ymWaxz1",
"Category": "DEPT",
"SortCode": "99",
"CreateTime": "2024-2-2 16:01:24.577",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[510753093025861,510753515745349,510753515745350]"
},
{
"Id": "510753515749445",
"ParentId": "510753093025861",
"DirectorId": "359177888051269",
"Name": "生产部",
"Names": "达达科技有限公司/生产部",
"Code": "nNmBAfO2dG",
"Category": "DEPT",
"SortCode": "3",
"CreateTime": "2024-2-2 16:01:24.577",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[510753093025861]"
},
{
"Id": "510753515749446",
"ParentId": "510753515749445",
"DirectorId": "",
"Name": "生产一部",
"Names": "达达科技有限公司/生产部/生产一部",
"Code": "D37d9K1QMn",
"Category": "DEPT",
"SortCode": "99",
"CreateTime": "2024-2-2 16:01:24.577",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[510753093025861,510753515749445]"
},
{
"Id": "510753515749447",
"ParentId": "510753093025861",
"DirectorId": "",
"Name": "销售部",
"Names": "达达科技有限公司/销售部",
"Code": "Jt6ZJfT4g2",
"Category": "DEPT",
"SortCode": "4",
"CreateTime": "2024-2-2 16:01:24.577",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[510753093025861]"
},
{
"Id": "510753541705799",
"ParentId": "510753219502149",
"DirectorId": "359177888051269",
"Name": "生产部",
"Names": "杰尼科技有限公司/生产部",
"Code": "LuOvsCpXL9",
"Category": "DEPT",
"SortCode": "3",
"CreateTime": "2024-2-2 16:01:30.917",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[510753219502149]"
},
{
"Id": "510753541709893",
"ParentId": "510753541705799",
"DirectorId": "",
"Name": "生产一部",
"Names": "杰尼科技有限公司/生产部/生产一部",
"Code": "3jz7oH2YdB",
"Category": "DEPT",
"SortCode": "99",
"CreateTime": "2024-2-2 16:01:30.92",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[510753219502149,510753541705799]"
},
{
"Id": "510753541709894",
"ParentId": "510753219502149",
"DirectorId": "",
"Name": "销售部",
"Names": "杰尼科技有限公司/销售部",
"Code": "1175P8fpKj",
"Category": "DEPT",
"SortCode": "4",
"CreateTime": "2024-2-2 16:01:30.92",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[510753219502149]"
},
{
"Id": "516762847445061",
"ParentId": "510753219502149",
"DirectorId": "",
"Name": "科技部",
"Names": "杰尼科技有限公司/科技部",
"Code": "aixpW3fg7h",
"Category": "DEPT",
"SortCode": "2",
"CreateTime": "2024-2-19 15:33:26.577",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[510753219502149]"
},
{
"Id": "516762847465541",
"ParentId": "516762847445061",
"DirectorId": "",
"Name": "科技一部",
"Names": "杰尼科技有限公司/科技部/科技一部",
"Code": "8IGvu1YbVv",
"Category": "DEPT",
"SortCode": "99",
"CreateTime": "2024-2-19 15:33:26.58",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[510753219502149,516762847445061]"
},
{
"Id": "516762847465542",
"ParentId": "516762847465541",
"DirectorId": "",
"Name": "科技一部1组",
"Names": "杰尼科技有限公司/科技部/科技一部/科技一部1组",
"Code": "7i2xo2x63S",
"Category": "DEPT",
"SortCode": "99",
"CreateTime": "2024-2-19 15:33:26.58",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[510753219502149,516762847445061,516762847465541]"
},
{
"Id": "517088662995013",
"ParentId": "510752889880645",
"DirectorId": "",
"Name": "研发部",
"Names": "旺仔科技有限公司/研发部",
"Code": "28s3SaDA24",
"Category": "DEPT",
"SortCode": "99",
"CreateTime": "2024-2-20 13:39:11.383",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "511724553736261",
"UpdateUserId": "",
"CreateUser": "旺仔科技管理员",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[510752889880645]"
},
{
"Id": "517125532377157",
"ParentId": "510753219502149",
"DirectorId": "212725263002001",
"Name": "果冻科技有限公司",
"Names": "杰尼科技有限公司/果冻科技有限公司",
"Code": "1wfUJ6288S",
"Category": "COMPANY",
"SortCode": "1",
"CreateTime": "2024-2-20 16:09:12.727",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "",
"CreateUser": "superAdmin",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[510753219502149]"
},
{
"Id": "517129906487365",
"ParentId": "510753219502149",
"DirectorId": "",
"Name": "研发部",
"Names": "杰尼科技有限公司/研发部",
"Code": "OMkYEanrD3",
"Category": "DEPT",
"SortCode": "99",
"CreateTime": "2024-2-20 16:27:02.277",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "",
"CreateUser": "superAdmin",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[510753219502149]"
},
{
"Id": "517130541625413",
"ParentId": "252885263003720",
"DirectorId": "",
"Name": "研发部",
"Names": "果冻科技有限公司/研发部",
"Code": "Ql894KJrdb",
"Category": "DEPT",
"SortCode": "99",
"CreateTime": "2024-2-20 16:29:35.677",
"UpdateTime": "2024-7-23 09:09:40.967",
"CreateUserId": "212725263002001",
"UpdateUserId": "",
"CreateUser": "superAdmin",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE",
"ParentIdList": "[252885263003720]"
}
]
}
@@ -0,0 +1,328 @@
{
"RECORDS": [
{
"Id": "212725263003001",
"OrgId": "252885263003720",
"Name": "董事长",
"Code": "rsz5dmh762",
"Category": "HIGH",
"SortCode": "1",
"CreateOrgId": "252885263003720",
"CreateTime": "2023-8-14 16:19:29.213",
"UpdateTime": "2024-7-23 09:09:41.073",
"CreateUserId": "",
"UpdateUserId": "",
"CreateUser": "",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE"
},
{
"Id": "212725263003002",
"OrgId": "252885263003720",
"Name": "总经理",
"Code": "wo1araqs2z",
"Category": "HIGH",
"SortCode": "2",
"CreateOrgId": "252885263003720",
"CreateTime": "2023-8-14 16:19:29.217",
"UpdateTime": "2024-7-23 09:09:41.073",
"CreateUserId": "",
"UpdateUserId": "",
"CreateUser": "",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE"
},
{
"Id": "212725263003003",
"OrgId": "252885263003720",
"Name": "副总经理",
"Code": "asqvwbsc16",
"Category": "HIGH",
"SortCode": "3",
"CreateOrgId": "252885263003720",
"CreateTime": "2023-8-14 16:19:29.217",
"UpdateTime": "2024-7-23 09:09:41.073",
"CreateUserId": "",
"UpdateUserId": "",
"CreateUser": "",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE"
},
{
"Id": "212725263003004",
"OrgId": "252885263003720",
"Name": "总经理助理",
"Code": "aln9y4tno6",
"Category": "HIGH",
"SortCode": "4",
"CreateOrgId": "252885263003720",
"CreateTime": "2023-8-14 16:19:29.217",
"UpdateTime": "2024-7-23 09:09:41.073",
"CreateUserId": "",
"UpdateUserId": "",
"CreateUser": "",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE"
},
{
"Id": "212725263003005",
"OrgId": "252885263003720",
"Name": "部门经理",
"Code": "krq0kj7oio",
"Category": "MIDDLE",
"SortCode": "5",
"CreateOrgId": "252885263003720",
"CreateTime": "2023-8-14 16:19:29.217",
"UpdateTime": "2024-7-23 09:09:41.073",
"CreateUserId": "",
"UpdateUserId": "",
"CreateUser": "",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE"
},
{
"Id": "359569658515525",
"OrgId": "359569393872965",
"Name": "总经理",
"Code": "4fuFapeKGy",
"Category": "MIDDLE",
"SortCode": "99",
"CreateOrgId": "0",
"CreateTime": "2023-8-14 16:19:29.217",
"UpdateTime": "2024-7-23 09:09:41.073",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE"
},
{
"Id": "360728646910021",
"OrgId": "360642028625989",
"Name": "销售主管",
"Code": "Zq1KvX44WN",
"Category": "MIDDLE",
"SortCode": "99",
"CreateOrgId": "0",
"CreateTime": "2023-8-14 16:19:29.217",
"UpdateTime": "2024-7-23 09:09:41.073",
"CreateUserId": "212725263002001",
"UpdateUserId": "",
"CreateUser": "",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE"
},
{
"Id": "361407055544389",
"OrgId": "252885263003720",
"Name": "普通员工",
"Code": "1Cy6JUDzeL",
"Category": "LOW",
"SortCode": "99",
"CreateOrgId": "252885263003720",
"CreateTime": "2023-8-14 16:19:29.217",
"UpdateTime": "2024-7-23 09:09:41.073",
"CreateUserId": "212725263002001",
"UpdateUserId": "",
"CreateUser": "",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE"
},
{
"Id": "361414036955205",
"OrgId": "361404296994885",
"Name": "研发人员",
"Code": "AImZqb6j2X",
"Category": "LOW",
"SortCode": "99",
"CreateOrgId": "252885263003720",
"CreateTime": "2023-8-14 16:19:29.217",
"UpdateTime": "2024-7-23 09:09:41.073",
"CreateUserId": "212725263002001",
"UpdateUserId": "",
"CreateUser": "",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE"
},
{
"Id": "361414093332549",
"OrgId": "361404346445893",
"Name": "财务总监",
"Code": "5JOEG44G62",
"Category": "HIGH",
"SortCode": "99",
"CreateOrgId": "252885263003720",
"CreateTime": "2023-8-14 16:19:29.217",
"UpdateTime": "2024-7-23 09:09:41.073",
"CreateUserId": "212725263002001",
"UpdateUserId": "",
"CreateUser": "",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE"
},
{
"Id": "361415094177861",
"OrgId": "361404296994885",
"Name": "项目经理",
"Code": "AmOE17p37x",
"Category": "MIDDLE",
"SortCode": "99",
"CreateOrgId": "252885263003720",
"CreateTime": "2023-8-14 16:19:29.217",
"UpdateTime": "2024-7-23 09:09:41.073",
"CreateUserId": "212725263002001",
"UpdateUserId": "",
"CreateUser": "",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE"
},
{
"Id": "485593012985925",
"OrgId": "464837557956677",
"Name": "组长",
"Code": "YWUz4Fc794",
"Category": "HIGH",
"SortCode": "99",
"CreateOrgId": "252885263003720",
"CreateTime": "2023-11-23 13:43:03.707",
"UpdateTime": "2024-7-23 09:09:41.073",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE"
},
{
"Id": "511723823370309",
"OrgId": "510752889880645",
"Name": "职工",
"Code": "2KVZ6Uz3ne",
"Category": "LOW",
"SortCode": "99",
"CreateOrgId": "252885263003720",
"CreateTime": "2024-2-5 09:49:36.083",
"UpdateTime": "2024-7-23 09:09:41.073",
"CreateUserId": "212725263002001",
"UpdateUserId": "",
"CreateUser": "superAdmin",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE"
},
{
"Id": "511723919061061",
"OrgId": "510753093025861",
"Name": "董事长",
"Code": "4RbqYeVTG7",
"Category": "HIGH",
"SortCode": "99",
"CreateOrgId": "252885263003720",
"CreateTime": "2024-2-5 09:49:59.447",
"UpdateTime": "2024-7-23 09:09:41.073",
"CreateUserId": "212725263002001",
"UpdateUserId": "",
"CreateUser": "superAdmin",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE"
},
{
"Id": "511723963043909",
"OrgId": "510753219502149",
"Name": "董事长",
"Code": "50wshEGBxd",
"Category": "HIGH",
"SortCode": "99",
"CreateOrgId": "252885263003720",
"CreateTime": "2024-2-5 09:50:10.187",
"UpdateTime": "2024-7-23 09:09:41.073",
"CreateUserId": "212725263002001",
"UpdateUserId": "",
"CreateUser": "superAdmin",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE"
},
{
"Id": "517095081300037",
"OrgId": "517088662995013",
"Name": "研发部经理",
"Code": "KXs5l2W2v9",
"Category": "HIGH",
"SortCode": "99",
"CreateOrgId": "510752889880645",
"CreateTime": "2024-2-20 14:05:18.353",
"UpdateTime": "2024-7-23 09:09:41.073",
"CreateUserId": "511724553736261",
"UpdateUserId": "",
"CreateUser": "旺仔科技管理员",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE"
},
{
"Id": "517129906495557",
"OrgId": "517129906487365",
"Name": "研发部经理",
"Code": "KXs5A2W3v9",
"Category": "HIGH",
"SortCode": "99",
"CreateOrgId": "252885263003720",
"CreateTime": "2024-2-20 16:27:02.323",
"UpdateTime": "2024-7-23 09:09:41.073",
"CreateUserId": "212725263002001",
"UpdateUserId": "212725263002001",
"CreateUser": "superAdmin",
"UpdateUser": "superAdmin",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE"
},
{
"Id": "517130541629509",
"OrgId": "517130541625413",
"Name": "研发部经理",
"Code": "0EyfLIDRJC",
"Category": "HIGH",
"SortCode": "99",
"CreateOrgId": "252885263003720",
"CreateTime": "2024-2-20 16:29:35.687",
"UpdateTime": "2024-7-23 09:09:41.073",
"CreateUserId": "212725263002001",
"UpdateUserId": "",
"CreateUser": "superAdmin",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE"
}
]
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,175 @@
{
"RECORDS": [
{
"Id": "212725263001001",
"OrgId": "",
"Name": "超级管理员",
"Code": "superAdmin",
"Category": "GLOBAL",
"DefaultDataScope": "{\"Level\":5,\"ScopeCategory\":\"SCOPE_ALL\",\"ScopeDefineOrgIdList\":[]}",
"SortCode": "1",
"CreateOrgId": "0",
"CreateTime": "2023-8-14 16:19:29.82",
"UpdateTime": "2024-7-23 09:09:42.077",
"CreateUserId": "",
"UpdateUserId": "",
"CreateUser": "",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE"
},
{
"Id": "212725263001002",
"OrgId": "",
"Name": "业务管理员",
"Code": "bizAdmin",
"Category": "GLOBAL",
"DefaultDataScope": "{\"Level\":5,\"ScopeCategory\":\"SCOPE_ALL\",\"ScopeDefineOrgIdList\":[]}",
"SortCode": "1",
"CreateOrgId": "0",
"CreateTime": "2023-8-14 16:19:29.9",
"UpdateTime": "2024-7-23 09:09:42.077",
"CreateUserId": "",
"UpdateUserId": "",
"CreateUser": "",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE"
},
{
"Id": "359567292014661",
"OrgId": "",
"Name": "所属组织及以下角色",
"Code": "41fP9R7YZI",
"Category": "GLOBAL",
"DefaultDataScope": "{\"Level\":4,\"ScopeCategory\":\"SCOPE_ORG_CHILD\",\"ScopeDefineOrgIdList\":[]}",
"SortCode": "99",
"CreateOrgId": "0",
"CreateTime": "2023-8-14 16:19:29.9",
"UpdateTime": "2024-7-23 09:09:42.077",
"CreateUserId": "",
"UpdateUserId": "212725263002001",
"CreateUser": "",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE"
},
{
"Id": "360645671104581",
"OrgId": "",
"Name": "所属组织角色",
"Code": "KtIpet8uq0",
"Category": "GLOBAL",
"DefaultDataScope": "{\"Level\":2,\"ScopeCategory\":\"SCOPE_ORG\",\"ScopeDefineOrgIdList\":[360642028625989,361404296994885]}",
"SortCode": "99",
"CreateOrgId": "0",
"CreateTime": "2023-8-14 16:19:29.9",
"UpdateTime": "2024-7-23 09:09:42.077",
"CreateUserId": "",
"UpdateUserId": "212725263002001",
"CreateUser": "",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE"
},
{
"Id": "360646281904197",
"OrgId": "",
"Name": "自定义组织角色",
"Code": "9b774qzY92",
"Category": "GLOBAL",
"DefaultDataScope": "{\"Level\":3,\"ScopeCategory\":\"SCOPE_ORG_DEFINE\",\"ScopeDefineOrgIdList\":[360642028625989,361404296994885,360642028625989,361404296994885]}",
"SortCode": "99",
"CreateOrgId": "0",
"CreateTime": "2023-8-14 16:19:29.903",
"UpdateTime": "2024-7-23 09:09:42.077",
"CreateUserId": "",
"UpdateUserId": "212725263002001",
"CreateUser": "",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE"
},
{
"Id": "360646662586437",
"OrgId": "",
"Name": "仅自己角色",
"Code": "182293I1ZC",
"Category": "GLOBAL",
"DefaultDataScope": "{\"Level\":1,\"ScopeCategory\":\"SCOPE_SELF\",\"ScopeDefineOrgIdList\":[]}",
"SortCode": "99",
"CreateOrgId": "0",
"CreateTime": "2023-8-14 16:19:29.903",
"UpdateTime": "2024-7-23 09:09:42.077",
"CreateUserId": "",
"UpdateUserId": "",
"CreateUser": "",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE"
},
{
"Id": "363084914917445",
"OrgId": "361404296994885",
"Name": "研发部管理员",
"Code": "sfEg40KhpZ",
"Category": "ORG",
"DefaultDataScope": "{\"Level\":4,\"ScopeCategory\":\"SCOPE_ORG_CHILD\",\"ScopeDefineOrgIdList\":[]}",
"SortCode": "99",
"CreateOrgId": "252885263003720",
"CreateTime": "2023-8-14 16:19:29.903",
"UpdateTime": "2024-7-23 09:09:42.077",
"CreateUserId": "212725263002001",
"UpdateUserId": "",
"CreateUser": "",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE"
},
{
"Id": "511793641513029",
"OrgId": "",
"Name": "租户管理员",
"Code": "1q8bMS9rgF",
"Category": "GLOBAL",
"DefaultDataScope": "{\"Level\":4,\"ScopeCategory\":\"SCOPE_ORG_CHILD\",\"ScopeDefineOrgIdList\":[]}",
"SortCode": "99",
"CreateOrgId": "252885263003720",
"CreateTime": "2024-2-5 14:33:41.53",
"UpdateTime": "2024-7-23 09:09:42.077",
"CreateUserId": "212725263002001",
"UpdateUserId": "",
"CreateUser": "superAdmin",
"UpdateUser": "",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE"
},
{
"Id": "517794467639365",
"OrgId": "510752889880645",
"Name": "测试",
"Code": "pwrxO3v8X5",
"Category": "ORG",
"DefaultDataScope": "{\"Level\":4,\"ScopeCategory\":\"SCOPE_ORG_CHILD\",\"ScopeDefineOrgIdList\":[]}",
"SortCode": "99",
"CreateOrgId": "510752889880645",
"CreateTime": "2024-2-22 13:31:06.97",
"UpdateTime": "2024-7-23 09:09:42.077",
"CreateUserId": "511724553736261",
"UpdateUserId": "511724553736261",
"CreateUser": "旺仔科技管理员",
"UpdateUser": "旺仔科技管理员",
"IsDelete": "0",
"ExtJson": "",
"Status": "ENABLE"
}
]
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,22 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 系统配置种子数据
/// </summary>
public class SysConfigSeedData : ISqlSugarEntitySeedData<SysConfig>
{
public IEnumerable<SysConfig> SeedData()
{
return SeedDataUtil.GetSeedData<SysConfig>("seed_sys_config.json");
}
}
@@ -0,0 +1,22 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 字典表种子数据
/// </summary>
public class SysDictSeedData : ISqlSugarEntitySeedData<SysDict>
{
public IEnumerable<SysDict> SeedData()
{
return SeedDataUtil.GetSeedData<SysDict>("seed_sys_dict.json");
}
}
@@ -0,0 +1,22 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 机构种子数据
/// </summary>
public class SysOrgSeedData : ISqlSugarEntitySeedData<SysOrg>
{
public IEnumerable<SysOrg> SeedData()
{
return SeedDataUtil.GetSeedData<SysOrg>("seed_sys_org.json");
}
}
@@ -0,0 +1,22 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 职位表种子数据
/// </summary>
public class SysPositionSeedData : ISqlSugarEntitySeedData<SysPosition>
{
public IEnumerable<SysPosition> SeedData()
{
return SeedDataUtil.GetSeedData<SysPosition>("seed_sys_position.json");
}
}
@@ -0,0 +1,22 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 关系表种子数据
/// </summary>
public class SysRelationSeedData : ISqlSugarEntitySeedData<SysRelation>
{
public IEnumerable<SysRelation> SeedData()
{
return SeedDataUtil.GetSeedData<SysRelation>("seed_sys_relation.json");
}
}
@@ -0,0 +1,22 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 资源表种子数据
/// </summary>
public class SysResourceSeedData : ISqlSugarEntitySeedData<SysResource>
{
public IEnumerable<SysResource> SeedData()
{
return SeedDataUtil.GetSeedData<SysResource>("seed_sys_resource.json");
}
}
@@ -0,0 +1,22 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 角色种子数据
/// </summary>
public class SysRoleSeedData : ISqlSugarEntitySeedData<SysRole>
{
public IEnumerable<SysRole> SeedData()
{
return SeedDataUtil.GetSeedData<SysRole>("seed_sys_role.json");
}
}
@@ -0,0 +1,22 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 用户表种子数据
/// </summary>
public class SysUserSeedData : ISqlSugarEntitySeedData<SysUser>
{
public IEnumerable<SysUser> SeedData()
{
return SeedDataUtil.GetSeedData<SysUser>("seed_sys_user.json");
}
}
@@ -0,0 +1,502 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System.Services.Auth;
/// <inheritdoc cref="IAuthService"/>
public class AuthService : IAuthService
{
private readonly ISimpleCacheService _simpleCacheService;
private readonly IEventPublisher _eventPublisher;
private readonly IConfigService _configService;
private readonly ISysUserService _userService;
private readonly ISysOrgService _sysOrgService;
public AuthService(ISimpleCacheService simpleCacheService, IEventPublisher eventPublisher, IConfigService configService,
ISysUserService userService, ISysOrgService sysOrgService)
{
_simpleCacheService = simpleCacheService;
_eventPublisher = eventPublisher;
_configService = configService;
_userService = userService;
_sysOrgService = sysOrgService;
}
/// <inheritdoc/>
public async Task<PicValidCodeOutPut> GetCaptchaInfo()
{
var config = await _configService.GetByConfigKey(CateGoryConst.CONFIG_LOGIN_POLICY, SysConfigConst.LOGIN_CAPTCHA_TYPE);
var captchaType = (CaptchaType)Enum.Parse(typeof(CaptchaType), config.ConfigValue);
//生成验证码
var captchaInfo = CaptchaUtil.CreateCaptcha(captchaType, 4, 100, 38);
//生成请求号,并将验证码放入缓存
var reqNo = AddValidCodeToRedis(captchaInfo.Code);
//返回验证码和请求号
return new PicValidCodeOutPut
{
ValidCodeBase64 = captchaInfo.Base64Str,
ValidCodeReqNo = reqNo
};
}
/// <inheritdoc/>
public async Task<string> GetPhoneValidCode(GetPhoneValidCodeInput input, LoginClientTypeEnum loginClientType)
{
await ValidPhoneValidCode(input, loginClientType);//校验手机号验证码
var phoneValidCode = RandomHelper.CreateNum(6);//生产随机数字;
#region 发送短信和记录数据库等操作
//这里为什么不封装阿里云或者腾讯云短信接口,是因为短信发送是一个通用功能,一般每个公司都有自己封装好的短信组件来适配各种项目,这里再封装一次显得多余了。
//这里不建议在该系统中封装短信发送接口,当然后续如果确实有需要也会增加
//这里执行发送短信验证码代码,这里先默认就是年月日
phoneValidCode = DateTime.Now.ToString("yyMMdd");
#endregion 发送短信和记录数据库等操作
//生成请求号,并将验证码放入缓存
var reqNo = AddValidCodeToRedis(phoneValidCode);
return reqNo;
}
/// <inheritdoc/>
public async Task<LoginOutPut> Login(LoginInput input, LoginClientTypeEnum loginClientType)
{
await CheckCaptcha(input);//检查验证码
await CheckWebOpen(input);//检查网站是否开启
var password = CryptogramUtil.Sm2Decrypt(input.Password);//SM2解密
//获取多租户配置
var isTenant = await _configService.IsTenant();
//获取登录策略
var loginPolicy = await _configService.GetConfigsByCategory(CateGoryConst.CONFIG_LOGIN_POLICY);
await BeforeLogin(loginPolicy, input, isTenant);//登录前校验
// 根据账号获取用户信息,根据B端或C端判断
if (loginClientType == LoginClientTypeEnum.B)//如果是B端
{
var userInfo = await _userService.GetUserByAccount(input.Account, input.TenantId);//获取用户信息
if (userInfo == null) throw Oops.Bah("用户不存在");//用户不存在
if (userInfo.Password != password)
{
LoginError(loginPolicy, input, isTenant);//登录错误操作
throw Oops.Bah("账号密码错误");//账号密码错误
}
var result = await ExecLoginB(userInfo, input.Device, loginClientType, input.TenantId);// 执行B端登录
return result;
}
//执行c端登录
return null;
}
/// <inheritdoc/>
public async Task<LoginOutPut> LoginByPhone(LoginByPhoneInput input, LoginClientTypeEnum loginClientType)
{
await ValidPhoneValidCode(input, loginClientType, false);//校验手机号和验证码,这里不删除Redis,防止输入错误又要重新输入验证码
// 根据手机号获取用户信息,根据B端或C端判断
if (loginClientType == LoginClientTypeEnum.B)//如果是B端
{
var userInfo = await _userService.GetUserByPhone(input.Phone);//获取信息
if (userInfo == null) throw Oops.Bah("用户不存在");//用户不存在
var result = await ExecLoginB(userInfo, input.Device, loginClientType, input.TenantId);// 执行B端登录
RemoveValidCodeFromRedis(input.ValidCodeReqNo);//删除验证码
return result;
}
//执行c端登录
return null;
}
/// <inheritdoc/>
public async Task LoginOut(string token, LoginClientTypeEnum loginClientType)
{
//获取用户信息
var userinfo = await _userService.GetUserByAccount(UserManager.UserAccount, UserManager.TenantId);
if (userinfo != null)
{
var loginEvent = new LoginEvent
{
Ip = App.HttpContext.GetRemoteIpAddressToIPv4(),
SysUser = userinfo,
Token = token
};
RemoveTokenFromRedis(loginEvent, loginClientType);//移除token
//发布登出事件总线
await _eventPublisher.PublishAsync(EventSubscriberConst.LOGIN_OUT_B, loginEvent);
}
}
/// <inheritdoc/>
public async Task<LoginUserOutput> GetLoginUser()
{
var userInfo = await _userService.GetUserByAccount(UserManager.UserAccount, UserManager.TenantId);//根据账号获取用户信息
if (userInfo != null)
{
userInfo.Avatar = await _userService.GetUserAvatar(userInfo.Id);//获取头像
return userInfo.Adapt<LoginUserOutput>();
}
return null;
}
#region 方法
/// <summary>
/// 检查验证码
/// </summary>
/// <param name="input"></param>
/// <exception cref="AppFriendlyException"></exception>
public async Task CheckCaptcha(LoginInput input)
{
//判断是否有验证码
var sysBase = await _configService.GetByConfigKey(CateGoryConst.CONFIG_LOGIN_POLICY, SysConfigConst.LOGIN_CAPTCHA_OPEN);
if (sysBase != null)//如果有这个配置项
{
if (sysBase.ConfigValue.ToBoolean())//如果需要验证码
{
//如果没填验证码,提示验证码不能为空
if (string.IsNullOrEmpty(input.ValidCode) || string.IsNullOrEmpty(input.ValidCodeReqNo))
throw Oops.Bah("验证码不能为空").StatusCode(410);
ValidValidCode(input.ValidCode, input.ValidCodeReqNo);//校验验证码
}
}
}
/// <summary>
/// 检查网站是否开启
/// </summary>
/// <param name="input"></param>
/// <exception cref="AppFriendlyException"></exception>
public async Task CheckWebOpen(LoginInput input)
{
//判断是否开启web访问
var webStatus = await _configService.GetByConfigKey(CateGoryConst.CONFIG_SYS_BASE, SysConfigConst.SYS_WEB_STATUS);
if (webStatus != null && webStatus.ConfigValue == CommonStatusConst.DISABLED
&& input.Account.ToLower() != SysRoleConst.SUPER_ADMIN.ToLower())//如果禁用了网站并且不是超级管理员
{
var closePrompt = await _configService.GetByConfigKey(CateGoryConst.CONFIG_SYS_BASE, SysConfigConst.SYS_WEB_CLOSE_PROMPT);
throw Oops.Bah(closePrompt.ConfigValue);
}
}
/// <summary>
/// 登录之前执行的方法
/// </summary>
/// <param name="loginPolicy"></param>
/// <param name="input"></param>
/// <param name="isTenant"></param>
public async Task BeforeLogin(List<SysConfig> loginPolicy, LoginInput input, bool isTenant)
{
var lockTime = loginPolicy.First(x => x.ConfigKey == SysConfigConst.LOGIN_ERROR_LOCK).ConfigValue.ToInt();//获取锁定时间
var errorCount = loginPolicy.First(x => x.ConfigKey == SysConfigConst.LOGIN_ERROR_COUNT).ConfigValue.ToInt();//获取错误次数
var key = SystemConst.CACHE_LOGIN_ERROR_COUNT;//获取登录错误次数Key值
//如果是关闭多租户则直接用账号
if (!isTenant)
key += input.Account;
else
{
//如果租户ID为空表示用域名登录
if (input.TenantId == null)
{
//获取域名
var origin = App.HttpContext.Request.Headers["Origin"].ToString();
// 如果Origin头不存在,可以尝试使用Referer头作为备选
if (string.IsNullOrEmpty(origin))
origin = App.HttpContext.Request.Headers["Referer"].ToString();
//根据域名获取二级域名
var domain = origin.Split("//")[1].Split(".")[0];
//根据二级域名获取租户
var tenantList = await _sysOrgService.GetTenantList();
var tenant = tenantList.FirstOrDefault(x => x.Code.ToLower() == domain);//获取租户默认是机构编码
if (tenant != null)
input.TenantId = tenant.Id;
else
throw Oops.Bah("租户不存在");
}
//如果是手动选择多租户则用账号+租户
key += $"{input.TenantId}:{input.Account}";
}
var errorCountCache = _simpleCacheService.Get<int>(key);//获取登录错误次数
if (errorCountCache >= errorCount)
{
_simpleCacheService.SetExpire(key, TimeSpan.FromMinutes(lockTime));//设置缓存
throw Oops.Bah($"密码错误次数过多,请{lockTime}分钟后再试");
}
}
/// <summary>
/// 登录错误操作
/// </summary>
/// <param name="loginPolicy"></param>
/// <param name="input"></param>
/// <param name="isTenant"></param>
public void LoginError(List<SysConfig> loginPolicy, LoginInput input, bool isTenant)
{
var resetTime = loginPolicy.First(x => x.ConfigKey == SysConfigConst.LOGIN_ERROR_RESET_TIME).ConfigValue.ToInt();//获取重置时间
var key = SystemConst.CACHE_LOGIN_ERROR_COUNT;//获取登录错误次数Key值
//如果是关闭多租户则直接用账号
if (!isTenant)
key += input.Account;
else
{
//如果是手动选择多租户则用账号+租户
key += $"{input.TenantId}:{input.Account}";
}
_simpleCacheService.Increment(key, 1);// 登录错误次数+1
_simpleCacheService.SetExpire(key, TimeSpan.FromMinutes(resetTime));//设置过期时间
}
/// <summary>
/// 校验验证码方法
/// </summary>
/// <param name="validCode">验证码</param>
/// <param name="validCodeReqNo">请求号</param>
/// <param name="isDelete">是否从Redis删除</param>
public void ValidValidCode(string validCode, string validCodeReqNo, bool isDelete = true)
{
var key = SystemConst.CACHE_CAPTCHA + validCodeReqNo;//获取验证码Key值
var code = _simpleCacheService.Get<string>(key);//从缓存拿数据
if (isDelete) RemoveValidCodeFromRedis(validCodeReqNo);//如果需要删除验证码
if (code != null && validCode != null)//如果有
{
//验证码如果不匹配直接抛错误,这里忽略大小写
if (validCode.ToLower() != code.ToLower()) throw Oops.Bah("验证码错误");
}
else
{
throw Oops.Bah("验证码不能为空");//抛出验证码不能为空
}
}
/// <summary>
/// 从Redis中删除验证码
/// </summary>
/// <param name="validCodeReqNo"></param>
public void RemoveValidCodeFromRedis(string validCodeReqNo)
{
var key = SystemConst.CACHE_CAPTCHA + validCodeReqNo;//获取验证码Key值
_simpleCacheService.Remove(key);//删除验证码
}
/// <summary>
/// 校验手机验证码
/// </summary>
/// <param name="input">输入参数</param>
/// <param name="loginClientType">登录端类型</param>
/// <param name="isDelete">是否删除</param>
/// <returns></returns>
public async Task ValidPhoneValidCode(GetPhoneValidCodeInput input, LoginClientTypeEnum loginClientType, bool isDelete = true)
{
ValidValidCode(input.ValidCode, input.ValidCodeReqNo, isDelete);//校验验证码
if (loginClientType == LoginClientTypeEnum.B)//B端登录
{
var userId = await _userService.GetIdByPhone(input.Phone);//获取用户名
if (userId == 0)
{
throw Oops.Bah("手机号不存在");//手机号不存在
}
}
else
{
//校验C段用户手机号
throw Oops.Bah("手机号不存在");//手机号不存在
}
}
/// <summary>
/// 添加验证码到缓存
/// </summary>
/// <param name="code">验证码</param>
/// <param name="expire">过期时间</param>
/// <returns>验证码请求号</returns>
public string AddValidCodeToRedis(string code, int expire = 5)
{
//生成请求号
var reqNo = CommonUtils.GetSingleId().ToString();
//插入缓存
_simpleCacheService.Set(SystemConst.CACHE_CAPTCHA + reqNo, code, TimeSpan.FromMinutes(expire));
return reqNo;
}
/// <summary>
/// 执行B端登录
/// </summary>
/// <param name="sysUser">用户信息</param>
/// <param name="device">登录设备</param>
/// <param name="loginClientType">登录类型</param>
/// <param name="tenantId">租户id</param>
/// <returns></returns>
public async Task<LoginOutPut> ExecLoginB(SysUser sysUser, AuthDeviceTypeEnum device, LoginClientTypeEnum loginClientType,
long? tenantId)
{
if (sysUser.Status == CommonStatusConst.DISABLED)
throw Oops.Bah("账号已停用");//账号冻结
if (sysUser.ModuleList.Count == 0) throw Oops.Bah("该账号未分配模块,请联系管理员");//没有分配菜单权限
var org = await _sysOrgService.GetSysOrgById(sysUser.OrgId);//获取机构
if (org.Status == CommonStatusConst.DISABLED) throw Oops.Bah("所属公司/部门已停用,请联系管理员");//机构冻结
//生成Token
var accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>
{
{
ClaimConst.USER_ID, sysUser.Id
},
{
ClaimConst.ACCOUNT, sysUser.Account
},
{
ClaimConst.NAME, sysUser.Name
},
{
ClaimConst.IS_SUPER_ADMIN, sysUser.RoleCodeList.Contains(SysRoleConst.SUPER_ADMIN)
},
{
ClaimConst.ORG_ID, sysUser.OrgId
},
{
ClaimConst.TENANT_ID, tenantId
}
});
var expire = App.GetConfig<int>("JWTSettings:ExpiredTime");//获取过期时间(分钟)
// 生成刷新Token令牌
var refreshToken = JWTEncryption.GenerateRefreshToken(accessToken, expire * 2);
// 设置Swagger自动登录
App.HttpContext.SigninToSwagger(accessToken);
// 设置响应报文头
App.HttpContext.SetTokensOfResponseHeaders(accessToken, refreshToken);
//登录事件参数
var loginEvent = new LoginEvent
{
Ip = App.HttpContext.GetRemoteIpAddressToIPv4(),
Device = device,
Expire = expire,
SysUser = sysUser,
Token = accessToken
};
await WriteTokenToRedis(loginEvent, loginClientType);//写入token到缓存
await _eventPublisher.PublishAsync(EventSubscriberConst.LOGIN_B, loginEvent);//发布登录事件总线
//返回结果
return new LoginOutPut
{
Token = accessToken,
Account = sysUser.Account,
Name = sysUser.Name,
DefaultModule = sysUser.DefaultModule,
ModuleList = sysUser.ModuleList
};
}
/// <summary>
/// 写入用户token到缓存
/// </summary>
/// <param name="loginEvent">登录事件参数</param>
/// <param name="loginClientType">登录类型</param>
private async Task WriteTokenToRedis(LoginEvent loginEvent, LoginClientTypeEnum loginClientType)
{
//获取token列表
var tokenInfos = GetTokenInfos(loginEvent.SysUser.Id);
var tokenTimeout = loginEvent.DateTime.AddMinutes(loginEvent.Expire);
//生成token信息
var tokenInfo = new TokenInfo
{
Device = loginEvent.Device.ToString(),
Expire = loginEvent.Expire,
TokenTimeout = tokenTimeout,
LoginClientType = loginClientType,
Token = loginEvent.Token
};
//如果缓存有数据
if (tokenInfos != null)
{
var isSingle = false;//默认不开启单用户登录
var singleConfig = await _configService.GetByConfigKey(CateGoryConst.CONFIG_LOGIN_POLICY, SysConfigConst.LOGIN_SINGLE_OPEN);//获取系统单用户登录选项
if (singleConfig != null)
isSingle = singleConfig.ConfigValue.ToBoolean();//如果配置不为空则设置单用户登录选项为系统配置的值
//判断是否单用户登录
if (isSingle)
{
await SingleLogin(loginEvent.SysUser.Id.ToString(), tokenInfos.Where(it => it.LoginClientType == loginClientType).ToList());//单用户登录方法
tokenInfos = tokenInfos.Where(it => it.LoginClientType != loginClientType).ToList();//去掉当前登录类型的token
tokenInfos.Add(tokenInfo);//添加到列表
}
else
{
tokenInfos.Add(tokenInfo);
}
}
else
{
tokenInfos = new List<TokenInfo>
{
tokenInfo
};//直接就一个
}
//添加到token列表
_simpleCacheService.HashAdd(CacheConst.CACHE_USER_TOKEN, loginEvent.SysUser.Id.ToString(), tokenInfos);
}
/// <summary>
/// 缓存删除用户token
/// </summary>
/// <param name="loginEvent">登录事件参数</param>
/// <param name="loginClientType">登录类型</param>
private void RemoveTokenFromRedis(LoginEvent loginEvent, LoginClientTypeEnum loginClientType)
{
//获取token列表
var tokenInfos = GetTokenInfos(loginEvent.SysUser.Id);
if (tokenInfos != null)
{
//获取当前用户的token
var token = tokenInfos.Where(it => it.Token == loginEvent.Token && it.LoginClientType == loginClientType).FirstOrDefault();
if (token != null)
tokenInfos.Remove(token);
if (tokenInfos.Count > 0)
{
//更新token列表
_simpleCacheService.HashAdd(CacheConst.CACHE_USER_TOKEN, loginEvent.SysUser.Id.ToString(), tokenInfos);
}
else
{
//从列表中删除
_simpleCacheService.HashDel<List<TokenInfo>>(CacheConst.CACHE_USER_TOKEN, loginEvent.SysUser.Id.ToString());
}
}
}
/// <summary>
/// 获取用户token列表
/// </summary>
/// <param name="userId">用户ID</param>
/// <returns>token列表</returns>
private List<TokenInfo> GetTokenInfos(long userId)
{
//缓存获取用户token列表
var tokenInfos = _simpleCacheService.HashGetOne<List<TokenInfo>>(CacheConst.CACHE_USER_TOKEN, userId.ToString());
if (tokenInfos != null)
{
tokenInfos = tokenInfos.Where(it => it.TokenTimeout > DateTime.Now).ToList();//去掉登录超时的
}
return tokenInfos;
}
/// <summary>
/// 单用户登录通知用户下线
/// </summary>
/// <param name="userId">用户ID</param>
/// <param name="tokenInfos">Token列表</param>
private async Task SingleLogin(string userId, List<TokenInfo> tokenInfos)
{
await _eventPublisher.PublishAsync(EventSubscriberConst.USER_LOGIN_OUT, new UserLoginOutEvent
{
Message = "您的账号已在别处登录!",
TokenInfos = tokenInfos,
UserId = userId
});//通知用户下线
}
#endregion 方法
}
@@ -0,0 +1,103 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 权限认证输入
/// </summary>
public class AuthInput
{
}
public class ValidCodeInput
{
/// <summary>
/// 验证码
/// </summary>
public string ValidCode { get; set; }
/// <summary>
/// 请求号
/// </summary>
public string ValidCodeReqNo { get; set; }
}
/// <summary>
/// 登录输入参数
/// </summary>
public class LoginInput : ValidCodeInput
{
/// <summary>
/// 账号
///</summary>
/// <example>superAdmin</example>
[Required(ErrorMessage = "账号不能为空")]
public string Account { get; set; }
/// <summary>
/// 密码
///</summary>
///<example>04fc514b346f14b23d7cf5e6f64663b030512aa380a9e7d311288ed1e8be7b863ae5ee0bb570df2405fc9daff2b2d1ac627a0fbbd49ef2c6b8fac4fd5e4b9a1b7120999bdc0a8e425aa37abab3aec6f9f3570775ff901f2845e957b0c2d0542e21fbf1bbb65c04</example>
[Required(ErrorMessage = "密码不能为空")]
public string Password { get; set; }
/// <summary>
/// 设备类型,默认PC
/// </summary>
/// <example>0</example>
public AuthDeviceTypeEnum Device { get; set; } = AuthDeviceTypeEnum.PC;
/// <summary>
/// 租户ID
/// </summary>
public long? TenantId { get; set; }
}
/// <summary>
/// 登出输入参数
/// </summary>
public class LoginOutInput
{
/// <summary>
/// token
/// </summary>
public string Token { get; set; }
}
/// <summary>
/// 获取短信验证码输入
/// </summary>
public class GetPhoneValidCodeInput : ValidCodeInput
{
/// <summary>
/// 手机号
/// </summary>
[Required(ErrorMessage = "手机号不能为空")]
[Phone(ErrorMessage = "手机号格式不对")]
public string Phone { get; set; }
}
/// <summary>
/// 手机号登录输入
/// </summary>
public class LoginByPhoneInput : GetPhoneValidCodeInput
{
/// <summary>
/// 设备类型,默认PC
/// </summary>
/// <example>0</example>
public AuthDeviceTypeEnum Device { get; set; } = AuthDeviceTypeEnum.PC;
/// <summary>
/// 租户ID
/// </summary>
public long? TenantId { get; set; }
}
@@ -0,0 +1,154 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
public class AuthOutPut
{
}
/// <summary>
/// 验证码返回
/// </summary>
public class PicValidCodeOutPut
{
/// <summary>
/// 验证码图片,Base64
/// </summary>
public string ValidCodeBase64 { get; set; }
/// <summary>
/// 验证码请求号
/// </summary>
public string ValidCodeReqNo { get; set; }
}
/// <summary>
/// 登录返回参数
/// </summary>
public class LoginOutPut
{
/// <summary>
/// 令牌Token
/// </summary>
public string Token { get; set; }
/// <summary>
/// 账号
/// </summary>
public string Account { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 默认模块
/// </summary>
public long? DefaultModule { get; set; }
/// <summary>
/// 模块列表
/// </summary>
public List<SysResource> ModuleList { get; set; }
}
/// <summary>
/// 登录用互信息
/// </summary>
public class LoginUserOutput
{
/// <summary>
/// 头像
///</summary>
public string Avatar { get; set; }
/// <summary>
/// 签名
///</summary>
public string Signature { get; set; }
/// <summary>
/// 账号
///</summary>
public string Account { get; set; }
/// <summary>
/// 姓名
///</summary>
public string Name { get; set; }
/// <summary>
/// 昵称
///</summary>
public string Nickname { get; set; }
/// <summary>
/// 手机号
/// </summary>
public string Phone { get; set; }
/// <summary>
/// 生日
/// </summary>
public string Birthday { get; set; }
/// <summary>
/// 邮箱
/// </summary>
public string Email { get; set; }
/// <summary>
/// 性别
///</summary>
public string Gender { get; set; }
/// <summary>
/// 家庭住址
///</summary>
public string HomeAddress { get; set; }
/// <summary>
/// 机构信息
/// </summary>
public string OrgName { get; set; }
/// <summary>
/// 机构信息全称
/// </summary>
public string OrgNames { get; set; }
/// <summary>
/// 职位信息
/// </summary>
public string PositionName { get; set; }
/// <summary>
/// 角色码集合
/// </summary>
public List<string> RoleCodeList { get; set; }
/// <summary>
/// 按钮码集合
/// </summary>
public List<string> ButtonCodeList { get; set; }
/// <summary>
/// 机构及以下机构ID集合
/// </summary>
public List<SysResource> ModuleList { get; set; } = new List<SysResource>();
/// <summary>
/// 默认模块
///</summary>
public long? DefaultModule { get; set; }
}
@@ -0,0 +1,61 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 权限校验服务
/// </summary>
public interface IAuthService : ITransient
{
/// <summary>
/// 获取图形验证码
/// </summary>
/// <returns></returns>
Task<PicValidCodeOutPut> GetCaptchaInfo();
/// <summary>
/// 获取登录用户信息
/// </summary>
/// <returns></returns>
Task<LoginUserOutput> GetLoginUser();
/// <summary>
/// 获取手机短信验证码
/// </summary>
/// <param name="input">验证码参数</param>
/// <param name="loginClientType">登录类型</param>
/// <returns></returns>
Task<string> GetPhoneValidCode(GetPhoneValidCodeInput input, LoginClientTypeEnum loginClientType);
/// <summary>
/// 登录
/// </summary>
/// <param name="input">登录参数</param>
/// <param name="loginClientType">登录类型</param>
/// <returns>Token信息</returns>
Task<LoginOutPut> Login(LoginInput input, LoginClientTypeEnum loginClientType);
/// <summary>
/// 手机号登录
/// </summary>
/// <param name="input">登录参数</param>
/// <param name="loginClientType">登录端类型</param>
/// <returns>Token信息</returns>
Task<LoginOutPut> LoginByPhone(LoginByPhoneInput input, LoginClientTypeEnum loginClientType);
/// <summary>
/// 退出登录
/// </summary>
/// <param name="token">token</param>
/// <param name="loginClientType">登出类型</param>
/// <returns></returns>
Task LoginOut(string token, LoginClientTypeEnum loginClientType);
}
@@ -0,0 +1,45 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 会话分页查询
/// </summary>
public class SessionPageInput : BasePageInput
{
/// <summary>
/// 账号
///</summary>
public virtual string Account { get; set; }
/// <summary>
/// 姓名
///</summary>
public virtual string Name { get; set; }
/// <summary>
/// 最新登录ip
///</summary>
public string LatestLoginIp { get; set; }
}
/// <summary>
/// Token退出参数
/// </summary>
public class ExitTokenInput : BaseIdInput
{
/// <summary>
/// token
/// </summary>
[Required(ErrorMessage = "Tokens不能为空")]
public List<string> Tokens { get; set; }
}
@@ -0,0 +1,94 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 会话输出
/// </summary>
public class SessionOutput
{
/// <summary>
/// 主键Id
/// </summary>
public virtual long Id { get; set; }
/// <summary>
/// 头像
///</summary>
public string Avatar { get; set; }
/// <summary>
/// 账号
///</summary>
public virtual string Account { get; set; }
/// <summary>
/// 姓名
///</summary>
public virtual string Name { get; set; }
/// <summary>
/// 在线状态
/// </summary>
public string OnlineStatus { get; set; }
/// <summary>
/// 最新登录ip
///</summary>
public string LatestLoginIp { get; set; }
/// <summary>
/// 最新登录地点
///</summary>
public string LatestLoginAddress { get; set; }
/// <summary>
/// 最新登录时间
///</summary>
public DateTime? LatestLoginTime { get; set; }
/// <summary>
/// 令牌数量
/// </summary>
public int TokenCount { get; set; }
/// <summary>
/// 令牌信息集合
/// </summary>
public List<TokenInfo> TokenSignList { get; set; }
}
/// <summary>
/// 会话统计结果
/// </summary>
public class SessionAnalysisOutPut
{
/// <summary>
/// 当前会话总数量
/// </summary>
public int CurrentSessionTotalCount { get; set; }
/// <summary>
/// 最大签发令牌数
/// </summary>
public int MaxTokenCount { get; set; }
/// <summary>
/// 在线用户数
/// </summary>
public int OnLineCount { get; set; }
/// <summary>
/// BC端会话比例
/// </summary>
public string ProportionOfBAndC { get; set; }
}
@@ -0,0 +1,49 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 会话管理服务
/// </summary>
public interface ISessionService : ITransient
{
/// <summary>
/// 会话统计
/// </summary>
/// <returns>统计结果</returns>
SessionAnalysisOutPut Analysis();
/// <summary>
/// 强退会话
/// </summary>
/// <param name="input">用户ID</param>
Task ExitSession(BaseIdInput input);
/// <summary>
/// 强退token
/// </summary>
/// <param name="input">token列表</param>
Task ExitToken(ExitTokenInput input);
/// <summary>
/// B端会话分页查询
/// </summary>
/// <param name="input">查询参数</param>
/// <returns>B端会话列表</returns>
Task<SqlSugarPagedList<SessionOutput>> PageB(SessionPageInput input);
/// <summary>
/// C端会话分页查询
/// </summary>
/// <param name="input">查询参数</param>
/// <returns>C端会话列表</returns>
Task<SqlSugarPagedList<SessionOutput>> PageC(SessionPageInput input);
}
@@ -0,0 +1,202 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
using Masuit.Tools.DateTimeExt;
namespace SimpleAdmin.System;
/// <summary>
/// <inheritdoc cref="ISessionService"/>
/// </summary>
public class SessionService : DbRepository<SysUser>, ISessionService
{
private readonly ISimpleCacheService _simpleCacheService;
private readonly IEventPublisher _eventPublisher;
public SessionService(ISimpleCacheService simpleCacheService, IEventPublisher eventPublisher)
{
_simpleCacheService = simpleCacheService;
_eventPublisher = eventPublisher;
}
/// <inheritdoc/>
public async Task<SqlSugarPagedList<SessionOutput>> PageB(SessionPageInput input)
{
//获取b端token列表
var bTokenInfoDic = GetTokenDicFromRedis();
//获取用户ID列表
var userIds = bTokenInfoDic.Keys.Select(it => it.ToLong()).ToList();
var query = Context.Queryable<SysUser>().Where(it => userIds.Contains(it.Id))//根据ID查询
.WhereIF(!string.IsNullOrEmpty(input.Name), it => it.Name.Contains(input.Name))//根据姓名查询
.WhereIF(!string.IsNullOrEmpty(input.Account), it => it.Account.Contains(input.Account))//根据账号查询
.WhereIF(!string.IsNullOrEmpty(input.LatestLoginIp), it => it.LatestLoginIp.Contains(input.LatestLoginIp))//根据IP查询
.OrderBy(it => it.LatestLoginTime, OrderByType.Desc).Select<SessionOutput>().Mapper(it =>
{
var tokenInfos = bTokenInfoDic[it.Id.ToString()];//获取用户token信息
GetTokenInfos(ref tokenInfos, LoginClientTypeEnum.B);//获取剩余时间
it.TokenCount = tokenInfos.Count;//令牌数量
it.TokenSignList = tokenInfos;//令牌列表
//如果有mqtt客户端ID就是在线
it.OnlineStatus = tokenInfos.Any(it => it.ClientIds.Count > 0)
? SysDictConst.ONLINE_STATUS_ONLINE
: SysDictConst.ONLINE_STATUS_OFFLINE;
});
var pageInfo = await query.ToPagedListAsync(input.PageNum, input.PageSize);//分页
pageInfo.List.OrderByDescending(it => it.TokenCount);
return pageInfo;
}
/// <inheritdoc/>
public async Task<SqlSugarPagedList<SessionOutput>> PageC(SessionPageInput input)
{
return new SqlSugarPagedList<SessionOutput> { PageNum = 1, PageSize = 20, Total = 0, Pages = 1, HasNextPages = false };
}
/// <inheritdoc/>
public SessionAnalysisOutPut Analysis()
{
var tokenDic = GetTokenDicFromRedis();//redisToken会话字典信息
var tokenInfosList = tokenDic.Values.ToList();//端token列表
var dicB = new Dictionary<string, List<TokenInfo>>();
var dicC = new Dictionary<string, List<TokenInfo>>();
var onLineCount = 0;
foreach (var token in tokenDic)
{
var b = token.Value.Where(it => it.LoginClientType == LoginClientTypeEnum.B).ToList();//获取该用户B端token
var c = token.Value.Where(it => it.LoginClientType == LoginClientTypeEnum.C).ToList();//获取该用户C端token
if (b.Count > 0)
dicB.Add(token.Key, b);
if (c.Count > 0)
dicC.Add(token.Key, c);
var count = token.Value.Count(it => it.ClientIds.Count > 0);//计算在线用户
onLineCount += count;
}
var tokenB = dicB.Values.ToList();//b端token列表
var tokenC = dicC.Values.ToList();//c端token列表
int maxCountB = 0, maxCountC = 0;
if (tokenB.Count > 0)
maxCountB = tokenB.OrderByDescending(it => it.Count).Take(1).First().Count;//b端最大会话数
if (tokenC.Count > 0)
maxCountC = tokenC.OrderByDescending(it => it.Count).Take(1).First().Count;//C端最大会话数
return new SessionAnalysisOutPut
{
OnLineCount = onLineCount,
CurrentSessionTotalCount = tokenB.Count + tokenC.Count,
MaxTokenCount = maxCountB > maxCountC ? maxCountB : maxCountC,
ProportionOfBAndC = $"{tokenB.Count}/{tokenC.Count}"
};
}
/// <inheritdoc/>
public async Task ExitSession(BaseIdInput input)
{
var userId = input.Id.ToString();
//token列表
var tokenInfos = _simpleCacheService.HashGetOne<List<TokenInfo>>(CacheConst.CACHE_USER_TOKEN, userId);
//从列表中删除
_simpleCacheService.HashDel<List<TokenInfo>>(CacheConst.CACHE_USER_TOKEN, userId);
await NoticeUserLoginOut(userId, tokenInfos);
}
/// <inheritdoc/>
public async Task ExitToken(ExitTokenInput input)
{
var userId = input.Id.ToString();
//获取该用户的token信息
var tokenInfos = _simpleCacheService.HashGetOne<List<TokenInfo>>(CacheConst.CACHE_USER_TOKEN, userId);
//当前需要踢掉用户的token
var deleteTokens = tokenInfos.Where(it => input.Tokens.Contains(it.Token)).ToList();
//踢掉包含token列表的token信息
tokenInfos = tokenInfos.Where(it => !input.Tokens.Contains(it.Token)).ToList();
if (tokenInfos.Count > 0)
_simpleCacheService.HashAdd(CacheConst.CACHE_USER_TOKEN, userId, tokenInfos);//如果还有token则更新token
else
_simpleCacheService.HashDel<List<TokenInfo>>(CacheConst.CACHE_USER_TOKEN, userId);//否则直接删除key
await NoticeUserLoginOut(userId, deleteTokens);
}
#region 方法
/// <summary>
/// 获取redis中token信息列表
/// </summary>
/// <returns></returns>
public Dictionary<string, List<TokenInfo>> GetTokenDicFromRedis()
{
var clockSkew = App.GetConfig<int>("JWTSettings:ClockSkew");//获取过期时间容错值(秒)
//redis获取token信息hash集合,并转成字典
var bTokenDic = _simpleCacheService.HashGetAll<List<TokenInfo>>(CacheConst.CACHE_USER_TOKEN).ToDictionary(u => u.Key, u => u.Value);
if (bTokenDic != null)
{
bTokenDic.ForEach(it =>
{
var tokens = it.Value.Where(it => it.TokenTimeout.AddSeconds(clockSkew) > DateTime.Now).ToList();//去掉登录超时的
if (tokens.Count == 0)
{
//表示都过期了
bTokenDic.Remove(it.Key);
}
else
{
bTokenDic[it.Key] = tokens;//重新赋值token
}
});
if (bTokenDic.Count > 0)
{
_simpleCacheService.HashSet(CacheConst.CACHE_USER_TOKEN, bTokenDic);//如果还有token则更新token
}
else
{
_simpleCacheService.Remove(CacheConst.CACHE_USER_TOKEN);//否则直接删除key
}
return bTokenDic;
}
return new Dictionary<string, List<TokenInfo>>();
}
/// <summary>
/// 获取token剩余时间信息
/// </summary>
/// <param name="tokenInfos">token列表</param>
/// <param name="loginClientType">登录类型</param>
public void GetTokenInfos(ref List<TokenInfo> tokenInfos, LoginClientTypeEnum loginClientType)
{
tokenInfos = tokenInfos.Where(it => it.LoginClientType == loginClientType).ToList();
tokenInfos.ForEach(it =>
{
var now = DateTime.Now;
it.TokenRemain = now.GetDiffTime(it.TokenTimeout);//获取时间差
var tokenSecond = it.TokenTimeout.AddMinutes(-it.Expire).ConvertDateTimeToLong();//颁发时间转为时间戳
var timeoutSecond = it.TokenTimeout.ConvertDateTimeToLong();//过期时间转为时间戳
var tokenRemainPercent =
1 - (now.ConvertDateTimeToLong() - tokenSecond) * 1.0 / (timeoutSecond - tokenSecond);//求百分比,用现在时间-token颁布时间除以超时时间-token颁布时间
it.TokenRemainPercent = tokenRemainPercent;
});
}
/// <summary>
/// 通知用户下线
/// </summary>
/// <returns></returns>
private async Task NoticeUserLoginOut(string userId, List<TokenInfo> tokenInfos)
{
await _eventPublisher.PublishAsync(EventSubscriberConst.USER_LOGIN_OUT, new UserLoginOutEvent
{
Message = "您已被强制下线!",
TokenInfos = tokenInfos,
UserId = userId
});//通知用户下线
}
#endregion 方法
}
@@ -0,0 +1,214 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// <inheritdoc cref="IBatchEditService"/>
/// </summary>
public class BatchEditService : DbRepository<BatchEdit>, IBatchEditService
{
private readonly ILogger<BatchEditService> _logger;
public BatchEditService(ILogger<BatchEditService> logger)
{
_logger = logger;
}
/// <inheritdoc/>
public async Task<SqlSugarPagedList<BatchEdit>> Page(BatchEditPageInput input)
{
var query = Context.Queryable<BatchEdit>()
.WhereIF(!string.IsNullOrWhiteSpace(input.ConfigId), it => it.ConfigId.Contains(input.ConfigId.Trim()))
.WhereIF(!string.IsNullOrWhiteSpace(input.EntityName), it => it.EntityName.Contains(input.EntityName.Trim()))
.WhereIF(!string.IsNullOrWhiteSpace(input.TableName), it => it.TableName.Contains(input.TableName.Trim()))
//.WhereIF(!string.IsNullOrEmpty(input.SearchKey), it => it.Name.Contains(input.SearchKey))//根据关键字查询
.OrderByIF(!string.IsNullOrEmpty(input.SortField), $"{input.SortField} {input.SortOrder}");
var pageInfo = await query.ToPagedListAsync(input.PageNum, input.PageSize);//分页
return pageInfo;
}
/// <inheritdoc />
public async Task Add(BatchEditAddInput input)
{
var entity = input.Adapt<BatchEdit>();//实体转换
await CheckInput(entity);//检查参数
var tableColumns = SqlSugarUtils.GetTableColumns(input.ConfigId, input.TableName);//获取表的字段信息
var batchEdiConfig = new List<BatchEditConfig>();//代码生成配置字段集合
//遍历字段
tableColumns.ForEach(it =>
{
//判断是否是主键或者通用字段
var isPkOrCommon = it.IsPrimaryKey || SqlSugarUtils.IsCommonColumn(it.ColumnName);
if (!isPkOrCommon)
{
//添加到字段集合
batchEdiConfig.Add(GetUpdateBatchConfig(it));
}
});
//事务
var result = await Tenant.UseTranAsync(async () =>
{
entity = await InsertReturnEntityAsync(entity);//输入参数转实体并插入
batchEdiConfig.ForEach(it => { it.UId = entity.Id; });//遍历字段赋值基础Id
await Context.Insertable(batchEdiConfig).ExecuteCommandAsync();
});
if (!result.IsSuccess)//如果失败了
{
//写日志
_logger.LogError(result.ErrorMessage, result.ErrorException);
throw Oops.Oh(ErrorCodeEnum.A0003);
}
}
/// <inheritdoc />
public async Task Config(List<BatchEditConfigInput> input)
{
var updateBatch = input.Adapt<List<BatchEditConfig>>();//实体转换
var configRep = ChangeRepository<DbRepository<BatchEditConfig>>();
var ids = input.Select(it => it.Id).ToList();//获取当前配置Id
if (ids.Any())
{
await configRep.DeleteAsync(it => !ids.Contains(it.Id) && it.UId == input.First().UId);//删除没有的
await Context.Updateable(updateBatch).ExecuteCommandAsync();//更新数据
}
}
/// <inheritdoc />
public async Task Delete(BaseIdListInput input)
{
//获取所有ID
var ids = input.Ids;
if (ids.Count > 0)
{
//事务
var result = await Tenant.UseTranAsync(async () =>
{
await DeleteByIdsAsync(ids.Cast<object>().ToArray());//删除数据
await Context.Deleteable<BatchEditConfig>().Where(it => ids.Contains(it.UId)).ExecuteCommandAsync();
});
if (!result.IsSuccess)//如果失败了
{
//写日志
_logger.LogError(result.ErrorMessage, result.ErrorException);
throw Oops.Oh(ErrorCodeEnum.A0003);
}
}
}
/// <inheritdoc />
public async Task SyncColumns(BaseIdInput input)
{
var config = await GetFirstAsync(it => it.Id == input.Id);
if (config != null)
{
var newColumns = new List<BatchEditConfig>();
//获取表的字段信息
var tableColumns = SqlSugarUtils.GetTableColumns(config.ConfigId, config.TableName);
//找到当前配置字段列表
var batchEdiConfig = await Context.Queryable<BatchEditConfig>().Where(it => it.UId == config.Id).ToListAsync();
foreach (var tableColumn in tableColumns)
{
//判断是否是主键或者通用字段
var isPkOrCommon = tableColumn.IsPrimaryKey || SqlSugarUtils.IsCommonColumn(tableColumn.ColumnName);
if (!isPkOrCommon)
{
//如果当前配置没有
if (!batchEdiConfig.Any(it => it.ColumnName == tableColumn.ColumnName))
{
var netType = SqlSugarUtils.ConvertDataType(tableColumn.DataType);
//添加到字段集合
newColumns.Add(GetUpdateBatchConfig(tableColumn));
}
}
}
if (newColumns.Count > 0)
{
newColumns.ForEach(it => it.UId = config.Id);
await Context.Insertable(newColumns).ExecuteCommandAsync();//插入新的字段数据
}
}
}
/// <inheritdoc />
public async Task<List<BatchEditConfig>> Columns(string code)
{
var batchEdiConfig = new List<BatchEditConfig>();
var updateBatch = await GetFirstAsync(it => it.Code == code);//根据code获取配置
if (updateBatch != null)
{
//找到对应字段
batchEdiConfig = await Context.Queryable<BatchEditConfig>().Where(it => it.UId == updateBatch.Id && it.Status == CommonStatusConst.ENABLE)
.ToListAsync();
}
return batchEdiConfig;
}
/// <inheritdoc/>
public List<SqlSugarTableInfo> GetTables()
{
return SqlSugarUtils.GetTablesByAttribute<BatchEditAttribute>();
}
/// <inheritdoc/>
public async Task<List<BatchEditConfig>> ConfigList(BaseIdInput input)
{
return await Context.Queryable<BatchEditConfig>().Where(u => u.UId == input.Id).OrderByDescending(it => it.Status).ToListAsync();
}
/// <inheritdoc/>
public async Task<Dictionary<string, object>> GetUpdateBatchConfigDict(string code, List<BatchEditColumn> columns)
{
var dic = new Dictionary<string, object>();
var configs = await Columns(code);
foreach (var item in columns)
{
var config = configs.Where(it => it.ColumnName == item.TableColumn).FirstOrDefault();
if (config == null) throw Oops.Bah("不存在的列");
dic.Add(item.TableColumn, item.ColumnValue.ToString());
}
return dic;
}
#region 方法
/// <summary>
/// 获取配置
/// </summary>
/// <param name="columnInfo"></param>
private BatchEditConfig GetUpdateBatchConfig(SqlSugarColumnInfo columnInfo)
{
var netType = SqlSugarUtils.ConvertDataType(columnInfo.DataType);
return new BatchEditConfig
{
ColumnName = columnInfo.ColumnName,
ColumnComment = string.IsNullOrWhiteSpace(columnInfo.ColumnDescription) ? columnInfo.ColumnName : columnInfo.ColumnDescription,
NetType = netType,
DataType = SqlSugarUtils.DataTypeToEff(netType),
Status = CommonStatusConst.DISABLED
};
}
/// <summary>
/// 检查输入参数
/// </summary>
/// <param name="updateBatch"></param>
private async Task CheckInput(BatchEdit updateBatch)
{
if (updateBatch.Id == 0)
{
var isExist = await IsAnyAsync(it => it.Code == updateBatch.Code);
if (isExist) throw Oops.Bah("唯一编码不能重复");
}
}
#endregion 方法
}
@@ -0,0 +1,138 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 批量分页查询参数
/// </summary>
public class BatchEditPageInput : BasePageInput
{
/// <summary>
/// 唯一编码
/// </summary>
public string Code { get; set; }
/// <summary>
/// 所属库
/// </summary>
public string ConfigId { get; set; }
/// <summary>
/// 实体名
/// </summary>
public string EntityName { get; set; }
/// <summary>
/// 表名
/// </summary>
public string TableName { get; set; }
}
/// <summary>
/// 添加批量参数
/// </summary>
public class BatchEditAddInput
{
/// <summary>
/// 唯一编码
/// </summary>
[Required(ErrorMessage = "Code必填")]
public string Code { get; set; }
/// <summary>
/// 所属库
/// </summary>
[Required(ErrorMessage = "ConfigId必填")]
public string ConfigId { get; set; }
/// <summary>
/// 实体名
/// </summary>
[Required(ErrorMessage = "EntityName必填")]
public string EntityName { get; set; }
/// <summary>
/// 表名
/// </summary>
[Required(ErrorMessage = "TableName必填")]
public string TableName { get; set; }
/// <summary>
/// 表描述
/// </summary>
public string TableDescription { get; set; }
}
/// <summary>
/// 修改批量参数
/// </summary>
public class BatchEditConfigInput : BatchEditConfig, IValidatableObject
{
/// <summary>
/// Id
/// </summary>
[IdNotNull(ErrorMessage = "Id不能为空")]
public override long Id { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (Status == CommonStatusConst.ENABLE)
{
//如果是api请求并且必填参数有空的
if (DataType.Contains("api") && (string.IsNullOrEmpty(RequestUrl) || string.IsNullOrEmpty(RequestType)
|| string.IsNullOrEmpty(RequestLabel) || string.IsNullOrEmpty(RequestValue)))
{
yield return new ValidationResult($"字段{ColumnName}接口信息必填", new[] { nameof(DataType) });
}
//如果是字典数据并且字典值为空
if (DataType.Contains("dict") && string.IsNullOrEmpty(DictTypeCode))
{
yield return new ValidationResult($"字段{ColumnName}字典值必填", new[] { nameof(DictTypeCode) });
}
}
}
}
/// <summary>
/// 批量修改输入
/// </summary>
public class BatchEditInput
{
/// <summary>
/// 批量编辑Code
/// </summary>
[Required(ErrorMessage = "Code不能为空")]
public string Code { get; set; }
/// <summary>
/// Id列表
/// </summary>
[Required(ErrorMessage = "Ids不能为空")]
public List<long>? Ids { get; set; }
/// <summary>
/// 字段列表
/// </summary>
[Required(ErrorMessage = "Columns不能为空")]
public List<BatchEditColumn>? Columns { get; set; }
}
/// <summary>
/// 批量修改DTO
/// </summary>
public class BatchEditColumn
{
[Required(ErrorMessage = "字段名必填")]
public string TableColumn { get; set; }
[Required(ErrorMessage = "字段值必填")]
public object ColumnValue { get; set; }
}
@@ -0,0 +1,14 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
@@ -0,0 +1,80 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 批量服务
/// </summary>
public interface IBatchEditService : ITransient
{
/// <summary>
/// 批量分页查询
/// </summary>
/// <param name="input">查询参数</param>
/// <returns>分页结果</returns>
Task<SqlSugarPagedList<BatchEdit>> Page(BatchEditPageInput input);
/// <summary>
/// 添加批量
/// </summary>
/// <param name="input">添加参数</param>
/// <returns></returns>
Task Add(BatchEditAddInput input);
/// <summary>
/// 删除批量
/// </summary>
/// <param name="input">删除参数</param>
/// <returns></returns>
Task Delete(BaseIdListInput input);
/// <summary>
/// 获取需要批量修改的表
/// </summary>
/// <returns></returns>
List<SqlSugarTableInfo> GetTables();
/// <summary>
/// 获取批量修改配置
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<List<BatchEditConfig>> ConfigList(BaseIdInput input);
/// <summary>
/// 配置字段
/// </summary>
/// <param name="input">字段信息</param>
/// <returns></returns>
Task Config(List<BatchEditConfigInput> input);
/// <summary>
/// 批量配置字段列表
/// </summary>
/// <param name="code">唯一编码</param>
/// <returns>列表</returns>
Task<List<BatchEditConfig>> Columns(string code);
/// <summary>
/// 获取字典配置
/// </summary>
/// <param name="code">唯一编码</param>
/// <param name="columns">字段信息</param>
/// <returns>SqlSugar对应字典</returns>
Task<Dictionary<string, object>> GetUpdateBatchConfigDict(string code, List<BatchEditColumn> columns);
/// <summary>
/// 同步字段
/// </summary>
/// <param name="input">id</param>
/// <returns></returns>
Task SyncColumns(BaseIdInput input);
}
@@ -0,0 +1,22 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 文件分页输出
/// </summary>
public class FilePageInput : BasePageInput
{
/// <summary>
/// 文件引擎
/// </summary>
public string Engine { get; set; }
}
@@ -0,0 +1,273 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// <inheritdoc cref="IFileService"/>
/// </summary>
public class FileService : DbRepository<SysFile>, IFileService
{
private readonly IConfigService _configService;
public FileService(IConfigService configService)
{
_configService = configService;
}
/// <inheritdoc/>
public async Task<SqlSugarPagedList<SysFile>> Page(FilePageInput input)
{
var query = Context.Queryable<SysFile>().WhereIF(!string.IsNullOrEmpty(input.Engine), it => it.Engine == input.Engine)//根据关键字查询
.WhereIF(!string.IsNullOrEmpty(input.SearchKey), it => it.Name.Contains(input.SearchKey))//根据关键字查询
.OrderByIF(!string.IsNullOrEmpty(input.SortField), $"{input.SortField} {input.SortOrder}")//排序
.OrderBy(it => it.Id);
var pageInfo = await query.ToPagedListAsync(input.PageNum, input.PageSize);//分页
return pageInfo;
}
/// <inheritdoc/>
public async Task<long> UploadFile(string engine, IFormFile file)
{
return await StorageFile(engine, file);
}
/// <inheritdoc/>
public async Task Delete(BaseIdListInput input)
{
var ids = input.Ids;//获取ID
await DeleteByIdsAsync(ids.Cast<object>().ToArray());//根据ID删除数据库
}
/// <inheritdoc/>
public FileStreamResult GetFileStreamResult(string path, string fileName, bool isPathFolder = false)
{
if (isPathFolder) path = path.CombinePath(fileName);
fileName = HttpUtility.UrlEncode(fileName, Encoding.GetEncoding("UTF-8"));//文件名转utf8不然前端下载会乱码
//文件转流
var result = new FileStreamResult(new FileStream(path, FileMode.Open), "application/octet-stream")
{
FileDownloadName = fileName
};
return result;
}
public async Task<FileStreamResult> GetFileStreamResultFromMinio(string objectName, string fileName)
{
var minioService = App.GetService<MinioUtils>();
var stream = await minioService.DownloadFileAsync(objectName);
fileName = HttpUtility.UrlEncode(fileName, Encoding.GetEncoding("UTF-8"));//文件名转utf8不然前端下载会乱码
//文件转流
var result = new FileStreamResult(stream, "application/octet-stream")
{
FileDownloadName = fileName
};
return result;
}
/// <inheritdoc/>
public FileStreamResult GetFileStreamResult(byte[] byteArray, string fileName)
{
fileName = HttpUtility.UrlEncode(fileName, Encoding.GetEncoding("UTF-8"));//文件名转utf8不然前端下载会乱码
//文件转流
var result = new FileStreamResult(new MemoryStream(byteArray), "application/octet-stream")
{
FileDownloadName = fileName
};
return result;
}
/// <inheritdoc/>
public async Task<FileStreamResult> Download(BaseIdInput input)
{
var devFile = await GetByIdAsync(input.Id);
if (devFile != null)
{
if (devFile.Engine == SysDictConst.FILE_ENGINE_LOCAL)
return GetFileStreamResult(devFile.StoragePath, devFile.Name);
if (devFile.Engine == SysDictConst.FILE_ENGINE_MINIO)
return await GetFileStreamResultFromMinio(devFile.ObjName, devFile.Name);
return null;
}
return null;
}
#region 方法
/// <summary>
/// 存储文件
/// </summary>
/// <param name="engine"></param>
/// <param name="file"></param>
private async Task<long> StorageFile(string engine, IFormFile file)
{
var bucketName = string.Empty;// 存储桶名称
var storageUrl = string.Empty;// 定义存储的url,本地文件返回文件实际路径,其他引擎返回网络地址
var objName = string.Empty;// 定义存储的url,本地文件返回文件实际路径,其他引擎返回网络地址
var objectId = CommonUtils.GetSingleId();//生成id
switch (engine)
{
//存储本地
case SysDictConst.FILE_ENGINE_LOCAL:
bucketName = "defaultBucketName";// 存储桶名称
storageUrl = await StorageLocal(objectId, file);
break;
//存储本地
case SysDictConst.FILE_ENGINE_MINIO:
var config = await _configService.GetByConfigKey(CateGoryConst.CONFIG_FILE_MINIO, SysConfigConst.FILE_MINIO_DEFAULT_BUCKET_NAME);
if (config != null)
{
bucketName = config.ConfigValue;// 存储桶名称
(objName, storageUrl) = await StorageMinio(objectId, file);
}
break;
default:
throw Oops.Bah("不支持的文件引擎");
}
var fileSizeKb = (long)(file.Length / 1024.0);// 文件大小KB
var fileSuffix = Path.GetExtension(file.FileName).ToLower();// 文件后缀
var devFile = new SysFile
{
Id = objectId,
Engine = engine,
Bucket = bucketName,
Name = file.FileName,
Suffix = fileSuffix.Split(".")[1],
ObjName = objName,
SizeKb = fileSizeKb,
SizeInfo = GetSizeInfo(fileSizeKb),
StoragePath = storageUrl
};
if (engine != CateGoryConst.CONFIG_FILE_LOCAL)//如果不是本地,设置下载地址
{
devFile.DownloadPath = storageUrl;
}
//如果是图片,生成缩略图
if (IsPic(fileSuffix))
{
//$"data:image/png;base64," + imgByte;
await using var fileStream = file.OpenReadStream();//获取文件流
var image = SKImage.FromEncodedData(fileStream);//获取图片
var bmp = SKBitmap.FromImage(image);
var thubnail = bmp.GetPicThumbnail(100, 100);//压缩图片
var thubnailBase64 = ImageUtil.ImgToBase64String(thubnail);//转base64
devFile.Thumbnail = "data:image/png;base64," + thubnailBase64;
}
await InsertAsync(devFile);
return objectId;
}
/// <summary>
/// 存储本地文件
/// </summary>
/// <param name="fileId"></param>
/// <param name="file"></param>
private async Task<string> StorageLocal(long fileId, IFormFile file)
{
string uploadFileFolder;
var configKey = string.Empty;
//判断是windows还是linux
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
configKey = SysConfigConst.FILE_LOCAL_FOLDER_FOR_UNIX;//Linux
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
configKey = SysConfigConst.FILE_LOCAL_FOLDER_FOR_WINDOWS;//Windows
}
//获取路径配置
var config = await _configService.GetByConfigKey(CateGoryConst.CONFIG_FILE_LOCAL, configKey);
if (config != null)
{
uploadFileFolder = config.ConfigValue;//赋值路径
var now = DateTime.Now.ToString("d");
var filePath = Path.Combine(uploadFileFolder, now);
if (!Directory.Exists(filePath))//如果不存在就创建文件夹
Directory.CreateDirectory(filePath);
var fileSuffix = Path.GetExtension(file.FileName).ToLower();// 文件后缀
var fileObjectName = $"{fileId}{fileSuffix}";//存储后的文件名
var fileName = Path.Combine(filePath, fileObjectName);//获取文件全路局
fileName = fileName.Replace("\\", "/");//格式化一系
//存储文件
using (var stream = File.Create(Path.Combine(filePath, fileObjectName)))
{
await file.CopyToAsync(stream);
}
return fileName;
}
throw Oops.Oh("文件存储路径未配置");
}
/// <summary>
/// 存储到minio
/// </summary>
/// <param name="fileId"></param>
/// <param name="file"></param>
/// <returns></returns>
private async Task<(string objName, string downloadUrl)> StorageMinio(long fileId, IFormFile file)
{
var minioService = App.GetService<MinioUtils>();
var now = DateTime.Now.ToString("d");
var fileSuffix = Path.GetExtension(file.FileName).ToLower();// 文件后缀
var fileObjectName = $"{now}/{fileId}{fileSuffix}";//存储后的文件名
var downloadUrl = await minioService.PutObjectAsync(fileObjectName, file);
return (fileObjectName, downloadUrl);
}
/// <summary>
/// 获取文件大小
/// </summary>
/// <param name="fileSizeKb"></param>
/// <returns></returns>
private string GetSizeInfo(long 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;
}
/// <summary>
/// 判断是否是图片
/// </summary>
/// <param name="suffix">后缀名</param>
/// <returns></returns>
private bool IsPic(string suffix)
{
//图片后缀名列表
var pics = new[]
{
".png", ".bmp", ".gif", ".jpg", ".jpeg", ".psd"
};
if (pics.Contains(suffix))
return true;
return false;
}
#endregion 方法
}
@@ -0,0 +1,63 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 文件管理服务
/// </summary>
public interface IFileService : ITransient
{
/// <summary>
/// 删除文件
/// </summary>
/// <param name="input">ID列表</param>
/// <returns></returns>
Task Delete(BaseIdListInput input);
/// <summary>
/// 文件下载
/// </summary>
/// <param name="input">文件iD</param>
/// <returns>文件流</returns>
Task<FileStreamResult> Download(BaseIdInput input);
/// <summary>
/// 获取FileStreamResult文件流
/// </summary>
/// <param name="path">路径</param>
/// <param name="fileName">文件名</param>
/// <param name="isPathFolder">路径是否是文件夹</param>
/// <returns></returns>
FileStreamResult GetFileStreamResult(string path, string fileName, bool isPathFolder = false);
/// <summary>
/// 获取FileStreamResult文件流
/// </summary>
/// <param name="byteArray">文件数组</param>
/// <param name="fileName">文件名</param>
/// <returns></returns>
FileStreamResult GetFileStreamResult(byte[] byteArray, string fileName);
/// <summary>
/// 文件分页查询
/// </summary>
/// <param name="input">查询参数</param>
/// <returns>文件列表</returns>
Task<SqlSugarPagedList<SysFile>> Page(FilePageInput input);
/// <summary>
/// 上传文件到本地返回下载url
/// </summary>
/// <param name="engine">文件引擎</param>
/// <param name="file">文件</param>
/// <returns></returns>
Task<long> UploadFile(string engine, IFormFile file);
}
@@ -0,0 +1,90 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
public class MessagePageInput : BasePageInput
{
/// <summary>
/// 站内信分类
/// </summary>
public string Category { get; set; }
}
/// <summary>
/// 发送参数
/// </summary>
public class MessageSendInput : SysMessage
{
/// <summary>
/// 主题
/// </summary>
[Required(ErrorMessage = "Subject不能为空")]
public override string Subject { get; set; }
/// <summary>
/// 分类
/// </summary>
[Required(ErrorMessage = "Category不能为空")]
public override string Category { get; set; }
/// <summary>
/// 接收人Id
/// </summary>
public List<long> ReceiverIdList { get; set; }
public override string Status { get; set; } = SysDictConst.MESSAGE_STATUS_READY;
}
public class MessageSendUpdateInput : MessageSendInput
{
/// <summary>
/// 消息Id
/// </summary>
[Required(ErrorMessage = "Id不能为空")]
public override long Id { get; set; }
}
/// <summary>
/// 消息详情输入参数
/// </summary>
public class MessageDetailInput : BaseIdInput
{
/// <summary>
/// 是否显示接收信息
/// </summary>
public bool ShowReceiveInfo { get; set; } = false;
/// <summary>
/// 是否已读
/// </summary>
public bool Read { get; set; } = false;
}
/// <summary>
/// 已读输入参数
/// </summary>
public class MessageReadInput
{
/// <summary>
/// 分类
/// </summary>
public string Category { get; set; }
/// <summary>
/// 用户Id
/// </summary>
public long Id { get; set; }
/// <summary>
/// 消息Id
/// </summary>
public List<long> Ids { get; set; } = new List<long>();
}
@@ -0,0 +1,34 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 消息详情
/// </summary>
public class MessageDetailOutPut : SysMessage
{
}
/// <summary>
/// 未读消息数量输出
/// </summary>
public class MessageUnReadOutPut
{
/// <summary>
/// 未读消息数量
/// </summary>
public int UnReadCount { get; set; }
/// <summary>
/// 分类
/// </summary>
public string Category { get; set; }
}
@@ -0,0 +1,97 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 站内信服务
/// </summary>
public interface IMessageService : ITransient
{
/// <summary>
/// 删除消息
/// </summary>
/// <param name="input">id列表</param>
/// <returns></returns>
Task Delete(BaseIdListInput input);
/// <summary>
/// 删除我的消息
/// </summary>
/// <param name="input"></param>
/// <param name="userId"></param>
/// <returns></returns>
Task DeleteMyMessage(BaseIdInput input, long userId);
/// <summary>
/// 获取消息详情
/// </summary>
/// <param name="input">输入参数</param>
/// <returns>消息详情</returns>
Task<SysMessage> Detail(MessageDetailInput input);
/// <summary>
/// 我的消息列表
/// </summary>
/// <param name="input"></param>
/// <param name="userId"></param>
/// <returns></returns>
Task<SqlSugarPagedList<SysMessage>> MyMessagePage(MessagePageInput input, long userId);
/// <summary>
/// 分页查询
/// </summary>
/// <param name="input">查询参数</param>
/// <returns></returns>
Task<SqlSugarPagedList<SysMessage>> Page(MessagePageInput input);
/// <summary>
/// 获取未读消息数
/// </summary>
/// <param name="userId">用户Id</param>
/// <returns></returns>
Task<List<MessageUnReadOutPut>> UnReadCount(long userId);
/// <summary>
/// 最新未读
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
Task<List<SysMessage>> NewUnRead(long userId);
/// <summary>
/// 标记已读
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<int> SetRead(MessageReadInput input);
/// <summary>
/// 删除消息
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<int> SetDelete(MessageReadInput input);
/// <summary>
/// 新增
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task Add(MessageSendInput input);
/// <summary>
/// 编辑
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task Edit(MessageSendUpdateInput input);
}
@@ -0,0 +1,339 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
using Masuit.Tools.DateTimeExt;
namespace SimpleAdmin.System;
/// <summary>
/// <inheritdoc cref="IMessageService"/>
/// </summary>
public class MessageService : DbRepository<SysMessage>, IMessageService
{
private readonly ILogger<MessageService> _logger;
private readonly ISimpleCacheService _simpleCacheService;
private readonly IRelationService _relationService;
private readonly IEventPublisher _eventPublisher;
public MessageService(ILogger<MessageService> logger, ISimpleCacheService simpleCacheService, IRelationService relationService,
IEventPublisher eventPublisher)
{
_logger = logger;
_simpleCacheService = simpleCacheService;
_relationService = relationService;
_eventPublisher = eventPublisher;
}
/// <inheritdoc />
public async Task<SqlSugarPagedList<SysMessage>> Page(MessagePageInput input)
{
var query = Context.Queryable<SysMessage>().WhereIF(!string.IsNullOrEmpty(input.Category), it => it.Category == input.Category)//根据分类查询
.WhereIF(!string.IsNullOrEmpty(input.SearchKey),
it => it.Subject.Contains(input.SearchKey) || it.Content.Contains(input.SearchKey))//根据关键字查询
.OrderByIF(!string.IsNullOrEmpty(input.SortField), $"{input.SortField} {input.SortOrder}")//排序
.OrderBy(it => it.CreateTime, OrderByType.Desc);
var pageInfo = await query.ToPagedListAsync(input.PageNum, input.PageSize);//分页
return pageInfo;
}
/// <inheritdoc />
public async Task<SqlSugarPagedList<SysMessage>> MyMessagePage(MessagePageInput input, long userId)
{
var query = Context.Queryable<SysMessageUser>().LeftJoin<SysMessage>((u, m) => u.MessageId == m.Id)
.Where((u, m) => u.IsDelete == false && u.UserId == userId && u.Status == SysDictConst.MESSAGE_STATUS_ALREADY)
.WhereIF(!string.IsNullOrEmpty(input.Category), (u, m) => m.Category == input.Category)//根据分类查询
.WhereIF(!string.IsNullOrEmpty(input.SearchKey),
(u, m) => m.Subject.Contains(input.SearchKey) || m.Content.Contains(input.SearchKey))//根据关键字查询
.OrderBy((u, m) => u.Read).OrderBy((u, m) => u.CreateTime, OrderByType.Desc).Select((u, m) => new SysMessage
{
Id = m.Id.SelectAll(),
Read = u.Read
});
var pageInfo = await query.ToPagedListAsync(input.PageNum, input.PageSize);//分页
return pageInfo;
}
/// <inheritdoc />
public async Task Add(MessageSendInput input)
{
CheckInput(input);
var sysMessage = input.Adapt<SysMessage>();//实体转换
sysMessage.Id = CommonUtils.GetSingleId();
//如果是立即发送的直接修改状态
if (sysMessage.SendWay == SysDictConst.SEND_WAY_NOW)
sysMessage.Status = SysDictConst.MESSAGE_STATUS_ALREADY;//已发送
var messageUsers = new List<SysMessageUser>();
var userIds = new List<long>();
//根据接收人获取需要发送的用户id
switch (sysMessage.ReceiverType)
{
case SysDictConst.RECEIVER_TYPE_ALL:
userIds = await Context.Queryable<SysUser>().Select(it => it.Id).ToListAsync();
break;
case SysDictConst.RECEIVER_TYPE_ROLE:
var roleIds = sysMessage.ReceiverInfo.Select(it => it.Id.ToString()).ToList();//获取角色ID列表
var roleUsers =
await _relationService.GetRelationListByTargetIdListAndCategory(roleIds, CateGoryConst.RELATION_SYS_USER_HAS_ROLE);//获取角色用户列表
userIds = roleUsers.Select(it => it.ObjectId).ToList();//获取用户ID列表
break;
case SysDictConst.RECEIVER_TYPE_APPOINT:
userIds = sysMessage.ReceiverInfo.Select(it => it.Id).ToList();
break;
}
//去掉自己
userIds = userIds.Where(it => it != UserManager.UserId).ToList();
//遍历用户ID
userIds.ForEach(userId =>
{
messageUsers.Add(new SysMessageUser
{
MessageId = sysMessage.Id,
UserId = userId,
Read = false,
IsDelete = false,
Status = sysMessage.SendWay == SysDictConst.SEND_WAY_NOW ? SysDictConst.MESSAGE_STATUS_ALREADY : SysDictConst.MESSAGE_STATUS_READY
});
});
//事务
var result = await Tenant.UseTranAsync(async () =>
{
await InsertAsync(sysMessage);//添加消息
await Context.Insertable(messageUsers).ExecuteCommandAsync();
});
if (result.IsSuccess)//如果成功了
{
await _eventPublisher.PublishAsync(EventSubscriberConst.NEW_MESSAGE, new NewMessageEvent
{
Id = sysMessage.Id,
SendWay = sysMessage.SendWay,
SendTime = sysMessage.SendTime
});//通知用户有新的消息
}
else
{
//写日志
_logger.LogError(result.ErrorMessage, result.ErrorException);
throw Oops.Oh(ErrorCodeEnum.A0003);
}
}
/// <inheritdoc />
public async Task Edit(MessageSendUpdateInput input)
{
CheckInput(input);
var sysMessage = input.Adapt<SysMessage>();//实体转换
await UpdateAsync(sysMessage);//更新数据
}
/// <inheritdoc />
public async Task<SysMessage> Detail(MessageDetailInput input)
{
//获取消息
var message = await GetFirstAsync(it => it.Id == input.Id);
if (message != null && message.SendWay == SysDictConst.SEND_WAY_DELAY)
{
//delayTime等于发送时间减掉创建时间
message.DelayTime = (int)(message.SendTime.GetTotalSeconds() - message.CreateTime.Value.GetTotalSeconds());
}
if (message != null && input.ShowReceiveInfo)
{
var messageUserRep = ChangeRepository<DbRepository<SysMessageUser>>();//切换仓储
var messageUsers = await messageUserRep.GetListAsync(it => it.MessageId == message.Id);
var userIds = messageUsers.Select(it => it.UserId).ToList();//获取用户ID列表
var userInfos = await Context.Queryable<SysUser>().Where(it => userIds.Contains(it.Id)).Select(it => new { it.Id, it.Name })
.ToListAsync();//获取用户姓名信息列表
//遍历关系
messageUsers.ForEach(messageUser =>
{
var user = userInfos.Where(u => u.Id == messageUser.UserId).FirstOrDefault();//获取用户信息
if (user != null)
{
//添加到已读列表
message.ReceiverDetail.Add(new ReceiverDetail
{
Id = user.Id,
Name = user.Name,
Read = messageUser.Read
});
}
});
}
//设置已读
if (input.Read)
{
await Context.Updateable<SysMessageUser>()
.SetColumns(it => it.Read == true)
.SetColumns(it => it.UpdateTime == DateTime.Now)
.Where(it => it.MessageId == input.Id && it.Read == false && it.UserId == UserManager.UserId).ExecuteCommandAsync();
}
return message;
}
/// <inheritdoc />
public async Task Delete(BaseIdListInput input)
{
//获取所有ID
var ids = input.Ids;
if (ids.Count > 0)
{
//事务
var result = await Tenant.UseTranAsync(async () =>
{
await DeleteAsync(it => ids.Contains(it.Id));
await Context.Deleteable<SysMessageUser>().Where(it => ids.Contains(it.MessageId)).ExecuteCommandAsync();
});
if (!result.IsSuccess)//如果失败了
{
//写日志
_logger.LogError(result.ErrorMessage, result.ErrorException);
throw Oops.Oh(ErrorCodeEnum.A0002);
}
}
}
/// <inheritdoc />
public async Task DeleteMyMessage(BaseIdInput input, long userId)
{
var messageUserRep = ChangeRepository<DbRepository<SysMessageUser>>();//切换仓储
await Context.Deleteable<SysMessageUser>().Where(it => it.UserId == userId && it.MessageId == input.Id).IsLogic().ExecuteCommandAsync();//逻辑删除
}
/// <inheritdoc />
public async Task<List<MessageUnReadOutPut>> UnReadCount(long userId)
{
// 连表查询未读
var unReadList = await Context.Queryable<SysMessage>().LeftJoin<SysMessageUser>((m, u) => u.MessageId == m.Id)
.Where((m, u) => u.UserId == userId && u.Read == false && u.IsDelete == false)
.Select<SysMessage>().ToListAsync();
//根据消息分类分组
var groupList = unReadList.GroupBy(it => it.Category).Select(it => new MessageUnReadOutPut
{
Category = it.Key,
UnReadCount = it.Count()
}).ToList();
return groupList;
}
/// <inheritdoc />
public async Task<List<SysMessage>> NewUnRead(long userId)
{
//根据消息分类分组,获取每组未读前五条
var result = await Context.Queryable<SysMessage>().LeftJoin<SysMessageUser>((m, u) => u.MessageId == m.Id)
.Where((m, u) => u.UserId == userId && u.IsDelete == false && u.Status == SysDictConst.MESSAGE_STATUS_ALREADY)
.Select((m, u) => new SysMessage
{
Index2 = SqlFunc.RowNumber($"{m.Id} desc",
m.Category),//order by id partition by name,参考sqlsugar分组查询https://www.donet5.com/Doc/1/2243
Subject = m.Subject,
CreateTime = m.CreateTime,
SendTime = m.SendTime,
Category = m.Category,
Read = u.Read
})
.MergeTable()//将结果合并成一个表
.Where(it => it.Index2 <= 5)//取第五条
.Mapper(it =>
{
it.SendTimeFormat = TimeHelper.FormatTimeAgo(it.SendTime);
})
.ToListAsync();
return result;
}
/// <inheritdoc />
public async Task<int> SetRead(MessageReadInput input)
{
//如果ID列表为空,就是全部已读
if (input.Ids.Count == 0 && input.Category != null)
{
var result = await Context.Updateable<SysMessageUser>()
.SetColumns(it => it.Read == true)
.SetColumns(it => it.UpdateTime == DateTime.Now)
.Where(it => it.UserId == UserManager.UserId && it.Read == false)
.Where(it => SqlFunc.Subqueryable<SysMessage>().Where(s => s.Id == it.MessageId && s.Category == input.Category).Any())
.ExecuteCommandAsync();
return result;
}
else
{
return await Context.Updateable<SysMessageUser>()
.SetColumns(it => it.Read == true)
.SetColumns(it => it.UpdateTime == DateTime.Now)
.Where(it => it.UserId == UserManager.UserId && input.Ids.Contains(it.MessageId))
.Where(it => it.Read == false)
.ExecuteCommandAsync();
}
}
/// <inheritdoc />
public async Task<int> SetDelete(MessageReadInput input)
{
//如果ID列表为空,就是全部删除
if (input.Ids.Count == 0 && input.Category != null)
{
var result = await Context.Updateable<SysMessageUser>()
.SetColumns(it => it.IsDelete == true)
.SetColumns(it => it.UpdateTime == DateTime.Now)
.Where(it => it.UserId == UserManager.UserId && it.IsDelete == false)
.Where(it => SqlFunc.Subqueryable<SysMessage>().Where(s => s.Id == it.MessageId && s.Category == input.Category).Any())
.ExecuteCommandAsync();
return result;
}
else
{
return await Context.Updateable<SysMessageUser>()
.SetColumns(it => it.IsDelete == true)
.SetColumns(it => it.UpdateTime == DateTime.Now)
.Where(it => it.UserId == UserManager.UserId && input.Ids.Contains(it.MessageId))
.Where(it => it.IsDelete == false)
.ExecuteCommandAsync();
}
}
#region 方法
/// <summary>
/// 检查输入
/// </summary>
/// <param name="input"></param>
private void CheckInput(MessageSendInput input)
{
if (input.Status == SysDictConst.MESSAGE_STATUS_ALREADY)
throw Oops.Oh("已发送的消息不能修改");
switch (input.SendWay)
{
case SysDictConst.SEND_WAY_NOW:
input.SendTime = DateTime.Now;
break;
case SysDictConst.SEND_WAY_DELAY:
if (input.CreateTime != null)
input.SendTime = input.CreateTime.Value.AddSeconds(input.DelayTime);
else
input.SendTime = DateTime.Now.AddSeconds(input.DelayTime);
break;
case SysDictConst.SEND_WAY_SCHEDULE:
if (input.SendTime < DateTime.Now)
throw Oops.Oh("发送时间不能小于当前时间");
input.SendTime = input.SendTime;
break;
}
}
#endregion
}
@@ -0,0 +1,180 @@
namespace SimpleAdmin.System;
/// <summary>
/// 代码生成基础添加参数
/// </summary>
public class GenBasicAddInput : GenBasic, IValidatableObject
{
/// <summary>
/// 所属库名称
/// </summary>
[Required(ErrorMessage = "ConfigId不能为空")]
public override string ConfigId { get; set; }
/// <summary>
/// 主表名称
/// </summary>
[Required(ErrorMessage = "BbTable不能为空")]
public override string DbTable { get; set; }
/// <summary>
/// 功能列表
/// </summary>
[Required(ErrorMessage = "FuncList不能为空")]
public override List<string>? FuncList { get; set; }
/// <summary>
/// 生成模版
/// </summary>
[Required(ErrorMessage = "ModuleType不能为空")]
public override string ModuleType { get; set; }
/// <summary>
/// 数据权限
/// </summary>
[Required(ErrorMessage = "DataPermission不能为空")]
public override string DataPermission { get; set; }
/// <summary>
/// 实体名称
/// </summary>
[Required(ErrorMessage = "EntityName不能为空")]
public override string EntityName { get; set; }
/// <summary>
/// 表前缀移除
/// </summary>
[Required(ErrorMessage = "TablePrefix不能为空")]
public override string TablePrefix { get; set; }
/// <summary>
/// 生成方式
/// </summary>
[Required(ErrorMessage = "GenerateType不能为空")]
public override string GenerateType { get; set; }
/// <summary>
/// 所属模块
/// </summary>
[IdNotNull(ErrorMessage = "Module不能为空")]
public override long Module { get; set; }
/// <summary>
/// 路由名
/// </summary>
[Required(ErrorMessage = "RouteName不能为空")]
public override string RouteName { get; set; }
/// <summary>
/// 图标
/// </summary>
[Required(ErrorMessage = "Icon不能为空")]
public override string Icon { get; set; }
/// <summary>
/// 功能名
/// </summary>
[Required(ErrorMessage = "FunctionName不能为空")]
public override string FunctionName { get; set; }
/// <summary>
/// 业务名
/// </summary>
[Required(ErrorMessage = "BusName不能为空")]
public override string BusName { get; set; }
/// <summary>
/// 类名
/// </summary>
[Required(ErrorMessage = "ClassName不能为空")]
public override string ClassName { get; set; }
/// <summary>
/// 表单布局
/// </summary>
[Required(ErrorMessage = "FormLayout不能为空")]
public override string FormLayout { get; set; }
/// <summary>
/// 使用栅格
/// </summary>
[Required(ErrorMessage = "GridWhether不能为空")]
public override string GridWhether { get; set; }
/// <summary>
/// 左侧树
/// </summary>
[Required(ErrorMessage = "LeftTree不能为空")]
public override string LeftTree { get; set; }
/// <summary>
/// 前端路径
/// </summary>
[Required(ErrorMessage = "FrontedPath不能为空")]
public override string FrontedPath { get; set; }
/// <summary>
/// 服务层
/// </summary>
[Required(ErrorMessage = "ServicePosition不能为空")]
public override string ServicePosition { get; set; }
/// <summary>
/// 控制器层
/// </summary>
[Required(ErrorMessage = "ControllerPosition不能为空")]
public override string ControllerPosition { get; set; }
/// <summary>
/// 排序
/// </summary>
[Required(ErrorMessage = "SortCode不能为空")]
public override int SortCode { get; set; }
/// <summary>
/// 作者名
/// </summary>
[Required(ErrorMessage = "AuthorName不能为空")]
public override string AuthorName { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
//如果是树形结构
if (ModuleType.Contains("tree"))
{
if (string.IsNullOrEmpty(TreeId) || string.IsNullOrEmpty(TreeName) || string.IsNullOrEmpty(TreePid))
yield return new ValidationResult($"必须配置树表相关信息", new[] { nameof(TreeId), nameof(TreeName), nameof(TreePid) });
}
//如果是树形结构
if (ModuleType.Contains("master"))
{
if (string.IsNullOrEmpty(ChildFk) || string.IsNullOrEmpty(ChildTable))
yield return new ValidationResult($"必须配置主子表相关信息", new[] { nameof(ChildTable), nameof(ChildFk) });
}
if (!FuncList.Contains("curd"))
{
yield return new ValidationResult($"必须包含基础的增删改查功能", new[] { nameof(FuncList) });
}
}
}
/// <summary>
/// 代码生成基础编辑参数
/// </summary>
public class GenBasicEditInput : GenBasicAddInput
{
[IdNotNull(ErrorMessage = "Id不能为空")]
public override long Id { get; set; }
}
/// <summary>
/// 执行代码生成参数
/// </summary>
public class ExecGenInput : BaseIdInput
{
/// <summary>
/// 生成类型
/// </summary>
public string ExecType { get; set; }
}
@@ -0,0 +1,67 @@
namespace SimpleAdmin.System;
/// <summary>
/// 表字段信息输出
/// </summary>
public class GenBasicColumnOutput
{
/// <summary>
/// 字段名称
/// </summary>
public string ColumnName { get; set; }
/// <summary>
/// 是否主键
/// </summary>
public bool IsPrimarykey { get; set; }
/// <summary>
/// 字段类型
/// </summary>
public string TypeName { get; set; }
/// <summary>
/// 字段注释
/// </summary>
public string ColumnRemark { get; set; }
}
/// <summary>
/// 预览代码生成结果
/// </summary>
public class GenBasePreviewOutput
{
/// <summary>
/// SQL代码结果集
/// </summary>
public List<GenBaseCodeResult> SqlResults { get; set; } = new List<GenBaseCodeResult>();
/// <summary>
/// 前端代码结果集
/// </summary>
public List<GenBaseCodeResult> CodeFrontendResults { get; set; } = new List<GenBaseCodeResult>();
/// <summary>
/// 后端代码结果集
/// </summary>
public List<GenBaseCodeResult> CodeBackendResults { get; set; } = new List<GenBaseCodeResult>();
public class GenBaseCodeResult
{
/// <summary>
/// 代码文件名称
/// </summary>
public string CodeFileName { get; set; }
/// <summary>
/// 文件路径
/// </summary>
public string FilePath { get; set; }
/// <summary>
/// 代码文件内容
/// </summary>
public string CodeFileContent { get; set; }
}
}
@@ -0,0 +1,254 @@
using StringHelper = SimpleTool.StringHelper;
namespace SimpleAdmin.System;
/// <summary>
/// 代码生成绑定视图
/// </summary>
public class GenViewModel : GenBasic
{
#region 基础
/// <summary>
/// 生成时间
/// </summary>
public string GenTime { get; set; } = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
/// <summary>
/// 表字段
/// </summary>
public List<GenConfig> TableFields { get; set; }
#endregion 基础
#region 菜单
/// <summary>
/// 菜单ID
/// </summary>
public long MenuId { get; set; } = CommonUtils.GetSingleId();
/// <summary>
/// 菜单编码
/// </summary>
public string MenuCode { get; set; }
/// <summary>
/// /菜单路径
/// </summary>
public string MenuPath
{
get { return $"/{RouteName}/{BusName}"; }
}
/// <summary>
/// /菜单路径
/// </summary>
public string MenuComponent
{
get { return $"{RouteName}/{BusName}/index"; }
}
#endregion 菜单
#region 按钮
/// <summary>
/// 添加按钮ID
/// </summary>
public long AddButtonId { get; set; } = CommonUtils.GetSingleId();
/// <summary>
/// 批量删除按钮ID
/// </summary>
public long BatchDeleteButtonId { get; set; } = CommonUtils.GetSingleId();
/// <summary>
/// 编辑按钮ID
/// </summary>
public long EditButtonId { get; set; } = CommonUtils.GetSingleId();
/// <summary>
/// 删除按钮ID
/// </summary>
public long DeleteButtonId { get; set; } = CommonUtils.GetSingleId();
#endregion 按钮
#region 后端
/// <summary>
/// 类名首字母小写
/// </summary>
public string ClassNameFirstLower
{
get { return StringHelper.FirstCharToLower(ClassName); }
}
/// <summary>
/// swagger分组名称
/// </summary>
public string ApiGroup
{
get
{
return ServicePosition.Split(".").Last();
}
}
/// <summary>
/// 服务名
/// </summary>
public string ServiceName
{
get { return ClassName + "Service"; }
}
/// <summary>
/// 服务名开头首字母小写
/// </summary>
public string ServiceFirstLower
{
get { return ClassNameFirstLower + "Service"; }
}
#endregion 后端
#region 注释描述
/// <summary>
/// 分页查询
/// </summary>
public string DescriptionPage
{
get { return FunctionName + "分页查询"; }
}
/// <summary>
/// 列表查询
/// </summary>
public string DescriptionList
{
get { return FunctionName + "列表查询"; }
}
/// <summary>
/// 添加
/// </summary>
public string DescriptionAdd
{
get { return "添加" + FunctionName; }
}
/// <summary>
/// 修改
/// </summary>
public string DescriptionEdit
{
get { return "修改" + FunctionName; }
}
/// <summary>
/// 修改
/// </summary>
public string DescriptionDelete
{
get { return "删除" + FunctionName; }
}
/// <summary>
/// 详情
/// </summary>
public string DescriptionDetail
{
get { return FunctionName + "详情"; }
}
/// <summary>
/// 导入
/// </summary>
public string DescriptionImport
{
get { return FunctionName + "导入"; }
}
/// <summary>
/// 导入模板下载
/// </summary>
public string DescriptionTemplate
{
get { return FunctionName + "导入模板下载"; }
}
/// <summary>
/// 导入预览
/// </summary>
public string DescriptionPreview
{
get { return FunctionName + "导入预览"; }
}
/// <summary>
/// 导入
/// </summary>
public string DescriptionExport
{
get { return FunctionName + "导出"; }
}
/// <summary>
/// 批量编辑
/// </summary>
public string DescriptionEdits
{
get { return FunctionName + "批量编辑"; }
}
/// <summary>
/// 树查询
/// </summary>
public string DescriptionTree
{
get { return FunctionName + "树"; }
}
#endregion 注释描述
#region 参数
/// <summary>
/// 分页参数
/// </summary>
public string PageInput
{
get { return ClassName + "PageInput"; }
}
/// <summary>
/// 添加参数
/// </summary>
public string AddInput
{
get { return ClassName + "AddInput"; }
}
/// <summary>
/// 编辑参数
/// </summary>
public string EditInput
{
get { return ClassName + "EditInput"; }
}
/// <summary>
/// 树查询参数
/// </summary>
public string TreeInput
{
get { return ClassName + "TreeInput"; }
}
#endregion 参数
}
@@ -0,0 +1,808 @@
using StringHelper = SimpleTool.StringHelper;
namespace SimpleAdmin.System;
/// <summary>
/// <inheritdoc cref="IGenbasicService"/>
/// </summary>
public class GenBasicService : DbRepository<GenBasic>, IGenbasicService
{
private readonly ILogger<GenBasicService> _logger;
private readonly IViewEngine _viewEngine;
private readonly IGenConfigService _genConfigService;
private readonly IMenuService _menuService;
private readonly IButtonService _buttonService;
private readonly ISysRoleService _roleService;
private readonly string _sqlDir = "Sql";
private readonly string _backendDir = "Backend";
private readonly string _frontDir = "Frontend";
private const string _interfaceDir = "interface";
private const string _modulesDir = "modules";
private const string _indexTs = "index.ts";
public GenBasicService(ILogger<GenBasicService> logger,
IViewEngine viewEngine,
IGenConfigService genConfigService,
IMenuService menuService,
IButtonService buttonService, ISysRoleService roleService)
{
_logger = logger;
_viewEngine = viewEngine;
_genConfigService = genConfigService;
_menuService = menuService;
_buttonService = buttonService;
_roleService = roleService;
}
/// <inheritdoc/>
public async Task<SqlSugarPagedList<GenBasic>> Page(BasePageInput input)
{
var query = Context.Queryable<GenBasic>()
.OrderByIF(!string.IsNullOrEmpty(input.SortField), $"{input.SortField} {input.SortOrder}")//排序
.OrderBy(it => it.SortCode, OrderByType.Desc)//默认排序
.OrderBy(it => it.CreateTime, OrderByType.Desc)//默认排序
.Mapper(it =>
{
it.FuncList = it.Functions.Split(",", StringSplitOptions.RemoveEmptyEntries).ToList();//功能集合转为列表
});
var pageInfo = await query.ToPagedListAsync(input.PageNum, input.PageSize);//分页
return pageInfo;
}
/// <inheritdoc/>
public List<SqlSugarTableInfo> GetTables(bool isAll = false)
{
if (isAll)
return SqlSugarUtils.GetTablesByAttribute<SugarTable>();
return SqlSugarUtils.GetTablesByAttribute<CodeGenAttribute>();
}
/// <inheritdoc/>
public List<string> GetAssemblies()
{
var names = new List<string>();//结果集
var excludeList = new List<string>
{
"Web.Entry", "Core", "Cache", "SqlSugar", "Plugin.Core", "Plugin.Aop"
};//排除的程序集
//获取所有程序集名称
var assemblies = App.Assemblies
.Where(it => !it.FullName.StartsWith("MoYu"))
.Select(it => it.FullName).ToList();
assemblies.ForEach(it =>
{
var name = it.Split(",")[0];//根据逗号分割取第一个
//根据.分割获取最后两个
var projectName = string.Join(".", name.Split(".").Skip(1).ToList());
if (!excludeList.Contains(projectName))//去掉排除的程序集
{
names.Add(name);
}
});
return names;
}
/// <inheritdoc/>
public async Task<GenBasic> Add(GenBasicAddInput input)
{
var entity = input.Adapt<GenBasic>();//输入参数转实体
entity.Functions = string.Join(",", input.FuncList);//功能集合
var tableColumns = SqlSugarUtils.GetTableColumns(input.ConfigId, input.DbTable);//获取表的字段信息
var genConfigs = new List<GenConfig>();//代码生成配置字段集合
//遍历字段
var sortCode = 0;
//遍历字段
tableColumns.ForEach(it =>
{
#region 判断是否想显示
var yesOrNo = GenConst.Yes;
if (it.IsPrimaryKey || SqlSugarUtils.IsCommonColumn(it.ColumnName))//如果是主键或者是公共字段则不显示
yesOrNo = GenConst.No;
else
yesOrNo = GenConst.Yes;
#endregion 判断是否想显示
//添加到字段集合
genConfigs.Add(new GenConfig
{
IsPrimaryKey = it.IsPrimaryKey ? GenConst.Yes : GenConst.No,
FieldName = it.ColumnName,
FieldType = it.DataType,
FieldNetType = SqlSugarUtils.ConvertDataType(it.DataType),
FieldRemark = it.ColumnDescription ?? it.ColumnName,
EffectType = EffTypeConst.INPUT,
Width = 100,
WhetherTable = yesOrNo,
WhetherAddUpdate = yesOrNo,
WhetherImportExport = yesOrNo,
WhetherResizable = GenConst.No,
WhetherRequired = GenConst.No,
WhetherRetract = GenConst.No,
QueryWhether = GenConst.No,
SortCode = yesOrNo == GenConst.No ? 99 : sortCode//如果是公共字段就排最后
});
sortCode++;
});
var index = 0;
genConfigs = genConfigs.OrderBy(it => it.SortCode).ToList();//排序
genConfigs.ForEach(it =>
{
it.FieldIndex = index;
index++;
});
if (!genConfigs.Any(it => it.IsPrimaryKey == GenConst.Yes))//判断是否有主键
{
throw Oops.Bah("要生成的表必须有主键");
}
//事务
var result = await Tenant.UseTranAsync(async () =>
{
entity = await InsertReturnEntityAsync(entity);//输入参数转实体并插入
genConfigs.ForEach(it => { it.BasicId = entity.Id; });//遍历字段赋值基础Id
await Context.Insertable(genConfigs).ExecuteCommandAsync();
});
if (!result.IsSuccess)//如果失败了
{
//写日志
_logger.LogError(result.ErrorMessage, result.ErrorException);
throw Oops.Oh(ErrorCodeEnum.A0003);
}
return entity;
}
/// <inheritdoc/>
public async Task Delete(BaseIdListInput input)
{
//获取所有ID
var ids = input.Ids.ToList();
if (ids.Count > 0)
{
//事务
var result = await Tenant.UseTranAsync(async () =>
{
await DeleteByIdsAsync(ids.Cast<object>().ToArray());//删除基础表
await Context.Deleteable<GenConfig>().Where(it => ids.Contains(it.BasicId))
.ExecuteCommandAsync();//删除配置表
});
if (!result.IsSuccess)//如果失败了
{
//写日志
_logger.LogError(result.ErrorMessage, result.ErrorException);
throw Oops.Oh(ErrorCodeEnum.A0002);
}
}
}
/// <inheritdoc/>
public async Task<GenBasic> Edit(GenBasicEditInput input)
{
var entity = input.Adapt<GenBasic>();//输入参数转实体
entity.Functions = string.Join(",", input.FuncList);//功能集合
await UpdateAsync(entity);
return entity;
}
/// <inheritdoc/>
public async Task<GenBasePreviewOutput> PreviewGen(BaseIdInput input)
{
var genBasic = await GetGenBasic(input.Id);//获取代码生成基础
return await PreviewGen(genBasic);
}
/// <inheritdoc/>
public async Task ExecGenPro(ExecGenInput input)
{
var genBasic = await GetGenBasic(input.Id);//获取代码生成基础
if (genBasic.GenerateType != GenConst.Pro) throw Oops.Bah("当前配置生成方式为:项目中");
var backendPath =
Path.Combine(new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent.FullName);//获取主工程目录
if (await CreateMenuButtonAndRelation(genBasic))
{
var previewCode = await PreviewGen(genBasic);//获取代码生成预览
if (input.ExecType != GenConst.ExecAll)//如果不是全部执行
{
if (input.ExecType == GenConst.ExecBackend)
ExecBackend(previewCode.CodeBackendResults);//执行后端代码生成
else if (input.ExecType == GenConst.ExecFrontend)
ExecFronted(previewCode.CodeFrontendResults);//执行前端代码生成
}
else
{
ExecBackend(previewCode.CodeBackendResults);//执行后端代码生成
ExecFronted(previewCode.CodeFrontendResults);//执行前端代码生成
}
}
else
{
throw Oops.Bah("代码生成失败");
}
}
/// <inheritdoc/>
public async Task<FileStreamResult> ExecGenZip(ExecGenInput input)
{
var genBasic = await GetGenBasic(input.Id);//获取代码生成基础
// if (genBasic.GenerateType != GenConst.Zip) throw Oops.Bah("当前配置生成方式为:压缩包");
var temDir = Path.GetTempPath().CombinePath(genBasic.ClassName);//获取临时目录并用类名做存放代码文件文件夹
File.Delete(temDir + ".zip");// 先删除压缩包
var previewCode = await PreviewGen(genBasic);//获取代码生成预览
if (input.ExecType != GenConst.ExecAll)//如果不是全部执行
{
if (input.ExecType == GenConst.ExecBackend)
{
ExecBackend(previewCode.CodeBackendResults, temDir.CombinePath(_backendDir), true);//执行后端代码生成
ExecSql(previewCode.SqlResults, temDir);//执行sql生成
}
else if (input.ExecType == GenConst.ExecFrontend)
ExecFronted(previewCode.CodeFrontendResults, temDir.CombinePath(_frontDir));//执行前端生成
}
else
{
ExecBackend(previewCode.CodeBackendResults, temDir.CombinePath(_backendDir), true);//执行后端代码生成
ExecFronted(previewCode.CodeFrontendResults, temDir.CombinePath(_frontDir));//执行前端生成
ExecSql(previewCode.SqlResults, temDir);//执行sql生成
}
var zipPath = ZipUtils.CompressDirectory(temDir, true);//压缩文件夹
var result = new FileStreamResult(new FileStream(zipPath, FileMode.Open), "application/octet-stream")
{ FileDownloadName = $"{genBasic.ClassName}.zip" };
return result;
}
#region 方法
/// <summary>
/// 生成后端代码文件
/// </summary>
/// <param name="baseCodeResults">后端代码模板</param>
/// <param name="genBasic">代码基础</param>
/// <param name="backendPath">后端生成路径</param>
/// <param name="isZip">是否是zip方式</param>
// public void ExecBackend(List<GenBasePreviewOutput.GenBaseCodeResult> baseCodeResults, GenBasic genBasic,
// string backendPath, bool isZip = false)
// {
// var serviceDir = "Services";//服务代码文件夹
// var controllerDir = "Controllers";//服务代码文件夹
// var tempDicName = "";//临时文件夹名称
// var dirList = new HashSet<string> { };//文件夹列表
// var postion = "";//文件夹位置
// var parentDir = _backendDir;//父文件文件夹名称
// var serviceName = genBasic.ServicePosition.Split(".").Last();//取服务层最后一个单词命名为接口层控制器下的文件夹
// baseCodeResults.ForEach(it =>
// {
// var fileInfo = new FileInfo(it.FilePath);//获取文件信息
// var dirName = fileInfo.Directory.Name;//获取文件文件夹名称
// var parentName = fileInfo.Directory.Parent.Name;//获取父文件文件夹名称
// if (dirName == controllerDir)//如果是控制器
// {
// dirList.Add(dirName);//添加到当前文件夹到文件夹列表
// dirList.Add(serviceName);//添加服务层目录名到文件夹列表
// postion = genBasic.ControllerPosition;//设置文件夹创建位置为Api层
// }
// else if (dirName == serviceDir)//如果是服务
// {
// dirList.Remove(controllerDir);//删除接口文件夹
// dirList.Remove(serviceName);//删除服务层目录
// dirList.Add(genBasic.ClassName);//添加ClassName到文件夹列表
// dirList.Add(dirName);//添加到当前文件夹到文件夹列表
// postion = genBasic.ServicePosition;//设置文件夹创建位置为服务层
// }
//
// if (parentDir != parentName)//如果当前文件的父文件夹不等于partDir表示层级有变动
// {
// dirList.Add(dirName);//添加到文件夹列表
// parentDir = parentName;//重新赋值父文件夹
// }
// else
// {
// if (tempDicName != dirName)//如果临时文件夹不是当前文件夹表示同级目录下的另一个文件夹
// {
// dirList.Remove(tempDicName);//删除上一个文件夹
// dirList.Add(dirName);//添加当前文件夹到文件夹列表
// }
// }
//
// tempDicName = dirName;//给临时文件夹赋值
// var path = backendPath;//后端文件目录
// if (!isZip) path = backendPath.CombinePath(postion);//如果不是zip方式就加上命名空间
// path = path.CombinePath(dirList.ToArray());
// if (!Directory.Exists(path))//如果文件夹不存在就创建文件夹
// Directory.CreateDirectory(path);
// //var fileName = genBasic.ClassName + it.CodeFileName;//文件名等于类名加代码文件名
// //if (it.CodeFileName.StartsWith("IService"))
// // fileName = $"I{genBasic.ClassName}Service.cs";//对IService接口要特殊处理
// //path = path.CombinePath(fileName);//最终生成文件地址
// File.WriteAllText(path.CombinePath(it.CodeFileName), it.CodeFileContent, Encoding.UTF8);//写入文件
// });
// }
public void ExecBackend(List<GenBasePreviewOutput.GenBaseCodeResult> baseCodeResults, string backendPath = null, bool isZip = false)
{
//遍历baseCodeResults
baseCodeResults.ForEach(it =>
{
var path = it.FilePath;
//判断path所属的文件夹
var dir = Path.GetDirectoryName(path);
//如果backendPath不为空,则将path设置为backendPath.CombinePath($"{it.CodeFileName}")
if (backendPath != null)
{
path = backendPath.CombinePath($"{it.CodeFileName}");
//重新获取path所属的文件夹
dir = Path.GetDirectoryName(path);
}
//如果不存在就创建文件夹
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
File.WriteAllText(path, it.CodeFileContent, Encoding.UTF8);//写入文件
});
}
/// <summary>
/// 生成前端代码文件
/// </summary>
/// <param name="baseCodeResults">前端代码模板</param>
/// <param name="frontedPath">前端生成路径</param>
public void ExecFronted(List<GenBasePreviewOutput.GenBaseCodeResult> baseCodeResults, string frontedPath = null)
{
baseCodeResults.ForEach(it =>
{
var path = it.FilePath;
//判断path所属的文件夹
var dir = Path.GetDirectoryName(path);
if (frontedPath != null)
{
path = frontedPath.CombinePath($"{it.CodeFileName}");
dir = Path.GetDirectoryName(path);
}
//如果不存在就创建文件夹
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
File.WriteAllText(path, it.CodeFileContent, Encoding.UTF8);//写入文件
});
}
/// <summary>
/// 生成sql代码文件
/// </summary>
/// <param name="baseCodeResults">后端代码模板</param>
/// <param name="execPath">生成路径</param>
public void ExecSql(List<GenBasePreviewOutput.GenBaseCodeResult> baseCodeResults, string execPath)
{
execPath = execPath.CombinePath(_sqlDir);//写在sql目录里面
if (!Directory.Exists(execPath))//如果文件夹不存在就创建文件夹
Directory.CreateDirectory(execPath);
baseCodeResults.ForEach(it =>
{
File.WriteAllText(execPath.CombinePath(it.CodeFileName), it.CodeFileContent, Encoding.UTF8);//写入文件
});
}
/// <summary>
/// 获取sql代码预览结果
/// </summary>
/// <param name="genViewModel">视图</param>
/// <param name="templatePath">模板路径</param>
/// <returns></returns>
public async Task<List<GenBasePreviewOutput.GenBaseCodeResult>> GetSqlCodeResult(GenViewModel genViewModel,
string templatePath)
{
var sqlCodeResults = new List<GenBasePreviewOutput.GenBaseCodeResult>();//结果集
var sqlTemplatePath = Path.Combine(templatePath, _sqlDir);//获取sql模板文件路径
var files = GetAllFileInfo(sqlTemplatePath);
foreach (var fileInfo in files)
{
var fileName = fileInfo.Name;//文件名
var fileNoPrefix = fileName.Split(fileInfo.Extension)[0];//不带模板后缀的文件名
var tContent = File.ReadAllText(fileInfo.FullName);//读取文件
var tResult = await GetViewEngine(tContent, genViewModel);//渲染
//将渲染结果添加到结果集
sqlCodeResults.Add(new GenBasePreviewOutput.GenBaseCodeResult
{
CodeFileContent = tResult,
CodeFileName = fileNoPrefix,
FilePath = fileInfo.FullName
});
}
return sqlCodeResults;
}
/// <summary>
/// 获取后端代码预览结果
/// </summary>
/// <param name="genViewModel">视图</param>
/// <param name="templatePath">模板路径</param>
/// <returns></returns>
public async Task<List<GenBasePreviewOutput.GenBaseCodeResult>> GetBackendCodeResult(GenViewModel genViewModel,
string templatePath)
{
var backendCodeResults = new List<GenBasePreviewOutput.GenBaseCodeResult>();//结果集
var backendTemplatePath = Path.Combine(templatePath, _backendDir);//获取后端模板文件路径
var serviceDir = new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent.FullName.CombinePath(genViewModel.ServicePosition);//服务文件夹
var serviceDicList = genViewModel.ServiceDictionary.Split("/").Where(it => !string.IsNullOrWhiteSpace(it)).ToList();//获取文件夹
foreach (var item in serviceDicList)
{
serviceDir = serviceDir.CombinePath(item);
}
serviceDir = serviceDir.CombinePath(genViewModel.ClassName);
//获取控制器文件夹和后面的路径
var controllerDir = new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent.FullName.CombinePath(genViewModel.ControllerPosition);
var controllerDicList = genViewModel.ControllerDictionary.Split("/").Where(it => !string.IsNullOrWhiteSpace(it)).ToList();
foreach (var item in controllerDicList)
{
controllerDir = controllerDir.CombinePath(item);
}
controllerDir = controllerDir.CombinePath(genViewModel.ClassName);
var files = GetAllFileInfo(backendTemplatePath);
// files = files.Where(it => it.Name == "Service.cs.vm").ToArray();//测试用
var serviceFiles = files.Where(it => it.FullName.Contains("Service.cs")).ToList();
var controllerFiles = files.Where(it => it.FullName.Contains("Controller.cs")).ToList();
var dtoDir = files.Where(it => it.FullName.Contains("Dto")).ToList();
foreach (var fileInfo in serviceFiles)
{
var nameWithPrefix = fileInfo.Name;//文件名
var fileNoPrefix = nameWithPrefix.Split(fileInfo.Extension)[0];//不带模板后缀的文件名
var tContent = File.ReadAllText(fileInfo.FullName);//读取文件
var fileName = genViewModel.ClassName + fileNoPrefix;//文件名等于类名加代码文件名
if (fileNoPrefix.StartsWith("IService"))
fileName = $"I{genViewModel.ClassName}Service.cs";//对IService接口要特殊处理
var tResult = await GetViewEngine(tContent, genViewModel);//渲染
//将渲染结果添加到结果集
backendCodeResults.Add(new GenBasePreviewOutput.GenBaseCodeResult
{
CodeFileContent = tResult,
CodeFileName = $"{genViewModel.ClassName}{fileNoPrefix}",
FilePath = serviceDir.CombinePath(fileName)
});
}
foreach (var fileInfo in controllerFiles)
{
var nameWithPrefix = fileInfo.Name;//文件名
var fileNoPrefix = nameWithPrefix.Split(fileInfo.Extension)[0];//不带模板后缀的文件名
var tContent = File.ReadAllText(fileInfo.FullName);//读取文件
var fileName = genViewModel.ClassName + fileNoPrefix;//文件名等于类名加代码文件名
var tResult = await GetViewEngine(tContent, genViewModel);//渲染
//将渲染结果添加到结果集
backendCodeResults.Add(new GenBasePreviewOutput.GenBaseCodeResult
{
CodeFileContent = tResult,
CodeFileName = $"{genViewModel.ClassName}{fileNoPrefix}",
FilePath = controllerDir.CombinePath(fileName)
});
}
foreach (var fileInfo in dtoDir)
{
var nameWithPrefix = fileInfo.Name;//文件名
var fileNoPrefix = nameWithPrefix.Split(fileInfo.Extension)[0];//不带模板后缀的文件名
var tContent = File.ReadAllText(fileInfo.FullName);//读取文件
var fileName = genViewModel.ClassName + fileNoPrefix;//文件名等于类名加代码文件名
var tResult = await GetViewEngine(tContent, genViewModel);//渲染
//将渲染结果添加到结果集
backendCodeResults.Add(new GenBasePreviewOutput.GenBaseCodeResult
{
CodeFileContent = tResult,
CodeFileName = $"{genViewModel.ClassName}{fileNoPrefix}",
FilePath = serviceDir.CombinePath("Dto").CombinePath(fileName)
});
}
return backendCodeResults;
}
/// <summary>
/// 获取前端代码预览结果
/// </summary>
/// <param name="genViewModel">视图</param>
/// <param name="templatePath">模板路径</param>
/// <returns></returns>
public async Task<List<GenBasePreviewOutput.GenBaseCodeResult>> GetForntCodeResult(GenViewModel genViewModel,
string templatePath)
{
var frontCodeResults = new List<GenBasePreviewOutput.GenBaseCodeResult>();//结果集
var frontTemplatePath = Path.Combine(templatePath, _frontDir);//获取前端模板文件路径
var files = GetAllFileInfo(frontTemplatePath);
var srcDir = genViewModel.FrontedPath.CombinePath("src");//src文件夹
var templateVm = "template.vm";//模板文件
var view = "views";//视图文件夹
var api = "api";//接口文件夹
var componentsDir = "components";//组件文件夹
var apiDir = srcDir.CombinePath(api);
var viewsDir = srcDir.CombinePath(view);
var template = files.Where(it => it.Name == templateVm).FirstOrDefault();
if (templatePath == null) throw Oops.Bah($"{templateVm}文件不存在");
var dirs = genViewModel.RouteName.Split("/").Where(it => !string.IsNullOrWhiteSpace(it)).ToList();// 根据路/分隔,获取文件夹名字
//读取模板文件内容,utf-8编码
var templateContent = File.ReadAllText(template.FullName, Encoding.UTF8);
var apiFiles = files.Where(it => it.FullName.Contains(api)).ToList();
var viewFiles = files.Where(it => it.FullName.Contains(view)).ToList();
foreach (var fileInfo in apiFiles)
{
var fileName = fileInfo.Name;//文件名
//获取文件所在文件夹名字
var dirName = fileInfo.Directory.Name;
var fileWhich = fileName.Split(".")[0];//获取是接口还是实现
if (fileName == templateVm) continue;
var fileNoPrefix = $"{fileWhich}{genViewModel.RouteName}/{genViewModel.BusName}.ts";//不带模板后缀的文件名
var filePath = apiDir.CombinePath(fileWhich);//生成文件路径
//以["biz","ops"]为例,先去找api/interface文件夹下的index.ts文件
//如果有就在index.ts文件中添加export * from "./biz",然后interfacePath路径就变成了api/interface/biz
//如果不存在这个文件夹,就表示需要创建这个文件夹,然后在这个文件夹下创建index.ts文件,导入下一层的文件也就是ops
for (var i = 0; i < dirs.Count; i++)
{
var it = dirs[i];//获取文件夹名
var indexPath = filePath.CombinePath(_indexTs);
// 判断interfacePath路径下是否有index.ts文件,这里因为是typescript,所以需要引入
if (File.Exists(indexPath))
{
//读取文件内容
var indexContent = File.ReadAllText(indexPath);
var content = $"export * from \"./{it}\";";//需要添加的内容
//判断content是否存在
if (!indexContent.Contains(content))
{
indexContent += content;
}
var pathSplit = indexPath.Split($"{fileWhich}")[1];
//先通过\分隔再用/合并字符串
var codeFileName = $"{fileWhich}{pathSplit}".Split("\\").Aggregate((a, b) => a + "/" + b);
//加到结果集
frontCodeResults.Add(new GenBasePreviewOutput.GenBaseCodeResult
{
CodeFileContent = indexContent,
CodeFileName = codeFileName,
FilePath = indexPath
});
}
filePath = filePath.CombinePath(it);//拼接文件夹路径
if (!Directory.Exists(filePath))//如果文件夹不存在
{
var index = filePath.CombinePath(_indexTs);
var pathSplit = index.Split($"{fileWhich}")[1];
var indexContent = i + 1 == dirs.Count ? genViewModel.BusName : dirs[i + 1];//如果是最后一个就是busName
// 在当前内容下添加内容
var content = templateContent + $"\n\nexport * from \"./{indexContent}\";";
//加到结果集
frontCodeResults.Add(new GenBasePreviewOutput.GenBaseCodeResult
{
CodeFileContent = content,
CodeFileName = $"{fileWhich}{pathSplit}",
FilePath = index
});
}
}
var tContent = File.ReadAllText(fileInfo.FullName);//读取文件
var tResult = await GetViewEngine(tContent, genViewModel);//渲染
//将渲染结果添加到结果集
frontCodeResults.Add(new GenBasePreviewOutput.GenBaseCodeResult
{
CodeFileContent = tResult,
CodeFileName = fileNoPrefix,
FilePath = filePath.CombinePath($"{genViewModel.BusName}.ts")
});
}
//遍历视图文件
foreach (var fileInfo in viewFiles)
{
var fileName = fileInfo.Name;//文件名
//获取文件所在文件夹名字
var dirName = fileInfo.Directory.Name;
var name = fileName.Split(".vm")[0];//不带模板后缀的文件名
var fileNoPrefix = $"{dirName}/{name}";//不带模板后缀的文件名
var filePath = viewsDir;
foreach (var dir in dirs)
{
filePath = filePath.CombinePath(dir);
}
filePath = filePath.CombinePath(genViewModel.BusName);
if (dirName == componentsDir)//如果是组件文件夹
{
fileNoPrefix = $"{view}/{dirName}/{name}";//不带模板后缀的文件名
filePath = filePath.CombinePath(componentsDir).CombinePath(name);//生成文件路径
}
else
filePath = filePath.CombinePath(name);//生成文件路径
var tContent = File.ReadAllText(fileInfo.FullName);//读取文件
var tResult = await GetViewEngine(tContent, genViewModel);//渲染
//将渲染结果添加到结果集
frontCodeResults.Add(new GenBasePreviewOutput.GenBaseCodeResult
{
CodeFileContent = tResult,
CodeFileName = fileNoPrefix,
FilePath = filePath
});
}
return frontCodeResults;
}
/// <summary>
/// 获取代码生成视图
/// </summary>
/// <param name="genBasic"></param>
/// <returns></returns>
public async Task<GenViewModel> GetGenViewModel(GenBasic genBasic)
{
//实体转视图
var genViewEngine = genBasic.Adapt<GenViewModel>();
//获取字段信息
var tableFieldList = await _genConfigService.List(genBasic.Id);
tableFieldList.ForEach(it =>
{
it.FieldNameFirstLower = StringHelper.FirstCharToLower(it.FieldName);//首字母小写
it.FieldNameFirstUpper = StringHelper.FirstCharToUpper(it.FieldName);//首字母大写
});
genViewEngine.TableFields = tableFieldList;//赋值表字段信息
return genViewEngine;
}
/// <summary>
/// 视图渲染
/// </summary>
/// <param name="tContent">模板内容</param>
/// <param name="genViewModel">参数</param>
/// <returns></returns>
public async Task<string> GetViewEngine(string tContent, GenViewModel genViewModel)
{
//视图引擎渲染
var tResult = await _viewEngine.RunCompileFromCachedAsync(tContent, genViewModel, builderAction: builder =>
{
builder.AddAssemblyReference(typeof(GenBasic));//添加程序集
builder.AddAssemblyReferenceByName("System.Collections");//添加程序集
builder.AddAssemblyReferenceByName("SimpleTool");//添加程序集
});
return tResult;
}
/// <summary>
/// 获得文件夹下所有的文件
/// </summary>
/// <param name="path">文件夹路径</param>
/// <returns></returns>
private FileInfo[] GetAllFileInfo(string path)
{
var dir = new DirectoryInfo(path);
return dir.GetFiles(".", SearchOption.AllDirectories);
}
/// <summary>
/// 代码生成预览
/// </summary>
/// <param name="genBasic">基础配置</param>
/// <returns></returns>
public async Task<GenBasePreviewOutput> PreviewGen(GenBasic genBasic)
{
var basePath = AppContext.BaseDirectory;//获取项目目录
var templatePath = basePath.CombinePath("ViewEngine").CombinePath("CodeGen");//获取文件路径
templatePath = "D:\\胡国东\\SimpleAdmin.Net\\SimpleAdmin\\SimpleAdmin.System\\ViewEngine\\CodeGen";//测试用
var genViewModel = await GetGenViewModel(genBasic);
var frontendResult = await GetForntCodeResult(genViewModel, templatePath);
var backendResult = await GetBackendCodeResult(genViewModel, templatePath);
var sqlResult = await GetSqlCodeResult(genViewModel, templatePath);
return new GenBasePreviewOutput
{
CodeBackendResults = backendResult,
SqlResults = sqlResult,
CodeFrontendResults = frontendResult
};
}
/// <summary>
/// 获取代码生成基础
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
private async Task<GenBasic> GetGenBasic(long id)
{
var genBasic = await GetByIdAsync(id);
if (genBasic == null)
throw Oops.Bah("代码生成配置不存在");
genBasic.FuncList = genBasic.Functions.Split(',').ToList();
return genBasic;
}
/// <summary>
/// 创建代码生成相关的菜单按钮和授权关系
/// </summary>
/// <param name="genBasic"></param>
/// <returns></returns>
private async Task<bool> CreateMenuButtonAndRelation(GenBasic genBasic)
{
try
{
#region 菜单
var title = genBasic.FunctionName + genBasic.FunctionNameSuffix;
var menuRep = ChangeRepository<DbRepository<SysResource>>();//切换仓储
//获取已经存在的旧菜单
var oldMenu = await menuRep.GetFirstAsync(it => it.Title == title
&& it.Category == CateGoryConst.RESOURCE_MENU
&& it.MenuType == SysResourceConst.MENU &&
it.Code != SysResourceConst.SYSTEM);
if (oldMenu != null)//如果存在就直接和删除(同时删除其下面的菜单、按钮,清除对应的角色与资源信息)
await _menuService.Delete(new BaseIdListInput()
{
Ids = new List<long>()
{
oldMenu.Id
}
});
//添加菜单参数
var menu = new MenuAddInput
{
Id = CommonUtils.GetSingleId(),
ParentId = genBasic.MenuPid,
Title = title,
Category = CateGoryConst.RESOURCE_MENU,
Module = genBasic.Module,
Icon = genBasic.Icon,
Name = genBasic.BusName,
Code = RandomHelper.CreateRandomString(10),
Path = $"{genBasic.RouteName}/{genBasic.BusName}",
Component = $"{genBasic.RouteName}/{genBasic.BusName}/index".TrimStart('/'),
SortCode = 99,
Status = CommonStatusConst.ENABLE,
IsKeepAlive = true
};
await _menuService.Add(menu);//添加菜单
#endregion 菜单
#region 按钮
//添加按钮参数
var button = new ButtonAddInput
{
Title = genBasic.FunctionName,
ParentId = menu.Id,
Code = StringHelper.FirstCharToLower(genBasic.ClassName),
Status = CommonStatusConst.ENABLE
};
var buttonIds = await _buttonService.AddBatch(button);//添加按钮
#endregion 按钮
#region 角色授权
var roleRep = ChangeRepository<DbRepository<SysRole>>();//切换仓储
var superAdmin = await roleRep.GetFirstAsync(it =>
it.Code == SysRoleConst.SUPER_ADMIN && it.Category == CateGoryConst.ROLE_GLOBAL);//获取超级管理员
//授权菜单参数
var grantResource = new GrantResourceInput
{
Id = superAdmin.Id,
GrantInfoList = new List<RelationRoleResource>
{ new RelationRoleResource { MenuId = menu.Id, ButtonInfo = buttonIds } },
IsCodeGen = true
};
await _roleService.GrantResource(grantResource);//授权菜单
#endregion 角色授权
return true;
}
catch (Exception ex)
{
_logger.LogError($"代码生成创建菜单和授权报错{ex.Message}", ex.InnerException);
return false;
}
}
#endregion 方法
}
@@ -0,0 +1,70 @@
namespace SimpleAdmin.System;
/// <summary>
/// 代码生成基础服务
/// </summary>
public interface IGenbasicService : ITransient
{
/// <summary>
/// 添加代码生成器基础
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<GenBasic> Add(GenBasicAddInput input);
/// <summary>
/// 删除代码生成配置
/// </summary>
/// <param name="input">ID列表</param>
/// <returns></returns>
Task Delete(BaseIdListInput input);
/// <summary>
/// 编辑代码生成基础配置
/// </summary>
/// <param name="input"></param>
/// <returns>代码生产基础</returns>
Task<GenBasic> Edit(GenBasicEditInput input);
/// <summary>
/// 执行代码生成:本地
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task ExecGenPro(ExecGenInput input);
/// <summary>
/// 执行代码生成:压缩包
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<FileStreamResult> ExecGenZip(ExecGenInput input);
/// <summary>
/// 获取项目所有程序集
/// </summary>
/// <returns>程序集列表</returns>
List<string> GetAssemblies();
/// <summary>
/// 获取表信息
/// </summary>
/// <param name="isAll">是否所有表</param>
/// <returns>实体表列表</returns>
List<SqlSugarTableInfo> GetTables(bool isAll = false);
/// <summary>
/// 获取代码生成基础分页
/// </summary>
/// <param name="input">查询参数</param>
/// <returns>代码生成基础分页列表</returns>
Task<SqlSugarPagedList<GenBasic>> Page(BasePageInput input);
/// <summary>
/// 代码生成预览
/// </summary>
/// <param name="input">代码生成基础Id</param>
/// <returns>预览结果</returns>
Task<GenBasePreviewOutput> PreviewGen(BaseIdInput input);
}
@@ -0,0 +1,5 @@
namespace SimpleAdmin.System;
public class GenConfigInput
{
}
@@ -0,0 +1,28 @@
namespace SimpleAdmin.System;
/// <summary>
/// <inheritdoc cref="IGenConfigService"/>
/// </summary>
public class GenConfigService : DbRepository<GenConfig>, IGenConfigService
{
private readonly ILogger<GenConfigService> logger;
public GenConfigService(ILogger<GenConfigService> logger)
{
this.logger = logger;
}
/// <inheritdoc/>
public async Task<List<GenConfig>> List(long basicId)
{
var configs = await GetListAsync(it => it.BasicId == basicId);//获取配置表相关配置
configs = configs.OrderBy(it => it.FieldIndex).ToList();//排序一下
return configs;
}
/// <inheritdoc/>
public async Task EditBatch(List<GenConfig> configs)
{
await UpdateRangeAsync(configs);//批量更新
}
}
@@ -0,0 +1,21 @@
namespace SimpleAdmin.System;
/// <summary>
/// 代码生成详细配置服务
/// </summary>
public interface IGenConfigService : ITransient
{
/// <summary>
/// 批量更新
/// </summary>
/// <param name="configs"></param>
/// <returns></returns>
Task EditBatch(List<GenConfig> configs);
/// <summary>
/// 查询代码生成详细配置列表
/// </summary>
/// <param name="basicId"></param>
/// <returns>配置列表</returns>
Task<List<GenConfig>> List(long basicId);
}
@@ -0,0 +1,18 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 导入预览输入
/// </summary>
public class ImportPreviewInput : BaseFileInput
{
}
@@ -0,0 +1,63 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 文件导入通用输出
/// </summary>
public class ImportPreviewOutput<T> where T : class
{
/// <summary>
/// 是否有错误
/// </summary>
public bool HasError { get; set; }
/// <summary>
/// 动态表头
/// </summary>
public List<TableColumns> TableColumns { get; set; } = new List<TableColumns>();
/// <summary>
/// 数据
/// </summary>
public List<T> Data { get; set; }
}
/// <summary>
/// 动态表头
/// </summary>
public class TableColumns
{
/// <summary>
/// 标题
/// </summary>
public string Title { get; set; }
/// <summary>
/// 数据源
/// </summary>
public string DataIndex { get; set; }
/// <summary>
/// 宽度
/// </summary>
public int Width { get; set; } = 120;
/// <summary>
/// 超过宽度将自动省略
/// </summary>
public bool Ellipsis { get; set; }
/// <summary>
/// 是否是日期格式
/// </summary>
public bool Date { get; set; }
}
@@ -0,0 +1,23 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 批量导入结果输入
/// </summary>
/// <typeparam name="T"></typeparam>
public class ImportResultInput<T> where T : class
{
/// <summary>
/// 数据
/// </summary>
public List<T> Data { get; set; }
}
@@ -0,0 +1,44 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 导入结果输出
/// </summary>
public class ImportResultOutPut<T> where T : class
{
/// <summary>
/// 是否成功
/// </summary>
public bool Success { get; set; } = true;
/// <summary>
/// 总数
/// </summary>
public int Total { get; set; }
/// <summary>
/// 导入数量
/// </summary>
public int ImportCount { get; set; }
/// <summary>
/// 错误数
/// </summary>
public int FailCount { get; set; }
/// <summary>
/// 数据
/// </summary>
public List<T> Data { get; set; } = new List<T>();
}
@@ -0,0 +1,36 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 导入基础输入
/// </summary>
[ExcelImporter(IsLabelingError = true)]
public class ImportTemplateInput
{
/// <summary>
/// Id
/// </summary>
[ImporterHeader(IsIgnore = true)]
public long Id { get; set; } = CommonUtils.GetSingleId();
/// <summary>
/// 是否有错误
/// </summary>
[ImporterHeader(IsIgnore = true)]
public bool HasError { get; set; }
/// <summary>
/// 错误详情
/// </summary>
[ImporterHeader(IsIgnore = true)]
public IDictionary<string, string> ErrorInfo { get; set; } = new Dictionary<string, string>();
}
@@ -0,0 +1,75 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 导入服务
/// </summary>
public interface IImportExportService : ITransient
{
/// <summary>
/// 导出数据
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data">数据</param>
/// <param name="fileName">文件名</param>
/// <returns>文件流</returns>
Task<FileStreamResult> Export<T>(List<T> data, string fileName) where T : class, new();
/// <summary>
/// 获取本地模板
/// </summary>
/// <param name="fileName">文件名</param>
/// <param name="templateFolder">模板文件夹路径:默认wwwroot下的Template</param>
/// <returns>文件流</returns>
FileStreamResult GenerateLocalTemplate(string fileName, string templateFolder = "Template");
/// <summary>
/// 生成模板
/// </summary>
/// <typeparam name="T">实体类</typeparam>
/// <param name="fileName">文件名</param>
/// <returns>文件流</returns>
Task<FileStreamResult> GenerateTemplate<T>(string fileName) where T : class, new();
/// <summary>
/// 获取导入预览
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="file">文件</param>
/// <returns>导入预览结果</returns>
Task<ImportPreviewOutput<T>> GetImportPreview<T>(IFormFile file) where T : ImportTemplateInput, new();
/// <summary>
/// 获取预计导入结果
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data">数据</param>
/// <param name="importData">成功导入数据</param>
/// <returns>预计导入结果</returns>
ImportResultOutPut<T> GetImportResultPreview<T>(List<T> data, out List<T> importData) where T : ImportTemplateInput;
/// <summary>
/// 导入文件验证
/// </summary>
/// <param name="file">文件</param>
/// <param name="maxSize">文件最大体积(M)</param>
/// <param name="allowTypes">允许的格式</param>
void ImportVerification(IFormFile file, int maxSize = 30, string[] allowTypes = null);
/// <summary>
/// 模板数据验证
/// </summary>
/// <typeparam name="T">模板类实体</typeparam>
/// <param name="importResult">结果</param>
/// <returns>导入预览数据</returns>
ImportPreviewOutput<T> TemplateDataVerification<T>(ImportResult<T> importResult) where T : ImportTemplateInput;
}
@@ -0,0 +1,204 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// <inheritdoc cref="IImportExportService"/>
/// </summary>
public class ImportExportService : IImportExportService
{
#region 导入
/// <inheritdoc/>
public void ImportVerification(IFormFile file, int maxSize = 30, string[] allowTypes = null)
{
if (file == null) throw Oops.Bah("文件不能为空");
if (file.Length > maxSize * 1024 * 1024) throw Oops.Bah($"文件大小不允许超过{maxSize}M");
var fileSuffix = Path.GetExtension(file.FileName).ToLower().Split(".")[1];// 文件后缀
var allowTypeS = allowTypes == null ? new[] { "xlsx" } : allowTypes;//允许上传的文件类型
if (!allowTypeS.Contains(fileSuffix)) throw Oops.Bah(errorMessage: "文件格式错误");
}
/// <inheritdoc/>
public ImportPreviewOutput<T> TemplateDataVerification<T>(ImportResult<T> importResult) where T : ImportTemplateInput
{
if (importResult.Exception != null) throw Oops.Bah("导入异常,请检查文件格式!");
////遍历模板错误
importResult.TemplateErrors.ForEach(error =>
{
if (error.Message.Contains("not found")) throw Oops.Bah($"列[{error.RequireColumnName}]未找到");
throw Oops.Bah($"列[{error.RequireColumnName}]:{error.Message}");
});
if (importResult.Data == null)
throw Oops.Bah("文件数据格式有误,请重新导入!");
//导入结果输出
var importPreview = new ImportPreviewOutput<T> { HasError = importResult.HasError };
var headerMap = new Dictionary<string, string>();
//遍历导入的表头列表信息
importResult.ImporterHeaderInfos.ForEach(it =>
{
headerMap.Add(it.Header.Name, it.PropertyName);
var tableColumns = new TableColumns
{ Title = it.Header.Name.Split("(")[0], DataIndex = it.PropertyName.FirstCharToLower() };//定义表头,部分表头有说明用(分组去掉说明
var antTableAttribute = it.PropertyInfo.GetCustomAttribute<AntTableAttribute>();//获取表格特性
if (antTableAttribute != null)
{
tableColumns.Date = antTableAttribute.IsDate;
tableColumns.Ellipsis = antTableAttribute.Ellipsis;
tableColumns.Width = antTableAttribute.Width;
}
importPreview.TableColumns.Add(tableColumns);//添加到表头
});
//导入的数据转集合
var data = importResult.Data.ToList();
var systemError = new string[] { };//系统错误提示
//遍历错误列,将错误字典中的中文改成英文跟实体对应
importResult.RowErrors.ForEach(row =>
{
IDictionary<string, string> fieldErrors = new Dictionary<string, string>();//定义字典
//遍历错误列,赋值给新的字典
row.FieldErrors.ForEach(it =>
{
var errrVaule = it.Value;
//value xx Invalid, please fill in the correct integer value!
//value xx Invalid, please fill in the correct date and time format!
if (it.Value.Contains("Invalid"))//如果错误信息有Invalid就提示格式错误
errrVaule = $"{it.Key}格式错误";
fieldErrors.Add(headerMap[it.Key], errrVaule);
});
row.FieldErrors = fieldErrors;//替换新的字典
row.RowIndex -= 2;//下表与列表中的下标一致
data[row.RowIndex].HasError = true;//错误的行HasError = true
data[row.RowIndex].ErrorInfo = fieldErrors;//替换新的字典
});
data = data.OrderByDescending(it => it.HasError).ToList();//排序
importPreview.Data = data;//重新赋值data
return importPreview;
}
/// <inheritdoc/>
public async Task<FileStreamResult> GenerateTemplate<T>(string fileName) where T : class, new()
{
IImporter importer = new ExcelImporter();
var byteArray = await importer.GenerateTemplateBytes<T>();
var result = GetFileStreamResult(byteArray, fileName);
return result;
}
/// <inheritdoc/>
public FileStreamResult GenerateLocalTemplate(string fileName, string templateFolder = "Template")
{
var folder = App.WebHostEnvironment.WebRootPath.CombinePath(templateFolder);
return GetFileStreamResult(folder, fileName, true);
}
/// <inheritdoc/>
public async Task<ImportPreviewOutput<T>> GetImportPreview<T>(IFormFile file) where T : ImportTemplateInput, new()
{
ImportVerification(file);//验证文件
IImporter importer = new ExcelImporter();
using var fileStream = file.OpenReadStream();//获取文件流
var import = await importer.Import<T>(fileStream);//导入的文件转化为带入结果
var importPreview = TemplateDataVerification(import);//验证数据完整度
return importPreview;
}
/// <inheritdoc/>
public ImportResultOutPut<T> GetImportResultPreview<T>(List<T> data, out List<T> importData) where T : ImportTemplateInput
{
//定义结果
var result = new ImportResultOutPut<T> { Total = data.Count };
//可以导入的数据
importData = data.Where(it => it.HasError == false).ToList();
//如果有错误
if (importData.Count != data.Count)
{
result.Success = false;
result.Data = data.Where(it => it.HasError).ToList();
result.FailCount = data.Count - importData.Count;
}
result.ImportCount = importData.Count;
return result;
}
#endregion 导入
#region 导出
public async Task<FileStreamResult> Export<T>(List<T> data, string fileName) where T : class, new()
{
IExporter exporter = new ExcelExporter();
var byteArray = await exporter.ExportAsByteArray(data);
var result = GetFileStreamResult(byteArray, fileName);
return result;
}
#endregion 导出
#region 方法
/// <summary>
/// 获取文件流
/// </summary>
/// <param name="path"></param>
/// <param name="fileName"></param>
/// <param name="isPathFolder"></param>
/// <returns></returns>
public FileStreamResult GetFileStreamResult(string path, string fileName, bool isPathFolder = false)
{
fileName = GetFileName(fileName);
if (isPathFolder) path = path.CombinePath(fileName);
//文件转流
var result = new FileStreamResult(new FileStream(path, FileMode.Open), "application/octet-stream") { FileDownloadName = fileName };
return result;
}
/// <summary>
/// 获取文件流
/// </summary>
/// <param name="byteArray"></param>
/// <param name="fileName"></param>
/// <returns></returns>
public FileStreamResult GetFileStreamResult(byte[] byteArray, string fileName)
{
fileName = GetFileName(fileName);
//文件转流
var result = new FileStreamResult(new MemoryStream(byteArray), "application/octet-stream") { FileDownloadName = fileName };
return result;
}
/// <summary>
/// 获取文件名
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public string GetFileName(string fileName)
{
if (!fileName.Contains("."))
fileName = fileName + ".xlsx";
fileName = HttpUtility.UrlEncode(fileName, Encoding.GetEncoding("UTF-8"));//文件名转utf8不然前端下载会乱码
return fileName;
}
/// <summary>
/// 获取本地模板路径
/// </summary>
/// <returns></returns>
public string GetTemplateFolder()
{
var folder = App.WebHostEnvironment.WebRootPath.CombinePath("Template");
return folder;
}
#endregion 方法
}
@@ -0,0 +1,44 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 日程列表查询参数
/// </summary>
public class ScheduleListInput
{
/// <summary>
/// 日程日期
/// </summary>
[Required(ErrorMessage = "ScheduleDate不能为空")]
public string ScheduleDate { get; set; }
}
public class ScheduleAddInput : RelationUserSchedule
{
/// <summary>
/// 日程日期
/// </summary>
[Required(ErrorMessage = "scheduleDate不能为空")]
public override string ScheduleDate { get; set; }
/// <summary>
/// 日程内容
/// </summary>
[Required(ErrorMessage = "ScheduleContent不能为空")]
public override string ScheduleContent { get; set; }
/// <summary>
/// 日程时间
/// </summary>
[Required(ErrorMessage = "ScheduleTime 不能为空")]
public override string ScheduleTime { get; set; }
}
@@ -0,0 +1,19 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
public class ScheduleListOutput : RelationUserSchedule
{
/// <summary>
/// ID
/// </summary>
public long Id { get; set; }
}
@@ -0,0 +1,38 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 首页服务
/// </summary>
public interface IIndexService : ITransient
{
/// <summary>
/// 添加日程
/// </summary>
/// <param name="input">日程参数</param>
/// <returns></returns>
Task AddSchedule(ScheduleAddInput input);
/// <summary>
/// 删除日程
/// </summary>
/// <param name="input">id列表</param>
/// <returns></returns>
Task DeleteSchedule(BaseIdListInput input);
/// <summary>
/// 获取日程列表
/// </summary>
/// <param name="input">查询参数</param>
/// <returns>日程列表</returns>
Task<List<ScheduleListOutput>> ScheduleList(ScheduleListInput input);
}

Some files were not shown because too many files have changed in this diff Show More