init commit

This commit is contained in:
路 范
2022-03-30 17:54:33 +08:00
parent df01841625
commit 904bdd16cd
500 changed files with 217251 additions and 0 deletions

View File

@@ -0,0 +1,100 @@
using System.ComponentModel.DataAnnotations;
namespace Ewide.Core.Service
{
/// <summary>
/// 系统应用参数
/// </summary>
public class AppInput : PageInputBase
{
/// <summary>
/// 名称
/// </summary>
public virtual string Name { get; set; }
/// <summary>
/// 编码
/// </summary>
public virtual string Code { get; set; }
/// <summary>
/// 图标
/// </summary>
public virtual string Icon { get; set; }
/// <summary>
/// 图标颜色
/// </summary>
public virtual string Color { get; set; }
/// <summary>
/// 是否默认激活Y-是N-否),只能有一个系统默认激活
/// 用户登录后默认展示此系统菜单
/// </summary>
public bool Active { get; set; }
/// <summary>
/// 状态(字典 0正常 1停用 2删除
/// </summary>
public CommonStatus Status { get; set; }
/// <summary>
/// 排序
/// </summary>
public int Sort { get; set; }
}
public class AddAppInput : AppInput
{
/// <summary>
/// 名称
/// </summary>
[Required(ErrorMessage = "应用名称不能为空")]
public override string Name { get; set; }
/// <summary>
/// 编码
/// </summary>
[Required(ErrorMessage = "应用编码不能为空")]
public override string Code { get; set; }
/// <summary>
/// 图标
/// </summary>
public override string Icon { get; set; }
/// <summary>
/// 图标颜色
/// </summary>
[RegularExpression("^#[0-9a-fA-F]{6}|#[0-9a-fA-F]{3}$", ErrorMessage = "")]
public override string Color { get; set; }
}
public class DeleteAppInput
{
/// <summary>
/// 应用Id
/// </summary>
[Required(ErrorMessage = "应用Id不能为空")]
public string Id { get; set; }
}
public class UpdateAppInput : AppInput
{
/// <summary>
/// 应用Id
/// </summary>
[Required(ErrorMessage = "应用Id不能为空")]
public string Id { get; set; }
}
public class QueryAppInput : DeleteAppInput
{
}
public class SetDefaultAppInput : DeleteAppInput
{
}
}

View File

@@ -0,0 +1,33 @@
namespace Ewide.Core.Service
{
/// <summary>
/// 系统应用参数
/// </summary>
public class AppOutput
{
/// <summary>
/// 应用Id
/// </summary>
public string Id { get; set; }
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 编码
/// </summary>
public string Code { get; set; }
/// <summary>
/// 是否默认
/// </summary>
public bool Active { get; set; }
/// <summary>
/// 排序
/// </summary>
public int Sort { get; set; }
}
}

View File

@@ -0,0 +1,18 @@
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
public interface ISysAppService
{
Task AddApp(AddAppInput input);
Task DeleteApp(DeleteAppInput input);
Task<SysApp> GetApp([FromQuery] QueryAppInput input);
Task<dynamic> GetAppList([FromQuery] AppInput input);
Task<dynamic> GetLoginApps(string userId);
Task<dynamic> QueryAppPageList([FromQuery] AppInput input);
Task SetAsDefault(SetDefaultAppInput input);
Task UpdateApp(UpdateAppInput input);
Task ChangeUserAppStatus(UpdateAppInput input);
}
}

View File

@@ -0,0 +1,204 @@
using Ewide.Core.Extension;
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
/// <summary>
/// 系统应用服务
/// </summary>
[ApiDescriptionSettings(Name = "App", Order = 100)]
public class SysAppService : ISysAppService, IDynamicApiController, ITransient
{
private readonly IRepository<SysApp> _sysAppRep; // 应用表仓储
private readonly IUserManager _userManager;
private readonly ISysMenuService _sysMenuService;
public SysAppService(IRepository<SysApp> sysAppRep,
IUserManager userManager,
ISysMenuService sysMenuService)
{
_sysAppRep = sysAppRep;
_userManager = userManager;
_sysMenuService = sysMenuService;
}
/// <summary>
/// 获取用户应用相关信息
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
[NonAction]
public async Task<dynamic> GetLoginApps(string userId)
{
var apps = _sysAppRep.DetachedEntities.Where(u => u.Status == (int)CommonStatus.ENABLE);
if (!_userManager.SuperAdmin)
{
var appCodeList = await _sysMenuService.GetUserMenuAppCodeList(userId);
apps = apps.Where(u => appCodeList.Contains(u.Code));
}
var appList = await apps.OrderBy(u => u.Sort).Select(u => new AppOutput
{
Id = u.Id,
Code = u.Code,
Name = u.Name,
Active = u.Active,
Sort = u.Sort
}).ToListAsync(); // .OrderByDescending(u => u.Active) // 将激活的放到第一个
//// 默认激活第一个应用
if (appList != null && appList.Count > 0 && !appList[0].Active)
appList[0].Active = true;
return appList;
}
/// <summary>
/// 分页查询系统应用
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysApp/page")]
public async Task<dynamic> QueryAppPageList([FromBody] AppInput input)
{
var apps = await _sysAppRep.DetachedEntities
.Where(
!string.IsNullOrEmpty(input.Name?.Trim()),
u => EF.Functions.Like(u.Name, $"%{input.Name.Trim()}%")
)
.Where(
!string.IsNullOrEmpty(input.Code?.Trim()),
u => EF.Functions.Like(u.Code, $"%{input.Code.Trim()}%")
)
.ToPageData(input);
return PageDataResult<SysApp>.PageResult(apps);
}
/// <summary>
/// 增加系统应用
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysApp/add")]
public async Task AddApp(AddAppInput input)
{
var isExist = await _sysAppRep.DetachedEntities.AnyAsync(u => u.Name == input.Name || u.Code == input.Code);
if (isExist)
throw Oops.Oh(ErrorCode.D5000);
if (input.Active)
{
isExist = await _sysAppRep.DetachedEntities.AnyAsync(u => u.Active == input.Active);
if (isExist)
throw Oops.Oh(ErrorCode.D5001);
}
var app = input.Adapt<SysApp>();
await app.InsertAsync();
}
/// <summary>
/// 删除系统应用
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysApp/delete")]
public async Task DeleteApp(DeleteAppInput input)
{
var app = await _sysAppRep.FirstOrDefaultAsync(u => u.Id == input.Id);
// 该应用下是否有状态为正常的菜单
var hasMenu = await _sysMenuService.HasMenu(app.Code);
if (hasMenu)
throw Oops.Oh(ErrorCode.D5002);
await app.DeleteAsync();
}
/// <summary>
/// 更新系统应用
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysApp/edit")]
public async Task UpdateApp(UpdateAppInput input)
{
var isExist = await _sysAppRep.DetachedEntities.AnyAsync(u => (u.Name == input.Name || u.Code == input.Code) && u.Id != input.Id);
if (isExist)
throw Oops.Oh(ErrorCode.D5000);
if (input.Active)
{
isExist = await _sysAppRep.DetachedEntities.AnyAsync(u => u.Active == input.Active && !u.Id.Equals(input.Id));
if (isExist)
throw Oops.Oh(ErrorCode.D5001);
}
var app = input.Adapt<SysApp>();
await app.UpdateExcludeAsync(new[] { nameof(SysApp.Status) }, true);
}
/// <summary>
/// 获取系统应用
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("/sysApp/detail")]
public async Task<SysApp> GetApp([FromQuery] QueryAppInput input)
{
return await _sysAppRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == input.Id);
}
/// <summary>
/// 获取系统应用列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("/sysApp/list")]
public async Task<dynamic> GetAppList([FromQuery] AppInput input)
{
return await _sysAppRep.DetachedEntities.Where(u => u.Status == (int)CommonStatus.ENABLE).OrderBy(u => u.Sort).ToListAsync();
}
/// <summary>
/// 设为默认应用
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysApp/setAsDefault")]
public async Task SetAsDefault(SetDefaultAppInput input)
{
var apps = await _sysAppRep.Where(u => u.Status == (int)CommonStatus.ENABLE).ToListAsync();
apps.ForEach(u =>
{
u.Active = false;
});
var app = await _sysAppRep.FirstOrDefaultAsync(u => u.Id == input.Id);
app.Active = true;
}
/// <summary>
/// 修改用户状态
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysApp/changeStatus")]
public async Task ChangeUserAppStatus(UpdateAppInput input)
{
if (!Enum.IsDefined(typeof(CommonStatus), input.Status))
throw Oops.Oh(ErrorCode.D3005);
var app = await _sysAppRep.FirstOrDefaultAsync(u => u.Id == input.Id);
app.Status = input.Status;
}
}
}

View File

@@ -0,0 +1,183 @@
using Ewide.Core.Extension;
using Ewide.Core.Service.Area.Dto;
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Furion.FriendlyException;
using Mapster;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Ewide.Core.Service.Area
{
public class AreaCodeService : IAreaCodeService, ITransient
{
private readonly IRepository<SysAreaCode> _areaCodeRep;
private readonly IRepository<SysOrg> _sysOrgRep;
private readonly ISysCacheService _sysCacheService;
private readonly IUserManager _userManager;
public AreaCodeService(IRepository<SysAreaCode> AreaCodeRep, ISysCacheService sysCacheService, IRepository<SysOrg> sysOrgRep, IUserManager userManager)
{
_areaCodeRep = AreaCodeRep;
_sysCacheService = sysCacheService;
_sysOrgRep = sysOrgRep;
_userManager = userManager;
}
/// <summary>
/// 添加一个区域
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task AddAreaCode(AreaCodeInput input)
{
CheckInput(input);
CheckCode(input);
CheckArea(input);
await _areaCodeRep.InsertNowAsync(input.Adapt<SysAreaCode>());
#if DEBUG
#else
await _sysCacheService.SetAreaCode(await _areaCodeRep.DetachedEntities.ToListAsync());
#endif
}
/// <summary>
/// 删除一个区域
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task DeleteAreaCode(DeleteAreaCodeInput input)
{
var AreaCode = await _areaCodeRep.FirstOrDefaultAsync(p => p.Code == input.Code);
if (await _sysOrgRep.DetachedEntities.AnyAsync(o => o.AreaCode == input.Code))
{
throw Oops.Oh("不能删除已包含区域的组织");
}
await AreaCode.DeleteNowAsync();
#if DEBUG
#else
await _sysCacheService.SetAreaCode(await _areaCodeRep.DetachedEntities.ToListAsync());
#endif
}
/// <summary>
/// 根据区域代码获取区域信息
/// </summary>
/// <param name="code">区域代码</param>
/// <returns></returns>
public async Task<SysAreaCode> GetAreaCode(string code)
{
var cachedAreaCodes = await _sysCacheService.GetAreaCode();
if (cachedAreaCodes == null || cachedAreaCodes.Count < 0)
{
cachedAreaCodes = await _areaCodeRep.DetachedEntities.ToListAsync();
#if DEBUG
#else
await _sysCacheService.SetAreaCode(cachedAreaCodes);
#endif
}
return cachedAreaCodes.FirstOrDefault(a => a.Code == code);
}
public async Task<List<SysAreaCode>> GetAreaCodeWithChildren(string code)
{
return await _areaCodeRep.DetachedEntities.Where(a => a.Code.StartsWith(code)).ToListAsync();
}
public async Task<dynamic> QueryAreaCodePageList(AreaCodeInput input)
{
var AreaCodes = await _areaCodeRep.DetachedEntities
.Where(input.LevelType.HasValue, a => a.LevelType == input.LevelType)
.Where(!string.IsNullOrEmpty(input.Code), a => a.Code.Contains(input.Code))
.Where(!string.IsNullOrEmpty(input.AdCode), a => a.AdCode.Contains(input.AdCode))
.Where(!string.IsNullOrEmpty(input.Name), a => a.Name.Contains(input.Name))
.Where(!string.IsNullOrEmpty(input.Pcode), a => a.Code.StartsWith(input.Pcode))
.ToPageData(input);
return PageDataResult<SysAreaCode>.PageResult(AreaCodes);
}
/// <summary>
/// 更新区域信息
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task UpdateAreaCode(AreaCodeInput input)
{
CheckInput(input);
CheckArea(input);
var area = input.Adapt<SysAreaCode>();
await area.UpdateNowAsync();
#if DEBUG
#else
await _sysCacheService.SetAreaCode(await _areaCodeRep.DetachedEntities.ToListAsync());
#endif
}
private bool CheckInput(AreaCodeInput input)
{
//检查level和区域长度
if (false)
{
throw Oops.Oh("数据异常");
}
//检查是否有子节点
return true;
}
private bool CheckArea(AreaCodeInput input)
{
var any = _areaCodeRep.DetachedEntities.Any(p => p.AdCode == input.AdCode && p.Code != input.Code);
if (any)
{
throw Oops.Oh("区域编码重复");
}
return true;
}
private bool CheckCode(AreaCodeInput input)
{
var any = _areaCodeRep.DetachedEntities.Any(p => p.Code == input.Code);
if (any)
{
throw Oops.Oh("编码重复");
}
return true;
}
public async Task<List<string>> GetAreaCodeListByOrgId(List<string> orgIdList)
{
return await _sysOrgRep.DetachedEntities.Where(p => orgIdList.Contains(p.Id)).Select(p => p.AreaCode).Distinct().ToListAsync();
}
/// <summary>
/// 获取区域目录树
/// </summary>
/// <returns></returns>
public async Task<List<AreaTreeNode>> GetAreaCodeTree(int? level)
{
level = level.GetValueOrDefault(100);
var cachedAreaCodes = await _sysCacheService.GetAreaCode();
if (cachedAreaCodes == null || cachedAreaCodes.Count < 0)
{
cachedAreaCodes = await _areaCodeRep.DetachedEntities.ToListAsync();
#if DEBUG
#else
await _sysCacheService.SetAreaCode(cachedAreaCodes);
#endif
}
if (!_userManager.SuperAdmin)
{
var userAreaList = await _userManager.GetUserAllAreaList();
cachedAreaCodes = cachedAreaCodes.Where(a => userAreaList.Contains(a.Code)).ToList();
}
return new TreeBuildUtil<AreaTreeNode>().DoTreeBuild(cachedAreaCodes.Select(u => new AreaTreeNode
{
Code = u.Code,
AdCode = u.AdCode,
ParentCode = u.ParentCode,
Name = u.Name,
LevelType = u.LevelType,
Note = u.Note
}).ToList());
}
}
}

View File

@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Ewide.Core.Service.Area.Dto
{
public class AreaCodeInput : InputBase
{
public string Code { get; set; }
public string AdCode { get; set; }
public string Name { get; set; }
public int? LevelType { get; set; }
public string Note { get; set; }
public int Sort { get; set; }
public string Pcode { get; set; }
}
public class UpdateAreaCodeInput
{
public string AdCode { get; set; }
public string Name { get; set; }
public int? LevelType { get; set; }
public string Note { get; set; }
public int Sort { get; set; }
}
public class DeleteAreaCodeInput
{
[Required(ErrorMessage ="区域代码不可为空")]
public string Code { get; set; }
}
}

View File

@@ -0,0 +1,33 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Ewide.Core.Service.Area.Dto
{
public class AreaCodeOutput:AreaCodeInput
{
public string ParentCode { get; set; }
}
public class AreaTreeNode : AreaCodeOutput, ITreeNode
{
public List<AreaTreeNode> Children { get; set; } = new List<AreaTreeNode>();
public string GetId()
{
return Code;
}
public string GetPid()
{
return ParentCode;
}
public void SetChildren(IList children)
{
Children = (List<AreaTreeNode>)children;
}
}
}

View File

@@ -0,0 +1,25 @@
using Ewide.Core.Service.Area.Dto;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Ewide.Core.Service.Area
{
public interface IAreaCodeService
{
Task AddAreaCode(AreaCodeInput input);
Task DeleteAreaCode(DeleteAreaCodeInput input);
Task UpdateAreaCode(AreaCodeInput input);
Task<SysAreaCode> GetAreaCode(string code);
Task<List<SysAreaCode>> GetAreaCodeWithChildren(string code);
Task<List<AreaTreeNode>> GetAreaCodeTree(int? level);
Task<dynamic> QueryAreaCodePageList([FromQuery] AreaCodeInput input);
Task<List<string>> GetAreaCodeListByOrgId(List<string> orgIdList);
}
}

View File

@@ -0,0 +1,358 @@
using Ewide.Core.Attributes;
using Ewide.Core.Util;
using Furion;
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DataEncryption;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using UAParser;
namespace Ewide.Core.Service
{
/// <summary>
/// 登录授权相关服务
/// </summary>
[ApiDescriptionSettings(Name = "Auth", Order = 160)]
public class AuthService : IAuthService, IDynamicApiController, ITransient
{
private readonly IRepository<SysUser> _sysUserRep; // 用户表仓储
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IUserManager _userManager; // 用户管理
private readonly ISysUserService _sysUserService; // 系统用户服务
private readonly ISysEmpService _sysEmpService; // 系统员工服务
private readonly ISysRoleService _sysRoleService; // 系统角色服务
private readonly ISysMenuService _sysMenuService; // 系统菜单服务
private readonly ISysAppService _sysAppService; // 系统应用服务
private readonly IClickWordCaptcha _captchaHandle;// 验证码服务
private readonly ISysConfigService _sysConfigService; // 验证码服务
public AuthService(IRepository<SysUser> sysUserRep,
IHttpContextAccessor httpContextAccessor,
IUserManager userManager,
ISysUserService sysUserService,
ISysEmpService sysEmpService,
ISysRoleService sysRoleService,
ISysMenuService sysMenuService,
ISysAppService sysAppService,
IClickWordCaptcha captchaHandle,
ISysConfigService sysConfigService)
{
_sysUserRep = sysUserRep;
_httpContextAccessor = httpContextAccessor;
_userManager = userManager;
_sysUserService = sysUserService;
_sysEmpService = sysEmpService;
_sysRoleService = sysRoleService;
_sysMenuService = sysMenuService;
_sysAppService = sysAppService;
_captchaHandle = captchaHandle;
_sysConfigService = sysConfigService;
}
/// <summary>
/// 用户登录
/// </summary>
/// <param name="input"></param>
/// <remarks>默认用户名/密码admin/admin</remarks>
/// <returns></returns>
[HttpPost("/loginswagger")]
[AllowAnonymous]
[Op(LogOpType.GRANT)]
public async Task<LoginOutput> LoginSwaggerAsync([Required] LoginInput input)
{
input.Password = RSAHandler.RSAEncrypt(input.Password);
return await LoginAsync(input);
}
/// <summary>
/// 用户登录
/// </summary>
/// <param name="input"></param>
/// <remarks>默认用户名/密码admin/admin</remarks>
/// <returns></returns>
[HttpPost("/login")]
[AllowAnonymous]
[Op(LogOpType.GRANT)]
public async Task<LoginOutput> LoginAsync([Required] LoginInput input)
{
#if !DEBUG
var password = RSAHandler.RSADecrypt(input.Password);
#endif
var user = await GetUser(input);
#if !DEBUG
// 验证密码强度
var pattern = App.Configuration.GetSection("SimplePassword:Pattern").Value;
if (!Regex.Match(password, pattern).Success)
{
return new LoginOutput
{
Passed = false,
Pattern = pattern,
Descriptions = App.Configuration.GetSection("SimplePassword:Descriptions").Value
};
}
#endif
return new LoginOutput
{
Passed = true,
Token = await HandlerLoginAsync(user)
};
}
[HttpPost("/loginPass")]
[AllowAnonymous]
public async Task<LoginOutput> LoginPassAsync([Required] LoginPassInput input)
{
var user = await GetUser(input);
var newPassword = RSAHandler.RSADecrypt(input.NewPassword);
// 验证新密码强度
var pattern = App.Configuration.GetSection("SimplePassword:Pattern").Value;
if (!Regex.Match(newPassword, pattern).Success)
{
throw Oops.Oh("新密码强度不符合规则");
}
newPassword = MD5Encryption.Encrypt(newPassword);
if (newPassword.Equals(user.Password))
throw Oops.Oh(ErrorCode.D10041);
user.Password = newPassword;
return new LoginOutput
{
Passed = true,
Token = await HandlerLoginAsync(user)
};
}
private async Task<SysUser> GetUser(LoginInput input)
{
#if !DEBUG
var password = RSAHandler.RSADecrypt(input.Password);
// 获取加密后的密码
var encryptPasswod = MD5Encryption.Encrypt(password);
#endif
#if DEBUG
var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Account.Equals(input.Account) || u.Phone.Equals(input.Account) || u.Email.Equals(input.Account));
#else
// 判断用户名和密码是否正确
var user = await _sysUserRep.FirstOrDefaultAsync(u => (u.Account.Equals(input.Account) || u.Phone.Equals(input.Account) || u.Email.Equals(input.Account)) && u.Password.Equals(encryptPasswod));
_ = user ?? throw Oops.Oh(ErrorCode.D1000);
#endif
// 验证账号是否被冻结
if (user.Status == CommonStatus.DISABLE)
throw Oops.Oh(ErrorCode.D1017);
return user;
}
private async Task<string> HandlerLoginAsync(SysUser user)
{
// 生成Token令牌
//var accessToken = await _jwtBearerManager.CreateTokenAdmin(user);
var accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>
{
{ ClaimConst.CLAINM_USERID, user.Id },
{ ClaimConst.CLAINM_ACCOUNT, user.Account },
{ ClaimConst.CLAINM_NAME, user.Name },
{ ClaimConst.CLAINM_SUPERADMIN, user.AdminType },
});
// 设置Swagger自动登录
_httpContextAccessor.HttpContext.SigninToSwagger(accessToken);
// 生成刷新Token令牌
var refreshToken = JWTEncryption.GenerateRefreshToken(accessToken, 30);
// 设置刷新Token令牌
_httpContextAccessor.HttpContext.Response.Headers["x-access-token"] = refreshToken;
// 增加登录日志
var loginUserOutput = user.Adapt<LoginUserOutput>();
var clent = Parser.GetDefault().Parse(App.GetService<IHttpContextAccessor>().HttpContext.Request.Headers["User-Agent"]);
loginUserOutput.LastLoginBrowser = clent.UA.Family + clent.UA.Major;
loginUserOutput.LastLoginOs = clent.OS.Family + clent.OS.Major;
await new SysLogVis
{
Name = "登录",
Success = true,
Message = "登录成功",
Ip = loginUserOutput.LastLoginIp,
Browser = loginUserOutput.LastLoginBrowser,
Os = loginUserOutput.LastLoginOs,
VisType = 1,
VisTime = loginUserOutput.LastLoginTime,
Account = loginUserOutput.Account
}.InsertAsync();
return accessToken;
}
/// <summary>
/// 获取当前登录用户信息
/// </summary>
/// <returns></returns>
[HttpGet("/getLoginUser")]
public async Task<LoginUserOutput> GetLoginUserAsync()
{
var user = _userManager.User;
var userId = user.Id;
var httpContext = App.GetService<IHttpContextAccessor>().HttpContext;
var loginOutput = user.Adapt<LoginUserOutput>();
// 隐藏手机号/邮箱中间几位
loginOutput.Phone = String.IsNullOrEmpty(loginOutput.Phone) ? loginOutput.Phone
: loginOutput.Phone.Substring(0, 3) + "****" + loginOutput.Phone.Substring(7, 4);
loginOutput.Email = String.IsNullOrEmpty(loginOutput.Email) ? loginOutput.Email
: String.Join("@", loginOutput.Email.Split('@').Select((p, i) =>
{
return i == 0 ? (p.Length > 3 ? p.Substring(0, 3).PadRight(p.Length, '*') : "".PadRight(3, '*')) : p;
}));
loginOutput.LastLoginTime = user.LastLoginTime = DateTime.Now;
var ip = httpContext.Request.Headers["X-Real-IP"].FirstOrDefault();
loginOutput.LastLoginIp = user.LastLoginIp = string.IsNullOrEmpty(user.LastLoginIp) ? httpContext.GetRemoteIpAddressToIPv4() : ip;
///如果真实ip为空的话就获取客户端主机IPv4地址
if (string.IsNullOrEmpty(ip))
{
loginOutput.LastLoginIp = httpContext.GetRemoteIpAddressToIPv4();
}
//var ipInfo = IpTool.Search(loginOutput.LastLoginIp);
//loginOutput.LastLoginAddress = ipInfo.Country + ipInfo.Province + ipInfo.City + "[" + ipInfo.NetworkOperator + "][" + ipInfo.Latitude + ipInfo.Longitude + "]";
var clent = Parser.GetDefault().Parse(httpContext.Request.Headers["User-Agent"]);
loginOutput.LastLoginBrowser = clent.UA.Family + clent.UA.Major;
loginOutput.LastLoginOs = clent.OS.Family + clent.OS.Major;
// 员工信息
loginOutput.LoginEmpInfo = await _sysEmpService.GetEmpInfo(userId);
// 角色信息
loginOutput.Roles = await _sysRoleService.GetUserRoleList(userId);
// 权限信息
loginOutput.Permissions = await _sysMenuService.GetLoginPermissionList(userId);
// 数据范围信息(机构Id集合)
loginOutput.DataScopes = await _userManager.GetUserAllDataScopeList();
// 具备应用信息(多系统,默认激活一个,可根据系统切换菜单),返回的结果中第一个为激活的系统
loginOutput.Apps = await _sysAppService.GetLoginApps(userId);
// 菜单信息
if (loginOutput.Apps.Count > 0)
{
//var defaultActiveAppCode = loginOutput.Apps.FirstOrDefault(u => u.Active == true).Code; // loginOutput.Apps[0].Code;
//loginOutput.Menus = await _sysMenuService.GetLoginMenusAntDesign(userId, defaultActiveAppCode);
foreach (var app in loginOutput.Apps)
{
loginOutput.Menus.AddRange(await _sysMenuService.GetLoginMenusAntDesign(userId, app.Code));
}
}
return loginOutput;
}
/// <summary>
/// 退出
/// </summary>
/// <returns></returns>
[HttpPost("/logout")]
public async Task LogoutAsync()
{
_httpContextAccessor.HttpContext.SignoutToSwagger();
//_httpContextAccessor.HttpContext.Response.Headers["access-token"] = "invalid token";
var user = _userManager.User;
var userId = user.Id;
var httpContext = App.GetService<IHttpContextAccessor>().HttpContext;
var loginOutput = user.Adapt<LoginUserOutput>();
var ip = httpContext.Request.Headers["X-Real-IP"];
var LastLoginIp = user.LastLoginIp = string.IsNullOrEmpty(user.LastLoginIp) ? httpContext.GetRemoteIpAddressToIPv4() : ip;
var clent = Parser.GetDefault().Parse(httpContext.Request.Headers["User-Agent"]);
loginOutput.LastLoginBrowser = clent.UA.Family + clent.UA.Major;
///如果真实ip为空的话就获取客户端主机IPv4地址
if (string.IsNullOrEmpty(ip))
{
LastLoginIp = httpContext.GetRemoteIpAddressToIPv4();
}
// 增加退出日志
await new SysLogVis
{
Name = "退出",
VisTime = DateTime.Now,
Success = true,
Message = "退出成功",
VisType = 2,
Browser = loginOutput.LastLoginBrowser,
Os = loginOutput.LastLoginOs,
Ip = LastLoginIp,
Account = loginOutput.Account
}.InsertAsync();
await Task.CompletedTask;
}
/// <summary>
/// 获取验证码开关
/// </summary>
/// <returns></returns>
[HttpGet("/getCaptchaOpen")]
[AllowAnonymous]
public async Task<bool> GetCaptchaOpen()
{
return await _sysConfigService.GetCaptchaOpenFlag();
}
/// <summary>
/// 获取验证码(默认点选模式)
/// </summary>
/// <returns></returns>
[HttpPost("/captcha/get")]
[AllowAnonymous]
[NonUnify]
public async Task<dynamic> GetCaptcha()
{
// 图片大小要与前端保持一致(坐标范围)
return await Task.FromResult(_captchaHandle.CreateCaptchaImage(_captchaHandle.RandomCode(6), 310, 155));
}
/// <summary>
/// 校验验证码
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/captcha/check")]
[AllowAnonymous]
[NonUnify]
public async Task<dynamic> VerificationCode(ClickWordCaptchaInput input)
{
return await Task.FromResult(_captchaHandle.CheckCode(input));
}
}
}

View File

@@ -0,0 +1,43 @@
using Furion;
using Furion.DependencyInjection;
using System.ComponentModel.DataAnnotations;
namespace Ewide.Core.Service
{
/// <summary>
/// 登录输入参数
/// </summary>
[SuppressSniffer]
public class LoginInput
{
/// <summary>
/// 用户名
/// </summary>
/// <example>superAdmin</example>
[Required(ErrorMessage = "用户名不能为空"), MinLength(3, ErrorMessage = "用户名不能少于3位字符")]
public virtual string Account { get; set; }
/// <summary>
/// 密码
/// </summary>
/// <example>1234567</example>
[Required(ErrorMessage = "密码不能为空"), MinLength(5, ErrorMessage = "密码不能少于5位字符")]
public virtual string Password { get; set; }
}
[SuppressSniffer]
public class LoginPassInput : LoginInput
{
/// <summary>
/// 新密码
/// </summary>
[Required(ErrorMessage = "新密码不能为空")]
public string NewPassword { get; set; }
/// <summary>
/// 确认密码
/// </summary>
[Required(ErrorMessage = "确认密码不能为空"), Compare(nameof(NewPassword), ErrorMessage = "两次密码不一致")]
public string Confirm { get; set; }
}
}

View File

@@ -0,0 +1,177 @@
using Furion.DependencyInjection;
using System;
using System.Collections.Generic;
namespace Ewide.Core.Service
{
[SuppressSniffer]
public class LoginOutput
{
public bool Passed { get; set; }
public string Pattern { get; set; }
public string Descriptions { get; set; }
public string Token { get; set; }
}
/// <summary>
/// 用户登录输出参数
/// </summary>
[SuppressSniffer]
public class LoginUserOutput
{
/// <summary>
/// 主键
/// </summary>
public string Id { get; set; }
/// <summary>
/// 账号
/// </summary>
public string Account { get; set; }
/// <summary>
/// 密码安全级别
/// </summary>
public int SecurityLevel { get; set; }
/// <summary>
/// 昵称
/// </summary>
public string NickName { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 头像
/// </summary>
public string Avatar { get; set; }
/// <summary>
/// 生日
/// </summary>
public DateTime? Birthday { get; set; }
/// <summary>
/// 性别(字典 1男 2女)
/// </summary>
public int Sex { get; set; }
/// <summary>
/// 邮箱
/// </summary>
public String Email { get; set; }
/// <summary>
/// 手机
/// </summary>
public String Phone { get; set; }
/// <summary>
/// 电话
/// </summary>
public String Tel { get; set; }
/// <summary>
/// 管理员类型0超级管理员 1非管理员
/// </summary>
public int AdminType { get; set; }
/// <summary>
/// 最后登陆IP
/// </summary>
public string LastLoginIp { get; set; }
/// <summary>
/// 最后登陆时间
/// </summary>
public DateTime LastLoginTime { get; set; }
/// <summary>
/// 最后登陆地址
/// </summary>
public string LastLoginAddress { get; set; }
/// <summary>
/// 最后登陆所用浏览器
/// </summary>
public string LastLoginBrowser { get; set; }
/// <summary>
/// 最后登陆所用系统
/// </summary>
public string LastLoginOs { get; set; }
/// <summary>
/// 员工信息
/// </summary>
public EmpOutput LoginEmpInfo { get; set; } = new EmpOutput();
/// <summary>
/// 具备应用信息
/// </summary>
public List<AppOutput> Apps { get; set; } = new List<AppOutput>();
/// <summary>
/// 角色信息
/// </summary>
public List<RoleOutput> Roles { get; set; } = new List<RoleOutput>();
/// <summary>
/// 权限信息
/// </summary>
public List<string> Permissions { get; set; } = new List<string>();
/// <summary>
/// 登录菜单信息---AntDesign版本菜单
/// </summary>
public List<AntDesignTreeNode> Menus { get; set; } = new List<AntDesignTreeNode>();
/// <summary>
/// 数据范围(机构)信息
/// </summary>
public List<string> DataScopes { get; set; } = new List<string>();
///// <summary>
///// 租户信息
///// </summary>
//public List<long> Tenants { get; set; }
///// <summary>
///// 密码
///// </summary>
//public string Password { get; set; }
///// <summary>
///// 账户过期
///// </summary>
//public string AccountNonExpired { get; set; }
///// <summary>
///// 凭证过期
///// </summary>
//public string CredentialsNonExpired { get; set; }
///// <summary>
///// 账户锁定
///// </summary>
//public bool AccountNonLocked { get; set; }
///// <summary>
///// 用户名称
///// </summary>
//public string UserName { get; set; }
///// <summary>
///// 权限
///// </summary>
//public List<long> Authorities { get; set; } = new List<long>();
///// <summary>
///// 是否启动
///// </summary>
//public bool Enabled { get; set; }
}
}

View File

@@ -0,0 +1,15 @@
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
public interface IAuthService
{
Task<dynamic> GetCaptcha();
Task<bool> GetCaptchaOpen();
Task<LoginUserOutput> GetLoginUserAsync();
Task<LoginOutput> LoginAsync([Required] LoginInput input);
Task LogoutAsync();
Task<dynamic> VerificationCode(ClickWordCaptchaInput input);
}
}

View File

@@ -0,0 +1,24 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
public interface ISysCacheService
{
Task<bool> DelAsync(string key);
Task<bool> DelByPatternAsync(string key);
List<string> GetAllCacheKeys();
Task<List<string>> GetDataScope(string userId);
Task<List<AntDesignTreeNode>> GetMenu(string userId, string appCode);
Task<List<string>> GetPermission(string userId);
Task SetDataScope(string userId, List<string> dataScopes);
Task SetMenu(string userId, string appCode, List<AntDesignTreeNode> menus);
Task SetPermission(string userId, List<string> permissions);
Task<List<SysAreaCode>> GetAreaCode();
Task SetAreaCode(List<SysAreaCode> areaCodes);
Task<bool> SetAsync(string key, object value);
Task<string> GetAsync(string key);
Task<T> GetAsync<T>(string key);
bool Exists(string cacheKey);
}
}

View File

@@ -0,0 +1,189 @@
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
/// <summary>
/// 系统缓存服务
/// </summary>
[ApiDescriptionSettings(Name = "Cache", Order = 100)]
public class SysCacheService : ISysCacheService, IDynamicApiController, ISingleton
{
private readonly ICache _cache;
private readonly CacheOptions _cacheOptions;
public SysCacheService(IOptions<CacheOptions> cacheOptions, Func<string, ISingleton, object> resolveNamed)
{
_cacheOptions = cacheOptions.Value;
_cache = resolveNamed(_cacheOptions.CacheType.ToString(), default) as ICache;
}
/// <summary>
/// 获取数据范围缓存机构Id集合
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
public async Task<List<string>> GetDataScope(string userId)
{
var cacheKey = CommonConst.CACHE_KEY_DATASCOPE + $"{userId}";
return await _cache.GetAsync<List<string>>(cacheKey);
}
/// <summary>
/// 缓存数据范围机构Id集合
/// </summary>
/// <param name="userId"></param>
/// <param name="dataScopes"></param>
/// <returns></returns>
[NonAction]
public async Task SetDataScope(string userId, List<string> dataScopes)
{
var cacheKey = CommonConst.CACHE_KEY_DATASCOPE + $"{userId}";
await _cache.SetAsync(cacheKey, dataScopes);
}
/// <summary>
/// 获取菜单缓存
/// </summary>
/// <param name="userId"></param>
/// <param name="appCode"></param>
/// <returns></returns>
public async Task<List<AntDesignTreeNode>> GetMenu(string userId, string appCode)
{
var cacheKey = CommonConst.CACHE_KEY_MENU + $"{userId}-{appCode}";
return await _cache.GetAsync<List<AntDesignTreeNode>>(cacheKey);
}
/// <summary>
/// 缓存菜单
/// </summary>
/// <param name="userId"></param>
/// <param name="appCode"></param>
/// <param name="menus"></param>
/// <returns></returns>
[NonAction]
public async Task SetMenu(string userId, string appCode, List<AntDesignTreeNode> menus)
{
var cacheKey = CommonConst.CACHE_KEY_MENU + $"{userId}-{appCode}";
await _cache.SetAsync(cacheKey, menus);
}
/// <summary>
/// 获取权限缓存(按钮)
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
public async Task<List<string>> GetPermission(string userId)
{
var cacheKey = CommonConst.CACHE_KEY_PERMISSION + $"{userId}";
return await _cache.GetAsync<List<string>>(cacheKey);
}
/// <summary>
/// 缓存权限
/// </summary>
/// <param name="userId"></param>
/// <param name="permissions"></param>
/// <returns></returns>
[NonAction]
public async Task SetPermission(string userId, List<string> permissions)
{
var cacheKey = CommonConst.CACHE_KEY_PERMISSION + $"{userId}";
await _cache.SetAsync(cacheKey, permissions);
}
/// <summary>
/// 获取所有缓存关键字
/// </summary>
/// <returns></returns>
public List<string> GetAllCacheKeys()
{
const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
var entries = _cache.GetType().GetField("_entries", flags).GetValue(_cache);
if (entries.GetType().GetProperty("Keys").GetValue(entries) is not ICollection<object> cacheItems) return new List<string>();
return cacheItems.Where(u => !u.ToString().StartsWith("mini-profiler"))
.Select(u => u.ToString()).ToList();
}
/// <summary>
/// 删除指定关键字缓存
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public Task<bool> DelAsync(string key)
{
_cache.DelAsync(key);
return Task.FromResult(true);
}
/// <summary>
/// 删除某特征关键字缓存
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public Task<bool> DelByPatternAsync(string key)
{
_cache.DelByPatternAsync(key);
return Task.FromResult(true);
}
/// <summary>
/// 设置缓存
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public async Task<bool> SetAsync(string key, object value)
{
return await _cache.SetAsync(key, value);
}
/// <summary>
/// 获取缓存
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public async Task<string> GetAsync(string key)
{
return await _cache.GetAsync(key);
}
/// <summary>
/// 获取缓存
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
public Task<T> GetAsync<T>(string key)
{
return _cache.GetAsync<T>(key);
}
public Task<List<SysAreaCode>> GetAreaCode()
{
return _cache.GetAsync<List<SysAreaCode>>(CommonConst.CACHE_AREA_CODE);
}
public async Task SetAreaCode(List<SysAreaCode> areaCodes)
{
await _cache.SetAsync(CommonConst.CACHE_AREA_CODE, areaCodes);
}
/// <summary>
/// 检查给定 key 是否存在
/// </summary>
/// <param name="cacheKey">键</param>
/// <returns></returns>
[NonAction]
public bool Exists(string cacheKey)
{
return _cache.Equals(cacheKey);
}
}
}

View File

@@ -0,0 +1,207 @@
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
/// <summary>
/// 代码生成详细配置服务
/// </summary>
[ApiDescriptionSettings(Name = "CodeGenConfig", Order = 100)]
public class CodeGenConfigService : ICodeGenConfigService, IDynamicApiController, ITransient
{
private readonly IRepository<SysCodeGenConfig> _sysCodeGenConfigRep; // 代码生成详细配置仓储
public CodeGenConfigService(IRepository<SysCodeGenConfig> sysCodeGenConfigRep)
{
_sysCodeGenConfigRep = sysCodeGenConfigRep;
}
/// <summary>
/// 代码生成详细配置列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("/sysCodeGenerateConfig/list")]
public async Task<List<CodeGenConfig>> List([FromQuery] CodeGenConfig input)
{
return await _sysCodeGenConfigRep.DetachedEntities.Where(u => u.CodeGenId == input.CodeGenId && u.WhetherCommon != YesOrNot.Y.ToString())
.Select(u => u.Adapt<CodeGenConfig>()).ToListAsync();
}
/// <summary>
/// 增加
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[NonAction]
public async Task Add(CodeGenConfig input)
{
var codeGenConfig = input.Adapt<SysCodeGenConfig>();
await codeGenConfig.InsertAsync();
}
/// <summary>
/// 删除
/// </summary>
/// <param name="codeGenId"></param>
/// <returns></returns>
[NonAction]
public async Task Delete(string codeGenId)
{
var codeGenConfigList = await _sysCodeGenConfigRep.Where(u => u.CodeGenId == codeGenId).ToListAsync();
codeGenConfigList.ForEach(u =>
{
u.Delete();
});
}
/// <summary>
/// 更新
/// </summary>
/// <param name="inputList"></param>
/// <returns></returns>
[HttpPost("/sysCodeGenerateConfig/edit")]
public async Task Update(List<CodeGenConfig> inputList)
{
if (inputList == null || inputList.Count < 1) return;
inputList.ForEach(u =>
{
var codeGenConfig = u.Adapt<SysCodeGenConfig>();
codeGenConfig.Update(true);
});
await Task.CompletedTask;
}
/// <summary>
/// 详情
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("/sysCodeGenerateConfig/detail")]
public async Task<SysCodeGenConfig> Detail(CodeGenConfig input)
{
return await _sysCodeGenConfigRep.FirstOrDefaultAsync(u => u.Id == input.Id);
}
/// <summary>
/// 批量增加
/// </summary>
/// <param name="tableColumnOuputList"></param>
/// <param name="codeGenerate"></param>
[NonAction]
public void AddList(List<TableColumnOuput> tableColumnOuputList, SysCodeGen codeGenerate)
{
if (tableColumnOuputList == null) return;
foreach (var tableColumn in tableColumnOuputList)
{
var codeGenConfig = new SysCodeGenConfig();
var YesOrNo = YesOrNot.Y.ToString();
if (Convert.ToBoolean(tableColumn.ColumnKey))
{
YesOrNo = YesOrNot.N.ToString();
}
if (IsCommonColumn(tableColumn.ColumnName))
{
codeGenConfig.WhetherCommon = YesOrNot.Y.ToString();
YesOrNo = YesOrNot.N.ToString();
}
else
{
codeGenConfig.WhetherCommon = YesOrNot.N.ToString();
}
codeGenConfig.CodeGenId = codeGenerate.Id;
codeGenConfig.ColumnName = tableColumn.ColumnName;
codeGenConfig.ColumnComment = tableColumn.ColumnComment;
codeGenConfig.NetType = ConvertDataType(tableColumn.DataType);
codeGenConfig.WhetherRetract = YesOrNot.N.ToString();
codeGenConfig.WhetherRequired = YesOrNot.N.ToString();
codeGenConfig.QueryWhether = YesOrNo;
codeGenConfig.WhetherAddUpdate = YesOrNo;
codeGenConfig.WhetherTable = YesOrNo;
codeGenConfig.ColumnKey = tableColumn.ColumnKey;
codeGenConfig.DataType = tableColumn.DataType;
codeGenConfig.EffectType = DataTypeToEff(codeGenConfig.NetType);
codeGenConfig.QueryType = "=="; // QueryTypeEnum.eq.ToString();
codeGenConfig.InsertAsync();
}
}
/// <summary>
/// 数据类型转显示类型
/// </summary>
/// <param name="dataType"></param>
/// <returns></returns>
private static string DataTypeToEff(string dataType)
{
if (string.IsNullOrEmpty(dataType)) return "";
return dataType switch
{
"string" => "input",
"int" => "inputnumber",
"long" => "input",
"float" => "input",
"double" => "input",
"decimal" => "input",
"bool" => "switch",
"Guid" => "input",
"DateTime" => "datepicker",
"DateTimeOffset" => "datepicker",
_ => "input",
};
}
// 转换.NET数据类型
[NonAction]
public string ConvertDataType(string dataType)
{
if (string.IsNullOrEmpty(dataType)) return "";
if (dataType.StartsWith("System.Nullable"))
dataType = new Regex(@"(?i)(?<=\[)(.*)(?=\])").Match(dataType).Value; // 中括号[]里面值
switch (dataType)
{
case "System.Guid": return "Guid";
case "System.String": return "string";
case "System.Int32": return "int";
case "System.Int64": return "long";
case "System.Single": return "float";
case "System.Double": return "double";
case "System.Decimal": return "decimal";
case "System.Boolean": return "bool";
case "System.DateTime": return "DateTime";
case "System.DateTimeOffset": return "DateTimeOffset";
case "System.Byte": return "byte";
case "System.Byte[]": return "byte[]";
default:
break;
}
return dataType;
}
// 是否通用字段
private static bool IsCommonColumn(string columnName)
{
var columnList = new List<string>() { "CreatedTime", "UpdatedTime", "CreatedUserId", "CreatedUserName", "UpdatedUserId", "UpdatedUserName", "IsDeleted" };
return columnList.Contains(columnName);
}
}
}

View File

@@ -0,0 +1,348 @@
using Furion;
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Furion.ViewEngine;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Ewide.Core.Service.CodeGen
{
/// <summary>
/// 代码生成器服务
/// </summary>
[ApiDescriptionSettings(Name = "CodeGen", Order = 100)]
public class CodeGenService : ICodeGenService, IDynamicApiController, ITransient
{
private readonly IRepository<SysCodeGen> _sysCodeGenRep; // 代码生成器仓储
private readonly ICodeGenConfigService _codeGenConfigService;
private readonly IViewEngine _viewEngine;
private readonly IRepository<SysMenu> _sysMenuRep; // 菜单表仓储
public CodeGenService(IRepository<SysCodeGen> sysCodeGenRep,
ICodeGenConfigService codeGenConfigService,
IViewEngine viewEngine,
IRepository<SysMenu> sysMenuRep)
{
_sysCodeGenRep = sysCodeGenRep;
_codeGenConfigService = codeGenConfigService;
_viewEngine = viewEngine;
_sysMenuRep = sysMenuRep;
}
/// <summary>
/// 分页查询
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/codeGenerate/page")]
public async Task<dynamic> QueryCodeGenPageList([FromBody] CodeGenInput input)
{
var tableName = !string.IsNullOrEmpty(input.TableName?.Trim());
var codeGens = await _sysCodeGenRep.DetachedEntities
.Where((tableName, u => EF.Functions.Like(u.TableName, $"%{input.TableName.Trim()}%")))
.ToPagedListAsync(input.PageIndex, input.PageSize);
return PageDataResult<SysCodeGen>.PageResult(codeGens);
}
/// <summary>
/// 增加
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/codeGenerate/add")]
public async Task AddCodeGen(AddCodeGenInput input)
{
var isExist = await _sysCodeGenRep.DetachedEntities.AnyAsync(u => u.TableName == input.TableName);
if (isExist)
throw Oops.Oh(ErrorCode.D1400);
var codeGen = input.Adapt<SysCodeGen>();
var newCodeGen = await codeGen.InsertNowAsync();
// 加入配置表中
_codeGenConfigService.AddList(GetColumnList(input), newCodeGen.Entity);
}
/// <summary>
/// 删除
/// </summary>
/// <param name="inputs"></param>
/// <returns></returns>
[HttpPost("/codeGenerate/delete")]
public async Task DeleteCodeGen(List<DeleteCodeGenInput> inputs)
{
if (inputs == null || inputs.Count < 1) return;
var codeGenConfigTaskList = new List<Task>();
inputs.ForEach(u =>
{
_sysCodeGenRep.Delete(u.Id);
// 删除配置表中
codeGenConfigTaskList.Add(_codeGenConfigService.Delete(u.Id));
});
await Task.WhenAll(codeGenConfigTaskList);
}
/// <summary>
/// 更新
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/codeGenerate/edit")]
public async Task UpdateCodeGen(UpdateCodeGenInput input)
{
var isExist = await _sysCodeGenRep.DetachedEntities.AnyAsync(u => u.TableName == input.TableName && u.Id != input.Id);
if (isExist)
throw Oops.Oh(ErrorCode.D1400);
var codeGen = input.Adapt<SysCodeGen>();
await codeGen.UpdateAsync();
}
/// <summary>
/// 详情
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("/codeGenerate/detail")]
public async Task<SysCodeGen> GetCodeGen([FromQuery] QueryCodeGenInput input)
{
return await _sysCodeGenRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == input.Id);
}
/// <summary>
/// 获取数据库表(实体)集合
/// </summary>
/// <returns></returns>
[HttpGet("/codeGenerate/InformationList")]
public List<TableOutput> GetTableList()
{
return Db.GetDbContext().Model.GetEntityTypes().Select(u => new TableOutput
{
TableName = u.GetDefaultTableName(),
TableComment = u.GetComment()
}).ToList();
}
/// <summary>
/// 获取数据表列(实体属性)集合
/// </summary>
/// <returns></returns>
[NonAction]
public List<TableColumnOuput> GetColumnList(AddCodeGenInput input)
{
var entityType = Db.GetDbContext().Model.GetEntityTypes().FirstOrDefault(u => u.ClrType.Name == input.TableName);
if (entityType == null) return null;
return entityType.GetProperties().Select(u => new TableColumnOuput
{
ColumnName = u.Name,
ColumnKey = u.IsKey().ToString(),
DataType = u.PropertyInfo.PropertyType.ToString(),
ColumnComment = u.GetComment()
}).ToList();
}
/// <summary>
/// 代码生成_本地项目
/// </summary>
/// <returns></returns>
[HttpPost("/codeGenerate/runLocal")]
public async void RunLocal(SysCodeGen input)
{
var templatePathList = GetTemplatePathList();
var targetPathList = GetTargetPathList(input);
for (var i = 0; i < templatePathList.Count; i++)
{
var tContent = File.ReadAllText(templatePathList[i]);
var tableFieldList = await _codeGenConfigService.List(new CodeGenConfig() { CodeGenId = input.Id }); // 字段集合
if (i >= 4) // 适应前端首字母小写
{
tableFieldList.ForEach(u =>
{
u.ColumnName = u.ColumnName.Substring(0, 1).ToLower() + u.ColumnName.Substring(1);
});
}
var queryWhetherList = tableFieldList.Where(u => u.QueryWhether == YesOrNot.Y.ToString()).ToList(); // 前端查询集合
var tResult = _viewEngine.RunCompileFromCached(tContent, new
{
input.AuthorName,
input.BusName,
input.NameSpace,
ClassName = input.TableName,
QueryWhetherList = queryWhetherList,
TableField = tableFieldList
});
var dirPath = new DirectoryInfo(targetPathList[i]).Parent.FullName;
if (!Directory.Exists(dirPath))
Directory.CreateDirectory(dirPath);
File.WriteAllText(targetPathList[i], tResult, Encoding.UTF8);
}
await AddMenu(input.TableName, input.BusName);
}
private async Task AddMenu(string className, string busName)
{
// 先删除该表已生成的菜单列表
var menus = await _sysMenuRep.DetachedEntities.Where(u => u.Code.StartsWith("dilon_" + className.ToLower())).ToListAsync();
menus.ForEach(u =>
{
u.Delete();
});
var emptyGuid = System.Guid.Empty.ToString();
// 目录
var menuType0 = new SysMenu
{
Pid = emptyGuid,
Pids = "["+ emptyGuid + "],",
Name = busName + "管理",
Code = "dilon_" + className.ToLower(),
Type = 1,
Icon = "robot",
Router = "/" + className.ToLower(),
Component = "PageView",
Application = "busapp"
};
var pid0 = _sysMenuRep.InsertNowAsync(menuType0).GetAwaiter().GetResult().Entity.Id;
// 菜单
var menuType1 = new SysMenu
{
Pid = pid0,
Pids = "[0],[" + pid0 + "],",
Name = busName + "管理",
Code = "dilon_" + className.ToLower() + "_mgr",
Type = 1,
Router = "/" + className.ToLower(),
Component = "main/" + className + "/index",
Application = "busapp",
OpenType = 1
};
var pid1 = _sysMenuRep.InsertNowAsync(menuType1).GetAwaiter().GetResult().Entity.Id;
// 按钮-page
var menuType2 = new SysMenu
{
Pid = pid1,
Pids = "[0],[" + pid0 + "],[" + pid1 + "],",
Name = busName + "查询",
Code = "dilon_" + className.ToLower() + "_mgr_page",
Type = 2,
Permission = className + ":page",
Application = "busapp",
}.InsertAsync();
// 按钮-detail
var menuType2_1 = new SysMenu
{
Pid = pid1,
Pids = "[0],[" + pid0 + "],[" + pid1 + "],",
Name = busName + "详情",
Code = "dilon_" + className.ToLower() + "_mgr_detail",
Type = 2,
Permission = className + ":detail",
Application = "busapp",
}.InsertAsync();
// 按钮-add
var menuType2_2 = new SysMenu
{
Pid = pid1,
Pids = "[0],[" + pid0 + "],[" + pid1 + "],",
Name = busName + "增加",
Code = "dilon_" + className.ToLower() + "_mgr_add",
Type = 2,
Permission = className + ":add",
Application = "busapp",
}.InsertAsync();
// 按钮-delete
var menuType2_3 = new SysMenu
{
Pid = pid1,
Pids = "[0],[" + pid0 + "],[" + pid1 + "],",
Name = busName + "删除",
Code = "dilon_" + className.ToLower() + "_mgr_delete",
Type = 2,
Permission = className + ":delete",
Application = "busapp",
}.InsertAsync();
// 按钮-edit
var menuType2_4 = new SysMenu
{
Pid = pid1,
Pids = "[0],[" + pid0 + "],[" + pid1 + "],",
Name = busName + "编辑",
Code = "dilon_" + className.ToLower() + "_mgr_edit",
Type = 2,
Permission = className + ":edit",
Application = "busapp",
}.InsertAsync();
}
/// <summary>
/// 获取模板文件路径集合
/// </summary>
/// <returns></returns>
private List<string> GetTemplatePathList()
{
var templatePath = App.WebHostEnvironment.WebRootPath + @"\Template\";
return new List<string>() {
templatePath + "Service.cs.vm",
templatePath + "IService.cs.vm",
templatePath + "Input.cs.vm",
templatePath + "Output.cs.vm",
templatePath + "index.vue.vm",
templatePath + "addForm.vue.vm",
templatePath + "editForm.vue.vm",
templatePath + "manage.js.vm",
};
}
/// <summary>
/// 设置生成文件路径
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
private List<string> GetTargetPathList(SysCodeGen input)
{
var backendPath = new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent.FullName + @"\Ewide.Application\Service\" + input.TableName + @"\";
var servicePath = backendPath + input.TableName + "Service.cs";
var iservicePath = backendPath + "I" + input.TableName + "Service.cs";
var inputPath = backendPath + @"Dto\" + input.TableName + "Input.cs";
var outputPath = backendPath + @"Dto\" + input.TableName + "Output.cs";
var frontendPath = new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent.Parent.FullName + @"\frontend\src\views\main\";
var indexPath = frontendPath + input.TableName + @"\index.vue";
var addFormPath = frontendPath + input.TableName + @"\addForm.vue";
var editFormPath = frontendPath + input.TableName + @"\editForm.vue";
var apiJsPath = new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent.Parent.FullName + @"\frontend\src\api\modular\main\" + input.TableName + "Manage.js";
return new List<string>() {
servicePath,
iservicePath,
inputPath,
outputPath,
indexPath,
addFormPath,
editFormPath,
apiJsPath
};
}
}
}

View File

@@ -0,0 +1,88 @@
namespace Ewide.Core.Service
{
/// <summary>
/// 代码生成详细配置参数
/// </summary>
public class CodeGenConfig
{
/// <summary>
/// 主键
/// </summary>
public string Id { get; set; }
/// <summary>
/// 代码生成主表ID
/// </summary>
public string CodeGenId { get; set; }
/// <summary>
/// 数据库字段名
/// </summary>
public string ColumnName { get; set; }
/// <summary>
/// 字段描述
/// </summary>
public string ColumnComment { get; set; }
/// <summary>
/// .NET类型
/// </summary>
public string NetType { get; set; }
/// <summary>
/// 作用类型(字典)
/// </summary>
public string EffectType { get; set; }
/// <summary>
/// 字典code
/// </summary>
public string DictTypeCode { get; set; }
/// <summary>
/// 列表是否缩进(字典)
/// </summary>
public string WhetherRetract { get; set; }
/// <summary>
/// 是否必填(字典)
/// </summary>
public string WhetherRequired { get; set; }
/// <summary>
/// 是否是查询条件
/// </summary>
public string QueryWhether { get; set; }
/// <summary>
/// 查询方式
/// </summary>
public string QueryType { get; set; }
/// <summary>
/// 列表显示
/// </summary>
public string WhetherTable { get; set; }
/// <summary>
/// 增改
/// </summary>
public string WhetherAddUpdate { get; set; }
/// <summary>
/// 主外键
/// </summary>
public string ColumnKey { get; set; }
/// <summary>
/// 数据库中类型(物理类型)
/// </summary>
public string DataType { get; set; }
/// <summary>
/// 是否是通用字段
/// </summary>
public string WhetherCommon { get; set; }
}
}

View File

@@ -0,0 +1,124 @@
using System.ComponentModel.DataAnnotations;
namespace Ewide.Core.Service
{
/// <summary>
/// 代码生成参数类
/// </summary>
public class CodeGenInput : InputBase
{
/// <summary>
/// 作者姓名
/// </summary>
public virtual string AuthorName { get; set; }
/// <summary>
/// 类名
/// </summary>
public virtual string ClassName { get; set; }
/// <summary>
/// 是否移除表前缀
/// </summary>
public virtual string TablePrefix { get; set; }
/// <summary>
/// 生成方式
/// </summary>
public virtual string GenerateType { get; set; }
/// <summary>
/// 数据库表名
/// </summary>
public virtual string TableName { get; set; }
/// <summary>
/// 命名空间
/// </summary>
public virtual string NameSpace { get; set; }
/// <summary>
/// 业务名(业务代码包名称)
/// </summary>
public virtual string BusName { get; set; }
/// <summary>
/// 功能名(数据库表名称)
/// </summary>
public virtual string TableComment { get; set; }
}
public class AddCodeGenInput : CodeGenInput
{
/// <summary>
/// 数据库表名
/// </summary>
[Required(ErrorMessage = "数据库表名不能为空")]
public override string TableName { get; set; }
/// <summary>
/// 业务名(业务代码包名称)
/// </summary>
[Required(ErrorMessage = "业务名不能为空")]
public override string BusName { get; set; }
/// <summary>
/// 命名空间
/// </summary>
[Required(ErrorMessage = "命名空间不能为空")]
public override string NameSpace { get; set; }
/// <summary>
/// 作者姓名
/// </summary>
[Required(ErrorMessage = "作者姓名不能为空")]
public override string AuthorName { get; set; }
///// <summary>
///// 类名
///// </summary>
//[Required(ErrorMessage = "类名不能为空")]
//public override string ClassName { get; set; }
///// <summary>
///// 是否移除表前缀
///// </summary>
//[Required(ErrorMessage = "是否移除表前缀不能为空")]
//public override string TablePrefix { get; set; }
/// <summary>
/// 生成方式
/// </summary>
[Required(ErrorMessage = "生成方式不能为空")]
public override string GenerateType { get; set; }
///// <summary>
///// 功能名(数据库表名称)
///// </summary>
//[Required(ErrorMessage = "数据库表名不能为空")]
//public override string TableComment { get; set; }
}
public class DeleteCodeGenInput
{
/// <summary>
/// 代码生成器Id
/// </summary>
[Required(ErrorMessage = "代码生成器Id不能为空")]
public string Id { get; set; }
}
public class UpdateCodeGenInput : CodeGenInput
{
/// <summary>
/// 代码生成器Id
/// </summary>
[Required(ErrorMessage = "代码生成器Id不能为空")]
public string Id { get; set; }
}
public class QueryCodeGenInput : DeleteCodeGenInput
{
}
}

View File

@@ -0,0 +1,53 @@
namespace Ewide.Core.Service
{
/// <summary>
/// 代码生成参数类
/// </summary>
public class CodeGenOutput
{
/// <summary>
/// 代码生成器Id
/// </summary>
public long Id { get; set; }
/// <summary>
/// 作者姓名
/// </summary>
public string AuthorName { get; set; }
/// <summary>
/// 类名
/// </summary>
public string ClassName { get; set; }
/// <summary>
/// 是否移除表前缀
/// </summary>
public string TablePrefix { get; set; }
/// <summary>
/// 生成方式
/// </summary>
public string GenerateType { get; set; }
/// <summary>
/// 数据库表名
/// </summary>
public string TableName { get; set; }
/// <summary>
/// 包名
/// </summary>
public string PackageName { get; set; }
/// <summary>
/// 业务名(业务代码包名称)
/// </summary>
public string BusName { get; set; }
/// <summary>
/// 功能名(数据库表名称)
/// </summary>
public string TableComment { get; set; }
}
}

View File

@@ -0,0 +1,28 @@
namespace Ewide.Core.Service
{
/// <summary>
/// 数据库表列
/// </summary>
public class TableColumnOuput
{
/// <summary>
/// 字段名
/// </summary>
public string ColumnName { get; set; }
/// <summary>
/// 数据库中类型
/// </summary>
public string DataType { get; set; }
/// <summary>
/// 字段描述
/// </summary>
public string ColumnComment { get; set; }
/// <summary>
/// 主外键
/// </summary>
public string ColumnKey { get; set; }
}
}

View File

@@ -0,0 +1,28 @@
namespace Ewide.Core.Service
{
/// <summary>
/// 数据库表列表参数
/// </summary>
public class TableOutput
{
/// <summary>
/// 表名(字母形式的)
/// </summary>
public string TableName { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public string CreateTime { get; set; }
/// <summary>
/// 更新时间
/// </summary>
public string UpdateTime { get; set; }
/// <summary>
/// 表名称描述(注释)(功能名)
/// </summary>
public string TableComment { get; set; }
}
}

View File

@@ -0,0 +1,17 @@
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
public interface ICodeGenConfigService
{
Task Add(CodeGenConfig input);
void AddList(List<TableColumnOuput> tableColumnOuputList, SysCodeGen codeGenerate);
string ConvertDataType(string dataType);
Task Delete(string codeGenId);
Task<SysCodeGenConfig> Detail(CodeGenConfig input);
Task<List<CodeGenConfig>> List([FromQuery] CodeGenConfig input);
Task Update(List<CodeGenConfig> inputList);
}
}

View File

@@ -0,0 +1,18 @@
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Ewide.Core.Service.CodeGen
{
public interface ICodeGenService
{
Task AddCodeGen(AddCodeGenInput input);
Task DeleteCodeGen(List<DeleteCodeGenInput> inputs);
Task<SysCodeGen> GetCodeGen([FromQuery] QueryCodeGenInput input);
List<TableColumnOuput> GetColumnList(AddCodeGenInput input);
List<TableOutput> GetTableList();
Task<dynamic> QueryCodeGenPageList([FromQuery] CodeGenInput input);
void RunLocal(SysCodeGen input);
Task UpdateCodeGen(UpdateCodeGenInput input);
}
}

View File

@@ -0,0 +1,83 @@
using System.ComponentModel.DataAnnotations;
namespace Ewide.Core.Service
{
/// <summary>
/// 参数配置
/// </summary>
public class ConfigInput : PageInputBase
{
/// <summary>
/// 名称
/// </summary>
public virtual string Name { get; set; }
/// <summary>
/// 编码
/// </summary>
public virtual string Code { get; set; }
/// <summary>
/// 属性值
/// </summary>
public virtual string Value { get; set; }
/// <summary>
/// 是否是系统参数Y-是N-否)
/// </summary>
public virtual string SysFlag { get; set; }
/// <summary>
/// 备注
/// </summary>
public virtual string Remark { get; set; }
/// <summary>
/// 状态(字典 0正常 1停用 2删除
/// </summary>
public virtual int Status { get; set; }
/// <summary>
/// 常量所属分类的编码,来自于“常量的分类”字典
/// </summary>
public virtual string GroupCode { get; set; }
}
public class AddConfigInput : ConfigInput
{
/// <summary>
/// 名称
/// </summary>
[Required(ErrorMessage = "参数名称不能为空")]
public override string Name { get; set; }
/// <summary>
/// 编码
/// </summary>
[Required(ErrorMessage = "参数编码不能为空")]
public override string Code { get; set; }
}
public class DeleteConfigInput
{
/// <summary>
/// 应用Id
/// </summary>
[Required(ErrorMessage = "参数Id不能为空")]
public string Id { get; set; }
}
public class UpdateConfigInput : AddConfigInput
{
/// <summary>
/// 应用Id
/// </summary>
[Required(ErrorMessage = "应用Id不能为空")]
public string Id { get; set; }
}
public class QueryConfigInput : DeleteConfigInput
{
}
}

View File

@@ -0,0 +1,18 @@
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
public interface ISysConfigService
{
Task AddConfig(AddConfigInput input);
Task DeleteConfig(DeleteConfigInput input);
Task<SysConfig> GetConfig([FromQuery] QueryConfigInput input);
Task<dynamic> GetConfigList([FromQuery] ConfigInput input);
Task<dynamic> QueryConfigPageList([FromQuery] ConfigInput input);
Task UpdateConfig(UpdateConfigInput input);
Task<bool> GetDemoEnvFlag();
Task<bool> GetCaptchaOpenFlag();
Task UpdateConfigCache(string code, object value);
}
}

View File

@@ -0,0 +1,175 @@
using Ewide.Core.Extension;
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
/// <summary>
/// 系统参数配置服务
/// </summary>
[ApiDescriptionSettings(Name = "Config", Order = 100)]
public class SysConfigService : ISysConfigService, IDynamicApiController, ITransient
{
private readonly IRepository<SysConfig> _sysConfigRep; // 参数配置表仓储
private readonly ISysCacheService _sysCacheService;
public SysConfigService(IRepository<SysConfig> sysConfigRep, ISysCacheService sysCacheService)
{
_sysConfigRep = sysConfigRep;
_sysCacheService = sysCacheService;
}
/// <summary>
/// 分页获取系统参数配置
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysConfig/page")]
public async Task<dynamic> QueryConfigPageList([FromBody] ConfigInput input)
{
var name = !string.IsNullOrEmpty(input.Name?.Trim());
var code = !string.IsNullOrEmpty(input.Code?.Trim());
var groupCode = !string.IsNullOrEmpty(input.GroupCode?.Trim());
var configs = await _sysConfigRep.DetachedEntities
.Where((name, u => EF.Functions.Like(u.Name, $"%{input.Name.Trim()}%")),
(code, u => EF.Functions.Like(u.Code, $"%{input.Code.Trim()}%")),
(groupCode, u => EF.Functions.Like(u.Code, $"%{input.GroupCode.Trim()}%")))
.Where(u => u.Status != CommonStatus.DELETED).OrderBy(u => u.GroupCode)
.ToPageData(input);
return PageDataResult<SysConfig>.PageResult(configs);
}
/// <summary>
/// 获取系统参数配置列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("/sysConfig/list")]
public async Task<dynamic> GetConfigList([FromQuery] ConfigInput input)
{
return await _sysConfigRep.DetachedEntities.Where(u => u.Status != CommonStatus.DELETED).ToListAsync();
}
/// <summary>
/// 增加系统参数配置
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysConfig/add")]
public async Task AddConfig(AddConfigInput input)
{
var isExist = await _sysConfigRep.DetachedEntities.AnyAsync(u => u.Name == input.Name || u.Code == input.Code);
if (isExist)
throw Oops.Oh(ErrorCode.D9000);
var config = input.Adapt<SysConfig>();
await config.InsertAsync();
}
/// <summary>
/// 删除系统参数配置
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysConfig/delete")]
public async Task DeleteConfig(DeleteConfigInput input)
{
var config = await _sysConfigRep.FirstOrDefaultAsync(u => u.Id == input.Id);
// 禁止删除系统参数
if (config.SysFlag == YesOrNot.Y.ToString())
throw Oops.Oh(ErrorCode.D9001);
await config.DeleteAsync();
}
/// <summary>
/// 更新系统参数配置
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysConfig/edit")]
public async Task UpdateConfig(UpdateConfigInput input)
{
var isExist = await _sysConfigRep.DetachedEntities.AnyAsync(u => (u.Name == input.Name || u.Code == input.Code) && u.Id != input.Id);
if (isExist)
throw Oops.Oh(ErrorCode.D9000);
var config = input.Adapt<SysConfig>();
await config.UpdateAsync(ignoreNullValues: true);
}
/// <summary>
/// 获取系统参数配置
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("/sysConfig/detail")]
public async Task<SysConfig> GetConfig([FromQuery] QueryConfigInput input)
{
return await _sysConfigRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == input.Id);
}
/// <summary>
/// 获取配置信息
/// </summary>
/// <param name="code"></param>
/// <returns></returns>
private async Task<dynamic> GetConfigCache(string code)
{
var value = await _sysCacheService.GetAsync(code);
if (string.IsNullOrEmpty(value))
{
var config = await _sysConfigRep.DetachedEntities.FirstOrDefaultAsync(u => u.Code == code);
value = config != null ? config.Value : "";
#if DEBUG
#else
await _sysCacheService.SetAsync(code, value);
#endif
}
return value;
}
/// <summary>
/// 更新配置缓存
/// </summary>
/// <param name="code"></param>
/// <param name="value"></param>
/// <returns></returns>
public async Task UpdateConfigCache(string code, object value)
{
#if DEBUG
#else
await _sysCacheService.SetAsync(code, value);
#endif
}
/// <summary>
/// 获取演示环境开关是否开启默认为false
/// </summary>
/// <returns></returns>
[NonAction]
public async Task<bool> GetDemoEnvFlag()
{
var value = await GetConfigCache("DILON_DEMO_ENV_FLAG");
return bool.Parse(value);
}
/// <summary>
/// 获取验证码开关标识
/// </summary>
/// <returns></returns>
public async Task<bool> GetCaptchaOpenFlag()
{
var value = await GetConfigCache("DILON_CAPTCHA_OPEN");
return bool.Parse(value);
}
}
}

View File

@@ -0,0 +1,99 @@
using Furion.DataValidation;
using System.ComponentModel.DataAnnotations;
namespace Ewide.Core.Service
{
/// <summary>
/// 字典值参数
/// </summary>
public class DictDataInput : PageInputBase
{
/// <summary>
/// 字典类型Id
/// </summary>
public virtual string TypeId { get; set; }
/// <summary>
/// 值
/// </summary>
public virtual string Value { get; set; }
/// <summary>
/// 编码
/// </summary>
public virtual string Code { get; set; }
/// <summary>
/// 扩展编码
/// </summary>
public virtual string ExtCode { get; set; }
/// <summary>
/// 排序
/// </summary>
public virtual int Sort { get; set; }
/// <summary>
/// 备注
/// </summary>
public virtual string Remark { get; set; }
/// <summary>
/// 状态(字典 0正常 1停用 2删除
/// </summary>
public virtual CommonStatus Status { get; set; }
}
public class QueryDictDataListInput
{
/// <summary>
/// 字典类型Id
/// </summary>
[Required(ErrorMessage = "字典类型Id不能为空")]
public string TypeId { get; set; }
}
public class AddDictDataInput : DictDataInput
{
/// <summary>
/// 字典类型Id
/// </summary>
[Required(ErrorMessage = "字典类型Id不能为空")]
public override string TypeId { get; set; }
/// <summary>
/// 值
/// </summary>
[Required(ErrorMessage = "字典值不能为空")]
public override string Value { get; set; }
/// <summary>
/// 编码
/// </summary>
[Required(ErrorMessage = "字典值编码不能为空")]
public override string Code { get; set; }
}
public class DeleteDictDataInput
{
/// <summary>
/// 字典值Id
/// </summary>
[Required(ErrorMessage = "字典值Id不能为空")]
public string Id { get; set; }
}
public class UpdateDictDataInput : AddDictDataInput
{
/// <summary>
/// 字典值Id
/// </summary>
[Required(ErrorMessage = "字典值Id不能为空")]
public string Id { get; set; }
}
public class QueryDictDataInput : DeleteDictDataInput
{
}
}

View File

@@ -0,0 +1,13 @@
namespace Ewide.Core.Service
{
/// <summary>
/// 字典值参数
/// </summary>
public class DictDataOutput : DictDataInput
{
/// <summary>
/// 字典Id
/// </summary>
public virtual string Id { get; set; }
}
}

View File

@@ -0,0 +1,108 @@
using System.Collections;
using System.Collections.Generic;
namespace Ewide.Core.Service
{
/// <summary>
/// 字典类型与字典值构造的树
/// </summary>
public class DictTreeOutput : ITreeNode
{
/// <summary>
/// Id
/// </summary>
public string Id { get; set; }
/// <summary>
/// 父Id
/// </summary>
public string Pid { get; set; }
/// <summary>
/// 编码-对应字典值的编码
/// </summary>
public string Code { get; set; }
/// <summary>
/// 名称-对应字典值的value
/// </summary>
public string Name { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { set; get; }
/// <summary>
/// 排序
/// </summary>
public int Sort { set; get; }
/// <summary>
/// 子节点集合
/// </summary>
public List<DictTreeOutput> Children { get; set; } = new List<DictTreeOutput>();
public string GetId()
{
return Id;
}
public string GetPid()
{
return Pid;
}
public void SetChildren(IList children)
{
Children = (List<DictTreeOutput>)children;
}
}
public class DictTreeNode : ITreeNode
{
/// <summary>
/// Id
/// </summary>
public string Id { get; set; }
/// <summary>
/// 父Id
/// </summary>
public string ParentId { get; set; }
/// <summary>
/// 名称
/// </summary>
public string Title { get; set; }
/// <summary>
/// 值
/// </summary>
public string Value { get; set; }
/// <summary>
/// 排序,越小优先级越高
/// </summary>
public int Weight { get; set; }
/// <summary>
/// 子节点
/// </summary>
public List<DictTreeNode> Children { get; set; } = new List<DictTreeNode>();
public string GetId()
{
return Id;
}
public string GetPid()
{
return ParentId;
}
public void SetChildren(IList children)
{
Children = (List<DictTreeNode>)children;
}
}
}

View File

@@ -0,0 +1,98 @@
using System.ComponentModel.DataAnnotations;
namespace Ewide.Core.Service
{
/// <summary>
/// 字典类型参数
/// </summary>
public class DictTypeInput : PageInputBase
{
public string Pid { get; set; }
/// <summary>
/// 名称
/// </summary>
public virtual string Name { get; set; }
/// <summary>
/// 编码
/// </summary>
public virtual string Code { get; set; }
public int Type { get; set; }
/// <summary>
/// 排序
/// </summary>
public virtual int Sort { get; set; }
/// <summary>
/// 备注
/// </summary>
public virtual string Remark { get; set; }
/// <summary>
/// 状态(字典 0正常 1停用 2删除
/// </summary>
public virtual CommonStatus Status { get; set; }
}
public class AddDictTypeInput : DictTypeInput
{
/// <summary>
/// 父Id
/// </summary>
public string Pid { get; set; }
/// <summary>
/// 名称
/// </summary>
[Required(ErrorMessage = "字典类型名称不能为空")]
public override string Name { get; set; }
/// <summary>
/// 编码
/// </summary>
public override string Code { get; set; }
}
public class DeleteDictTypeInput
{
/// <summary>
/// 编号Id
/// </summary>
[Required(ErrorMessage = "字典类型Id不能为空")]
public string Id { get; set; }
}
public class UpdateDictTypeInput : AddDictTypeInput
{
/// <summary>
/// Id
/// </summary>
[Required(ErrorMessage = "字典类型Id不能为空")]
public string Id { get; set; }
}
public class DropDownDictTypeInput
{
/// <summary>
/// 编码
/// </summary>
[Required(ErrorMessage = "字典类型编码不能为空")]
public string Code { get; set; }
}
public class DropDownDictTypesInput
{
/// <summary>
/// 编码
/// </summary>
[Required(ErrorMessage = "字典类型编码不能为空")]
public string[] Code { get; set; }
}
public class QueryDictTypeInfoInput : DeleteDictTypeInput
{
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Ewide.Core.Service.Dict.Dto
{
public class EnumDictOutput
{
public string FullName { get; set; }
public string Desc { get; set; }
public string Code { get; set; }
public List<EnumDictData> Datas { get; set; }
}
public class EnumDictData
{
public string Desc { get; set; }
public string Code { get; set; }
public string Value { get; set; }
}
}

View File

@@ -0,0 +1,20 @@
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
public interface ISysDictDataService
{
Task AddDictData(AddDictDataInput input);
Task ChangeDictDataStatus(UpdateDictDataInput input);
Task DeleteByTypeId(string dictTypeId);
Task DeleteDictData(DeleteDictDataInput input);
Task<dynamic> GetDictData([FromQuery] QueryDictDataInput input);
Task<dynamic> GetDictDataList([FromQuery] QueryDictDataListInput input);
Task<dynamic> GetDictDataListByDictTypeId(string dictTypeId);
Task<dynamic> GetDictDataListByDictTypeIds(SysDictType[] dictTypes);
Task<dynamic> QueryDictDataPageList([FromQuery] DictDataInput input);
Task DeleteDictDataBatch(string[] Ids);
Task UpdateDictData(UpdateDictDataInput input);
}
}

View File

@@ -0,0 +1,22 @@
using Ewide.Core.Service.Dict.Dto;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
public interface ISysDictTypeService
{
Task AddDictType(AddDictTypeInput input);
Task ChangeDictTypeStatus(UpdateDictTypeInput input);
Task DeleteDictType(DeleteDictTypeInput input);
Task<List<DictTreeNode>> GetDictTree();
Task<dynamic> GetDictType([FromQuery] QueryDictTypeInfoInput input);
Task<dynamic> GetDictTypeDropDown([FromQuery] DropDownDictTypeInput input);
Task<dynamic> GetDictTypeDropDowns([FromQuery] DropDownDictTypesInput input);
Task<dynamic> GetDictTypeList();
Task<dynamic> QueryDictTypePageList([FromQuery] DictTypeInput input);
Task UpdateDictType(UpdateDictTypeInput input);
Task<List<EnumDictOutput>> GetEnumDictDataList([FromQuery] DictTypeInput input);
}
}

View File

@@ -0,0 +1,231 @@
using Furion.DatabaseAccessor;
using Ewide.Core.Extension;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace Ewide.Core.Service
{
/// <summary>
/// 字典值服务
/// </summary>
[ApiDescriptionSettings(Name = "DictData", Order = 100)]
public class SysDictDataService : ISysDictDataService, IDynamicApiController, ITransient
{
private readonly IRepository<SysDictData> _sysDictDataRep; // 字典类型表仓储
private readonly IRepository<SysDictType> _sysDictTypeRep;
public SysDictDataService(IRepository<SysDictData> sysDictDataRep, IRepository<SysDictType> sysDictTypeRep)
{
_sysDictTypeRep = sysDictTypeRep;
_sysDictDataRep = sysDictDataRep;
}
/// <summary>
/// 分页查询字典值
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysDictData/page")]
public async Task<dynamic> QueryDictDataPageList([FromBody] DictDataInput input)
{
var code = !string.IsNullOrEmpty(input.Code?.Trim());
var value = !string.IsNullOrEmpty(input.Value?.Trim());
var dictDatas = await _sysDictDataRep.DetachedEntities
.Where(u => u.TypeId == input.TypeId)
.Where((code, u => EF.Functions.Like(u.Code, $"%{input.Code.Trim()}%")),
(value, u => EF.Functions.Like(u.Value, $"%{input.Value.Trim()}%")))
.Where(u => u.Status != CommonStatus.DELETED).OrderBy(u => u.Sort)
//.Select(u => u.Adapt<DictDataOutput>())
// .ToPagedListAsync(input.PageNo, input.PageSize)
.ToPageData<SysDictData, DictDataOutput>(input);
return PageDataResult<DictDataOutput>.PageResult(dictDatas);
}
/// <summary>
/// 获取某个字典类型下字典值列表
/// </summary>
/// <returns></returns>
[HttpGet("/sysDictData/list")]
public async Task<dynamic> GetDictDataList([FromQuery] QueryDictDataListInput input)
{
return await _sysDictDataRep.DetachedEntities.Where(u => u.TypeId == input.TypeId).Where(u => u.Status != CommonStatus.DELETED).OrderBy(u => u.Sort).ToListAsync();
}
/// <summary>
/// 增加字典值
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysDictData/add")]
public async Task AddDictData(AddDictDataInput input)
{
var isExist = await _sysDictDataRep.AnyAsync(u => (u.Code == input.Code || u.Value == input.Value) && u.TypeId == input.TypeId, false);
if (isExist) throw Oops.Oh(ErrorCode.D3003);
//datatype 的code 为null 则不能添加
var dataType = _sysDictTypeRep.Where(s => s.Id == input.TypeId).FirstOrDefault();
if (string.IsNullOrEmpty(dataType.Code)) throw Oops.Oh("此处类型不能添加数据");
input.ExtCode = CheckExtCode(input.ExtCode);
var dictData = input.Adapt<SysDictData>();
await _sysDictDataRep.InsertAsync(dictData);
}
/// <summary>
/// 删除字典值
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysDictData/delete")]
public async Task DeleteDictData(DeleteDictDataInput input)
{
var dictData = await _sysDictDataRep.FirstOrDefaultAsync(u => u.Id == input.Id);
if (dictData == null) throw Oops.Oh(ErrorCode.D3004);
await dictData.DeleteAsync();
}
/// <summary>
/// 删除字典值 id数组传入
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
[HttpPost("/sysDictData/deleteBatch")]
public async Task DeleteDictDataBatch([FromBody] string[] ids)
{
var dictDataList = await _sysDictDataRep.Where(s => ids.Contains(s.Id)).ToListAsync();
if (dictDataList.Count == 0) throw Oops.Oh(ErrorCode.D3004);
dictDataList.ForEach(s =>
{
s.DeleteAsync();
});
}
/// <summary>
/// 更新字典值
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysDictData/edit")]
public async Task UpdateDictData(UpdateDictDataInput input)
{
var isExist = await _sysDictDataRep.AnyAsync(u => u.Id == input.Id, false);
if (!isExist) throw Oops.Oh(ErrorCode.D3004);
// 排除自己并且判断与其他是否相同
isExist = await _sysDictDataRep.AnyAsync(u => (u.Value == input.Value || u.Code == input.Code) && u.TypeId == input.TypeId && u.Id != input.Id, false);
if (isExist) throw Oops.Oh(ErrorCode.D3003);
input.ExtCode = CheckExtCode(input.ExtCode);
var dictData = input.Adapt<SysDictData>();
await _sysDictDataRep.UpdateAsync(dictData, ignoreNullValues: true);
}
/// <summary>
/// 字典值详情
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("/sysDictData/detail")]
public async Task<dynamic> GetDictData([FromQuery] QueryDictDataInput input)
{
return await _sysDictDataRep.FirstOrDefaultAsync(u => u.Id == input.Id, false);
}
/// <summary>
/// 修改字典值状态
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysDictData/changeStatus")]
public async Task ChangeDictDataStatus(UpdateDictDataInput input)
{
var dictData = await _sysDictDataRep.FirstOrDefaultAsync(u => u.Id == input.Id);
if (dictData == null) throw Oops.Oh(ErrorCode.D3004);
if (!Enum.IsDefined(typeof(CommonStatus), input.Status))
throw Oops.Oh(ErrorCode.D3005);
dictData.Status = input.Status;
}
/// <summary>
/// 根据字典类型Id获取字典值集合
/// </summary>
/// <param name="dictTypeId"></param>
/// <returns></returns>
[NonAction]
public async Task<dynamic> GetDictDataListByDictTypeId(string dictTypeId)
{
return await _sysDictDataRep.DetachedEntities.Where(u => u.SysDictType.Id == dictTypeId)
.Where(u => u.Status != CommonStatus.DELETED).OrderBy(u => u.Sort)
.Select(u => new
{
u.Code,
u.Value,
ExtCode = String.IsNullOrEmpty(u.ExtCode) ? null : Newtonsoft.Json.JsonConvert.DeserializeObject<object>(u.ExtCode),
u.Remark
}).ToListAsync();
}
[NonAction]
public async Task<dynamic> GetDictDataListByDictTypeIds(SysDictType[] dictTypes)
{
var dictTypeIds = dictTypes.Select(u => u.Id);
var dictData = await _sysDictDataRep.DetachedEntities.Where(u => dictTypeIds.Contains(u.SysDictType.Id))
.Where(u => u.Status != CommonStatus.DELETED).OrderBy(u => u.Sort)
.ToListAsync();
var result = new Dictionary<string, dynamic>();
foreach (var dictType in dictTypes)
{
result.Add(dictType.Code, dictData.Where(u => u.TypeId == dictType.Id)
.Select(u => new
{
u.Code,
u.Value,
ExtCode = String.IsNullOrEmpty(u.ExtCode) ? null : Newtonsoft.Json.JsonConvert.DeserializeObject<object>(u.ExtCode),
u.Remark
}));
}
return result;
}
/// <summary>
/// 删除字典下所有值
/// </summary>
/// <param name="dictTypeId"></param>
[NonAction]
public async Task DeleteByTypeId(string dictTypeId)
{
var dictDatas = await _sysDictDataRep.Where(u => u.TypeId == dictTypeId).ToListAsync();
dictDatas.ForEach(u =>
{
u.Delete();
});
}
[NonAction]
private string CheckExtCode(string extCode)
{
if (!string.IsNullOrEmpty(extCode))
{
try
{
if (extCode.StartsWith('{') && extCode.EndsWith('}'))
{
return Newtonsoft.Json.JsonConvert.SerializeObject(Newtonsoft.Json.JsonConvert.DeserializeObject(extCode));
}
}
catch { }
}
return null;
}
}
}

View File

@@ -0,0 +1,250 @@
using Ewide.Core.Extension;
using Ewide.Core.Service.Dict.Dto;
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
/// <summary>
/// 字典类型服务
/// </summary>
[ApiDescriptionSettings(Name = "DictType", Order = 100)]
public class SysDictTypeService : ISysDictTypeService, IDynamicApiController, ITransient
{
private readonly IRepository<SysDictType> _sysDictTypeRep; // 字典类型表仓储
private readonly ISysDictDataService _sysDictDataService;
public SysDictTypeService(ISysDictDataService sysDictDataService,
IRepository<SysDictType> sysDictTypeRep)
{
_sysDictDataService = sysDictDataService;
_sysDictTypeRep = sysDictTypeRep;
}
/// <summary>
/// 分页查询字典类型
/// </summary>
/// <returns></returns>
[HttpPost("/sysDictType/page")]
public async Task<dynamic> QueryDictTypePageList([FromBody] DictTypeInput input)
{
var code = !string.IsNullOrEmpty(input.Code?.Trim());
var name = !string.IsNullOrEmpty(input.Name?.Trim());
var pId = !string.IsNullOrEmpty(input.Pid?.Trim());
var type = input.Type > 0;
var dictTypes = await _sysDictTypeRep.DetachedEntities
.Where(pId, u => EF.Functions.Like(u.Pids, $"%[{input.Pid.Trim()}]%") || u.Id == input.Pid.Trim())
.Where((code, u => EF.Functions.Like(u.Code, $"%{input.Code.Trim()}%")),
(name, u => EF.Functions.Like(u.Name, $"%{input.Name.Trim()}%")))
.Where(type, u => input.Type == 1 ? string.IsNullOrEmpty(u.Code) : !string.IsNullOrEmpty(u.Code))
.Where(u => u.Status != CommonStatus.DELETED).OrderBy(u => u.Sort)
//.ToPagedListAsync(input.PageNo, input.PageSize);
.ToPageData(input);
return PageDataResult<SysDictType>.PageResult(dictTypes);
}
/// <summary>
/// 获取字典类型列表
/// </summary>
/// <returns></returns>
[HttpGet("/sysDictType/list")]
public async Task<dynamic> GetDictTypeList()
{
return await _sysDictTypeRep.DetachedEntities.Where(u => u.Status != CommonStatus.DELETED).ToListAsync();
}
/// <summary>
/// 获取字典类型下所有字典值
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("/sysDictType/dropDown")]
public async Task<dynamic> GetDictTypeDropDown([FromQuery] DropDownDictTypeInput input)
{
var dictType = await _sysDictTypeRep.FirstOrDefaultAsync(u => u.Code == input.Code, false);
if (dictType == null) throw Oops.Oh(ErrorCode.D3000);
return await _sysDictDataService.GetDictDataListByDictTypeId(dictType.Id);
}
/// <summary>
///
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("/sysDictType/dropDowns")]
public async Task<dynamic> GetDictTypeDropDowns([FromQuery] DropDownDictTypesInput input)
{
var dictTypes = await _sysDictTypeRep.Where(u => input.Code.Contains(u.Code), false).ToArrayAsync();
if (dictTypes.Length == 0) throw Oops.Oh(ErrorCode.D3000);
return await _sysDictDataService.GetDictDataListByDictTypeIds(dictTypes);
}
/// <summary>
/// 添加字典类型
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysDictType/add")]
public async Task AddDictType(AddDictTypeInput input)
{
var isExist = await _sysDictTypeRep.AnyAsync(u => u.Name == input.Name, false);
if (isExist) throw Oops.Oh(ErrorCode.D3001);
var dictTypeEntity = _sysDictTypeRep.Where(s => s.Id == input.Pid).FirstOrDefault();
if (dictTypeEntity != null && dictTypeEntity.Code != null) throw new Exception("此类型下不能添加子类型");
var dictType = input.Adapt<SysDictType>();
dictType.Pids = await CreateNewPids(input.Pid);
if (input.Code == string.Empty) dictType.Code = null;
await _sysDictTypeRep.InsertAsync(dictType);
}
/// <summary>
/// 删除字典类型
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysDictType/delete")]
public async Task DeleteDictType(DeleteDictTypeInput input)
{
var dictType = await _sysDictTypeRep.FirstOrDefaultAsync(u => u.Id == input.Id);
if (dictType == null) throw Oops.Oh(ErrorCode.D3000);
var dictDatas = await _sysDictDataService.GetDictDataListByDictTypeId(input.Id); //_sysDictDataService.DeleteByTypeId(input.Id);
if (dictDatas != null && dictDatas.Count > 0) throw Oops.Oh(ErrorCode.D3002);
await dictType.DeleteAsync();
}
/// <summary>
/// 更新字典类型
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysDictType/edit"),]
public async Task UpdateDictType(UpdateDictTypeInput input)
{
var isExist = await _sysDictTypeRep.AnyAsync(u => u.Id == input.Id, false);
if (!isExist) throw Oops.Oh(ErrorCode.D3000);
if (input.Id == input.Pid) throw Oops.Oh(ErrorCode.D4006);
// 排除自己并且判断与其他是否相同
isExist = await _sysDictTypeRep.AnyAsync(u => (u.Name == input.Name || u.Code == input.Code) && u.Id != input.Id, false);
if (isExist) throw Oops.Oh(ErrorCode.D3001);
var dictType = input.Adapt<SysDictType>();
dictType.Pids = await CreateNewPids(input.Pid);
dictType.Code = input.Code == string.Empty ? null : input.Code;
await dictType.UpdateIncludeAsync(new string[] { nameof(SysDictType.Pid), nameof(SysDictType.Pids), nameof(SysDictType.Name), nameof(SysDictType.Code), nameof(SysDictType.Sort), nameof(SysDictType.Remark) }, false);
}
/// <summary>
/// 字典类型详情
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("/sysDictType/detail")]
public async Task<dynamic> GetDictType([FromQuery] QueryDictTypeInfoInput input)
{
return await _sysDictTypeRep.FirstOrDefaultAsync(u => u.Id == input.Id, false);
}
/// <summary>
/// 更新字典类型状态
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysDictType/changeStatus")]
public async Task ChangeDictTypeStatus(UpdateDictTypeInput input)
{
var dictType = await _sysDictTypeRep.FirstOrDefaultAsync(u => u.Id == input.Id);
if (dictType == null) throw Oops.Oh(ErrorCode.D3000);
if (!Enum.IsDefined(typeof(CommonStatus), input.Status))
throw Oops.Oh(ErrorCode.D3005);
dictType.Status = input.Status;
}
/// <summary>
/// 字典类型与字典值构造的字典树
/// </summary>
/// <returns></returns>
[AllowAnonymous]
[HttpGet("/sysDictType/tree")]
public async Task<List<DictTreeNode>> GetDictTree()
{
var DictTypeList = await _sysDictTypeRep.AsQueryable().Where(p => string.IsNullOrEmpty(p.Code)).ToListAsync();
return new TreeBuildUtil<DictTreeNode>().DoTreeBuild(DictTypeList
.OrderBy(s => s.Sort)
.Select(u => new DictTreeNode
{
Title = u.Name,
ParentId = u.Pid,
Id = u.Id,
Value = u.Id
}).ToList());
}
/// <summary>
/// 创建Pids格式
/// 如果pid是0顶级节点pids就是 [0];
/// 如果pid不是顶级节点pids就是 pid菜单的 pids + [pid] + ,
/// </summary>
/// <param name="pid"></param>
/// <returns></returns>
private async Task<string> CreateNewPids(string pid)
{
if (pid.Equals(System.Guid.Empty.ToString()))
{
return "[" + System.Guid.Empty + "],";
}
else
{
var dtype = await _sysDictTypeRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == pid);
return dtype.Pids + "[" + pid + "],";
}
}
[HttpGet("/sysDictType/enumDictList")]
public Task<List<EnumDictOutput>> GetEnumDictDataList([FromQuery] DictTypeInput input)
{
var typeList = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.IsEnum);
typeList = typeList.Concat(Assembly.Load("Ewide.Application").GetTypes().Where(t => t.IsEnum));
var list = new List<EnumDictOutput>();
foreach (var type in typeList)
{
var dictType = new EnumDictOutput
{
Desc = type.GetCustomAttribute<DescriptionAttribute>()?.Description,
FullName = type.FullName,
Code = type.Name,
Datas = new List<EnumDictData>(),
};
var fields = type.GetFields(BindingFlags.Static | BindingFlags.Public);
foreach (var field in fields)
{
var value = field.GetValue(null);
var dictData = new EnumDictData
{
Desc = field.GetCustomAttribute<DescriptionAttribute>()?.Description,
Code = field.Name,
Value = Convert.ChangeType(value, Enum.GetUnderlyingType(value.GetType())).ToString(),
};
dictType.Datas.Add(dictData);
}
list.Add(dictType);
}
return Task.FromResult(list);
}
}
}

View File

@@ -0,0 +1,38 @@
namespace Ewide.Core.Service
{
/// <summary>
/// 附属机构和职位参数
/// </summary>
public class EmpExtOrgPosOutput
{
/// <summary>
/// 附属机构id
/// </summary>
public string OrgId { get; set; }
/// <summary>
/// 附属机构编码
/// </summary>
public string OrgCode { get; set; }
/// <summary>
/// 附属机构名称
/// </summary>
public string OrgName { get; set; }
/// <summary>
/// 附属职位id
/// </summary>
public string PosId { get; set; }
/// <summary>
/// 附属职位编码
/// </summary>
public string PosCode { get; set; }
/// <summary>
/// 附属职位名称
/// </summary>
public string PosName { get; set; }
}
}

View File

@@ -0,0 +1,35 @@
using System.Collections.Generic;
namespace Ewide.Core.Service
{
/// <summary>
/// 员工信息参数
/// </summary>
public class EmpOutput
{
/// <summary>
/// 工号
/// </summary>
public string JobNum { get; set; }
/// <summary>
/// 机构id
/// </summary>
public string OrgId { get; set; }
/// <summary>
/// 机构名称
/// </summary>
public string OrgName { get; set; }
/// <summary>
/// 机构与职位信息
/// </summary>
public List<EmpExtOrgPosOutput> ExtOrgPos { get; set; } = new List<EmpExtOrgPosOutput>();
/// <summary>
/// 职位信息
/// </summary>
public List<EmpPosOutput> Positions { get; set; } = new List<EmpPosOutput>();
}
}

View File

@@ -0,0 +1,40 @@
using System.Collections.Generic;
namespace Ewide.Core.Service
{
/// <summary>
/// 员工信息参数2
/// </summary>
public class EmpOutput2
{
/// <summary>
/// 员工Id
/// </summary>
public string Id { get; set; }
/// <summary>
/// 工号
/// </summary>
public string JobNum { get; set; }
/// <summary>
/// 机构Id
/// </summary>
public string OrgId { get; set; }
/// <summary>
/// 机构名称
/// </summary>
public string OrgName { get; set; }
/// <summary>
/// 附属机构
/// </summary>
public List<EmpExtOrgPosOutput> ExtIds { get; set; } = new List<EmpExtOrgPosOutput>();
/// <summary>
/// 职位集合
/// </summary>
public List<string> PosIdList { get; set; } = new List<string>();
}
}

View File

@@ -0,0 +1,23 @@
namespace Ewide.Core.Service
{
/// <summary>
/// 员工职位参数
/// </summary>
public class EmpPosOutput
{
/// <summary>
/// 职位Id
/// </summary>
public string PosId { get; set; }
/// <summary>
/// 职位编码
/// </summary>
public string PosCode { get; set; }
/// <summary>
/// 职位名称
/// </summary>
public string PosName { get; set; }
}
}

View File

@@ -0,0 +1,14 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
public interface ISysEmpExtOrgPosService
{
Task AddOrUpdate(string empId, List<EmpExtOrgPosOutput> extIdList);
Task DeleteEmpExtInfoByUserId(string empId);
Task<List<EmpExtOrgPosOutput>> GetEmpExtOrgPosList(string empId);
Task<bool> HasExtOrgEmp(string orgId);
Task<bool> HasExtPosEmp(string posId);
}
}

View File

@@ -0,0 +1,13 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
public interface ISysEmpPosService
{
Task AddOrUpdate(string empId, List<string> posIdList);
Task DeleteEmpPosInfoByUserId(string empId);
Task<List<EmpPosOutput>> GetEmpPosList(string empId);
Task<bool> HasPosEmp(string posId);
}
}

View File

@@ -0,0 +1,14 @@
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
public interface ISysEmpService
{
Task AddOrUpdate(EmpOutput2 sysEmpParam);
Task DeleteEmpInfoByUserId(string empId);
Task<EmpOutput> GetEmpInfo(string empId);
Task<string> GetEmpOrgId(string empId);
Task<bool> HasOrgEmp(string orgId);
Task UpdateEmpOrgInfo(string orgId, string orgName);
}
}

View File

@@ -0,0 +1,100 @@
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
/// <summary>
/// 员工附属机构和职位服务
/// </summary>
public class SysEmpExtOrgPosService : ISysEmpExtOrgPosService, ITransient
{
private readonly IRepository<SysEmpExtOrgPos> _sysEmpExtOrgPosRep; // 附属机构表仓储
public SysEmpExtOrgPosService(IRepository<SysEmpExtOrgPos> sysEmpExtOrgPosRep)
{
_sysEmpExtOrgPosRep = sysEmpExtOrgPosRep;
}
/// <summary>
/// 保存或编辑附属机构相关信息
/// </summary>
/// <returns></returns>
[UnitOfWork]
public async Task AddOrUpdate(string empId, List<EmpExtOrgPosOutput> extIdList)
{
// 先删除
await DeleteEmpExtInfoByUserId(empId);
var tasks = new List<Task>();
extIdList.ForEach(u =>
{
tasks.Add(new SysEmpExtOrgPos
{
SysEmpId = empId,
SysOrgId = u.OrgId,
SysPosId = u.PosId
}.InsertAsync());
});
await Task.WhenAll(tasks);
}
/// <summary>
/// 获取附属机构和职位信息
/// </summary>
/// <param name="empId"></param>
/// <returns></returns>
public async Task<List<EmpExtOrgPosOutput>> GetEmpExtOrgPosList(string empId)
{
return await _sysEmpExtOrgPosRep.DetachedEntities
.Where(u => u.SysEmpId == empId)
.Select(u => new EmpExtOrgPosOutput
{
OrgId = u.SysOrg.Id,
OrgCode = u.SysOrg.Code,
OrgName = u.SysOrg.Name,
PosId = u.SysPos.Id,
PosCode = u.SysPos.Code,
PosName = u.SysPos.Name
}).ToListAsync();
}
/// <summary>
/// 根据机构Id判断该附属机构下是否有员工
/// </summary>
/// <param name="orgId"></param>
/// <returns></returns>
public async Task<bool> HasExtOrgEmp(string orgId)
{
return await _sysEmpExtOrgPosRep.DetachedEntities.AnyAsync(u => u.SysOrgId == orgId);
}
/// <summary>
/// 根据职位Id判断该附属职位下是否有员工
/// </summary>
/// <param name="posId"></param>
/// <returns></returns>
public async Task<bool> HasExtPosEmp(string posId)
{
return await _sysEmpExtOrgPosRep.DetachedEntities.AnyAsync(u => u.SysPosId == posId);
}
/// <summary>
/// 根据员工Id删除对应的员工-附属信息
/// </summary>
/// <param name="empId"></param>
/// <returns></returns>
public async Task DeleteEmpExtInfoByUserId(string empId)
{
var empExtOrgPos = await _sysEmpExtOrgPosRep.Where(u => u.SysEmpId == empId).ToListAsync();
empExtOrgPos.ForEach(u =>
{
u.Delete();
});
}
}
}

View File

@@ -0,0 +1,85 @@
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
/// <summary>
/// 员工职位服务
/// </summary>
public class SysEmpPosService : ISysEmpPosService, ITransient
{
private readonly IRepository<SysEmpPos> _sysEmpPosRep; // 员工职位表仓储
public SysEmpPosService(IRepository<SysEmpPos> sysEmpPosRep)
{
_sysEmpPosRep = sysEmpPosRep;
}
/// <summary>
/// 增加或编辑员工职位相关信息
/// </summary>
/// <param name="empId">员工Id用户Id</param>
/// <param name="posIdList">职位id集合</param>
/// <returns></returns>
[UnitOfWork]
public async Task AddOrUpdate(string empId, List<string> posIdList)
{
// 先删除
await DeleteEmpPosInfoByUserId(empId);
posIdList.ForEach(u =>
{
new SysEmpPos
{
SysEmpId = empId,
SysPosId = u
}.Insert();
});
}
/// <summary>
/// 获取所属职位信息
/// </summary>
/// <param name="empId">员工Id用户Id</param>
public async Task<List<EmpPosOutput>> GetEmpPosList(string empId)
{
return await _sysEmpPosRep.DetachedEntities
.Where(u => u.SysEmpId == empId)
.Select(u => new EmpPosOutput
{
PosId = u.SysPos.Id,
PosCode = u.SysPos.Code,
PosName = u.SysPos.Name
}).ToListAsync();
}
/// <summary>
/// 根据职位Id判断该职位下是否有员工
/// </summary>
/// <param name="posId"></param>
/// <returns></returns>
public async Task<bool> HasPosEmp(string posId)
{
return await _sysEmpPosRep.DetachedEntities.AnyAsync(u => u.SysPosId == posId);
}
/// <summary>
/// 根据员工Id删除对用的员工-职位信息
/// </summary>
/// <param name="empId"></param>
/// <returns></returns>
public async Task DeleteEmpPosInfoByUserId(string empId)
{
var empPos = await _sysEmpPosRep.Where(u => u.SysEmpId == empId).ToListAsync();
empPos.ForEach(u =>
{
u.Delete();
});
}
}
}

View File

@@ -0,0 +1,126 @@
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Mapster;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
/// <summary>
/// 员工服务
/// </summary>
public class SysEmpService : ISysEmpService, ITransient
{
private readonly IRepository<SysEmp> _sysEmpRep; // 员工表仓储
private readonly ISysEmpExtOrgPosService _sysEmpExtOrgPosService;
private readonly ISysEmpPosService _sysEmpPosService;
public SysEmpService(IRepository<SysEmp> sysEmpRep,
ISysEmpExtOrgPosService sysEmpExtOrgPosService,
ISysEmpPosService sysEmpPosService)
{
_sysEmpRep = sysEmpRep;
_sysEmpExtOrgPosService = sysEmpExtOrgPosService;
_sysEmpPosService = sysEmpPosService;
}
/// <summary>
/// 获取用户员工相关信息(包括登录)
/// </summary>
/// <param name="empId"></param>
/// <returns></returns>
public async Task<EmpOutput> GetEmpInfo(string empId)
{
var empInfoOutput = new EmpOutput();
var sysEmp = await _sysEmpRep.FirstOrDefaultAsync(u => u.Id == empId, false);
if (sysEmp == null) return empInfoOutput;
empInfoOutput = sysEmp.Adapt<EmpOutput>();
empInfoOutput.ExtOrgPos = await _sysEmpExtOrgPosService.GetEmpExtOrgPosList(empId);
empInfoOutput.Positions = await _sysEmpPosService.GetEmpPosList(empId);
return empInfoOutput;
}
/// <summary>
/// 增加或编辑员工相关信息
/// </summary>
/// <returns></returns>
[UnitOfWork]
public async Task AddOrUpdate(EmpOutput2 sysEmpParam)
{
// 先删除员工信息
var emps = await _sysEmpRep.Where(u => u.Id == sysEmpParam.Id).ToListAsync();
emps.ForEach(u =>
{
u.Delete();
});
// 再新增新员工信息
var emp = sysEmpParam.Adapt<SysEmp>();
emp.OrgName = (await Db.GetRepository<SysOrg>().DetachedEntities.FirstOrDefaultAsync(p => p.Id.Equals(emp.OrgId))).Name;
await _sysEmpRep.InsertAsync(emp);
// 更新附属机构职位信息
await _sysEmpExtOrgPosService.AddOrUpdate(emp.Id, sysEmpParam.ExtIds);
// 更新职位信息
await _sysEmpPosService.AddOrUpdate(emp.Id, sysEmpParam.PosIdList);
}
/// <summary>
/// 修改员工相关机构信息
/// </summary>
/// <param name="orgId"></param>
/// <param name="orgName"></param>
/// <returns></returns>
public async Task UpdateEmpOrgInfo(string orgId, string orgName)
{
var emps = await _sysEmpRep.Where(u => u.OrgId == orgId).ToListAsync();
emps.ForEach(u =>
{
u.OrgName = orgName;
});
}
/// <summary>
/// 根据机构Id判断该机构下是否有员工
/// </summary>
/// <param name="orgId"></param>
/// <returns></returns>
public async Task<bool> HasOrgEmp(string orgId)
{
return await _sysEmpRep.DetachedEntities.AnyAsync(u => u.OrgId == orgId);
}
/// <summary>
/// 根据员工Id删除对应的员工表信息
/// </summary>
/// <param name="empId"></param>
/// <returns></returns>
[UnitOfWork]
public async Task DeleteEmpInfoByUserId(string empId)
{
// 删除员工信息
var emp = await _sysEmpRep.FirstOrDefaultAsync(u => u.Id == empId);
await emp.DeleteAsync();
// 级联删除对应的员工-附属信息
await _sysEmpExtOrgPosService.DeleteEmpExtInfoByUserId(empId);
// 级联删除对用的员工-职位信息
await _sysEmpPosService.DeleteEmpPosInfoByUserId(empId);
}
/// <summary>
/// 获取员工机构Id
/// </summary>
/// <param name="empId"></param>
/// <returns></returns>
public async Task<string> GetEmpOrgId(string empId)
{
return (await _sysEmpRep.FirstOrDefaultAsync(u => u.Id == empId, false)).OrgId;
}
}
}

View File

@@ -0,0 +1,64 @@
using System.ComponentModel.DataAnnotations;
namespace Ewide.Core.Service
{
/// <summary>
/// 上传文件参数
/// </summary>
public class FileInput : PageInputBase
{
/// <summary>
/// 文件存储位置1:阿里云2:腾讯云3:minio4:本地)
/// </summary>
public int FileLocation { get; set; }
/// <summary>
/// 文件仓库
/// </summary>
public string FileBucket { get; set; }
/// <summary>
/// 文件名称(上传时候的文件名)
/// </summary>
public string FileOriginName { get; set; }
/// <summary>
/// 文件后缀
/// </summary>
public string FileSuffix { get; set; }
/// <summary>
/// 文件大小kb
/// </summary>
public long FileSizeKb { get; set; }
/// <summary>
/// 文件大小信息,计算后的
/// </summary>
public string FileSizeInfo { get; set; }
/// <summary>
/// 存储到bucket的名称文件唯一标识id
/// </summary>
public string FileObjectName { get; set; }
/// <summary>
/// 存储路径
/// </summary>
public string FilePath { get; set; }
}
public class DeleteFileInfoInput
{
/// <summary>
/// 文件Id
/// </summary>
[Required(ErrorMessage = "文件Id不能为空")]
public string Id { get; set; }
}
public class QueryFileInoInput : DeleteFileInfoInput
{
}
}

View File

@@ -0,0 +1,14 @@
namespace Ewide.Core.Service
{
/// <summary>
/// 上传文件参数
/// </summary>
public class FileOutput : FileInput
{
/// <summary>
/// 文件Id
/// </summary>
public string Id { get; set; }
public System.DateTime CreatedTime { get; set; }
}
}

View File

@@ -0,0 +1,21 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
public interface ISysFileService
{
Task DeleteFileInfo(DeleteFileInfoInput input);
Task<IActionResult> DownloadFileInfo([FromQuery] QueryFileInoInput input);
Task<SysFile> GetFileInfo([FromQuery] QueryFileInoInput input);
Task<List<SysFile>> GetFileInfoList([FromQuery] FileOutput input);
Task<IActionResult> PreviewFileInfo([FromQuery] QueryFileInoInput input);
Task<dynamic> QueryFileInfoPageList([FromQuery] FileInput input);
Task<string> UploadFileAvatar(IFormFile file);
Task<string> UploadFileDefault(IFormFile file);
Task<string> UploadFileDocument(IFormFile file);
Task<string> UploadFileShop(IFormFile file);
}
}

View File

@@ -0,0 +1,207 @@
using Ewide.Core.Extension;
using Furion;
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
namespace Ewide.Core.Service
{
/// <summary>
/// 文件服务
/// </summary>
[ApiDescriptionSettings(Name = "File", Order = 100)]
public class SysFileService : ISysFileService, IDynamicApiController, ITransient
{
private readonly IRepository<SysFile> _sysFileInfoRep; // 文件信息表仓储
private readonly IConfiguration _configuration;
public SysFileService(IRepository<SysFile> sysFileInfoRep, IConfiguration configuration)
{
_sysFileInfoRep = sysFileInfoRep;
_configuration = configuration;
}
/// <summary>
/// 分页获取文件列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysFileInfo/page")]
public async Task<dynamic> QueryFileInfoPageList([FromBody] FileInput input)
{
var fileBucket = !string.IsNullOrEmpty(input.FileBucket?.Trim());
var fileOriginName = !string.IsNullOrEmpty(input.FileOriginName?.Trim());
var files = await _sysFileInfoRep.DetachedEntities
.Where(input.FileLocation > 0, u => u.FileLocation == input.FileLocation)
.Where(fileBucket, u => EF.Functions.Like(u.FileBucket, $"%{input.FileBucket.Trim()}%"))
.Where(fileOriginName, u => EF.Functions.Like(u.FileOriginName, $"%{input.FileOriginName.Trim()}%"))
.ToPageData<SysFile, FileOutput>(input);
return PageDataResult<FileOutput>.PageResult(files);
}
/// <summary>
/// 获取文件列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("/sysFileInfo/list")]
public async Task<List<SysFile>> GetFileInfoList([FromQuery] FileOutput input)
{
return await _sysFileInfoRep.DetachedEntities.ToListAsync();
}
/// <summary>
/// 删除文件
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysFileInfo/delete")]
public async Task DeleteFileInfo(DeleteFileInfoInput input)
{
var file = await _sysFileInfoRep.FirstOrDefaultAsync(u => u.Id == input.Id);
if (file != null)
{
await file.DeleteAsync();
var filePath = Path.Combine(App.WebHostEnvironment.WebRootPath, file.FileBucket, file.FileObjectName);
if (File.Exists(filePath))
File.Delete(filePath);
}
}
/// <summary>
/// 获取文件详情
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("/sysFileInfo/detail")]
public async Task<SysFile> GetFileInfo([FromQuery] QueryFileInoInput input)
{
var file = await _sysFileInfoRep.FirstOrDefaultAsync(u => u.Id == input.Id);
if (file == null)
throw Oops.Oh(ErrorCode.D8000);
return file;
}
/// <summary>
/// 预览文件
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("/sysFileInfo/preview")]
public async Task<IActionResult> PreviewFileInfo([FromQuery] QueryFileInoInput input)
{
return await DownloadFileInfo(input);
}
/// <summary>
/// 上传文件
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
[HttpPost("/sysFileInfo/upload")]
public async Task<string> UploadFileDefault(IFormFile file)
{
return await UploadFile(file, _configuration["UploadFile:Default:path"]);
}
/// <summary>
/// 下载文件
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("/sysFileInfo/download")]
public async Task<IActionResult> DownloadFileInfo([FromQuery] QueryFileInoInput input)
{
var file = await GetFileInfo(input);
var filePath = Path.Combine(App.WebHostEnvironment.WebRootPath, file.FileBucket, file.FileObjectName);
var fileName = HttpUtility.UrlEncode(file.FileOriginName, Encoding.GetEncoding("UTF-8"));
return new FileStreamResult(new FileStream(filePath, FileMode.Open), Util.MimeMapping.GetMimeMapping(filePath)) { FileDownloadName = fileName };
}
/// <summary>
/// 上传头像
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
public async Task<string> UploadFileAvatar(IFormFile file)
{
return await UploadFile(file, _configuration["UploadFile:Avatar:path"]);
}
/// <summary>
/// 上传文档
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
public async Task<string> UploadFileDocument(IFormFile file)
{
return await UploadFile(file, _configuration["UploadFile:Document:path"]);
}
/// <summary>
/// 上传商店图片
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
public async Task<string> UploadFileShop(IFormFile file)
{
return await UploadFile(file, _configuration["UploadFile:Shop:path"]);
}
/// <summary>
/// 上传文件
/// </summary>
/// <param name="file"></param>
/// <param name="pathType"></param>
/// <returns></returns>
private static async Task<string> UploadFile(IFormFile file, string pathType)
{
var fileId = Guid.NewGuid().ToString();
var fileSizeKb = (long)(file.Length / 1024.0); // 文件大小KB
var originalFilename = file.FileName; // 文件原始名称
var fileSuffix = Path.GetExtension(file.FileName).ToLower(); // 文件后缀
var finalName = fileId + fileSuffix; // 生成文件的最终名称
var filePath = Path.Combine(App.WebHostEnvironment.WebRootPath, pathType);
if (!Directory.Exists(filePath))
Directory.CreateDirectory(filePath);
using (var stream = File.Create(Path.Combine(filePath, finalName)))
{
await file.CopyToAsync(stream);
}
var sysFileInfo = new SysFile
{
Id = fileId,
FileLocation = (int)FileLocation.LOCAL,
FileBucket = pathType,
FileObjectName = finalName,
FileOriginName = originalFilename,
FileSuffix = fileSuffix.TrimStart('.'),
FileSizeKb = fileSizeKb
};
await sysFileInfo.InsertAsync();
return fileId;
}
}
}

View File

@@ -0,0 +1,95 @@
using System;
namespace Ewide.Core.Service
{
/// <summary>
/// 请求日志参数
/// </summary>
public class OpLogInput : PageInputBase
{
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 操作类型0其他 1增加 2删除 3编辑见LogAnnotionOpTypeEnum
/// </summary>
public int? OpType { get; set; }
/// <summary>
/// 是否执行成功Y-是N-否)
/// </summary>
public bool? Success { get; set; }
/// <summary>
/// 具体消息
/// </summary>
public string Message { get; set; }
/// <summary>
/// ip
/// </summary>
public string Ip { get; set; }
/// <summary>
/// 地址
/// </summary>
public string Location { get; set; }
/// <summary>
/// 浏览器
/// </summary>
public string Browser { get; set; }
/// <summary>
/// 操作系统
/// </summary>
public string Os { get; set; }
/// <summary>
/// 请求地址
/// </summary>
public string Url { get; set; }
/// <summary>
/// 类名称
/// </summary>
public string ClassName { get; set; }
/// <summary>
/// 方法名称
/// </summary>
public string MethodName { get; set; }
/// <summary>
/// 请求方式GET POST PUT DELETE)
/// </summary>
public string ReqMethod { get; set; }
/// <summary>
/// 请求参数
/// </summary>
public string Param { get; set; }
/// <summary>
/// 返回结果
/// </summary>
public string Result { get; set; }
/// <summary>
/// 耗时(毫秒)
/// </summary>
public long ElapsedTime { get; set; }
/// <summary>
/// 操作时间
/// </summary>
public DateTime OpTime { get; set; }
/// <summary>
/// 操作人
/// </summary>
public string Account { get; set; }
}
}

View File

@@ -0,0 +1,10 @@
namespace Ewide.Core.Service
{
/// <summary>
/// 请求日志参数
/// </summary>
public class OpLogOutput : OpLogInput
{
public int Id { get; set; }
}
}

View File

@@ -0,0 +1,60 @@
using System;
namespace Ewide.Core.Service
{
/// <summary>
/// 访问日志参数
/// </summary>
public class VisLogInput : PageInputBase
{
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 是否执行成功Y-是N-否)
/// </summary>
public bool? Success { get; set; }
/// <summary>
/// 具体消息
/// </summary>
public string Message { get; set; }
/// <summary>
/// IP
/// </summary>
public string Ip { get; set; }
/// <summary>
/// 地址
/// </summary>
public string Location { get; set; }
/// <summary>
/// 浏览器
/// </summary>
public string Browser { get; set; }
/// <summary>
/// 操作系统
/// </summary>
public string Os { get; set; }
/// <summary>
/// 访问类型(字典 1登入 2登出
/// </summary>
public int? VisType { get; set; }
/// <summary>
/// 访问时间
/// </summary>
public DateTime VisTime { get; set; }
/// <summary>
/// 访问人
/// </summary>
public string Account { get; set; }
}
}

View File

@@ -0,0 +1,10 @@
namespace Ewide.Core.Service
{
/// <summary>
/// 访问日志参数
/// </summary>
public class VisLogOutput : VisLogInput
{
public int Id { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
public interface ISysOpLogService
{
Task ClearOpLog();
Task<dynamic> QueryOpLogPageList([FromQuery] OpLogInput input);
}
}

View File

@@ -0,0 +1,11 @@
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
public interface ISysVisLogService
{
Task ClearVisLog();
Task<dynamic> QueryVisLogPageList([FromQuery] VisLogInput input);
}
}

View File

@@ -0,0 +1,63 @@
using Dapper;
using Ewide.Core.Extension;
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
/// <summary>
/// 操作日志服务
/// </summary>
[ApiDescriptionSettings(Name = "OpLog", Order = 100)]
public class SysOpLogService : ISysOpLogService, IDynamicApiController, ITransient
{
private readonly IRepository<SysLogOp> _sysOpLogRep; // 操作日志表仓储
private readonly IDapperRepository<SysLogOp> _dapperRepository;
public SysOpLogService(IRepository<SysLogOp> sysOpLogRep, IDapperRepository<SysLogOp> dapperRepository)
{
_sysOpLogRep = sysOpLogRep;
_dapperRepository = dapperRepository;
}
/// <summary>
/// 分页查询操作日志
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysOpLog/page")]
public async Task<dynamic> QueryOpLogPageList([FromBody] OpLogInput input)
{
var name = !string.IsNullOrEmpty(input.Name?.Trim());
var success = input.Success.HasValue;
var searchBeginTime = !string.IsNullOrEmpty(input.SearchBeginTime?.Trim());
var opLogs = await _sysOpLogRep.DetachedEntities
.Where((name, u => EF.Functions.Like(u.Name, $"%{input.Name.Trim()}%")))
.Where(input.OpType > 0, u => u.OpType == input.OpType)
.Where(success, u => u.Success == input.Success.Value)
.Where(searchBeginTime, u => u.OpTime >= DateTime.Parse(input.SearchBeginTime.Trim()) &&
u.OpTime <= DateTime.Parse(input.SearchEndTime.Trim()))
.ToPageData<SysLogOp, OpLogOutput>(input);
return PageDataResult<OpLogOutput>.PageResult(opLogs);
}
/// <summary>
/// 清空操作日志
/// </summary>
/// <returns></returns>
[HttpPost("/sysOpLog/delete")]
public async Task ClearOpLog()
{
await _dapperRepository.ExecuteAsync("DELETE FROM sys_log_op");
}
}
}

View File

@@ -0,0 +1,63 @@
using Ewide.Core.Extension;
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
/// <summary>
/// 访问日志服务
/// </summary>
[ApiDescriptionSettings(Name = "VisLog", Order = 100)]
public class SysVisLogService : ISysVisLogService, IDynamicApiController, ITransient
{
private readonly IRepository<SysLogVis> _sysVisLogRep; // 访问日志表仓储
public SysVisLogService(IRepository<SysLogVis> sysVisLogRep)
{
_sysVisLogRep = sysVisLogRep;
}
/// <summary>
/// 分页查询访问日志
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysVisLog/page")]
public async Task<dynamic> QueryVisLogPageList([FromBody] VisLogInput input)
{
var name = !string.IsNullOrEmpty(input.Name?.Trim());
var success = input.Success.HasValue;
var searchBeginTime = !string.IsNullOrEmpty(input.SearchBeginTime?.Trim());
var visLogs = await _sysVisLogRep.DetachedEntities
.Where((name, u => EF.Functions.Like(u.Name, $"%{input.Name.Trim()}%")))
.Where(input.VisType > 0, u => u.VisType == input.VisType)
.Where(success, u => u.Success == input.Success.Value)
.Where(searchBeginTime, u => u.VisTime >= DateTime.Parse(input.SearchBeginTime.Trim()) &&
u.VisTime <= DateTime.Parse(input.SearchEndTime.Trim()))
.ToPageData<SysLogVis, VisLogOutput>(input);
return PageDataResult<VisLogOutput>.PageResult(visLogs);
}
/// <summary>
/// 清空访问日志
/// </summary>
/// <returns></returns>
[HttpPost("/sysVisLog/delete")]
public async Task ClearVisLog()
{
var visLogs = await _sysVisLogRep.Entities.ToListAsync();
visLogs.ForEach(u =>
{
u.Delete();
});
}
}
}

View File

@@ -0,0 +1,86 @@
namespace Ewide.Core.Service
{
/// <summary>
/// 登录菜单-AntDesign菜单类型
/// </summary>
public class AntDesignTreeNode
{
/// <summary>
/// id
/// </summary>
public string Id { get; set; }
/// <summary>
/// 父id
/// </summary>
public string Pid { get; set; }
/// <summary>
/// 路由名称, 必须设置,且不能重名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 组件
/// </summary>
public string Component { get; set; }
/// <summary>
/// 重定向地址, 访问这个路由时, 自定进行重定向
/// </summary>
public string Redirect { get; set; }
/// <summary>
/// 路由元信息(路由附带扩展信息)
/// </summary>
public Meta Meta { get; set; }
/// <summary>
/// 路径
/// </summary>
public string Link { get; set; }
/// <summary>
/// 控制路由和子路由是否显示在 sidebar
/// </summary>
public bool Hidden { get; set; }
/// <summary>
/// 打开方式
/// </summary>
public int OpenType { get; set; }
public string Application { get; set; }
}
/// <summary>
/// 路由元信息内部类
/// </summary>
public class Meta
{
/// <summary>
/// 路由标题, 用于显示面包屑, 页面标题 *推荐设置
/// </summary>
public string Title { get; set; }
/// <summary>
/// 图标
/// </summary>
public string Icon { get; set; }
/// <summary>
/// 是否可见
/// </summary>
public bool Show { get; set; }
/// <summary>
/// 如需外部打开增加_blank
/// </summary>
public string Target { get; set; }
/// <summary>
/// 内链打开http链接
/// </summary>
public string Link { get; set; }
}
}

View File

@@ -0,0 +1,148 @@
using System.ComponentModel.DataAnnotations;
namespace Ewide.Core.Service
{
/// <summary>
/// 菜单参数
/// </summary>
public class MenuInput
{
/// <summary>
/// 父Id
/// </summary>
public virtual string Pid { get; set; } = System.Guid.Empty.ToString();
/// <summary>
/// 名称
/// </summary>
public virtual string Name { get; set; }
/// <summary>
/// 编码
/// </summary>
public virtual string Code { get; set; }
/// <summary>
/// 菜单类型(字典 0目录 1菜单 2按钮
/// </summary>
public virtual int Type { get; set; }
/// <summary>
/// 图标
/// </summary>
public string Icon { get; set; }
/// <summary>
/// 路由地址
/// </summary>
public virtual string Router { get; set; }
/// <summary>
/// 组件地址
/// </summary>
public virtual string Component { get; set; }
/// <summary>
/// 权限标识
/// </summary>
public virtual string Permission { get; set; }
/// <summary>
/// 应用分类(应用编码)
/// </summary>
public virtual string Application { get; set; }
/// <summary>
/// 打开方式(字典 0无 1组件 2内链 3外链
/// </summary>
public virtual int OpenType { get; set; }
/// <summary>
/// 是否可见Y-是N-否)
/// </summary>
public bool Visible { get; set; }
/// <summary>
/// 内链地址
/// </summary>
public string Link { get; set; }
/// <summary>
/// 重定向地址
/// </summary>
public string Redirect { get; set; }
/// <summary>
/// 权重(字典 1系统权重 2业务权重
/// </summary>
public string Weight { get; set; }
/// <summary>
/// 排序
/// </summary>
public int Sort { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
/// <summary>
/// 绑定上级菜单显示
/// </summary>
public bool VisibleParent { get; set; }
}
public class AddMenuInput : MenuInput
{
/// <summary>
/// 菜单类型(字典 0目录 1菜单 2按钮
/// </summary>
[Required(ErrorMessage = "菜单类型不能为空")]
public override int Type { get; set; }
/// <summary>
/// 打开方式(字典 0无 1组件 2内链 3外链
/// </summary>
[Required(ErrorMessage = "打开方式不能为空")]
public override int OpenType { get; set; }
}
public class DeleteMenuInput
{
/// <summary>
/// 菜单Id
/// </summary>
[Required(ErrorMessage = "菜单Id不能为空")]
public string Id { get; set; }
}
public class UpdateMenuInput : AddMenuInput
{
/// <summary>
/// 菜单Id
/// </summary>
[Required(ErrorMessage = "菜单Id不能为空")]
public string Id { get; set; }
/// <summary>
/// 父Id
/// </summary>DeleteMenuInput
[Required(ErrorMessage = "父级菜单Id不能为空")]
public override string Pid { get; set; }
}
public class QueryMenuInput : DeleteMenuInput
{
}
public class ChangeAppMenuInput : MenuInput
{
/// <summary>
/// 应用编码
/// </summary>DeleteMenuInput
[Required(ErrorMessage = "应用编码不能为空")]
public override string Application { get; set; }
}
}

View File

@@ -0,0 +1,36 @@
using System.Collections;
using System.Collections.Generic;
namespace Ewide.Core.Service
{
/// <summary>
/// 菜单树(列表形式)
/// </summary>
public class MenuOutput : MenuInput, ITreeNode
{
/// <summary>
/// 菜单Id
/// </summary>
public string Id { get; set; }
/// <summary>
/// 子节点
/// </summary>
public List<MenuOutput> Children { get; set; } = new List<MenuOutput>();
public string GetId()
{
return Id;
}
public string GetPid()
{
return Pid;
}
public void SetChildren(IList children)
{
Children = (List<MenuOutput>)children;
}
}
}

View File

@@ -0,0 +1,76 @@
using System.Collections;
using System.Collections.Generic;
namespace Ewide.Core.Service
{
/// <summary>
/// 菜单树---授权、新增编辑时选择
/// </summary>
public class MenuTreeOutput : ITreeNode
{
/// <summary>
/// 主键
/// </summary>
public string Id { get; set; }
/// <summary>
/// 父Id
/// </summary>
public string ParentId { get; set; }
/// <summary>
/// 名称
/// </summary>
public string Title { get; set; }
/// <summary>
/// 值
/// </summary>
public string Value { get; set; }
/// <summary>
/// 菜单类型
/// </summary>
public int Type { get; set; }
/// <summary>
/// 关联显示父级
/// </summary>
public bool VisibleParent { get; set; }
/// <summary>
/// 权限标识
/// </summary>
public string Permission { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
/// <summary>
/// 排序,越小优先级越高
/// </summary>
public int Sort { get; set; }
/// <summary>
/// 子节点
/// </summary>
public List<MenuTreeOutput> Children { get; set; } = new List<MenuTreeOutput>();
public string GetId()
{
return Id;
}
public string GetPid()
{
return ParentId;
}
public void SetChildren(IList children)
{
Children = (List<MenuTreeOutput>)children;
}
}
}

View File

@@ -0,0 +1,22 @@
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
public interface ISysMenuService
{
Task AddMenu(AddMenuInput input);
Task<List<AntDesignTreeNode>> ChangeAppMenu(ChangeAppMenuInput input);
Task DeleteMenu(DeleteMenuInput input);
Task<List<AntDesignTreeNode>> GetLoginMenusAntDesign(string userId, string appCode);
Task<List<string>> GetLoginPermissionList(string userId);
Task<dynamic> GetMenu(QueryMenuInput input);
Task<dynamic> GetMenuList([FromQuery] MenuInput input);
Task<dynamic> GetMenuTree([FromQuery] MenuInput input);
Task<List<string>> GetUserMenuAppCodeList(string userId);
Task<bool> HasMenu(string appCode);
Task<dynamic> TreeForGrant([FromQuery] MenuInput input);
Task UpdateMenu(UpdateMenuInput input);
}
}

View File

@@ -0,0 +1,494 @@
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
/// <summary>
/// 系统菜单服务
/// </summary>
[ApiDescriptionSettings(Name = "Menu", Order = 146)]
public class SysMenuService : ISysMenuService, IDynamicApiController, ITransient
{
private readonly IRepository<SysMenu> _sysMenuRep; // 菜单表仓储
private readonly IUserManager _userManager;
private readonly ISysCacheService _sysCacheService;
private readonly ISysUserRoleService _sysUserRoleService;
private readonly ISysRoleMenuService _sysRoleMenuService;
public SysMenuService(IRepository<SysMenu> sysMenuRep,
IUserManager userManager,
ISysCacheService sysCacheService,
ISysUserRoleService sysUserRoleService,
ISysRoleMenuService sysRoleMenuService)
{
_sysMenuRep = sysMenuRep;
_userManager = userManager;
_sysCacheService = sysCacheService;
_sysUserRoleService = sysUserRoleService;
_sysRoleMenuService = sysRoleMenuService;
}
/// <summary>
/// 获取用户权限(按钮权限标识集合)
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
[NonAction]
public async Task<List<string>> GetLoginPermissionList(string userId)
{
var permissions = await _sysCacheService.GetPermission(userId); // 先从缓存里面读取
if (permissions == null || permissions.Count < 1)
{
var roleIdList = await _sysUserRoleService.GetUserRoleIdList(userId);
var menuIdList = await _sysRoleMenuService.GetRoleMenuIdList(roleIdList);
permissions = await _sysMenuRep.DetachedEntities.Where(u => menuIdList.Contains(u.Id))
.Where(u => u.Type == (int)MenuType.FUNCTION)
.Where(u => u.Status == (int)CommonStatus.ENABLE)
.Select(u => u.Permission).ToListAsync();
#if DEBUG
#else
await _sysCacheService.SetPermission(userId, permissions); // 缓存结果
#endif
}
return permissions;
}
/// <summary>
/// 获取用户AntDesign菜单集合
/// </summary>
/// <param name="userId"></param>
/// <param name="appCode"></param>
/// <returns></returns>
[NonAction]
public async Task<List<AntDesignTreeNode>> GetLoginMenusAntDesign(string userId, string appCode)
{
var antDesignTreeNodes = await _sysCacheService.GetMenu(userId, appCode); // 先从缓存里面读取
if (antDesignTreeNodes == null || antDesignTreeNodes.Count < 1)
{
var sysMenuList = new List<SysMenu>();
// 管理员则展示所有系统权重菜单,不能展示业务权重菜单
if (_userManager.SuperAdmin)
{
sysMenuList = await _sysMenuRep.DetachedEntities
.Where(u => u.Status == (int)CommonStatus.ENABLE)
.Where(u => u.Application == appCode)
.Where(u => u.Type != (int)MenuType.FUNCTION)
.Where(u => u.Weight != (int)MenuWeight.DEFAULT_WEIGHT)
.OrderBy(u => u.Sort).ToListAsync();
}
else
{
// 非管理员则获取自己角色所拥有的菜单集合
var roleIdList = await _sysUserRoleService.GetUserRoleIdList(userId);
var menuIdList = await _sysRoleMenuService.GetRoleMenuIdList(roleIdList);
sysMenuList = await _sysMenuRep.DetachedEntities
.Where(u => menuIdList.Contains(u.Id))
.Where(u => u.Status == (int)CommonStatus.ENABLE)
.Where(u => u.Application == appCode)
.Where(u => u.Type != (int)MenuType.FUNCTION)
.OrderBy(u => u.Sort).ToListAsync();
}
// 转换成登录菜单
antDesignTreeNodes = sysMenuList.Select(u => new AntDesignTreeNode
{
Id = u.Id,
Pid = u.Pid,
Name = u.Code,
Component = u.Component,
Redirect = u.Redirect,
Link = u.Link,
OpenType = u.OpenType,
Meta = new Meta
{
Title = u.Name,
Icon = u.Icon,
Show = u.Visible,
Link = u.Link,
Target = u.OpenType == (int)MenuOpenType.OUTER ? "_blank" : ""
},
Application = u.Application
}).ToList();
#if DEBUG
#else
await _sysCacheService.SetMenu(userId, appCode, antDesignTreeNodes); // 缓存结果
#endif
}
return antDesignTreeNodes;
}
/// <summary>
/// 获取用户菜单所属的应用编码集合
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
[NonAction]
public async Task<List<string>> GetUserMenuAppCodeList(string userId)
{
var roleIdList = await _sysUserRoleService.GetUserRoleIdList(userId);
var menuIdList = await _sysRoleMenuService.GetRoleMenuIdList(roleIdList);
return await _sysMenuRep.DetachedEntities
.Where(u => (u.Type == 2 && u.VisibleParent) || u.Type < 2)
.Where(u => menuIdList.Contains(u.Id))
.Where(u => u.Status == (int)CommonStatus.ENABLE)
.Select(u => u.Application).ToListAsync();
}
/// <summary>
/// 系统菜单列表(树表)
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("/sysMenu/list")]
public async Task<dynamic> GetMenuList([FromQuery] MenuInput input)
{
var application = !string.IsNullOrEmpty(input.Application?.Trim());
var name = !string.IsNullOrEmpty(input.Name?.Trim());
var menus = await _sysMenuRep.DetachedEntities.Where((application, u => u.Application == input.Application.Trim()),
(name, u => EF.Functions.Like(u.Name, $"%{input.Name.Trim()}%")))
.Where(u => u.Status == (int)CommonStatus.ENABLE).OrderBy(u => u.Sort)
.Select(u => u.Adapt<MenuOutput>())
.ToListAsync();
return new TreeBuildUtil<MenuOutput>().DoTreeBuild(menus);
}
/// <summary>
/// 创建Pids格式
/// 如果pid是0顶级节点pids就是 [0];
/// 如果pid不是顶级节点pids就是 pid菜单的 pids + [pid] + ,
/// </summary>
/// <param name="pid"></param>
/// <returns></returns>
private async Task<string> CreateNewPids(string pid)
{
if (pid.Equals(System.Guid.Empty.ToString()))
{
return "[" + System.Guid.Empty + "],";
}
else
{
var pmenu = await _sysMenuRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == pid);
return pmenu.Pids + "[" + pid + "],";
}
}
/// <summary>
/// 增加和编辑时检查参数
/// </summary>
/// <param name="input"></param>
private async Task CheckMenuParam(MenuInput input)
{
var type = input.Type;
var router = input.Router;
var permission = input.Permission;
var openType = input.OpenType;
var isVisibleParent = input.VisibleParent;
if (type.Equals((int)MenuType.DIR))
{
//if (string.IsNullOrEmpty(router))
// throw Oops.Oh(ErrorCode.D4001);
}
else if (type.Equals((int)MenuType.MENU))
{
//if (string.IsNullOrEmpty(router))
// throw Oops.Oh(ErrorCode.D4001);
//if (string.IsNullOrEmpty(openType))
// throw Oops.Oh(ErrorCode.D4002);
}
else if (type.Equals((int)MenuType.FUNCTION))
{
if (string.IsNullOrEmpty(permission))
throw Oops.Oh(ErrorCode.D4003);
if (!permission.Contains(":"))
throw Oops.Oh(ErrorCode.D4004);
// 判断该资源是否存在
//permission = ":" + permission;
//var urlSet = resourceCache.getAllResources();
//if (!urlSet.Contains(permission.Replace(":","/")))
// throw Oops.Oh(ErrorCode.meu1005);
}
// 检查上级菜单的类型是否正确
var pid = input.Pid;
var flag = true;
var empty = System.Guid.Empty.ToString();
switch(type)
{
// 目录必须在顶级下
case (int)MenuType.DIR:
flag = pid.Equals(empty);
break;
// 菜单必须在顶级或目录下
case (int)MenuType.MENU:
if (!pid.Equals(empty))
{
var parent = await _sysMenuRep.DetachedEntities.FirstOrDefaultAsync(p => p.Id == pid);
flag = parent.Type.Equals((int)MenuType.DIR);
}
break;
// 功能必须在菜单下
case (int)MenuType.FUNCTION:
{
var parent = await _sysMenuRep.DetachedEntities.FirstOrDefaultAsync(p => p.Id == pid);
flag = parent == null ? false : parent.Type.Equals((int)MenuType.MENU);
}
break;
}
if (!flag)
{
throw Oops.Oh("父级菜单类型错误");
}
}
/// <summary>
/// 增加系统菜单
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysMenu/add")]
public async Task AddMenu(AddMenuInput input)
{
if (!string.IsNullOrEmpty(input.Code))
{
var isExist = await _sysMenuRep.DetachedEntities.AnyAsync(u => u.Code == input.Code); // u.Name == input.Name
if (isExist)
throw Oops.Oh(ErrorCode.D4000);
}
// 校验参数
await CheckMenuParam(input);
var menu = input.Adapt<SysMenu>();
menu.Pids = await CreateNewPids(input.Pid);
menu.Status = (int)CommonStatus.ENABLE;
await menu.InsertAsync();
// 清除缓存
await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_MENU);
}
/// <summary>
/// 删除系统菜单
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysMenu/delete")]
[UnitOfWork]
public async Task DeleteMenu(DeleteMenuInput input)
{
var childIdList = await _sysMenuRep.DetachedEntities.Where(u => u.Pids.Contains(input.Id.ToString()))
.Select(u => u.Id).ToListAsync();
childIdList.Add(input.Id);
var menus = await _sysMenuRep.Where(u => childIdList.Contains(u.Id)).ToListAsync();
menus.ForEach(u =>
{
u.Delete();
});
// 级联删除该菜单及子菜单对应的角色-菜单表信息
await _sysRoleMenuService.DeleteRoleMenuListByMenuIdList(childIdList);
// 清除缓存
await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_MENU);
}
/// <summary>
/// 更新系统菜单
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysMenu/edit"),]
public async Task UpdateMenu(UpdateMenuInput input)
{
// Pid和Id不能一致一致会导致无限递归
if (input.Id == input.Pid)
throw Oops.Oh(ErrorCode.D4006);
if (!string.IsNullOrEmpty(input.Code))
{
var isExist = await _sysMenuRep.DetachedEntities.AnyAsync(u => u.Code == input.Code && u.Id != input.Id); // u.Name == input.Name
if (isExist)
throw Oops.Oh(ErrorCode.D4000);
}
// 校验参数
await CheckMenuParam(input);
// 如果是编辑父id不能为自己的子节点
var childIdList = await _sysMenuRep.DetachedEntities.Where(u => u.Pids.Contains(input.Id.ToString()))
.Select(u => u.Id).ToListAsync();
if (childIdList.Contains(input.Pid))
throw Oops.Oh(ErrorCode.D4006);
var oldMenu = await _sysMenuRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == input.Id);
// 生成新的pids
var newPids = await CreateNewPids(input.Pid);
// 是否更新子应用的标识
var updateSubAppsFlag = false;
// 是否更新子节点的pids的标识
var updateSubPidsFlag = false;
// 如果应用有变化
if (input.Application != oldMenu.Application)
{
// 父节点不是根节点不能移动应用
if (!oldMenu.Pid.Equals(System.Guid.Empty.ToString()))
throw Oops.Oh(ErrorCode.D4007);
updateSubAppsFlag = true;
}
// 父节点有变化
if (input.Pid != oldMenu.Pid)
updateSubPidsFlag = true;
// 开始更新所有子节点的配置
if (updateSubAppsFlag || updateSubPidsFlag)
{
// 查找所有叶子节点,包含子节点的子节点
var menuList = await _sysMenuRep.Where(u => EF.Functions.Like(u.Pids, $"%{oldMenu.Id}%")).ToListAsync();
// 更新所有子节点的应用为当前菜单的应用
if (menuList.Count > 0)
{
// 更新所有子节点的application
if (updateSubAppsFlag)
{
menuList.ForEach(u =>
{
u.Application = input.Application;
});
}
// 更新所有子节点的pids
if (updateSubPidsFlag)
{
menuList.ForEach(u =>
{
// 子节点pids组成 = 当前菜单新pids + 当前菜单id + 子节点自己的pids后缀
var oldParentCodesPrefix = oldMenu.Pids + "[" + oldMenu.Id + "],";
var oldParentCodesSuffix = u.Pids.Substring(oldParentCodesPrefix.Length);
var menuParentCodes = newPids + "[" + oldMenu.Id + "]," + oldParentCodesSuffix;
u.Pids = menuParentCodes;
});
}
}
}
// 更新当前菜单
oldMenu = input.Adapt<SysMenu>();
oldMenu.Pids = newPids;
await oldMenu.UpdateExcludeAsync(new[] { nameof(SysMenu.Type) }, ignoreNullValues: true);
// 清除缓存
await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_MENU);
}
/// <summary>
/// 获取系统菜单
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysMenu/detail")]
public async Task<dynamic> GetMenu(QueryMenuInput input)
{
return await _sysMenuRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == input.Id);
}
/// <summary>
/// 获取系统菜单树,用于新增、编辑时选择上级节点
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("/sysMenu/tree")]
public async Task<dynamic> GetMenuTree([FromQuery] MenuInput input)
{
var application = !string.IsNullOrEmpty(input.Application?.Trim());
var menus = await _sysMenuRep.DetachedEntities
.Where(application, u => u.Application == input.Application.Trim())
.Where(u => u.Status == (int)CommonStatus.ENABLE)
.Where(u => u.Type == (int)MenuType.DIR || u.Type == (int)MenuType.MENU)
.OrderBy(u => u.Sort)
.Select(u => new MenuTreeOutput
{
Id = u.Id,
ParentId = u.Pid,
Value = u.Id.ToString(),
Title = u.Name,
Type = u.Type,
VisibleParent = u.VisibleParent,
Sort = u.Sort
}).ToListAsync();
return new TreeBuildUtil<MenuTreeOutput>().DoTreeBuild(menus);
}
/// <summary>
/// 获取系统菜单树,用于给角色授权时选择
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("/sysMenu/treeForGrant")]
public async Task<dynamic> TreeForGrant([FromQuery] MenuInput input)
{
var menuIdList = new List<string>();
if (_userManager.SuperAdmin)
{
var roleIdList = await _sysUserRoleService.GetUserRoleIdList(_userManager.UserId);
menuIdList = await _sysRoleMenuService.GetRoleMenuIdList(roleIdList);
}
var application = !string.IsNullOrEmpty(input.Application?.Trim());
var menus = await _sysMenuRep.DetachedEntities
.Where(application, u => u.Application == input.Application.Trim())
.Where(u => u.Status == (int)CommonStatus.ENABLE)
.Where(menuIdList.Count > 0, u => menuIdList.Contains(u.Id))
.OrderBy(u => u.Sort).Select(u => new MenuTreeOutput
{
Id = u.Id,
ParentId = u.Pid,
Value = u.Id.ToString(),
Title = u.Name,
Type = u.Type,
VisibleParent = u.VisibleParent,
Permission = u.Permission,
Remark = u.Remark,
Sort = u.Sort
}).ToListAsync();
return new TreeBuildUtil<MenuTreeOutput>().DoTreeBuild(menus);
}
/// <summary>
/// 根据应用编码判断该机构下是否有状态为正常的菜单
/// </summary>
/// <param name="appCode"></param>
/// <returns></returns>
[NonAction]
public async Task<bool> HasMenu(string appCode)
{
return await _sysMenuRep.DetachedEntities.AnyAsync(u => u.Application == appCode && u.Status != CommonStatus.DELETED);
}
/// <summary>
/// 根据系统应用切换菜单
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[AllowAnonymous]
[HttpPost("/sysMenu/change")]
public async Task<List<AntDesignTreeNode>> ChangeAppMenu(ChangeAppMenuInput input)
{
return await GetLoginMenusAntDesign(_userManager.UserId, input.Application);
}
}
}

View File

@@ -0,0 +1,11 @@
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
public interface IMachineService
{
Task<dynamic> GetMachineBaseInfo();
Task<dynamic> GetMachineNetWorkInfo();
Task<dynamic> GetMachineUseInfo();
}
}

View File

@@ -0,0 +1,53 @@
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
/// <summary>
/// 服务器信息服务
/// </summary>
[AllowAnonymous]
[ApiDescriptionSettings(Name = "Machine", Order = 100)]
public class MachineService : IMachineService, IDynamicApiController, ITransient
{
public MachineService()
{
}
/// <summary>
/// 获取服务器资源信息
/// </summary>
/// <returns></returns>
[HttpGet("/sysMachine/use")]
public async Task<dynamic> GetMachineUseInfo()
{
var useInfo = MachineUtil.GetMachineUseInfo();
return await Task.FromResult(useInfo);
}
/// <summary>
/// 获取服务器基本参数
/// </summary>
/// <returns></returns>
[HttpGet("/sysMachine/base")]
public async Task<dynamic> GetMachineBaseInfo()
{
return await MachineUtil.GetMachineBaseInfo();
}
/// <summary>
/// 动态获取网络信息
/// </summary>
/// <returns></returns>
[HttpGet("/sysMachine/network")]
public async Task<dynamic> GetMachineNetWorkInfo()
{
var baseInfo = MachineUtil.GetMachineNetWorkInfo();
return await Task.FromResult(baseInfo);
}
}
}

View File

@@ -0,0 +1,64 @@
using System;
namespace Ewide.Core.Service
{
/// <summary>
/// 通知公告参数
/// </summary>
public class NoticeBase
{
/// <summary>
/// ID
/// </summary>
public string Id { set; get; }
/// <summary>
/// 标题
/// </summary>
public string Title { get; set; }
/// <summary>
/// 内容
/// </summary>
public string Content { get; set; }
/// <summary>
/// 类型(字典 1通知 2公告
/// </summary>
public int Type { get; set; }
/// <summary>
/// 发布人Id
/// </summary>
public string PublicUserId { get; set; }
/// <summary>
/// 发布人姓名
/// </summary>
public string PublicUserName { get; set; }
/// <summary>
/// 发布机构Id
/// </summary>
public string PublicOrgId { get; set; }
/// <summary>
/// 发布机构名称
/// </summary>
public string PublicOrgName { get; set; }
/// <summary>
/// 发布时间
/// </summary>
public DateTime PublicTime { get; set; }
/// <summary>
/// 撤回时间
/// </summary>
public DateTime CancelTime { get; set; }
/// <summary>
/// 状态(字典 0草稿 1发布 2撤回 3删除
/// </summary>
public int Status { get; set; }
}
}

View File

@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
namespace Ewide.Core.Service
{
/// <summary>
/// 系统通知公告详情参数
/// </summary>
public class NoticeDetailOutput : NoticeBase
{
/// <summary>
/// 通知到的用户Id集合
/// </summary>
public List<string> NoticeUserIdList { get; set; }
/// <summary>
/// 通知到的用户阅读信息集合
/// </summary>
public List<NoticeUserRead> NoticeUserReadInfoList { get; set; }
/// <summary>
/// 上传文件Id集合
/// </summary>
public string Attachments { set; get; }
}
public class NoticeUserRead
{
/// <summary>
/// 用户Id
/// </summary>
public string UserId { get; set; }
/// <summary>
/// 用户名称
/// </summary>
public string UserName { get; set; }
/// <summary>
/// 状态(字典 0未读 1已读
/// </summary>
public int ReadStatus { get; set; }
/// <summary>
/// 阅读时间
/// </summary>
public DateTime? ReadTime { get; set; }
}
}

View File

@@ -0,0 +1,106 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Ewide.Core.Service
{
/// <summary>
/// 通知公告参数
/// </summary>
public class NoticeInput : PageInputBase
{
/// <summary>
/// 标题
/// </summary>
public virtual string Title { get; set; }
/// <summary>
/// 内容
/// </summary>
public virtual string Content { get; set; }
/// <summary>
/// 类型(字典 1通知 2公告
/// </summary>
public virtual int Type { get; set; }
/// <summary>
/// 状态(字典 0草稿 1发布 2撤回 3删除
/// </summary>
public virtual int Status { get; set; }
/// <summary>
/// 通知到的人
/// </summary>
public virtual List<string> NoticeUserIdList { get; set; }
}
public class AddNoticeInput : NoticeInput
{
/// <summary>
/// 标题
/// </summary>
[Required(ErrorMessage = "标题不能为空")]
public override string Title { get; set; }
/// <summary>
/// 内容
/// </summary>
[Required(ErrorMessage = "内容不能为空")]
public override string Content { get; set; }
/// <summary>
/// 类型(字典 1通知 2公告
/// </summary>
[Required(ErrorMessage = "类型不能为空")]
public override int Type { get; set; }
/// <summary>
/// 状态(字典 0草稿 1发布 2撤回 3删除
/// </summary>
[Required(ErrorMessage = "状态不能为空")]
public override int Status { get; set; }
/// <summary>
/// 通知到的人
/// </summary>
[Required(ErrorMessage = "通知到的人不能为空")]
public override List<string> NoticeUserIdList { get; set; }
/// <summary>
/// 上传文件集合
/// </summary>
public List<string> Attachments { set; get; }
}
public class DeleteNoticeInput
{
/// <summary>
/// Id
/// </summary>
[Required(ErrorMessage = "通知公告Id不能为空")]
public string Id { get; set; }
}
public class UpdateNoticeInput : AddNoticeInput
{
/// <summary>
/// Id
/// </summary>
[Required(ErrorMessage = "通知公告Id不能为空")]
public string Id { get; set; }
}
public class QueryNoticeInput : DeleteNoticeInput
{
}
public class ChangeStatusNoticeInput : DeleteNoticeInput
{
/// <summary>
/// 状态(字典 0草稿 1发布 2撤回 3删除
/// </summary>
[Required(ErrorMessage = "状态不能为空")]
public int Status { get; set; }
}
}

View File

@@ -0,0 +1,22 @@
using System;
namespace Ewide.Core.Service
{
/// <summary>
/// 通知公告接收参数
/// </summary>
public class NoticeReceiveOutput : NoticeBase
{
/// <summary>
/// 阅读状态(字典 0未读 1已读
/// </summary>
public int ReadStatus { get; set; }
/// <summary>
/// 阅读时间
/// </summary>
public DateTime ReadTime { get; set; }
public string Avatar { get; set; }
}
}

View File

@@ -0,0 +1,16 @@
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
namespace Ewide.Core.Service.Notice
{
public interface ISysNoticeService
{
Task AddNotice(AddNoticeInput input);
Task ChangeStatus(ChangeStatusNoticeInput input);
Task DeleteNotice(DeleteNoticeInput input);
Task<NoticeDetailOutput> GetNotice([FromQuery] QueryNoticeInput input);
Task<dynamic> QueryNoticePageList([FromQuery] NoticeInput input);
Task<dynamic> ReceivedNoticePageList([FromQuery] NoticeInput input);
Task UpdateNotice(UpdateNoticeInput input);
}
}

View File

@@ -0,0 +1,13 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Ewide.Core.Service.Notice
{
public interface ISysNoticeUserService
{
Task Add(string noticeId, List<string> noticeUserIdList, int noticeUserStatus);
Task<List<SysNoticeUser>> GetNoticeUserListByNoticeId(string noticeId);
Task Read(string noticeId, string userId, int status);
Task Update(string noticeId, List<string> noticeUserIdList, int noticeUserStatus);
}
}

View File

@@ -0,0 +1,277 @@
using Dapper;
using Ewide.Core.Extension;
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Ewide.Core.Service.Notice
{
/// <summary>
/// 通知公告服务
/// </summary>
[ApiDescriptionSettings(Name = "Notice", Order = 100)]
public class SysNoticeService : ISysNoticeService, IDynamicApiController, ITransient
{
private readonly IRepository<SysNotice> _sysNoticeRep; // 通知公告表仓储
private readonly IRepository<SysNoticeUser> _sysNoticeUserRep; // 通知公告用户表仓储
private readonly IUserManager _userManager;
private readonly ISysNoticeUserService _sysNoticeUserService;
private readonly IDapperRepository _dapperRepository;
public SysNoticeService(IRepository<SysNotice> sysNoticeRep,
IRepository<SysNoticeUser> sysNoticeUserRep,
IUserManager userManager,
ISysNoticeUserService sysNoticeUserService, IDapperRepository dapperRepository)
{
_sysNoticeRep = sysNoticeRep;
_sysNoticeUserRep = sysNoticeUserRep;
_userManager = userManager;
_sysNoticeUserService = sysNoticeUserService;
_dapperRepository = dapperRepository;
}
/// <summary>
/// 分页查询通知公告
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysNotice/page")]
public async Task<dynamic> QueryNoticePageList([FromBody] NoticeInput input)
{
var searchValue = !string.IsNullOrEmpty(input.SearchValue?.Trim());
var notices = await _sysNoticeRep.DetachedEntities
.Where(searchValue, u => EF.Functions.Like(u.Title, $"%{input.SearchValue.Trim()}%") ||
EF.Functions.Like(u.Content, $"%{input.SearchValue.Trim()}%"))
.Where(input.Type > 0, u => u.Type == input.Type)
.Where(u => u.Status != (int)NoticeStatus.DELETED)
.ToPagedListAsync(input.PageIndex, input.PageSize);
return PageDataResult<SysNotice>.PageResult(notices);
}
/// <summary>
/// 增加通知公告
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysNotice/add")]
[UnitOfWork]
public async Task AddNotice(AddNoticeInput input)
{
_sysNoticeRep.EnsureTransaction();
if (input.Status != (int)NoticeStatus.DRAFT && input.Status != (int)NoticeStatus.PUBLIC)
throw Oops.Oh(ErrorCode.D7000);
var config = new TypeAdapterConfig().ForType<AddNoticeInput, SysNotice>()
.Map(target => target.Attachments, src => String.Join(",", src.Attachments))
.Config;
var notice = input.Adapt<SysNotice>(config);
var id = System.Guid.NewGuid().ToString().ToLower();
notice.Id = id;
await UpdatePublicInfo(notice);
// 如果是发布,则设置发布时间
if (input.Status == (int)NoticeStatus.PUBLIC)
notice.PublicTime = DateTime.Now;
await notice.InsertAsync();
// 通知到的人
var noticeUserIdList = input.NoticeUserIdList;
var noticeUserStatus = (int)NoticeUserStatus.UNREAD;
await _sysNoticeUserService.Add(id, noticeUserIdList, noticeUserStatus);
}
/// <summary>
/// 删除通知公告
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysNotice/delete")]
public async Task DeleteNotice(DeleteNoticeInput input)
{
var notice = await _sysNoticeRep.FirstOrDefaultAsync(u => u.Id == input.Id);
if (notice.Status != (int)NoticeStatus.DRAFT && notice.Status != (int)NoticeStatus.CANCEL) // 只能删除草稿和撤回的
throw Oops.Oh(ErrorCode.D7001);
//notice.Status = (int)NoticeStatus.DELETED;
await notice.DeleteAsync();
}
/// <summary>
/// 更新通知公告
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysNotice/edit")]
public async Task UpdateNotice(UpdateNoticeInput input)
{
if (input.Status != (int)NoticeStatus.DRAFT && input.Status != (int)NoticeStatus.PUBLIC)
throw Oops.Oh(ErrorCode.D7000);
// 非草稿状态
if (input.Status != (int)NoticeStatus.DRAFT)
throw Oops.Oh(ErrorCode.D7002);
var notice = input.Adapt<SysNotice>();
if (input.Attachments != null)
notice.Attachments = string.Join(",", input.Attachments);
if (input.Status == (int)NoticeStatus.PUBLIC)
{
notice.PublicTime = DateTime.Now;
await UpdatePublicInfo(notice);
}
await notice.UpdateAsync(true);
// 通知到的人
var noticeUserIdList = input.NoticeUserIdList;
var noticeUserStatus = (int)NoticeUserStatus.UNREAD;
await _sysNoticeUserService.Update(input.Id, noticeUserIdList, noticeUserStatus);
}
/// <summary>
/// 获取通知公告详情
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("/sysNotice/detail")]
public async Task<NoticeDetailOutput> GetNotice([FromQuery] QueryNoticeInput input)
{
var notice = await _sysNoticeRep.FirstOrDefaultAsync(u => u.Id == input.Id);
// 获取通知到的用户
var noticeUserList = await _sysNoticeUserService.GetNoticeUserListByNoticeId(input.Id);
var noticeUserIdList = new List<string>();
var noticeUserReadInfoList = new List<NoticeUserRead>();
if (noticeUserList != null)
{
noticeUserList.ForEach(u =>
{
noticeUserIdList.Add(u.UserId.ToString());
var noticeUserRead = new NoticeUserRead
{
UserId = u.UserId,
ReadStatus = u.ReadStatus,
ReadTime = u.ReadTime
};
noticeUserReadInfoList.Add(noticeUserRead);
});
}
var noticeResult = notice.Adapt<NoticeDetailOutput>();
if (_userManager.SuperAdmin)
{
noticeResult.NoticeUserIdList = noticeUserIdList;
noticeResult.NoticeUserReadInfoList = noticeUserReadInfoList;
}
// 如果该条通知公告为已发布,则将当前用户的该条通知公告设置为已读
if (notice.Status == (int)NoticeStatus.PUBLIC)
await _sysNoticeUserService.Read(notice.Id, _userManager.UserId, (int)NoticeUserStatus.READ);
return noticeResult;
}
/// <summary>
/// 修改通知公告状态
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysNotice/changeStatus")]
public async Task ChangeStatus(ChangeStatusNoticeInput input)
{
// 状态应为撤回或删除或发布
if (input.Status != (int)NoticeStatus.CANCEL && input.Status != (int)NoticeStatus.DELETED && input.Status != (int)NoticeStatus.PUBLIC)
throw Oops.Oh(ErrorCode.D7000);
var notice = await _sysNoticeRep.FirstOrDefaultAsync(u => u.Id == input.Id);
notice.Status = input.Status;
if (input.Status == (int)NoticeStatus.CANCEL)
{
notice.CancelTime = DateTime.Now;
}
else if (input.Status == (int)NoticeStatus.PUBLIC)
{
notice.PublicTime = DateTime.Now;
}
await notice.UpdateAsync();
}
/// <summary>
/// 获取接收的通知公告
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysNotice/received")]
public async Task<dynamic> ReceivedNoticePageList([FromBody] NoticeInput input)
{
var sql = @"SELECT
SN.*,
SU.Avatar,
SNU.ReadStatus,
SNU.ReadTime
FROM sys_notice SN
LEFT JOIN sys_notice_user SNU ON SN.Id = SNU.NoticeId
LEFT JOIN sys_user SU ON SN.PublicUserId = SU.Id
WHERE SNU.UserId = @UserId AND SN.Status = @Status";
var data = await _dapperRepository.QueryPageDataDynamic(
sql,
input,
new
{
_userManager.UserId,
Status = (int)NoticeStatus.PUBLIC
},
new[] { "Type", "Title", "ReadStatus" }
);
data.Items = data.Items.Select(p =>
{
var r = p.Adapt<NoticeReceiveOutput>();
var content = Regex.Replace(r.Content, @"<\/?.+?\/?>|[\r\n]", "");
r.Content = content.Substring(0, content.Length > 50 ? 50 : content.Length);
return r;
});
return data;
}
/// <summary>
/// 获取接收到的通知公告总数
/// </summary>
/// <returns></returns>
[HttpGet("/sysNotice/unread")]
public async Task<int> GetUnreadCount()
{
//删除 或者 草稿 未发布 都不让显示
var noticeList = await _sysNoticeRep.Where(u => u.Status == (int)NoticeStatus.PUBLIC).Select(s => s.Id).ToListAsync();
return await _sysNoticeUserRep.Where(u => u.UserId == _userManager.UserId && noticeList.Contains(u.NoticeId) && u.ReadStatus == (int)NoticeUserStatus.UNREAD).CountAsync();
}
/// <summary>
/// 更新发布信息
/// </summary>
/// <param name="notice"></param>
[NonAction]
private async Task UpdatePublicInfo(SysNotice notice)
{
var emp = await _userManager.GetUserEmpInfo(_userManager.UserId);
notice.PublicUserId = _userManager.UserId;
notice.PublicUserName = _userManager.Name;
notice.PublicOrgId = emp.OrgId;
notice.PublicOrgName = emp.OrgName;
}
}
}

View File

@@ -0,0 +1,98 @@
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Ewide.Core.Service.Notice
{
/// <summary>
/// 通知公告用户
/// </summary>
[ApiDescriptionSettings(Name = "NoticeUser", Order = 100)]
public class SysNoticeUserService : ISysNoticeUserService, IDynamicApiController, ITransient
{
private readonly IRepository<SysNoticeUser> _sysNoticeUserRep; // 通知公告用户表仓储
private readonly IUserManager _userManager;
private readonly IRepository<SysNotice> _sysNoticeRep;
public SysNoticeUserService(IRepository<SysNoticeUser> sysNoticeUserRep, IUserManager userManager, IRepository<SysNotice> sysNoticeRep)
{
_sysNoticeUserRep = sysNoticeUserRep;
_userManager = userManager;
_sysNoticeRep = sysNoticeRep;
}
/// <summary>
/// 增加
/// </summary>
/// <param name="noticeId"></param>
/// <param name="noticeUserIdList"></param>
/// <param name="noticeUserStatus"></param>
/// <returns></returns>
public async Task Add(string noticeId, List<string> noticeUserIdList, int noticeUserStatus)
{
foreach (var u in noticeUserIdList)
{
await new SysNoticeUser
{
Id = Guid.NewGuid().ToString(),
NoticeId = noticeId,
UserId = u,
ReadStatus = noticeUserStatus
}.InsertAsync();
}
}
/// <summary>
/// 更新
/// </summary>
/// <param name="noticeId"></param>
/// <param name="noticeUserIdList"></param>
/// <param name="noticeUserStatus"></param>
/// <returns></returns>
public async Task Update(string noticeId, List<string> noticeUserIdList, int noticeUserStatus)
{
var noticeUsers = await _sysNoticeUserRep.Where(u => u.NoticeId == noticeId).ToListAsync();
noticeUsers.ForEach(u =>
{
u.Delete();
});
await Add(noticeId, noticeUserIdList, noticeUserStatus);
}
/// <summary>
/// 获取通知公告用户列表
/// </summary>
/// <param name="noticeId"></param>
/// <returns></returns>
public async Task<List<SysNoticeUser>> GetNoticeUserListByNoticeId(string noticeId)
{
return await _sysNoticeUserRep.Where(u => u.NoticeId == noticeId).ToListAsync();
}
/// <summary>
/// 设置通知公告读取状态
/// </summary>
/// <param name="noticeId"></param>
/// <param name="userId"></param>
/// <param name="status"></param>
/// <returns></returns>
public async Task Read(string noticeId, string userId, int status)
{
var noticeUser = await _sysNoticeUserRep.FirstOrDefaultAsync(u => u.NoticeId == noticeId && u.UserId == userId);
if (noticeUser != null)
{
noticeUser.ReadStatus = status;
noticeUser.ReadTime = DateTime.Now;
await noticeUser.UpdateAsync();
}
}
}
}

View File

@@ -0,0 +1,12 @@
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
namespace Ewide.Core.Service.OAuth
{
public interface ISysOauthService
{
Task<dynamic> GetWechatUserInfo([FromQuery] string token, [FromQuery] string openId);
Task WechatLogin();
Task WechatLoginCallback([FromQuery] string code, [FromQuery] string state, [FromQuery] string error_description = "");
}
}

View File

@@ -0,0 +1,68 @@
using Ewide.Core.OAuth;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
namespace Ewide.Core.Service.OAuth
{
/// <summary>
/// OAuth服务
/// </summary>
[ApiDescriptionSettings(Name = "OAuth", Order = 159)]
[AllowAnonymous]
public class SysOauthService : ISysOauthService, IDynamicApiController, ITransient
{
private readonly HttpContext _httpContext;
private readonly WechatOAuth _wechatOAuth;
public SysOauthService(IHttpContextAccessor httpContextAccessor, WechatOAuth wechatOAuth)
{
_httpContext = httpContextAccessor.HttpContext;
_wechatOAuth = wechatOAuth;
}
/// <summary>
/// 微信登录授权
/// </summary>
[HttpGet("oauth/wechat")]
public Task WechatLogin()
{
_httpContext.Response.Redirect(_wechatOAuth.GetAuthorizeUrl("Ewide"));
return Task.CompletedTask;
}
/// <summary>
/// 微信登录授权回调
/// </summary>
/// <param name="code"></param>
/// <param name="state"></param>
/// <param name="error_description"></param>
/// <returns></returns>
[HttpGet("oauth/wechatcallback")]
public async Task WechatLoginCallback([FromQuery] string code, [FromQuery] string state, [FromQuery] string error_description = "")
{
if (!string.IsNullOrEmpty(error_description))
throw Oops.Oh(error_description);
var accessTokenModel = await _wechatOAuth.GetAccessTokenAsync(code, state);
//var userInfoModel = await _wechatOAuth.GetUserInfoAsync(accessTokenModel.AccessToken, accessTokenModel.OpenId);
await _httpContext.Response.WriteAsJsonAsync(accessTokenModel);
}
/// <summary>
/// 获取微信用户基本信息
/// </summary>
/// <param name="token"></param>
/// <param name="openId"></param>
/// <returns></returns>
[HttpGet("oauth/wechat/user")]
public async Task<dynamic> GetWechatUserInfo([FromQuery] string token, [FromQuery] string openId)
{
return await _wechatOAuth.GetUserInfoAsync(token, openId);
}
}
}

View File

@@ -0,0 +1,102 @@
using System.ComponentModel.DataAnnotations;
namespace Ewide.Core.Service
{
/// <summary>
/// 组织机构参数
/// </summary>
public class OrgInput : InputBase
{
/// <summary>
/// 父Id
/// </summary>
public virtual string Pid { get; set; }
/// <summary>
/// 父Ids
/// </summary>
public string Pids { get; set; }
/// <summary>
/// 名称
/// </summary>
public virtual string Name { get; set; }
/// <summary>
/// 编码
/// </summary>
public virtual string Code { get; set; }
/// <summary>
/// 机构类型
/// </summary>
public virtual int Type { get; set; }
/// <summary>
/// 电话
/// </summary>
public virtual string Tel { get; set; }
/// <summary>
/// 排序
/// </summary>
public int Sort { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
/// <summary>
/// 状态(字典 0正常 1停用 2删除
/// </summary>
public int Status { get; set; }
/// <summary>
/// 机构所在区域
/// </summary>
public virtual string AreaCode { get; set; }
}
public class AddOrgInput : OrgInput
{
/// <summary>
/// 名称
/// </summary>
[Required(ErrorMessage = "机构名称不能为空")]
public override string Name { get; set; }
/// <summary>
/// 机构所在区域
/// </summary>
[Required(ErrorMessage = "机构所在区域不能为空")]
public override string AreaCode { get; set; }
}
public class DeleteOrgInput
{
/// <summary>
/// 机构Id
/// </summary>
[Required(ErrorMessage = "机构Id不能为空")]
public string Id { get; set; }
}
public class UpdateOrgInput : AddOrgInput
{
/// <summary>
/// 机构Id
/// </summary>
[Required(ErrorMessage = "机构Id不能为空")]
public string Id { get; set; }
}
public class QueryOrgInput : DeleteOrgInput
{
}
public class PageOrgInput : OrgInput
{
public string Id { get; set; }
}
}

View File

@@ -0,0 +1,13 @@
namespace Ewide.Core.Service
{
/// <summary>
/// 组织机构参数
/// </summary>
public class OrgOutput : OrgInput
{
/// <summary>
/// 机构Id
/// </summary>
public string Id { get; set; }
}
}

View File

@@ -0,0 +1,66 @@
using System.Collections;
using System.Collections.Generic;
namespace Ewide.Core.Service
{
/// <summary>
/// 组织机构树
/// </summary>
public class OrgTreeNode : ITreeNode
{
/// <summary>
/// Id
/// </summary>
public string Id { get; set; }
/// <summary>
/// 父Id
/// </summary>
public string ParentId { get; set; }
/// <summary>
/// 名称
/// </summary>
public string Title { get; set; }
/// <summary>
/// 值
/// </summary>
public string Value { get; set; }
/// <summary>
/// 类型
/// </summary>
public int Type { get; set; }
/// <summary>
/// 排序,越小优先级越高
/// </summary>
public int Weight { get; set; }
/// <summary>
/// 子节点
/// </summary>
public List<OrgTreeNode> Children { get; set; } = new List<OrgTreeNode>();
/// <summary>
/// 上一级Id
/// </summary>
public long Pid { get; set; }
public string GetId()
{
return Id;
}
public string GetPid()
{
return ParentId;
}
public void SetChildren(IList children)
{
Children = (List<OrgTreeNode>)children;
}
}
}

View File

@@ -0,0 +1,32 @@
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
public interface ISysOrgService
{
Task AddOrg(AddOrgInput input);
Task DeleteOrg(DeleteOrgInput input);
Task<List<string>> GetDataScopeListByDataScopeType(int dataScopeType, string orgId);
List<string> GetDataScopeList(List<string> dataScopes);
Task<SysOrg> GetOrg([FromQuery] QueryOrgInput input);
Task<List<OrgOutput>> GetOrgList([FromQuery] OrgInput input);
Task<dynamic> GetOrgTree([FromQuery] OrgInput input);
Task<dynamic> QueryOrgPageList([FromQuery] PageOrgInput input);
Task UpdateOrg(UpdateOrgInput input);
/// <summary>
/// 根据区域信息获取单位id
/// </summary>
/// <param name="dataScopeType">代表区域范围的类型</param>
/// <param name="areaNumberCode">区域代码</param>
/// <returns></returns>
Task<List<string>> GetAreaDataScopeIdList(int dataScopeType,string areaNumberCode);
/// <summary>
/// 当前区域信息不包括子区域
/// </summary>
/// <param name="areaNumberCode">区域代码</param>
/// <returns></returns>
Task<List<string>> GetAreaDataScopeIdListWithoutChildrenArea(string areaNumberCode);
}
}

View File

@@ -0,0 +1,361 @@
using Ewide.Core.Extension;
using Furion;
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
/// <summary>
/// 组织机构服务
/// </summary>
[ApiDescriptionSettings(Name = "Org", Order = 148)]
public class SysOrgService : ISysOrgService, IDynamicApiController, ITransient
{
private readonly IRepository<SysOrg> _sysOrgRep; // 组织机构表仓储
private readonly IUserManager _userManager;
private readonly ISysEmpService _sysEmpService;
private readonly ISysEmpExtOrgPosService _sysEmpExtOrgPosService;
private readonly ISysRoleDataScopeService _sysRoleDataScopeService;
private readonly ISysUserDataScopeService _sysUserDataScopeService;
public SysOrgService(IRepository<SysOrg> sysOrgRep,
IUserManager userManager,
ISysEmpService sysEmpService,
ISysEmpExtOrgPosService sysEmpExtOrgPosService,
ISysRoleDataScopeService sysRoleDataScopeService,
ISysUserDataScopeService sysUserDataScopeService)
{
_sysOrgRep = sysOrgRep;
_userManager = userManager;
_sysEmpService = sysEmpService;
_sysEmpExtOrgPosService = sysEmpExtOrgPosService;
_sysRoleDataScopeService = sysRoleDataScopeService;
_sysUserDataScopeService = sysUserDataScopeService;
}
/// <summary>
/// 分页查询组织机构
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysOrg/page")]
public async Task<dynamic> QueryOrgPageList([FromBody] PageOrgInput input)
{
var dataScopeList = GetDataScopeList(await _userManager.GetUserAllDataScopeList());
var name = !string.IsNullOrEmpty(input.Name?.Trim());
var id = !string.IsNullOrEmpty(input.Id?.Trim());
var pId = !string.IsNullOrEmpty(input.Pid?.Trim());
var orgs = await _sysOrgRep.DetachedEntities
.Where((name, u => EF.Functions.Like(u.Name, $"%{input.Name.Trim()}%")), // 根据机构名称模糊查询
(id, u => u.Id == input.Id.Trim()), // 根据机构id查询
(pId, u => input.TreeNodeDataScope.GetValueOrDefault(1) == 2 ? (EF.Functions.Like(u.Pids, $"%[{input.Pid.Trim()}]%")
|| u.Id == input.Pid.Trim()) : u.Id == input.Pid.Trim() )) // 根据父机构id查询
.Where(dataScopeList.Count > 0, u => dataScopeList.Contains(u.Id)) // 非管理员范围限制
.Where(u => u.Status != CommonStatus.DELETED).OrderBy(u => u.Sort)
.ToPageData<SysOrg,OrgOutput>(input);
//.Select(u => u.Adapt<OrgOutput>())
//.ToPagedListAsync(input.PageNo, input.PageSize);
return PageDataResult<OrgOutput>.PageResult(orgs);
}
/// <summary>
/// (非管理员)获取当前用户数据范围机构Id
/// </summary>
/// <param name="dataScopes"></param>
/// <returns></returns>
public List<string> GetDataScopeList(List<string> dataScopes)
{
var dataScopeList = new List<string>();
// 如果是超级管理员则获取所有组织机构,否则只获取其数据范围的机构数据
if (!_userManager.SuperAdmin)
{
if (dataScopes.Count < 1)
return dataScopeList;
// 不需要去查找上级节点
// 此处获取所有的上级节点,用于构造完整树
//dataScopes.ForEach(u =>
//{
// var sysOrg = _sysOrgRep.DetachedEntities.FirstOrDefault(c => c.Id == u);
// var parentAndChildIdListWithSelf = sysOrg.Pids.TrimEnd(',').Replace("[", "").Replace("]", "")
// .Split(",").ToList();
// dataScopeList.AddRange(parentAndChildIdListWithSelf);
//});
dataScopeList = dataScopes;
}
return dataScopeList.Distinct().ToList();
}
/// <summary>
/// 获取组织机构列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("/sysOrg/list")]
public async Task<List<OrgOutput>> GetOrgList([FromQuery] OrgInput input)
{
var dataScopeList = GetDataScopeList(await _userManager.GetUserAllDataScopeList());
var pId = !string.IsNullOrEmpty(input.Pid?.Trim());
var orgs = await _sysOrgRep.DetachedEntities
.Where(pId, u => u.Pid == input.Pid)
.Where(dataScopeList.Count > 0, u => dataScopeList.Contains(u.Id))
.Where(u => u.Status != CommonStatus.DELETED).OrderBy(u => u.Sort).ToListAsync();
return orgs.Adapt<List<OrgOutput>>();
}
/// <summary>
/// 增加组织机构
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysOrg/add")]
public async Task AddOrg(AddOrgInput input)
{
var isExist = await _sysOrgRep.DetachedEntities
.AnyAsync(u => (u.Pid == input.Pid && u.Name == input.Name) || (!string.IsNullOrEmpty(input.Code) && u.Code == input.Code));
if (isExist)
throw Oops.Oh(ErrorCode.D2002);
if (!_userManager.SuperAdmin)
{
// 如果新增的机构父Id不是0则进行数据权限校验
if (input.Pid != "0" && !string.IsNullOrEmpty(input.Pid))
{
// 新增组织机构的父机构不在自己的数据范围内
var dataScopes = await _userManager.GetUserAllDataScopeList();
if (dataScopes.Count < 1 || !dataScopes.Contains(input.Pid))
throw Oops.Oh(ErrorCode.D2003);
}
else
throw Oops.Oh(ErrorCode.D2003);
}
var sysOrg = input.Adapt<SysOrg>();
await FillPids(sysOrg);
await sysOrg.InsertAsync();
}
/// <summary>
/// 填充父Ids字段
/// </summary>
/// <param name="sysOrg"></param>
/// <returns></returns>
private async Task FillPids(SysOrg sysOrg)
{
if (sysOrg.Pid.Equals(System.Guid.Empty.ToString()))
{
sysOrg.Pids = "[" + System.Guid.Empty + "],";
}
else
{
var t = await _sysOrgRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == sysOrg.Pid);
sysOrg.Pids = t.Pids + "[" + t.Id + "],";
}
}
/// <summary>
/// 删除组织机构
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysOrg/delete")]
[UnitOfWork]
public async Task DeleteOrg(DeleteOrgInput input)
{
var sysOrg = await _sysOrgRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == input.Id);
// 检测数据范围能不能操作这个机构
var dataScopes = await _userManager.GetUserAllDataScopeList();
if (!_userManager.SuperAdmin && (dataScopes.Count < 1 || !dataScopes.Contains(sysOrg.Id)))
throw Oops.Oh(ErrorCode.D2003);
// 该机构下有员工,则不能删
var hasOrgEmp = await _sysEmpService.HasOrgEmp(sysOrg.Id);
if (hasOrgEmp)
throw Oops.Oh(ErrorCode.D2004);
// 该附属机构下若有员工,则不能删
var hasExtOrgEmp = await _sysEmpExtOrgPosService.HasExtOrgEmp(sysOrg.Id);
if (hasExtOrgEmp)
throw Oops.Oh(ErrorCode.D2005);
// 级联删除子节点
var childIdList = await GetChildIdListWithSelfById(sysOrg.Id);
var orgs = await _sysOrgRep.Where(u => childIdList.Contains(u.Id)).ToListAsync();
orgs.ForEach(u =>
{
u.Delete();
});
// 级联删除该机构及子机构对应的角色-数据范围关联信息
await _sysRoleDataScopeService.DeleteRoleDataScopeListByOrgIdList(childIdList);
// 级联删除该机构子机构对应的用户-数据范围关联信息
await _sysUserDataScopeService.DeleteUserDataScopeListByOrgIdList(childIdList);
}
/// <summary>
/// 更新组织机构
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysOrg/edit")]
[UnitOfWork]
public async Task UpdateOrg(UpdateOrgInput input)
{
if (!input.Pid.Equals(System.Guid.Empty.ToString()) && !string.IsNullOrEmpty(input.Pid))
{
var org = await _sysOrgRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == input.Pid);
_ = org ?? throw Oops.Oh(ErrorCode.D2000);
}
if (input.Id == input.Pid)
throw Oops.Oh(ErrorCode.D2001);
// 如果是编辑父id不能为自己的子节点
var childIdListById = await GetChildIdListWithSelfById(input.Id);
if (childIdListById.Contains(input.Pid))
throw Oops.Oh(ErrorCode.D2001);
var sysOrg = await _sysOrgRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == input.Id);
// 检测数据范围能不能操作这个机构
var dataScopes = await _userManager.GetUserAllDataScopeList();
if (!_userManager.SuperAdmin && (dataScopes.Count < 1 || !dataScopes.Contains(sysOrg.Id)))
throw Oops.Oh(ErrorCode.D2003);
var isExist = await _sysOrgRep.DetachedEntities
.AnyAsync(u => ((u.Pid == input.Pid && u.Name == input.Name) || (!string.IsNullOrEmpty(input.Code) && u.Code == input.Code)) && u.Id != sysOrg.Id);
if (isExist)
throw Oops.Oh(ErrorCode.D2002);
// 如果名称有变化,则修改对应员工的机构相关信息
if (!sysOrg.Name.Equals(input.Name))
await _sysEmpService.UpdateEmpOrgInfo(sysOrg.Id, sysOrg.Name);
sysOrg = input.Adapt<SysOrg>();
await FillPids(sysOrg);
await sysOrg.UpdateAsync(ignoreNullValues: true);
//// 将所有子的父id进行更新
//childIdListById.ForEach(u=> {
// var child = _sysOrgRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == u.Id);
// var newInput = child.Adapt<UpdateOrgInput>();
// UpdateOrg(newInput).GetAwaiter();
//});
}
/// <summary>
/// 获取组织机构信息
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("/sysOrg/detail")]
public async Task<SysOrg> GetOrg([FromQuery] QueryOrgInput input)
{
return await _sysOrgRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == input.Id);
}
/// <summary>
/// 根据节点Id获取所有子节点Id集合包含自己
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
private async Task<List<string>> GetChildIdListWithSelfById(string id)
{
var childIdList = await _sysOrgRep.DetachedEntities
.Where(u => EF.Functions.Like(u.Pids, $"%{id}%"))
.Select(u => u.Id).ToListAsync();
childIdList.Add(id);
return childIdList;
}
/// <summary>
/// 获取组织机构树
/// </summary>
/// <returns></returns>
[HttpGet("/sysOrg/tree")]
public async Task<dynamic> GetOrgTree([FromQuery] OrgInput input)
{
var dataScopeList = new List<string>();
if (!_userManager.SuperAdmin)
{
var dataScopes = await _userManager.GetUserAllDataScopeList();
if (dataScopes.Count < 1)
return dataScopeList;
dataScopeList = GetDataScopeList(dataScopes);
}
var orgs = await _sysOrgRep.DetachedEntities.Where(dataScopeList.Count > 0, u => dataScopeList.Contains(u.Id))
.Where(u => u.Status == (int)CommonStatus.ENABLE).OrderBy(u => u.Sort)
.Where(input.Type != 0 , u=>u.Type < input.Type)
.Select(u => new OrgTreeNode
{
Id = u.Id,
ParentId = u.Pid,
Title = u.Name,
Type = u.Type,
Value = u.Id.ToString(),
Weight = u.Sort
}).ToListAsync();
return new TreeBuildUtil<OrgTreeNode>().DoTreeBuild(orgs);
}
/// <summary>
/// 根据数据范围类型获取当前用户的数据范围机构Id集合
/// </summary>
/// <param name="dataScopeType"></param>
/// <param name="orgId"></param>
/// <returns></returns>
[NonAction]
public async Task<List<string>> GetDataScopeListByDataScopeType(int dataScopeType, string orgId)
{
var orgIdList = new List<string>();
if (string.IsNullOrEmpty(orgId))
return orgIdList;
// 如果是范围类型是全部数据则获取当前所有的组织架构Id
if (dataScopeType == (int)DataScopeType.ALL)
{
orgIdList = await _sysOrgRep.DetachedEntities.Where(u => u.Status == (int)CommonStatus.ENABLE).Select(u => u.Id).ToListAsync();
}
// 如果范围类型是本部门及以下部门,则查询本节点和子节点集合,包含本节点
else if (dataScopeType == (int)DataScopeType.DEPT_WITH_CHILD)
{
orgIdList = await GetChildIdListWithSelfById(orgId);
}
// 如果数据范围是本部门,不含子节点,则直接返回本部门
else if (dataScopeType == (int)DataScopeType.DEPT)
{
orgIdList.Add(orgId);
}
return orgIdList;
}
public async Task<List<string>> GetAreaDataScopeIdList(int dataScopeType, string orgId)
{
var org = await _sysOrgRep.FirstOrDefaultAsync(o => o.Id == orgId);
if (dataScopeType == (int)DataScopeType.AREA_WITH_CHILD)
return await _sysOrgRep.DetachedEntities.Where(p => p.AreaCode.StartsWith(org.AreaCode)).Select(p => p.Id).ToListAsync();
if (dataScopeType == (int)DataScopeType.AREA)
return await _sysOrgRep.DetachedEntities.Where(p => p.AreaCode == org.AreaCode).Select(p => p.Id).ToListAsync();
return new List<string>();
}
public async Task<List<string>> GetAreaDataScopeIdListWithoutChildrenArea(string areaNumberCode)
{
return await _sysOrgRep.DetachedEntities.Where(p => p.AreaCode == areaNumberCode).Select(p => p.Id).ToListAsync();
}
}
}

View File

@@ -0,0 +1,83 @@
using System.ComponentModel.DataAnnotations;
namespace Ewide.Core.Service
{
/// <summary>
/// 职位参数
/// </summary>
public class PosInput : PageInputBase
{
/// <summary>
/// 名称
/// </summary>
public virtual string Name { get; set; }
/// <summary>
/// 编码
/// </summary>
public virtual string Code { get; set; }
/// <summary>
/// 排序
/// </summary>
public int Sort { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
/// <summary>
/// 状态(字典 0正常 1停用 2删除
/// </summary>
public int Status { get; set; }
/// <summary>
/// 当前页码
/// </summary>
public int PageNo { get; set; } = 1;
/// <summary>
/// 页码容量
/// </summary>
public int PageSize { get; set; } = 20;
}
public class AddPosInput : PosInput
{
/// <summary>
/// 名称
/// </summary>
[Required(ErrorMessage ="职位名称不能为空")]
public override string Name { get; set; }
/// <summary>
/// 编码
/// </summary>
[Required(ErrorMessage = "职位编码不能为空")]
public override string Code { get; set; }
}
public class DeletePosInput
{
/// <summary>
/// 职位Id
/// </summary>
[Required(ErrorMessage = "职位Id不能为空")]
public string Id { get; set; }
}
public class UpdatePosInput : AddPosInput
{
/// <summary>
/// 职位Id
/// </summary>
[Required(ErrorMessage = "职位Id不能为空")]
public string Id { get; set; }
}
public class QueryPosInput : DeletePosInput
{
}
}

View File

@@ -0,0 +1,15 @@
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
public interface ISysPosService
{
Task AddPos(AddPosInput input);
Task DeletePos(DeletePosInput input);
Task<SysPos> GetPos([FromQuery] QueryPosInput input);
Task<dynamic> GetPosList([FromQuery] PosInput input);
Task<dynamic> QueryPosPageList([FromQuery] PosInput input);
Task UpdatePos(UpdatePosInput input);
}
}

View File

@@ -0,0 +1,132 @@
using Ewide.Core.Extension;
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
/// <summary>
/// 职位服务
/// </summary>
[ApiDescriptionSettings(Name = "Pos", Order = 147)]
public class SysPosService : ISysPosService, IDynamicApiController, ITransient
{
private readonly IRepository<SysPos> _sysPosRep; // 职位表仓储
private readonly ISysEmpPosService _sysEmpPosService;
private readonly ISysEmpExtOrgPosService _sysEmpExtOrgPosService;
public SysPosService(IRepository<SysPos> sysPosRep,
ISysEmpPosService sysEmpPosService,
ISysEmpExtOrgPosService sysEmpExtOrgPosService)
{
_sysPosRep = sysPosRep;
_sysEmpPosService = sysEmpPosService;
_sysEmpExtOrgPosService = sysEmpExtOrgPosService;
}
/// <summary>
/// 分页获取职位
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysPos/page")]
public async Task<dynamic> QueryPosPageList([FromBody] PosInput input)
{
var name = !string.IsNullOrEmpty(input.Name?.Trim());
var code = !string.IsNullOrEmpty(input.Code?.Trim());
var pos = await _sysPosRep.DetachedEntities
.Where((name, u => EF.Functions.Like(u.Name, $"%{input.Name.Trim()}%")),
(code, u => EF.Functions.Like(u.Code, $"%{input.Code.Trim()}%")))
.Where(u => u.Status == CommonStatus.ENABLE).OrderBy(u => u.Sort)
.ToPageData(input);
//.ToPagedListAsync(input.PageNo, input.PageSize);
return PageDataResult<SysPos>.PageResult(pos);
}
/// <summary>
/// 获取职位列表
/// </summary>
/// <returns></returns>
[HttpGet("/sysPos/list")]
public async Task<dynamic> GetPosList([FromQuery] PosInput input)
{
var code = !string.IsNullOrEmpty(input.Code?.Trim());
return await _sysPosRep.DetachedEntities.Where(code, u => EF.Functions.Like(u.Code, $"%{input.Code.Trim()}%"))
.Where(u => u.Status != CommonStatus.DELETED)
.OrderBy(u => u.Sort).ToListAsync();
}
/// <summary>
/// 增加职位
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysPos/add")]
public async Task AddPos(AddPosInput input)
{
var isExist = await _sysPosRep.DetachedEntities.AnyAsync(u => u.Name == input.Name || u.Code == input.Code);
if (isExist)
throw Oops.Oh(ErrorCode.D6000);
var pos = input.Adapt<SysPos>();
await pos.InsertAsync();
}
/// <summary>
/// 删除职位
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysPos/delete")]
public async Task DeletePos(DeletePosInput input)
{
// 该职位下是否有员工
var hasPosEmp = await _sysEmpPosService.HasPosEmp(input.Id);
if (hasPosEmp)
throw Oops.Oh(ErrorCode.D6001);
// 该附属职位下是否有员工
var hasExtPosEmp = await _sysEmpExtOrgPosService.HasExtPosEmp(input.Id);
if (hasExtPosEmp)
throw Oops.Oh(ErrorCode.D6001);
var pos = await _sysPosRep.FirstOrDefaultAsync(u => u.Id == input.Id);
await pos.DeleteAsync();
}
/// <summary>
/// 更新职位
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysPos/edit")]
public async Task UpdatePos(UpdatePosInput input)
{
var isExist = await _sysPosRep.DetachedEntities.AnyAsync(u => (u.Name == input.Name || u.Code == input.Code) && u.Id != input.Id);
if (isExist)
throw Oops.Oh(ErrorCode.D6000);
var pos = input.Adapt<SysPos>();
await pos.UpdateAsync(ignoreNullValues: true);
}
/// <summary>
/// 获取职位
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("/sysPos/detail")]
public async Task<SysPos> GetPos([FromQuery] QueryPosInput input)
{
return await _sysPosRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == input.Id);
}
}
}

View File

@@ -0,0 +1,91 @@
using System.ComponentModel.DataAnnotations;
namespace Ewide.Core.Service
{
/// <summary>
/// 角色参数
/// </summary>
public class RoleInput : InputBase
{
/// <summary>
/// 名称
/// </summary>
public virtual string Name { get; set; }
/// <summary>
/// 编码
/// </summary>
public virtual string Code { get; set; }
/// <summary>
/// 排序
/// </summary>
public int Sort { get; set; }
/// <summary>
/// 数据范围类型(字典 1全部数据 2本部门及以下数据 3本部门数据 4仅本人数据 5自定义数据
/// </summary>
public int DataScopeType { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
}
public class AddRoleInput : RoleInput
{
/// <summary>
/// 名称
/// </summary>
[Required(ErrorMessageResourceName = "角色名称不能为空")]
public override string Name { get; set; }
/// <summary>
/// 编码
/// </summary>
[Required(ErrorMessageResourceName = "角色编码不能为空")]
public override string Code { get; set; }
}
public class DeleteRoleInput
{
/// <summary>
/// 角色Id
/// </summary>
[Required(ErrorMessageResourceName = "角色Id不能为空")]
public string Id { get; set; }
}
public class UpdateRoleInput : AddRoleInput
{
/// <summary>
/// 角色Id
/// </summary>
[Required(ErrorMessageResourceName = "角色Id不能为空")]
public string Id { get; set; }
}
public class QueryRoleInput : DeleteRoleInput
{
}
public class GrantRoleMenuInput : RoleInput
{
/// <summary>
/// 角色Id
/// </summary>
[Required(ErrorMessageResourceName = "角色Id不能为空")]
public string Id { get; set; }
}
public class GrantRoleDataInput : GrantRoleMenuInput
{
}
public class GrantAreaDataInput : GrantRoleMenuInput
{
}
}

View File

@@ -0,0 +1,23 @@
namespace Ewide.Core.Service
{
/// <summary>
/// 登录用户角色参数
/// </summary>
public class RoleOutput
{
/// <summary>
/// Id
/// </summary>
public string Id { get; set; }
/// <summary>
/// 编码
/// </summary>
public string Code { get; set; }
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
}
}

View File

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
public interface ISysRoleAreaService
{
Task DeleteRoleAreaListByAreaCodeList(List<string> areaCodeList);
Task DeleteRoleAreaListByRoleId(string roleId);
Task<List<string>> GetRoleAreaCodeList(List<string> roleIdList);
Task GrantArea(GrantAreaDataInput input);
}
}

View File

@@ -0,0 +1,13 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
public interface ISysRoleDataScopeService
{
Task DeleteRoleDataScopeListByOrgIdList(List<string> orgIdList);
Task DeleteRoleDataScopeListByRoleId(string roleId);
Task<List<string>> GetRoleDataScopeIdList(List<string> roleIdList);
Task GrantDataScope(GrantRoleDataInput input);
}
}

View File

@@ -0,0 +1,13 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
public interface ISysRoleMenuService
{
Task DeleteRoleMenuListByMenuIdList(List<string> menuIdList);
Task DeleteRoleMenuListByRoleId(string roleId);
Task<List<string>> GetRoleMenuIdList(List<string> roleIdList);
Task GrantMenu(GrantRoleMenuInput input);
}
}

View File

@@ -0,0 +1,24 @@
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
public interface ISysRoleService
{
Task AddRole(AddRoleInput input);
Task DeleteRole(DeleteRoleInput input);
Task<string> GetNameByRoleId(string roleId);
Task<dynamic> GetRoleDropDown();
Task<SysRole> GetRoleInfo([FromQuery] QueryRoleInput input);
Task<dynamic> GetRoleList([FromQuery] RoleInput input);
Task<List<RoleOutput>> GetUserRoleList(string userId);
Task GrantData(GrantRoleDataInput input);
Task GrantMenu(GrantRoleMenuInput input);
Task<List<string>> OwnData([FromQuery] QueryRoleInput input);
Task<List<string>> OwnMenu([FromQuery] QueryRoleInput input);
Task<List<string>> OwnArea([FromQuery] QueryRoleInput input);
Task<dynamic> QueryRolePageList([FromQuery] RoleInput input);
Task UpdateRole(UpdateRoleInput input);
}
}

View File

@@ -0,0 +1,64 @@
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Ewide.Core.Service.Role
{
public class SysRoleAreaService : ISysRoleAreaService,ITransient
{
public readonly IRepository<SysRoleArea> _sysRoleAreaRep;
public SysRoleAreaService(IRepository<SysRoleArea> sysRolleAreaRep)
{
_sysRoleAreaRep = sysRolleAreaRep;
}
public async Task DeleteRoleAreaListByAreaCodeList(List<string> areaCodeList)
{
var dataScopes = await _sysRoleAreaRep.DetachedEntities.Where(u => areaCodeList.Contains(u.AreaCode)).ToListAsync();
dataScopes.ForEach(u =>
{
u.Delete();
});
}
public async Task DeleteRoleAreaListByRoleId(string roleId)
{
var dataScopes = await _sysRoleAreaRep.DetachedEntities.Where(u => roleId==u.SysRoleId).ToListAsync();
dataScopes.ForEach(u =>
{
u.Delete();
});
}
public async Task<List<string>> GetRoleAreaCodeList(List<string> roleIdList)
{
return await _sysRoleAreaRep.DetachedEntities.Where(u => roleIdList.Contains(u.SysRoleId)).Select(u=>u.AreaCode).Distinct().ToListAsync();
}
public async Task GrantArea(GrantAreaDataInput input)
{
var dataScopes = await _sysRoleAreaRep.Where(u => u.SysRoleId == input.Id).ToListAsync();
dataScopes.ForEach(u =>
{
u.Delete();
});
input.GrantAreaCodeList.ForEach(u =>
{
new SysRoleArea
{
SysRoleId = input.Id,
AreaCode = u
}.Insert();
});
}
}
}

View File

@@ -0,0 +1,95 @@
using Ewide.Core.Service.Role;
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Mapster;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
/// <summary>
/// 角色数据范围服务
/// </summary>
public class SysRoleDataScopeService : ISysRoleDataScopeService, ITransient
{
private readonly IRepository<SysRoleDataScope> _sysRoleDataScopeRep; // 角色数据范围表仓储
private readonly ISysRoleAreaService _sysRoleAreaService;
public SysRoleDataScopeService(IRepository<SysRoleDataScope> sysRoleDataScopeRep, ISysRoleAreaService sysRoleAreaService)
{
_sysRoleDataScopeRep = sysRoleDataScopeRep;
_sysRoleAreaService = sysRoleAreaService;
}
/// <summary>
/// 授权角色数据范围
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[UnitOfWork]
public async Task GrantDataScope(GrantRoleDataInput input)
{
if (new[] { (int)DataScopeType.AREA, (int)DataScopeType.AREA_WITH_CHILD }.Contains(input.DataScopeType))
{
await _sysRoleAreaService.GrantArea(input.Adapt<GrantAreaDataInput>());
return;
}
var dataScopes = await _sysRoleDataScopeRep.DetachedEntities.Where(u => u.SysRoleId == input.Id).ToListAsync();
dataScopes.ForEach(u =>
{
u.Delete();
});
input.GrantOrgIdList.ForEach(u =>
{
new SysRoleDataScope
{
SysRoleId = input.Id,
SysOrgId = u
}.Insert();
});
}
/// <summary>
/// 根据角色Id集合获取角色数据范围集合
/// </summary>
/// <param name="roleIdList"></param>
/// <returns></returns>
public async Task<List<string>> GetRoleDataScopeIdList(List<string> roleIdList)
{
return await _sysRoleDataScopeRep.DetachedEntities
.Where(u => roleIdList.Contains(u.SysRoleId))
.Select(u => u.SysOrgId).ToListAsync();
}
/// <summary>
/// 根据机构Id集合删除对应的角色-数据范围关联信息
/// </summary>
/// <param name="orgIdList"></param>
/// <returns></returns>
public async Task DeleteRoleDataScopeListByOrgIdList(List<string> orgIdList)
{
var dataScopes = await _sysRoleDataScopeRep.DetachedEntities.Where(u => orgIdList.Contains(u.SysOrgId)).ToListAsync();
dataScopes.ForEach(u =>
{
u.Delete();
});
}
/// <summary>
/// 根据角色Id删除对应的角色-数据范围关联信息
/// </summary>
/// <param name="roleId"></param>
/// <returns></returns>
public async Task DeleteRoleDataScopeListByRoleId(string roleId)
{
var dataScopes = await _sysRoleDataScopeRep.DetachedEntities.Where(u => u.SysRoleId == roleId).ToListAsync();
dataScopes.ForEach(u =>
{
u.Delete();
});
}
}
}

View File

@@ -0,0 +1,93 @@
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
/// <summary>
/// 角色菜单
/// </summary>
public class SysRoleMenuService : ISysRoleMenuService, ITransient
{
private readonly IRepository<SysRoleMenu> _sysRoleMenuRep; // 角色菜单表仓储
private readonly ISysCacheService _sysCacheService;
public SysRoleMenuService(IRepository<SysRoleMenu> sysRoleMenuRep, ISysCacheService sysCacheService)
{
_sysRoleMenuRep = sysRoleMenuRep;
_sysCacheService = sysCacheService;
}
/// <summary>
/// 获取角色的菜单Id集合
/// </summary>
/// <param name="roleIdList"></param>
/// <returns></returns>
public async Task<List<string>> GetRoleMenuIdList(List<string> roleIdList)
{
return await _sysRoleMenuRep.DetachedEntities
.Where(u => roleIdList.Contains(u.SysRoleId))
.Select(u => u.SysMenuId).ToListAsync();
}
/// <summary>
/// 授权角色菜单
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[UnitOfWork]
public async Task GrantMenu(GrantRoleMenuInput input)
{
var roleMenus = await _sysRoleMenuRep.DetachedEntities.Where(u => u.SysRoleId == input.Id).ToListAsync();
roleMenus.ForEach(u =>
{
u.Delete();
});
input.GrantMenuIdList.ForEach(u =>
{
new SysRoleMenu
{
SysRoleId = input.Id,
SysMenuId = u
}.Insert();
});
// 清除缓存
await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_MENU);
await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_PERMISSION);
}
/// <summary>
/// 根据菜单Id集合删除对应的角色-菜单表信息
/// </summary>
/// <param name="menuIdList"></param>
/// <returns></returns>
public async Task DeleteRoleMenuListByMenuIdList(List<string> menuIdList)
{
var roleMenus = await _sysRoleMenuRep.DetachedEntities.Where(u => menuIdList.Contains(u.SysMenuId)).ToListAsync();
roleMenus.ForEach(u =>
{
u.Delete();
});
}
/// <summary>
/// 根据角色Id删除对应的角色-菜单表关联信息
/// </summary>
/// <param name="roleId"></param>
/// <returns></returns>
public async Task DeleteRoleMenuListByRoleId(string roleId)
{
var roleMenus = await _sysRoleMenuRep.DetachedEntities.Where(u => u.SysRoleId == roleId).ToListAsync();
roleMenus.ForEach(u =>
{
u.Delete();
});
}
}
}

View File

@@ -0,0 +1,282 @@
using Ewide.Core.Extension;
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
/// <summary>
/// 角色服务
/// </summary>
[ApiDescriptionSettings(Name = "Role", Order = 149)]
public class SysRoleService : ISysRoleService, IDynamicApiController, ITransient
{
private readonly IRepository<SysRole> _sysRoleRep; // 角色表仓储
private readonly IRepository<SysUserRole> _sysUserRoleRep; // 用户角色表仓储
private readonly IUserManager _userManager;
private readonly ISysRoleDataScopeService _sysRoleDataScopeService;
private readonly ISysOrgService _sysOrgService;
private readonly ISysRoleMenuService _sysRoleMenuService;
public SysRoleService(IRepository<SysRole> sysRoleRep,
IRepository<SysUserRole> sysUserRoleRep,
IUserManager userManager,
ISysRoleDataScopeService sysRoleDataScopeService,
ISysOrgService sysOrgService,
ISysRoleMenuService sysRoleMenuService)
{
_sysRoleRep = sysRoleRep;
_sysUserRoleRep = sysUserRoleRep;
_userManager = userManager;
_sysRoleDataScopeService = sysRoleDataScopeService;
_sysOrgService = sysOrgService;
_sysRoleMenuService = sysRoleMenuService;
}
/// <summary>
/// 获取用户角色相关信息(登录)
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
[NonAction]
public async Task<List<RoleOutput>> GetUserRoleList(string userId)
{
return await _sysRoleRep.DetachedEntities.Join(_sysUserRoleRep.DetachedEntities, u => u.Id, e => e.SysRoleId, (u, e) => new { u, e })
.Where(x => x.e.SysUserId == userId)
.Select(x => x.u.Adapt<RoleOutput>()).ToListAsync();
}
/// <summary>
/// 分页获取角色列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysRole/page")]
public async Task<dynamic> QueryRolePageList([FromBody] RoleInput input)
{
var name = !string.IsNullOrEmpty(input.Name?.Trim());
var code = !string.IsNullOrEmpty(input.Code?.Trim());
var roles = await _sysRoleRep.DetachedEntities
.Where((name, u => EF.Functions.Like(u.Name, $"%{input.Name.Trim()}%")),
(code, u => EF.Functions.Like(u.Code, $"%{input.Code.Trim()}%")))
.Where(u => u.Status == (int)CommonStatus.ENABLE).OrderBy(u => u.Sort)
.ToPageData(input);
return PageDataResult<SysRole>.PageResult(roles);
}
/// <summary>
/// 获取角色列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[NonAction]
public async Task<dynamic> GetRoleList([FromQuery] RoleInput input)
{
var name = !string.IsNullOrEmpty(input.Name?.Trim());
var code = !string.IsNullOrEmpty(input.Code?.Trim());
return await _sysRoleRep.DetachedEntities
.Where((name, u => EF.Functions.Like(u.Name, $"%{input.Name.Trim()}%")),
(code, u => EF.Functions.Like(u.Code, $"%{input.Code.Trim()}%")))
.Where(u => u.Status == (int)CommonStatus.ENABLE).OrderBy(u => u.Sort)
.Select(u => new
{
u.Id,
Name = u.Name + "[" + u.Code + "]"
}).ToListAsync();
}
/// <summary>
/// 角色下拉(用于授权角色时选择)
/// </summary>
/// <returns></returns>
[HttpGet("/sysRole/dropDown")]
public async Task<dynamic> GetRoleDropDown()
{
// 如果不是超级管理员,则查询自己拥有的角色集合
var roles = _userManager.SuperAdmin
? await _sysUserRoleRep.Where(u => u.SysUserId == _userManager.UserId).Select(u => u.SysRoleId).ToListAsync()
: new List<string>();
return await _sysRoleRep.DetachedEntities
.Where(roles.Count > 0, u => roles.Contains(u.Id))
.Where(u => u.Status == (int)CommonStatus.ENABLE)
.Select(u => new
{
u.Id,
u.Code,
u.Name
}).ToListAsync();
}
/// <summary>
/// 增加角色
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysRole/add")]
public async Task AddRole(AddRoleInput input)
{
var isExist = await _sysRoleRep.DetachedEntities.AnyAsync(u => u.Code == input.Code || u.Name == input.Name);
if (isExist)
throw Oops.Oh(ErrorCode.D1006);
var role = input.Adapt<SysRole>();
role.DataScopeType = 1; // 新角色默认全部数据范围
await role.InsertAsync();
}
/// <summary>
/// 删除角色
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysRole/delete")]
[UnitOfWork]
public async Task DeleteRole(DeleteRoleInput input)
{
var sysRole = await _sysRoleRep.FirstOrDefaultAsync(u => u.Id == input.Id);
await sysRole.DeleteAsync();
//级联删除该角色对应的角色-数据范围关联信息
await _sysRoleDataScopeService.DeleteRoleDataScopeListByRoleId(sysRole.Id);
////级联删除该角色对应的用户-角色表关联信息
//await _sysUserRoleService.DeleteUserRoleListByRoleId(sysRole.Id); // 避免循环引用,故用下面逻辑
var userRoles = await _sysUserRoleRep.Where(u => u.SysRoleId == sysRole.Id).ToListAsync();
userRoles.ForEach(u =>
{
u.Delete();
});
//级联删除该角色对应的角色-菜单表关联信息
await _sysRoleMenuService.DeleteRoleMenuListByRoleId(sysRole.Id);
}
/// <summary>
/// 更新角色
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysRole/edit")]
public async Task UpdateRole(UpdateRoleInput input)
{
var isExist = await _sysRoleRep.DetachedEntities.AnyAsync(u => (u.Name == input.Name || u.Code == input.Code) && u.Id != input.Id);
if (isExist)
throw Oops.Oh(ErrorCode.D1006);
var sysRole = input.Adapt<SysRole>();
await sysRole.UpdateAsync();
}
/// <summary>
/// 获取角色
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("/sysRole/detail")]
public async Task<SysRole> GetRoleInfo([FromQuery] QueryRoleInput input)
{
return await _sysRoleRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == input.Id);
}
/// <summary>
/// 授权角色菜单
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysRole/grantMenu")]
public async Task GrantMenu(GrantRoleMenuInput input)
{
await _sysRoleMenuService.GrantMenu(input);
}
/// <summary>
/// 授权角色数据
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysRole/grantData")]
public async Task GrantData(GrantRoleDataInput input)
{
var role = await _sysRoleRep.FirstOrDefaultAsync(u => u.Id == input.Id);
var dataScopeType = input.DataScopeType;
if (!_userManager.SuperAdmin)
{
//如果授权的角色的数据范围类型为全部,则没权限,只有超级管理员有
if ((int)DataScopeType.ALL == dataScopeType)
throw Oops.Oh(ErrorCode.D1016);
//如果授权的角色数据范围类型为自定义,则要判断授权的数据范围是否在自己的数据范围内
if ((int)DataScopeType.DEFINE == dataScopeType)
{
var dataScopes = await _userManager.GetUserAllDataScopeList();
var grantOrgIdList = input.GrantOrgIdList; //要授权的数据范围列表
if (grantOrgIdList.Count > 0)
{
if (dataScopes.Count < 1)
throw Oops.Oh(ErrorCode.D1016);
else if (!dataScopes.All(u => grantOrgIdList.Any(c => c == u)))
throw Oops.Oh(ErrorCode.D1016);
}
}
}
role.DataScopeType = dataScopeType;
await _sysRoleDataScopeService.GrantDataScope(input);
}
/// <summary>
/// 根据角色Id获取角色名称
/// </summary>
/// <param name="roleId"></param>
/// <returns></returns>
[NonAction]
public async Task<string> GetNameByRoleId(string roleId)
{
var role = await _sysRoleRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == roleId);
if (role == null)
throw Oops.Oh(ErrorCode.D1002);
return role.Name;
}
/// <summary>
/// 获取角色拥有菜单Id集合
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("/sysRole/ownMenu")]
public async Task<List<string>> OwnMenu([FromQuery] QueryRoleInput input)
{
return await _sysRoleMenuService.GetRoleMenuIdList(new List<string> { input.Id });
}
/// <summary>
/// 获取角色拥有数据Id集合
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("/sysRole/ownData")]
public async Task<List<string>> OwnData([FromQuery] QueryRoleInput input)
{
return await _userManager.GetRoleExtraDataScopeList(input.Id);
}
/// <summary>
/// 获取角色拥有区域Id集合
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("/sysRole/ownArea")]
public Task<List<string>> OwnArea([FromQuery] QueryRoleInput input)
{
return _userManager.GetRoleExtraAreaScopeList(input.Id);
}
}
}

View File

@@ -0,0 +1,94 @@
using System.ComponentModel.DataAnnotations;
namespace Ewide.Core.Service
{
/// <summary>
/// 租户参数
/// </summary>
public class TenantInput : PageInputBase
{
/// <summary>
/// 名称
/// </summary>
public virtual string Name { get; set; }
/// <summary>
/// 主机
/// </summary>
public virtual string Host { get; set; }
/// <summary>
/// 电子邮箱
/// </summary>
public string Email { get; set; }
/// <summary>
/// 电话号码
/// </summary>
public string Phone { get; set; }
/// <summary>
/// 模式
/// </summary>
public string Schema { get; set; }
/// <summary>
/// 数据库连接
/// </summary>
public virtual string Connection { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public string CreatedTime { get; set; }
}
public class AddTenantInput : TenantInput
{
/// <summary>
/// 租户名称
/// </summary>
[Required(ErrorMessage = "租户名称不能为空")]
public override string Name { get; set; }
/// <summary>
/// 主机名称
/// </summary>
[Required(ErrorMessage = "主机名称不能为空")]
public override string Host { get; set; }
/// <summary>
/// 数据库连接
/// </summary>
[Required(ErrorMessage = "数据库连接不能为空")]
public override string Connection { get; set; }
}
public class DeleteTenantInput
{
/// <summary>
/// 租户Id
/// </summary>
[Required(ErrorMessage = "租户Id不能为空")]
public string Id { get; set; }
}
public class UpdateTenantInput : TenantInput
{
/// <summary>
/// 租户Id
/// </summary>
[Required(ErrorMessage = "租户Id不能为空")]
public string Id { get; set; }
}
public class QueryTenantInput : DeleteTenantInput
{
}
}

View File

@@ -0,0 +1,53 @@
namespace Ewide.Core.Service
{
/// <summary>
/// 租户参数
/// </summary>
public class TenantOutput
{
/// <summary>
/// 租户Id
/// </summary>
public long Id { get; set; }
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 主机
/// </summary>
public string Host { get; set; }
/// <summary>
/// 电子邮箱
/// </summary>
public string Email { get; set; }
/// <summary>
/// 电话号码
/// </summary>
public string Phone { get; set; }
/// <summary>
/// 模式
/// </summary>
public string Schema { get; set; }
/// <summary>
/// 数据库连接
/// </summary>
public string Connection { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public string CreatedTime { get; set; }
}
}

View File

@@ -0,0 +1,14 @@
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
public interface ISysTenantService
{
Task AddTenant(AddTenantInput input);
Task DeleteTenant(DeleteTenantInput input);
Task<SysTenant> GetTenant([FromQuery] QueryTenantInput input);
Task<dynamic> QueryTenantPageList([FromQuery] TenantInput input);
Task UpdateTenant(UpdateTenantInput input);
}
}

View File

@@ -0,0 +1,100 @@
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
/// <summary>
/// 租户服务
/// </summary>
[ApiDescriptionSettings(Name = "Tenant", Order = 100)]
public class SysTenantService : ISysTenantService, IDynamicApiController, ITransient
{
private readonly IRepository<SysTenant, MultiTenantDbContextLocator> _sysTenantRep; // 租户表仓储
public SysTenantService(IRepository<SysTenant, MultiTenantDbContextLocator> sysTenantRep)
{
_sysTenantRep = sysTenantRep;
}
/// <summary>
/// 分页查询租户
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysTenant/page")]
public async Task<dynamic> QueryTenantPageList([FromBody] TenantInput input)
{
var name = !string.IsNullOrEmpty(input.Name?.Trim());
var host = !string.IsNullOrEmpty(input.Host?.Trim());
var tenants = await _sysTenantRep.DetachedEntities
.Where((name, u => EF.Functions.Like(u.Name, $"%{input.Name.Trim()}%")),
(host, u => EF.Functions.Like(u.Host, $"%{input.Host.Trim()}%")))
.Select(u => u.Adapt<TenantOutput>())
.ToPagedListAsync(input.PageIndex, input.PageSize);
return PageDataResult<TenantOutput>.PageResult(tenants);
}
/// <summary>
/// 增加租户
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysTenant/add")]
public async Task AddTenant(AddTenantInput input)
{
var isExist = await _sysTenantRep.DetachedEntities.AnyAsync(u => u.Name == input.Name || u.Host == input.Host);
if (isExist)
throw Oops.Oh(ErrorCode.D1300);
var tenant = input.Adapt<SysTenant>();
await _sysTenantRep.InsertAsync(tenant);
}
/// <summary>
/// 删除租户
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysTenant/delete")]
public async Task DeleteTenant(DeleteTenantInput input)
{
var tenant = await _sysTenantRep.FirstOrDefaultAsync(u => u.Id == input.Id);
await _sysTenantRep.DeleteAsync(tenant);
}
/// <summary>
/// 更新租户
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/sysTenant/edit")]
public async Task UpdateTenant(UpdateTenantInput input)
{
var isExist = await _sysTenantRep.DetachedEntities.AnyAsync(u => (u.Name == input.Name || u.Host == input.Host) && u.Id != input.Id);
if (isExist)
throw Oops.Oh(ErrorCode.D1300);
var tenant = input.Adapt<SysTenant>();
await _sysTenantRep.UpdateAsync(tenant, true);
}
/// <summary>
/// 获取租户
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("/sysTenant/detail")]
public async Task<SysTenant> GetTenant([FromQuery] QueryTenantInput input)
{
return await _sysTenantRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == input.Id);
}
}
}

View File

@@ -0,0 +1,230 @@
using Furion.DataValidation;
using Furion.TaskScheduler;
using System;
using System.ComponentModel.DataAnnotations;
namespace Ewide.Core.Service
{
/// <summary>
/// 任务调度参数
/// </summary>
public class JobPageInput : PageInputBase
{
/// <summary>
/// 任务名称
/// </summary>
public string JobName { get; set; }
/// <summary>
/// 只执行一次
/// </summary>
public bool DoOnce { get; set; } = false;
/// <summary>
/// 立即执行(默认等待启动)
/// </summary>
public bool StartNow { get; set; } = false;
/// <summary>
/// 执行类型(并行、列队)
/// </summary>
public SpareTimeExecuteTypes ExecuteType { get; set; }
/// <summary>
/// 执行间隔时间(单位秒)
/// </summary>
/// <example>5</example>
public int Interval { get; set; }
/// <summary>
/// Cron表达式
/// </summary>
public string Cron { get; set; }
/// <summary>
/// 定时器类型
/// </summary>
public SpareTimeTypes TimerType { get; set; }
/// <summary>
/// 请求url
/// </summary>
public string RequestUrl { get; set; }
/// <summary>
/// 请求参数PostPut请求用
/// </summary>
public string RequestParameters { get; set; }
/// <summary>
/// Headers(可以包含如Authorization授权认证)
/// 格式:{"Authorization":"userpassword.."}
/// </summary>
public string Headers { get; set; }
/// <summary>
/// 请求类型
/// </summary>
public RequestTypeEnum RequestType { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
}
public class AddJobInput
{
/// <summary>
/// 任务名称
/// </summary>
public string JobName { get; set; }
/// <summary>
/// 只执行一次
/// </summary>
public bool DoOnce { get; set; } = false;
/// <summary>
/// 立即执行(默认等待启动)
/// </summary>
public bool StartNow { get; set; } = false;
/// <summary>
/// 执行类型(并行、列队)
/// </summary>
public SpareTimeExecuteTypes ExecuteType { get; set; }
/// <summary>
/// 执行间隔时间(单位秒)
/// </summary>
/// <example>5</example>
public int Interval { get; set; }
/// <summary>
/// Cron表达式
/// </summary>
public string Cron { get; set; }
/// <summary>
/// 定时器类型
/// </summary>
public SpareTimeTypes TimerType { get; set; }
/// <summary>
/// 请求url
/// </summary>
public string RequestUrl { get; set; }
/// <summary>
/// 请求参数PostPut请求用
/// </summary>
public string RequestParameters { get; set; }
/// <summary>
/// Headers(可以包含如Authorization授权认证)
/// 格式:{"Authorization":"userpassword.."}
/// </summary>
public string Headers { get; set; }
/// <summary>
/// 请求类型
/// </summary>
public RequestTypeEnum RequestType { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
}
public class StopJobInput
{
public string JobName { get; set; }
}
public class DeleteJobInput : QueryJobInput
{
}
public class UpdateJobInput : QueryJobInput
{
/// <summary>
/// 任务名称
/// </summary>
/// <example>dilon</example>
[Required, MaxLength(20)]
public string JobName { get; set; }
/// <summary>
/// 只执行一次
/// </summary>
public bool DoOnce { get; set; } = false;
/// <summary>
/// 立即执行(默认等待启动)
/// </summary>
public bool StartNow { get; set; } = false;
/// <summary>
/// 执行类型(并行、列队)
/// </summary>
public SpareTimeExecuteTypes ExecuteType { get; set; } = SpareTimeExecuteTypes.Parallel;
/// <summary>
/// 执行间隔时间(单位秒)
/// </summary>
/// <example>5</example>
public int? Interval { get; set; } = 5;
/// <summary>
/// Cron表达式
/// </summary>
/// <example></example>
[MaxLength(20)]
public string Cron { get; set; }
/// <summary>
/// 定时器类型
/// </summary>
public SpareTimeTypes TimerType { get; set; } = SpareTimeTypes.Interval;
/// <summary>
/// 请求url
/// </summary>
[MaxLength(200)]
public string RequestUrl { get; set; }
/// <summary>
/// 请求参数PostPut请求用
/// </summary>
public string RequestParameters { get; set; }
/// <summary>
/// Headers(可以包含如Authorization授权认证)
/// 格式:{"Authorization":"userpassword.."}
/// </summary>
public string Headers { get; set; }
/// <summary>
/// 请求类型
/// </summary>
/// <example>2</example>
public RequestTypeEnum RequestType { get; set; } = RequestTypeEnum.Post;
/// <summary>
/// 备注
/// </summary>
[MaxLength(100)]
public string Remark { get; set; }
}
public class QueryJobInput
{
[Required(ErrorMessage = "Id不能为空")]
public string Id { get; set; }
}
}

View File

@@ -0,0 +1,150 @@
using Furion.TaskScheduler;
using Quartz;
using System;
namespace Ewide.Core.Service
{
/// <summary>
/// 任务信息---任务详情
/// </summary>
public class JobOutput
{
/// <summary>
/// Id
/// </summary>
public string Id { get; set; }
/// <summary>
/// 已执行次数
/// </summary>
public long? RunNumber { get; set; }
/// <summary>
/// 定时器状态
/// </summary>
public SpareTimeStatus TimerStatus { get; set; } = SpareTimeStatus.Stopped;
/// <summary>
/// 异常信息
/// </summary>
public string Exception { get; set; }
/// <summary>
/// 任务名称
/// </summary>
public string JobName { get; set; }
/// <summary>
/// 只执行一次
/// </summary>
public bool DoOnce { get; set; } = false;
/// <summary>
/// 立即执行(默认等待启动)
/// </summary>
public bool StartNow { get; set; } = false;
/// <summary>
/// 执行类型(并行、列队)
/// </summary>
public SpareTimeExecuteTypes ExecuteType { get; set; }
/// <summary>
/// 执行间隔时间(单位秒)
/// </summary>
public int Interval { get; set; }
/// <summary>
/// Cron表达式
/// </summary>
public string Cron { get; set; }
/// <summary>
/// 定时器类型
/// </summary>
public SpareTimeTypes TimerType { get; set; }
/// <summary>
/// 请求url
/// </summary>
public string RequestUrl { get; set; }
/// <summary>
/// 请求类型
/// </summary>
/// <example>2</example>
public RequestTypeEnum RequestType { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
}
/// <summary>
/// 任务方法信息
/// </summary>
public class TaskMethodInfo
{
/// <summary>
/// 方法名
/// </summary>
public string MethodName { get; set; }
/// <summary>
/// 方法所属类的Type对象
/// </summary>
public Type DeclaringType { get; set; }
/// <summary>
/// 任务名称
/// </summary>
public string JobName { get; set; }
/// <summary>
/// 只执行一次
/// </summary>
public bool DoOnce { get; set; } = false;
/// <summary>
/// 立即执行(默认等待启动)
/// </summary>
public bool StartNow { get; set; } = false;
/// <summary>
/// 执行类型(并行、列队)
/// </summary>
public SpareTimeExecuteTypes ExecuteType { get; set; }
/// <summary>
/// 执行间隔时间(单位秒)
/// </summary>
public int Interval { get; set; }
/// <summary>
/// Cron表达式
/// </summary>
public string Cron { get; set; }
/// <summary>
/// 定时器类型
/// </summary>
public SpareTimeTypes TimerType { get; set; }
/// <summary>
/// 请求url
/// </summary>
public string RequestUrl { get; set; }
/// <summary>
/// 请求类型
/// </summary>
/// <example>2</example>
public RequestTypeEnum RequestType { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
}
}

View File

@@ -0,0 +1,68 @@
using Furion.JsonSerialization;
using Furion.RemoteRequest.Extensions;
using Quartz;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
[DisallowConcurrentExecution]
public class HttpJob : IJob
{
//protected readonly int _maxLogCount = 20; //最多保存日志数量
//protected Stopwatch _stopwatch = new();
public async Task Execute(IJobExecutionContext context)
{
// 获取相关参数
var requestUrl = context.JobDetail.JobDataMap.GetString(SchedulerDef.REQUESTURL)?.Trim();
requestUrl = requestUrl?.IndexOf("http") == 0 ? requestUrl : "http://" + requestUrl;
var requestParameters = context.JobDetail.JobDataMap.GetString(SchedulerDef.REQUESTPARAMETERS);
var headersString = context.JobDetail.JobDataMap.GetString(SchedulerDef.HEADERS);
var headers = !string.IsNullOrWhiteSpace(headersString) ? JSON.GetJsonSerializer().Deserialize<Dictionary<string, string>>(headersString.Trim()) : null;
var requestType = (RequestTypeEnum)int.Parse(context.JobDetail.JobDataMap.GetString(SchedulerDef.REQUESTTYPE));
// var response = new HttpResponseMessage();
switch (requestType)
{
case RequestTypeEnum.Get:
await requestUrl.SetHeaders(headers).GetAsync();
break;
case RequestTypeEnum.Post:
await requestUrl.SetHeaders(headers).SetQueries(requestParameters).PostAsync();
break;
case RequestTypeEnum.Put:
await requestUrl.SetHeaders(headers).SetQueries(requestParameters).PutAsync();
break;
case RequestTypeEnum.Delete:
await requestUrl.SetHeaders(headers).DeleteAsync();
break;
}
//_stopwatch.Restart(); // 开始监视代码运行时间
//// var beginTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
//Debug.WriteLine(DateTimeOffset.Now.ToString());
//// var endTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
//_stopwatch.Stop(); // 停止监视
////// 执行次数
////var runNumber = context.JobDetail.JobDataMap.GetString(SchedulerDef.RUNNUMBER);
////context.JobDetail.JobDataMap[SchedulerDef.RUNNUMBER] = runNumber;
//// 耗时
//var seconds = _stopwatch.Elapsed.TotalSeconds; // 总秒数
//var executeTime = seconds >= 1 ? seconds + "秒" : _stopwatch.Elapsed.TotalMilliseconds + "毫秒";
////// 只保留20条记录
////var logs = context.JobDetail.JobDataMap[SchedulerDef.LOGLIST] as List<string> ?? new List<string>();
////if (logs.Count >= _maxLogCount)
//// logs.RemoveRange(0, logs.Count - _maxLogCount);
////logs.Add($"<p class='msgList'><span class='time'>{beginTime} 至 {endTime} 【耗时】{executeTime}</span></p>");
////context.JobDetail.JobDataMap[SchedulerDef.LOGLIST] = logs;
}
}
}

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