This commit is contained in:
100
Api/Dilon.Core/Service/App/Dto/AppInput.cs
Normal file
100
Api/Dilon.Core/Service/App/Dto/AppInput.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Dilon.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 string 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 long Id { get; set; }
|
||||
}
|
||||
|
||||
public class UpdateAppInput : AppInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 应用Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "应用Id不能为空")]
|
||||
public long Id { get; set; }
|
||||
}
|
||||
|
||||
public class QueryAppInput : DeleteAppInput
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class SetDefaultAppInput : DeleteAppInput
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
33
Api/Dilon.Core/Service/App/Dto/AppOutput.cs
Normal file
33
Api/Dilon.Core/Service/App/Dto/AppOutput.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 系统应用参数
|
||||
/// </summary>
|
||||
public class AppOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// 应用Id
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 编码
|
||||
/// </summary>
|
||||
public string Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否默认
|
||||
/// </summary>
|
||||
public string Active { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序
|
||||
/// </summary>
|
||||
public int Sort { get; set; }
|
||||
}
|
||||
}
|
||||
18
Api/Dilon.Core/Service/App/ISysAppService.cs
Normal file
18
Api/Dilon.Core/Service/App/ISysAppService.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.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(long userId);
|
||||
Task<dynamic> QueryAppPageList([FromQuery] AppInput input);
|
||||
Task SetAsDefault(SetDefaultAppInput input);
|
||||
Task UpdateApp(UpdateAppInput input);
|
||||
Task ChangeUserAppStatus(UpdateAppInput input);
|
||||
}
|
||||
}
|
||||
198
Api/Dilon.Core/Service/App/SysAppService.cs
Normal file
198
Api/Dilon.Core/Service/App/SysAppService.cs
Normal file
@@ -0,0 +1,198 @@
|
||||
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 Dilon.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(long 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
|
||||
{
|
||||
Code = u.Code,
|
||||
Name = u.Name,
|
||||
Active = u.Active
|
||||
}).ToListAsync(); // .OrderByDescending(u => u.Active) // 将激活的放到第一个
|
||||
|
||||
//// 默认激活第一个应用
|
||||
//if (appList != null && appList.Count > 0 && appList[0].Active != YesOrNot.Y.ToString())
|
||||
// appList[0].Active = YesOrNot.Y.ToString();
|
||||
return appList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分页查询系统应用
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("/sysApp/page")]
|
||||
public async Task<dynamic> QueryAppPageList([FromQuery] AppInput input)
|
||||
{
|
||||
var name = !string.IsNullOrEmpty(input.Name?.Trim());
|
||||
var code = !string.IsNullOrEmpty(input.Code?.Trim());
|
||||
var apps = await _sysAppRep.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)
|
||||
.ToPagedListAsync(input.PageNo, input.PageSize);
|
||||
return XnPageResult<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 == YesOrNot.Y.ToString())
|
||||
{
|
||||
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 == YesOrNot.Y.ToString())
|
||||
{
|
||||
isExist = await _sysAppRep.DetachedEntities.AnyAsync(u => u.Active == input.Active);
|
||||
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).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 = YesOrNot.N.ToString();
|
||||
});
|
||||
|
||||
var app = await _sysAppRep.FirstOrDefaultAsync(u => u.Id == input.Id);
|
||||
app.Active = YesOrNot.Y.ToString();
|
||||
}
|
||||
|
||||
/// <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;
|
||||
}
|
||||
}
|
||||
}
|
||||
227
Api/Dilon.Core/Service/Auth/AuthService.cs
Normal file
227
Api/Dilon.Core/Service/Auth/AuthService.cs
Normal file
@@ -0,0 +1,227 @@
|
||||
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.Threading.Tasks;
|
||||
using UAParser;
|
||||
|
||||
namespace Dilon.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("/login")]
|
||||
[AllowAnonymous]
|
||||
public async Task<string> LoginAsync([Required] LoginInput input)
|
||||
{
|
||||
// 获取加密后的密码
|
||||
var encryptPasswod = MD5Encryption.Encrypt(input.Password);
|
||||
|
||||
// 判断用户名和密码是否正确
|
||||
var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Account.Equals(input.Account) && u.Password.Equals(encryptPasswod));
|
||||
_ = user ?? throw Oops.Oh(ErrorCode.D1000);
|
||||
|
||||
// 验证账号是否被冻结
|
||||
if (user.Status == CommonStatus.DISABLE)
|
||||
throw Oops.Oh(ErrorCode.D1017);
|
||||
|
||||
// 生成Token令牌
|
||||
//var accessToken = await _jwtBearerManager.CreateTokenAdmin(user);
|
||||
var accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>
|
||||
{
|
||||
{ ClaimConst.CLAINM_USERID, user.Id },
|
||||
{ ClaimConst.CLAINM_ACCOUNT, user.Account },
|
||||
{ ClaimConst.CLAINM_NAME, user.Name },
|
||||
{ ClaimConst.CLAINM_SUPERADMIN, user.AdminType },
|
||||
});
|
||||
|
||||
// 设置Swagger自动登录
|
||||
_httpContextAccessor.SigninToSwagger(accessToken);
|
||||
|
||||
// 生成刷新Token令牌
|
||||
var refreshToken = JWTEncryption.GenerateRefreshToken(accessToken, 30);
|
||||
|
||||
// 设置刷新Token令牌
|
||||
_httpContextAccessor.HttpContext.Response.Headers["x-access-token"] = refreshToken;
|
||||
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前登录用户信息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("/getLoginUser")]
|
||||
public async Task<LoginOutput> GetLoginUserAsync()
|
||||
{
|
||||
var user = _userManager.User;
|
||||
var userId = user.Id;
|
||||
|
||||
var httpContext = App.GetService<IHttpContextAccessor>().HttpContext;
|
||||
var loginOutput = user.Adapt<LoginOutput>();
|
||||
|
||||
loginOutput.LastLoginTime = user.LastLoginTime = DateTimeOffset.Now;
|
||||
var ip = httpContext.Request.Headers["X-Real-IP"].FirstOrDefault();
|
||||
loginOutput.LastLoginIp = user.LastLoginIp = string.IsNullOrEmpty(user.LastLoginIp) ? httpContext.GetRemoteIpAddressToIPv4() : ip;
|
||||
|
||||
//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 _sysUserService.GetUserDataScopeIdList(userId);
|
||||
|
||||
// 具备应用信息(多系统,默认激活一个,可根据系统切换菜单),返回的结果中第一个为激活的系统
|
||||
loginOutput.Apps = await _sysAppService.GetLoginApps(userId);
|
||||
|
||||
// 菜单信息
|
||||
if (loginOutput.Apps.Count > 0)
|
||||
{
|
||||
var defaultActiveAppCode = loginOutput.Apps.FirstOrDefault(u => u.Active == YesOrNot.Y.ToString()).Code; // loginOutput.Apps[0].Code;
|
||||
loginOutput.Menus = await _sysMenuService.GetLoginMenusAntDesign(userId, defaultActiveAppCode);
|
||||
}
|
||||
|
||||
// 增加登录日志
|
||||
await new SysLogVis
|
||||
{
|
||||
Name = "登录",
|
||||
Success = YesOrNot.Y.ToString(),
|
||||
Message = "登录成功",
|
||||
Ip = loginOutput.LastLoginIp,
|
||||
Browser = loginOutput.LastLoginBrowser,
|
||||
Os = loginOutput.LastLoginOs,
|
||||
VisType = 1,
|
||||
VisTime = loginOutput.LastLoginTime,
|
||||
Account = loginOutput.Account
|
||||
}.InsertAsync();
|
||||
|
||||
return loginOutput;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 退出
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("/logout")]
|
||||
public async Task LogoutAsync()
|
||||
{
|
||||
_httpContextAccessor.SignoutToSwagger();
|
||||
//_httpContextAccessor.HttpContext.Response.Headers["access-token"] = "invalid token";
|
||||
|
||||
// 增加退出日志
|
||||
await new SysLogVis
|
||||
{
|
||||
Name = "退出",
|
||||
Success = YesOrNot.Y.ToString(),
|
||||
Message = "退出成功",
|
||||
VisType = 2
|
||||
}.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));
|
||||
}
|
||||
}
|
||||
}
|
||||
26
Api/Dilon.Core/Service/Auth/Dto/LoginInput.cs
Normal file
26
Api/Dilon.Core/Service/Auth/Dto/LoginInput.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Furion.DependencyInjection;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 登录输入参数
|
||||
/// </summary>
|
||||
[SkipScan]
|
||||
public class LoginInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户名
|
||||
/// </summary>
|
||||
/// <example>superAdmin</example>
|
||||
[Required(ErrorMessage = "用户名不能为空"), MinLength(3, ErrorMessage = "用户名不能少于3位字符")]
|
||||
public string Account { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
/// <example>123456</example>
|
||||
[Required(ErrorMessage = "密码不能为空"), MinLength(5, ErrorMessage = "密码不能少于5位字符")]
|
||||
public string Password { get; set; }
|
||||
}
|
||||
}
|
||||
163
Api/Dilon.Core/Service/Auth/Dto/LoginOutput.cs
Normal file
163
Api/Dilon.Core/Service/Auth/Dto/LoginOutput.cs
Normal file
@@ -0,0 +1,163 @@
|
||||
using Furion.DependencyInjection;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户登录输出参数
|
||||
/// </summary>
|
||||
[SkipScan]
|
||||
public class LoginOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// 主键
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 账号
|
||||
/// </summary>
|
||||
public string Account { 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 DateTimeOffset 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 DateTimeOffset 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<long> DataScopes { get; set; } = new List<long>();
|
||||
|
||||
///// <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; }
|
||||
}
|
||||
}
|
||||
15
Api/Dilon.Core/Service/Auth/IAuthService.cs
Normal file
15
Api/Dilon.Core/Service/Auth/IAuthService.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
public interface IAuthService
|
||||
{
|
||||
Task<dynamic> GetCaptcha();
|
||||
Task<bool> GetCaptchaOpen();
|
||||
Task<LoginOutput> GetLoginUserAsync();
|
||||
Task<string> LoginAsync([Required] LoginInput input);
|
||||
Task LogoutAsync();
|
||||
Task<dynamic> VerificationCode(ClickWordCaptchaInput input);
|
||||
}
|
||||
}
|
||||
21
Api/Dilon.Core/Service/Cache/ISysCacheService.cs
Normal file
21
Api/Dilon.Core/Service/Cache/ISysCacheService.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
public interface ISysCacheService
|
||||
{
|
||||
Task<bool> DelAsync(string key);
|
||||
Task<bool> DelByPatternAsync(string key);
|
||||
List<string> GetAllCacheKeys();
|
||||
Task<List<long>> GetDataScope(long userId);
|
||||
Task<List<AntDesignTreeNode>> GetMenu(long userId, string appCode);
|
||||
Task<List<string>> GetPermission(long userId);
|
||||
Task SetDataScope(long userId, List<long> dataScopes);
|
||||
Task SetMenu(long userId, string appCode, List<AntDesignTreeNode> menus);
|
||||
Task SetPermission(long userId, List<string> permissions);
|
||||
Task<bool> SetAsync(string key, object value);
|
||||
Task<string> GetAsync(string key);
|
||||
Task<T> GetAsync<T>(string key);
|
||||
}
|
||||
}
|
||||
169
Api/Dilon.Core/Service/Cache/SysCacheService.cs
Normal file
169
Api/Dilon.Core/Service/Cache/SysCacheService.cs
Normal file
@@ -0,0 +1,169 @@
|
||||
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 Dilon.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<long>> GetDataScope(long userId)
|
||||
{
|
||||
var cacheKey = CommonConst.CACHE_KEY_DATASCOPE + $"{userId}";
|
||||
return await _cache.GetAsync<List<long>>(cacheKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 缓存数据范围(机构Id集合)
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="dataScopes"></param>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
public async Task SetDataScope(long userId, List<long> 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(long 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(long 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(long 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(long 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
207
Api/Dilon.Core/Service/CodeGen/CodeGenConfigService.cs
Normal file
207
Api/Dilon.Core/Service/CodeGen/CodeGenConfigService.cs
Normal 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 Dilon.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(long 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
348
Api/Dilon.Core/Service/CodeGen/CodeGenService.cs
Normal file
348
Api/Dilon.Core/Service/CodeGen/CodeGenService.cs
Normal 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 Dilon.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>
|
||||
[HttpGet("/codeGenerate/page")]
|
||||
public async Task<dynamic> QueryCodeGenPageList([FromQuery] 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.PageNo, input.PageSize);
|
||||
return XnPageResult<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 menuType0 = new SysMenu
|
||||
{
|
||||
Pid = 0,
|
||||
Pids = "[0],",
|
||||
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 + @"\Dilon.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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
88
Api/Dilon.Core/Service/CodeGen/Dto/CodeGenConfig.cs
Normal file
88
Api/Dilon.Core/Service/CodeGen/Dto/CodeGenConfig.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 代码生成详细配置参数
|
||||
/// </summary>
|
||||
public class CodeGenConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 主键
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 代码生成主表ID
|
||||
/// </summary>
|
||||
public long 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; }
|
||||
}
|
||||
}
|
||||
124
Api/Dilon.Core/Service/CodeGen/Dto/CodeGenInput.cs
Normal file
124
Api/Dilon.Core/Service/CodeGen/Dto/CodeGenInput.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 代码生成参数类
|
||||
/// </summary>
|
||||
public class CodeGenInput : XnInputBase
|
||||
{
|
||||
/// <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 long Id { get; set; }
|
||||
}
|
||||
|
||||
public class UpdateCodeGenInput : CodeGenInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 代码生成器Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "代码生成器Id不能为空")]
|
||||
public long Id { get; set; }
|
||||
}
|
||||
|
||||
public class QueryCodeGenInput : DeleteCodeGenInput
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
53
Api/Dilon.Core/Service/CodeGen/Dto/CodeGenOutput.cs
Normal file
53
Api/Dilon.Core/Service/CodeGen/Dto/CodeGenOutput.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
namespace Dilon.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; }
|
||||
}
|
||||
}
|
||||
28
Api/Dilon.Core/Service/CodeGen/Dto/TableColumnOuput.cs
Normal file
28
Api/Dilon.Core/Service/CodeGen/Dto/TableColumnOuput.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
namespace Dilon.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; }
|
||||
}
|
||||
}
|
||||
28
Api/Dilon.Core/Service/CodeGen/Dto/TableOutput.cs
Normal file
28
Api/Dilon.Core/Service/CodeGen/Dto/TableOutput.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
namespace Dilon.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; }
|
||||
}
|
||||
}
|
||||
52
Api/Dilon.Core/Service/CodeGen/Dto/XnCodeGenOutput.cs
Normal file
52
Api/Dilon.Core/Service/CodeGen/Dto/XnCodeGenOutput.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
public class XnCodeGenOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// 作者姓名
|
||||
/// </summary>
|
||||
public string AuthorName { 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 TableNameAss { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 代码包名
|
||||
/// </summary>
|
||||
public string PackageName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 生成时间(string类型的)
|
||||
/// </summary>
|
||||
public string CreateTimestring { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据库表中字段集合
|
||||
/// </summary>
|
||||
public List<SysCodeGenConfig> ConfigList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 业务名
|
||||
/// </summary>
|
||||
public string BusName { get; set; }
|
||||
}
|
||||
}
|
||||
17
Api/Dilon.Core/Service/CodeGen/ICodeGenConfigService.cs
Normal file
17
Api/Dilon.Core/Service/CodeGen/ICodeGenConfigService.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
public interface ICodeGenConfigService
|
||||
{
|
||||
Task Add(CodeGenConfig input);
|
||||
void AddList(List<TableColumnOuput> tableColumnOuputList, SysCodeGen codeGenerate);
|
||||
string ConvertDataType(string dataType);
|
||||
Task Delete(long codeGenId);
|
||||
Task<SysCodeGenConfig> Detail(CodeGenConfig input);
|
||||
Task<List<CodeGenConfig>> List([FromQuery] CodeGenConfig input);
|
||||
Task Update(List<CodeGenConfig> inputList);
|
||||
}
|
||||
}
|
||||
18
Api/Dilon.Core/Service/CodeGen/ICodeGenService.cs
Normal file
18
Api/Dilon.Core/Service/CodeGen/ICodeGenService.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.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);
|
||||
}
|
||||
}
|
||||
83
Api/Dilon.Core/Service/Config/Dto/ConfigInput.cs
Normal file
83
Api/Dilon.Core/Service/Config/Dto/ConfigInput.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Dilon.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 long Id { get; set; }
|
||||
}
|
||||
|
||||
public class UpdateConfigInput : AddConfigInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 应用Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "应用Id不能为空")]
|
||||
public long Id { get; set; }
|
||||
}
|
||||
|
||||
public class QueryConfigInput : DeleteConfigInput
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
18
Api/Dilon.Core/Service/Config/ISysConfigService.cs
Normal file
18
Api/Dilon.Core/Service/Config/ISysConfigService.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.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);
|
||||
}
|
||||
}
|
||||
168
Api/Dilon.Core/Service/Config/SysConfigService.cs
Normal file
168
Api/Dilon.Core/Service/Config/SysConfigService.cs
Normal file
@@ -0,0 +1,168 @@
|
||||
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 Dilon.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>
|
||||
[HttpGet("/sysConfig/page")]
|
||||
public async Task<dynamic> QueryConfigPageList([FromQuery] 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)
|
||||
.ToPagedListAsync(input.PageNo, input.PageSize);
|
||||
return XnPageResult<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 : "";
|
||||
await _sysCacheService.SetAsync(code, value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新配置缓存
|
||||
/// </summary>
|
||||
/// <param name="code"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public async Task UpdateConfigCache(string code, object value)
|
||||
{
|
||||
await _sysCacheService.SetAsync(code, value);
|
||||
}
|
||||
|
||||
/// <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);
|
||||
}
|
||||
}
|
||||
}
|
||||
94
Api/Dilon.Core/Service/Dict/Dto/DictDataInput.cs
Normal file
94
Api/Dilon.Core/Service/Dict/Dto/DictDataInput.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
using Furion.DataValidation;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 字典值参数
|
||||
/// </summary>
|
||||
public class DictDataInput : PageInputBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 字典类型Id
|
||||
/// </summary>
|
||||
public virtual long TypeId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 值
|
||||
/// </summary>
|
||||
public virtual string Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 编码
|
||||
/// </summary>
|
||||
public virtual string Code { 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不能为空"), DataValidation(ValidationTypes.Numeric)]
|
||||
public long TypeId { get; set; }
|
||||
}
|
||||
|
||||
public class AddDictDataInput : DictDataInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 字典类型Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "字典类型Id不能为空"), DataValidation(ValidationTypes.Numeric)]
|
||||
public override long 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不能为空"), DataValidation(ValidationTypes.Numeric)]
|
||||
public long Id { get; set; }
|
||||
}
|
||||
|
||||
public class UpdateDictDataInput : AddDictDataInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 字典值Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "字典值Id不能为空"), DataValidation(ValidationTypes.Numeric)]
|
||||
public long Id { get; set; }
|
||||
}
|
||||
|
||||
public class QueryDictDataInput : DeleteDictDataInput
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
13
Api/Dilon.Core/Service/Dict/Dto/DictDataOutput.cs
Normal file
13
Api/Dilon.Core/Service/Dict/Dto/DictDataOutput.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 字典值参数
|
||||
/// </summary>
|
||||
public class DictDataOutput : DictDataInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 字典Id
|
||||
/// </summary>
|
||||
public virtual long Id { get; set; }
|
||||
}
|
||||
}
|
||||
35
Api/Dilon.Core/Service/Dict/Dto/DictTreeOutput.cs
Normal file
35
Api/Dilon.Core/Service/Dict/Dto/DictTreeOutput.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 字典类型与字典值构造的树
|
||||
/// </summary>
|
||||
public class DictTreeOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 父Id
|
||||
/// </summary>
|
||||
public long Pid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 编码-对应字典值的编码
|
||||
/// </summary>
|
||||
public string Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 名称-对应字典值的value
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 子节点集合
|
||||
/// </summary>
|
||||
public List<DictTreeOutput> Children { get; set; } = new List<DictTreeOutput>();
|
||||
}
|
||||
}
|
||||
82
Api/Dilon.Core/Service/Dict/Dto/DictTypeInput.cs
Normal file
82
Api/Dilon.Core/Service/Dict/Dto/DictTypeInput.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 字典类型参数
|
||||
/// </summary>
|
||||
public class DictTypeInput : PageInputBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
public virtual string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 编码
|
||||
/// </summary>
|
||||
public virtual string Code { 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>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "字典类型名称不能为空")]
|
||||
public override string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 编码
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "字典类型编码不能为空")]
|
||||
public override string Code { get; set; }
|
||||
}
|
||||
|
||||
public class DeleteDictTypeInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 编号Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "字典类型Id不能为空")]
|
||||
public long Id { get; set; }
|
||||
}
|
||||
|
||||
public class UpdateDictTypeInput : AddDictTypeInput
|
||||
{
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "字典类型Id不能为空")]
|
||||
public long Id { get; set; }
|
||||
}
|
||||
|
||||
public class DropDownDictTypeInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 编码
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "字典类型编码不能为空")]
|
||||
public string Code { get; set; }
|
||||
}
|
||||
|
||||
public class QueryDictTypeInfoInput : DeleteDictTypeInput
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
18
Api/Dilon.Core/Service/Dict/ISysDictDataService.cs
Normal file
18
Api/Dilon.Core/Service/Dict/ISysDictDataService.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
public interface ISysDictDataService
|
||||
{
|
||||
Task AddDictData(AddDictDataInput input);
|
||||
Task ChangeDictDataStatus(UpdateDictDataInput input);
|
||||
Task DeleteByTypeId(long dictTypeId);
|
||||
Task DeleteDictData(DeleteDictDataInput input);
|
||||
Task<dynamic> GetDictData([FromQuery] QueryDictDataInput input);
|
||||
Task<dynamic> GetDictDataList([FromQuery] QueryDictDataListInput input);
|
||||
Task<dynamic> GetDictDataListByDictTypeId(long dictTypeId);
|
||||
Task<dynamic> QueryDictDataPageList([FromQuery] DictDataInput input);
|
||||
Task UpdateDictData(UpdateDictDataInput input);
|
||||
}
|
||||
}
|
||||
19
Api/Dilon.Core/Service/Dict/ISysDictTypeService.cs
Normal file
19
Api/Dilon.Core/Service/Dict/ISysDictTypeService.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
public interface ISysDictTypeService
|
||||
{
|
||||
Task AddDictType(AddDictTypeInput input);
|
||||
Task ChangeDictTypeStatus(UpdateDictTypeInput input);
|
||||
Task DeleteDictType(DeleteDictTypeInput input);
|
||||
Task<List<DictTreeOutput>> GetDictTree();
|
||||
Task<dynamic> GetDictType([FromQuery] QueryDictTypeInfoInput input);
|
||||
Task<dynamic> GetDictTypeDropDown([FromQuery] DropDownDictTypeInput input);
|
||||
Task<dynamic> GetDictTypeList();
|
||||
Task<dynamic> QueryDictTypePageList([FromQuery] DictTypeInput input);
|
||||
Task UpdateDictType(UpdateDictTypeInput input);
|
||||
}
|
||||
}
|
||||
164
Api/Dilon.Core/Service/Dict/SysDictDataService.cs
Normal file
164
Api/Dilon.Core/Service/Dict/SysDictDataService.cs
Normal file
@@ -0,0 +1,164 @@
|
||||
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 Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 字典值服务
|
||||
/// </summary>
|
||||
[ApiDescriptionSettings(Name = "DictData", Order = 100)]
|
||||
public class SysDictDataService : ISysDictDataService, IDynamicApiController, ITransient
|
||||
{
|
||||
private readonly IRepository<SysDictData> _sysDictDataRep; // 字典类型表仓储
|
||||
|
||||
public SysDictDataService(IRepository<SysDictData> sysDictDataRep)
|
||||
{
|
||||
_sysDictDataRep = sysDictDataRep;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分页查询字典值
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("/sysDictData/page")]
|
||||
public async Task<dynamic> QueryDictDataPageList([FromQuery] 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);
|
||||
return XnPageResult<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);
|
||||
|
||||
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>
|
||||
/// 更新字典值
|
||||
/// </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);
|
||||
|
||||
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(long 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
|
||||
}).ToListAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除字典下所有值
|
||||
/// </summary>
|
||||
/// <param name="dictTypeId"></param>
|
||||
[NonAction]
|
||||
public async Task DeleteByTypeId(long dictTypeId)
|
||||
{
|
||||
var dictDatas = await _sysDictDataRep.Where(u => u.TypeId == dictTypeId).ToListAsync();
|
||||
dictDatas.ForEach(u =>
|
||||
{
|
||||
u.Delete();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
175
Api/Dilon.Core/Service/Dict/SysDictTypeService.cs
Normal file
175
Api/Dilon.Core/Service/Dict/SysDictTypeService.cs
Normal file
@@ -0,0 +1,175 @@
|
||||
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.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.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>
|
||||
[HttpGet("/sysDictType/page")]
|
||||
public async Task<dynamic> QueryDictTypePageList([FromQuery] DictTypeInput input)
|
||||
{
|
||||
var code = !string.IsNullOrEmpty(input.Code?.Trim());
|
||||
var name = !string.IsNullOrEmpty(input.Name?.Trim());
|
||||
var dictTypes = await _sysDictTypeRep.DetachedEntities
|
||||
.Where((code, u => EF.Functions.Like(u.Code, $"%{input.Code.Trim()}%")),
|
||||
(name, u => EF.Functions.Like(u.Name, $"%{input.Name.Trim()}%")))
|
||||
.Where(u => u.Status != CommonStatus.DELETED).OrderBy(u => u.Sort)
|
||||
.ToPagedListAsync(input.PageNo, input.PageSize);
|
||||
return XnPageResult<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>
|
||||
[AllowAnonymous]
|
||||
[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>
|
||||
[HttpPost("/sysDictType/add")]
|
||||
public async Task AddDictType(AddDictTypeInput input)
|
||||
{
|
||||
var isExist = await _sysDictTypeRep.AnyAsync(u => u.Name == input.Name || u.Code == input.Code, false);
|
||||
if (isExist) throw Oops.Oh(ErrorCode.D3001);
|
||||
|
||||
var dictType = input.Adapt<SysDictType>();
|
||||
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);
|
||||
|
||||
// 排除自己并且判断与其他是否相同
|
||||
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>();
|
||||
await _sysDictTypeRep.UpdateAsync(dictType, ignoreNullValues: true);
|
||||
}
|
||||
|
||||
/// <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<DictTreeOutput>> GetDictTree()
|
||||
{
|
||||
return await _sysDictTypeRep.DetachedEntities.Select(u => new DictTreeOutput
|
||||
{
|
||||
Id = u.Id,
|
||||
Code = u.Code,
|
||||
Name = u.Name,
|
||||
Children = u.SysDictDatas.Select(c => new DictTreeOutput
|
||||
{
|
||||
Id = c.Id,
|
||||
Pid = c.TypeId,
|
||||
Code = c.Code,
|
||||
Name = c.Value
|
||||
}).ToList()
|
||||
}).ToListAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
38
Api/Dilon.Core/Service/Emp/Dto/EmpExtOrgPosOutput.cs
Normal file
38
Api/Dilon.Core/Service/Emp/Dto/EmpExtOrgPosOutput.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 附属机构和职位参数
|
||||
/// </summary>
|
||||
public class EmpExtOrgPosOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// 附属机构id
|
||||
/// </summary>
|
||||
public long OrgId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 附属机构编码
|
||||
/// </summary>
|
||||
public string OrgCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 附属机构名称
|
||||
/// </summary>
|
||||
public string OrgName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 附属职位id
|
||||
/// </summary>
|
||||
public long PosId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 附属职位编码
|
||||
/// </summary>
|
||||
public string PosCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 附属职位名称
|
||||
/// </summary>
|
||||
public string PosName { get; set; }
|
||||
}
|
||||
}
|
||||
35
Api/Dilon.Core/Service/Emp/Dto/EmpOutput.cs
Normal file
35
Api/Dilon.Core/Service/Emp/Dto/EmpOutput.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Dilon.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>();
|
||||
}
|
||||
}
|
||||
40
Api/Dilon.Core/Service/Emp/Dto/EmpOutput2.cs
Normal file
40
Api/Dilon.Core/Service/Emp/Dto/EmpOutput2.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Dilon.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<long> PosIdList { get; set; } = new List<long>();
|
||||
}
|
||||
}
|
||||
23
Api/Dilon.Core/Service/Emp/Dto/EmpPosOutput.cs
Normal file
23
Api/Dilon.Core/Service/Emp/Dto/EmpPosOutput.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 员工职位参数
|
||||
/// </summary>
|
||||
public class EmpPosOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// 职位Id
|
||||
/// </summary>
|
||||
public long PosId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 职位编码
|
||||
/// </summary>
|
||||
public string PosCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 职位名称
|
||||
/// </summary>
|
||||
public string PosName { get; set; }
|
||||
}
|
||||
}
|
||||
14
Api/Dilon.Core/Service/Emp/ISysEmpExtOrgPosService.cs
Normal file
14
Api/Dilon.Core/Service/Emp/ISysEmpExtOrgPosService.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
public interface ISysEmpExtOrgPosService
|
||||
{
|
||||
Task AddOrUpdate(long empId, List<EmpExtOrgPosOutput> extIdList);
|
||||
Task DeleteEmpExtInfoByUserId(long empId);
|
||||
Task<List<EmpExtOrgPosOutput>> GetEmpExtOrgPosList(long empId);
|
||||
Task<bool> HasExtOrgEmp(long orgId);
|
||||
Task<bool> HasExtPosEmp(long posId);
|
||||
}
|
||||
}
|
||||
13
Api/Dilon.Core/Service/Emp/ISysEmpPosService.cs
Normal file
13
Api/Dilon.Core/Service/Emp/ISysEmpPosService.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
public interface ISysEmpPosService
|
||||
{
|
||||
Task AddOrUpdate(long empId, List<long> posIdList);
|
||||
Task DeleteEmpPosInfoByUserId(long empId);
|
||||
Task<List<EmpPosOutput>> GetEmpPosList(long empId);
|
||||
Task<bool> HasPosEmp(long posId);
|
||||
}
|
||||
}
|
||||
14
Api/Dilon.Core/Service/Emp/ISysEmpService.cs
Normal file
14
Api/Dilon.Core/Service/Emp/ISysEmpService.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
public interface ISysEmpService
|
||||
{
|
||||
Task AddOrUpdate(EmpOutput2 sysEmpParam);
|
||||
Task DeleteEmpInfoByUserId(long empId);
|
||||
Task<EmpOutput> GetEmpInfo(long empId);
|
||||
Task<long> GetEmpOrgId(long empId);
|
||||
Task<bool> HasOrgEmp(long orgId);
|
||||
Task UpdateEmpOrgInfo(long orgId, string orgName);
|
||||
}
|
||||
}
|
||||
100
Api/Dilon.Core/Service/Emp/SysEmpExtOrgPosService.cs
Normal file
100
Api/Dilon.Core/Service/Emp/SysEmpExtOrgPosService.cs
Normal 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 Dilon.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(long 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(long 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(long orgId)
|
||||
{
|
||||
return await _sysEmpExtOrgPosRep.DetachedEntities.AnyAsync(u => u.SysOrgId == orgId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据职位Id判断该附属职位下是否有员工
|
||||
/// </summary>
|
||||
/// <param name="posId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> HasExtPosEmp(long posId)
|
||||
{
|
||||
return await _sysEmpExtOrgPosRep.DetachedEntities.AnyAsync(u => u.SysPosId == posId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据员工Id删除对应的员工-附属信息
|
||||
/// </summary>
|
||||
/// <param name="empId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task DeleteEmpExtInfoByUserId(long empId)
|
||||
{
|
||||
var empExtOrgPos = await _sysEmpExtOrgPosRep.Where(u => u.SysEmpId == empId).ToListAsync();
|
||||
empExtOrgPos.ForEach(u =>
|
||||
{
|
||||
u.Delete();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
85
Api/Dilon.Core/Service/Emp/SysEmpPosService.cs
Normal file
85
Api/Dilon.Core/Service/Emp/SysEmpPosService.cs
Normal 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 Dilon.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(long empId, List<long> 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(long 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(long posId)
|
||||
{
|
||||
return await _sysEmpPosRep.DetachedEntities.AnyAsync(u => u.SysPosId == posId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据员工Id删除对用的员工-职位信息
|
||||
/// </summary>
|
||||
/// <param name="empId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task DeleteEmpPosInfoByUserId(long empId)
|
||||
{
|
||||
var empPos = await _sysEmpPosRep.Where(u => u.SysEmpId == empId).ToListAsync();
|
||||
empPos.ForEach(u =>
|
||||
{
|
||||
u.Delete();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
125
Api/Dilon.Core/Service/Emp/SysEmpService.cs
Normal file
125
Api/Dilon.Core/Service/Emp/SysEmpService.cs
Normal file
@@ -0,0 +1,125 @@
|
||||
using Furion.DatabaseAccessor;
|
||||
using Furion.DatabaseAccessor.Extensions;
|
||||
using Furion.DependencyInjection;
|
||||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.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(long 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 == long.Parse(sysEmpParam.Id)).ToListAsync();
|
||||
emps.ForEach(u =>
|
||||
{
|
||||
u.DeleteNow();
|
||||
});
|
||||
|
||||
// 再新增新员工信息
|
||||
var emp = sysEmpParam.Adapt<SysEmp>();
|
||||
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(long 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(long orgId)
|
||||
{
|
||||
return await _sysEmpRep.DetachedEntities.AnyAsync(u => u.OrgId == orgId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据员工Id删除对应的员工表信息
|
||||
/// </summary>
|
||||
/// <param name="empId"></param>
|
||||
/// <returns></returns>
|
||||
[UnitOfWork]
|
||||
public async Task DeleteEmpInfoByUserId(long 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<long> GetEmpOrgId(long empId)
|
||||
{
|
||||
return (await _sysEmpRep.FirstOrDefaultAsync(u => u.Id == empId, false)).OrgId;
|
||||
}
|
||||
}
|
||||
}
|
||||
64
Api/Dilon.Core/Service/File/Dto/FileInput.cs
Normal file
64
Api/Dilon.Core/Service/File/Dto/FileInput.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 上传文件参数
|
||||
/// </summary>
|
||||
public class FileInput : PageInputBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件存储位置(1:阿里云,2:腾讯云,3:minio,4:本地)
|
||||
/// </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 long Id { get; set; }
|
||||
}
|
||||
|
||||
public class QueryFileInoInput : DeleteFileInfoInput
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
13
Api/Dilon.Core/Service/File/Dto/FileOutput.cs
Normal file
13
Api/Dilon.Core/Service/File/Dto/FileOutput.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 上传文件参数
|
||||
/// </summary>
|
||||
public class FileOutput : FileInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件Id
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
}
|
||||
}
|
||||
21
Api/Dilon.Core/Service/File/ISysFileService.cs
Normal file
21
Api/Dilon.Core/Service/File/ISysFileService.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.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 UploadFileAvatar(IFormFile file);
|
||||
Task UploadFileDefault(IFormFile file);
|
||||
Task UploadFileDocument(IFormFile file);
|
||||
Task UploadFileShop(IFormFile file);
|
||||
}
|
||||
}
|
||||
205
Api/Dilon.Core/Service/File/SysFileService.cs
Normal file
205
Api/Dilon.Core/Service/File/SysFileService.cs
Normal file
@@ -0,0 +1,205 @@
|
||||
using Furion;
|
||||
using Furion.DatabaseAccessor;
|
||||
using Furion.DatabaseAccessor.Extensions;
|
||||
using Furion.DependencyInjection;
|
||||
using Furion.DynamicApiController;
|
||||
using Furion.FriendlyException;
|
||||
using Furion.Snowflake;
|
||||
using Mapster;
|
||||
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 Dilon.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>
|
||||
[HttpGet("/sysFileInfo/page")]
|
||||
public async Task<dynamic> QueryFileInfoPageList([FromQuery] 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()}%"))
|
||||
.Select(u => u.Adapt<FileOutput>())
|
||||
.ToPagedListAsync(input.PageNo, input.PageSize);
|
||||
return XnPageResult<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 UploadFileDefault(IFormFile file)
|
||||
{
|
||||
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), "application/octet-stream") { FileDownloadName = fileName };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 上传头像
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <returns></returns>
|
||||
public async Task UploadFileAvatar(IFormFile file)
|
||||
{
|
||||
await UploadFile(file, _configuration["UploadFile:Avatar:path"]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 上传文档
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <returns></returns>
|
||||
public async Task UploadFileDocument(IFormFile file)
|
||||
{
|
||||
await UploadFile(file, _configuration["UploadFile:Document:path"]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 上传商店图片
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <returns></returns>
|
||||
public async Task UploadFileShop(IFormFile file)
|
||||
{
|
||||
await UploadFile(file, _configuration["UploadFile:Shop:path"]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 上传文件
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <param name="pathType"></param>
|
||||
/// <returns></returns>
|
||||
private static async Task UploadFile(IFormFile file, string pathType)
|
||||
{
|
||||
var fileId = IDGenerator.NextId();
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
95
Api/Dilon.Core/Service/Log/Dto/OpLogInput.cs
Normal file
95
Api/Dilon.Core/Service/Log/Dto/OpLogInput.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
using System;
|
||||
|
||||
namespace Dilon.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 string 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 DateTimeOffset OpTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 操作人
|
||||
/// </summary>
|
||||
public string Account { get; set; }
|
||||
}
|
||||
}
|
||||
10
Api/Dilon.Core/Service/Log/Dto/OpLogOutput.cs
Normal file
10
Api/Dilon.Core/Service/Log/Dto/OpLogOutput.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 请求日志参数
|
||||
/// </summary>
|
||||
public class OpLogOutput : OpLogInput
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
60
Api/Dilon.Core/Service/Log/Dto/VisLogInput.cs
Normal file
60
Api/Dilon.Core/Service/Log/Dto/VisLogInput.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 访问日志参数
|
||||
/// </summary>
|
||||
public class VisLogInput : PageInputBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否执行成功(Y-是,N-否)
|
||||
/// </summary>
|
||||
public string 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 DateTimeOffset VisTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 访问人
|
||||
/// </summary>
|
||||
public string Account { get; set; }
|
||||
}
|
||||
}
|
||||
10
Api/Dilon.Core/Service/Log/Dto/VisLogOutput.cs
Normal file
10
Api/Dilon.Core/Service/Log/Dto/VisLogOutput.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 访问日志参数
|
||||
/// </summary>
|
||||
public class VisLogOutput : VisLogInput
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
11
Api/Dilon.Core/Service/Log/ISysOpLogService.cs
Normal file
11
Api/Dilon.Core/Service/Log/ISysOpLogService.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
public interface ISysOpLogService
|
||||
{
|
||||
Task ClearOpLog();
|
||||
Task<dynamic> QueryOpLogPageList([FromQuery] OpLogInput input);
|
||||
}
|
||||
}
|
||||
11
Api/Dilon.Core/Service/Log/ISysVisLogService.cs
Normal file
11
Api/Dilon.Core/Service/Log/ISysVisLogService.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
public interface ISysVisLogService
|
||||
{
|
||||
Task ClearVisLog();
|
||||
Task<dynamic> QueryVisLogPageList([FromQuery] VisLogInput input);
|
||||
}
|
||||
}
|
||||
64
Api/Dilon.Core/Service/Log/SysOpLogService.cs
Normal file
64
Api/Dilon.Core/Service/Log/SysOpLogService.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
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 Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 操作日志服务
|
||||
/// </summary>
|
||||
[ApiDescriptionSettings(Name = "OpLog", Order = 100)]
|
||||
public class SysOpLogService : ISysOpLogService, IDynamicApiController, ITransient
|
||||
{
|
||||
private readonly IRepository<SysLogOp> _sysOpLogRep; // 操作日志表仓储
|
||||
|
||||
public SysOpLogService(IRepository<SysLogOp> sysOpLogRep)
|
||||
{
|
||||
_sysOpLogRep = sysOpLogRep;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分页查询操作日志
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("/sysOpLog/page")]
|
||||
public async Task<dynamic> QueryOpLogPageList([FromQuery] OpLogInput input)
|
||||
{
|
||||
var name = !string.IsNullOrEmpty(input.Name?.Trim());
|
||||
var success = !string.IsNullOrEmpty(input.Success?.Trim());
|
||||
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.Trim())
|
||||
.Where(searchBeginTime, u => u.OpTime >= DateTime.Parse(input.SearchBeginTime.Trim()) &&
|
||||
u.OpTime <= DateTime.Parse(input.SearchEndTime.Trim()))
|
||||
.OrderByDescending(u => u.Id)
|
||||
.Select(u => u.Adapt<OpLogOutput>())
|
||||
.ToPagedListAsync(input.PageNo, input.PageSize);
|
||||
return XnPageResult<OpLogOutput>.PageResult(opLogs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清空操作日志
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost("/sysOpLog/delete")]
|
||||
public async Task ClearOpLog()
|
||||
{
|
||||
var opLogs = await _sysOpLogRep.Entities.ToListAsync();
|
||||
opLogs.ForEach(u =>
|
||||
{
|
||||
u.Delete();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
64
Api/Dilon.Core/Service/Log/SysVisLogService.cs
Normal file
64
Api/Dilon.Core/Service/Log/SysVisLogService.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
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 Dilon.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>
|
||||
[HttpGet("/sysVisLog/page")]
|
||||
public async Task<dynamic> QueryVisLogPageList([FromQuery] VisLogInput input)
|
||||
{
|
||||
var name = !string.IsNullOrEmpty(input.Name?.Trim());
|
||||
var success = !string.IsNullOrEmpty(input.Success?.Trim());
|
||||
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.Trim())
|
||||
.Where(searchBeginTime, u => u.VisTime >= DateTime.Parse(input.SearchBeginTime.Trim()) &&
|
||||
u.VisTime <= DateTime.Parse(input.SearchEndTime.Trim()))
|
||||
.OrderByDescending(u => u.Id)
|
||||
.Select(u => u.Adapt<VisLogOutput>())
|
||||
.ToPagedListAsync(input.PageNo, input.PageSize);
|
||||
return XnPageResult<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();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
79
Api/Dilon.Core/Service/Menu/Dto/AntDesignTreeNode.cs
Normal file
79
Api/Dilon.Core/Service/Menu/Dto/AntDesignTreeNode.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 登录菜单-AntDesign菜单类型
|
||||
/// </summary>
|
||||
public class AntDesignTreeNode
|
||||
{
|
||||
/// <summary>
|
||||
/// id
|
||||
/// </summary>
|
||||
public long? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 父id
|
||||
/// </summary>
|
||||
public long? 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 Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 控制路由和子路由是否显示在 sidebar
|
||||
/// </summary>
|
||||
public bool Hidden { 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; }
|
||||
}
|
||||
}
|
||||
137
Api/Dilon.Core/Service/Menu/Dto/MenuInput.cs
Normal file
137
Api/Dilon.Core/Service/Menu/Dto/MenuInput.cs
Normal file
@@ -0,0 +1,137 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 菜单参数
|
||||
/// </summary>
|
||||
public class MenuInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 父Id
|
||||
/// </summary>
|
||||
public virtual long Pid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
public virtual string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 编码
|
||||
/// </summary>
|
||||
public virtual string Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 菜单类型(字典 0目录 1菜单 2按钮)
|
||||
/// </summary>
|
||||
public virtual string 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 string OpenType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否可见(Y-是,N-否)
|
||||
/// </summary>
|
||||
public string 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; }
|
||||
}
|
||||
|
||||
public class AddMenuInput : MenuInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 菜单类型(字典 0目录 1菜单 2按钮)
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "菜单类型不能为空")]
|
||||
public override string Type { get; set; }
|
||||
}
|
||||
|
||||
public class DeleteMenuInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 菜单Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "菜单Id不能为空")]
|
||||
public long Id { get; set; }
|
||||
}
|
||||
|
||||
public class UpdateMenuInput : AddMenuInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 菜单Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "菜单Id不能为空")]
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 父Id
|
||||
/// </summary>DeleteMenuInput
|
||||
[Required(ErrorMessage = "父级菜单Id不能为空")]
|
||||
public override long Pid { get; set; }
|
||||
}
|
||||
|
||||
public class QueryMenuInput : DeleteMenuInput
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class ChangeAppMenuInput : MenuInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 应用编码
|
||||
/// </summary>DeleteMenuInput
|
||||
[Required(ErrorMessage = "应用编码不能为空")]
|
||||
public override string Application { get; set; }
|
||||
}
|
||||
}
|
||||
36
Api/Dilon.Core/Service/Menu/Dto/MenuOutput.cs
Normal file
36
Api/Dilon.Core/Service/Menu/Dto/MenuOutput.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 菜单树(列表形式)
|
||||
/// </summary>
|
||||
public class MenuOutput : MenuInput, ITreeNode
|
||||
{
|
||||
/// <summary>
|
||||
/// 菜单Id
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 子节点
|
||||
/// </summary>
|
||||
public List<MenuOutput> Children { get; set; } = new List<MenuOutput>();
|
||||
|
||||
public long GetId()
|
||||
{
|
||||
return Id;
|
||||
}
|
||||
|
||||
public long GetPid()
|
||||
{
|
||||
return Pid;
|
||||
}
|
||||
|
||||
public void SetChildren(IList children)
|
||||
{
|
||||
Children = (List<MenuOutput>)children;
|
||||
}
|
||||
}
|
||||
}
|
||||
56
Api/Dilon.Core/Service/Menu/Dto/MenuTreeOutput.cs
Normal file
56
Api/Dilon.Core/Service/Menu/Dto/MenuTreeOutput.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 菜单树---授权、新增编辑时选择
|
||||
/// </summary>
|
||||
public class MenuTreeOutput : ITreeNode
|
||||
{
|
||||
/// <summary>
|
||||
/// 主键
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 父Id
|
||||
/// </summary>
|
||||
public long 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<MenuTreeOutput> Children { get; set; } = new List<MenuTreeOutput>();
|
||||
|
||||
public long GetId()
|
||||
{
|
||||
return Id;
|
||||
}
|
||||
|
||||
public long GetPid()
|
||||
{
|
||||
return ParentId;
|
||||
}
|
||||
|
||||
public void SetChildren(IList children)
|
||||
{
|
||||
Children = (List<MenuTreeOutput>)children;
|
||||
}
|
||||
}
|
||||
}
|
||||
22
Api/Dilon.Core/Service/Menu/ISysMenuService.cs
Normal file
22
Api/Dilon.Core/Service/Menu/ISysMenuService.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
public interface ISysMenuService
|
||||
{
|
||||
Task AddMenu(AddMenuInput input);
|
||||
Task<List<AntDesignTreeNode>> ChangeAppMenu(ChangeAppMenuInput input);
|
||||
Task DeleteMenu(DeleteMenuInput input);
|
||||
Task<List<AntDesignTreeNode>> GetLoginMenusAntDesign(long userId, string appCode);
|
||||
Task<List<string>> GetLoginPermissionList(long userId);
|
||||
Task<dynamic> GetMenu(QueryMenuInput input);
|
||||
Task<dynamic> GetMenuList([FromQuery] MenuInput input);
|
||||
Task<dynamic> GetMenuTree([FromQuery] MenuInput input);
|
||||
Task<List<string>> GetUserMenuAppCodeList(long userId);
|
||||
Task<bool> HasMenu(string appCode);
|
||||
Task<dynamic> TreeForGrant([FromQuery] MenuInput input);
|
||||
Task UpdateMenu(UpdateMenuInput input);
|
||||
}
|
||||
}
|
||||
438
Api/Dilon.Core/Service/Menu/SysMenuService.cs
Normal file
438
Api/Dilon.Core/Service/Menu/SysMenuService.cs
Normal file
@@ -0,0 +1,438 @@
|
||||
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 Dilon.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(long 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.BTN)
|
||||
.Where(u => u.Status == (int)CommonStatus.ENABLE)
|
||||
.Select(u => u.Permission).ToListAsync();
|
||||
await _sysCacheService.SetPermission(userId, permissions); // 缓存结果
|
||||
}
|
||||
return permissions;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户AntDesign菜单集合
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="appCode"></param>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
public async Task<List<AntDesignTreeNode>> GetLoginMenusAntDesign(long 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.BTN)
|
||||
//.Where(u => u.Weight != (int)MenuWeight.DEFAULT_WEIGHT)
|
||||
.OrderBy(u => u.Sort).ToListAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
// 非管理员则获取自己角色所拥有的菜单集合
|
||||
var roleIdList = await _sysUserRoleService.GetUserRoleIdList(userId);
|
||||
var menuIdList = await _sysRoleMenuService.GetRoleMenuIdList(roleIdList);
|
||||
sysMenuList = await _sysMenuRep.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.BTN)
|
||||
.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.OpenType == (int)MenuOpenType.OUTER ? u.Link : u.Redirect,
|
||||
Path = u.OpenType == (int)MenuOpenType.OUTER ? u.Link : u.Router,
|
||||
Meta = new Meta
|
||||
{
|
||||
Title = u.Name,
|
||||
Icon = u.Icon,
|
||||
Show = u.Visible == YesOrNot.Y.ToString(),
|
||||
Link = u.Link,
|
||||
Target = u.OpenType == (int)MenuOpenType.OUTER ? "_blank" : ""
|
||||
}
|
||||
}).ToList();
|
||||
await _sysCacheService.SetMenu(userId, appCode, antDesignTreeNodes); // 缓存结果
|
||||
}
|
||||
return antDesignTreeNodes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户菜单所属的应用编码集合
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
public async Task<List<string>> GetUserMenuAppCodeList(long userId)
|
||||
{
|
||||
var roleIdList = await _sysUserRoleService.GetUserRoleIdList(userId);
|
||||
var menuIdList = await _sysRoleMenuService.GetRoleMenuIdList(roleIdList);
|
||||
return await _sysMenuRep.DetachedEntities.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(long pid)
|
||||
{
|
||||
if (pid == 0L)
|
||||
{
|
||||
return "[0],";
|
||||
}
|
||||
else
|
||||
{
|
||||
var pmenu = await _sysMenuRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == pid);
|
||||
return pmenu.Pids + "[" + pid + "],";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增加和编辑时检查参数
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
private static void CheckMenuParam(MenuInput input)
|
||||
{
|
||||
var type = input.Type;
|
||||
var router = input.Router;
|
||||
var permission = input.Permission;
|
||||
var openType = input.OpenType;
|
||||
|
||||
if (type.Equals((int)MenuType.DIR))
|
||||
{
|
||||
if (string.IsNullOrEmpty(router))
|
||||
throw Oops.Oh(ErrorCode.D4001);
|
||||
}
|
||||
else if (type.Equals((int)MenuType.MENU))
|
||||
{
|
||||
if (string.IsNullOrEmpty(router))
|
||||
throw Oops.Oh(ErrorCode.D4001);
|
||||
if (string.IsNullOrEmpty(openType))
|
||||
throw Oops.Oh(ErrorCode.D4002);
|
||||
}
|
||||
else if (type.Equals((int)MenuType.BTN))
|
||||
{
|
||||
if (string.IsNullOrEmpty(permission))
|
||||
throw Oops.Oh(ErrorCode.D4003);
|
||||
if (!permission.Contains(":"))
|
||||
throw Oops.Oh(ErrorCode.D4004);
|
||||
// 判断该资源是否存在
|
||||
//permission = ":" + permission;
|
||||
//var urlSet = resourceCache.getAllResources();
|
||||
//if (!urlSet.Contains(permission.Replace(":","/")))
|
||||
// throw Oops.Oh(ErrorCode.meu1005);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增加系统菜单
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("/sysMenu/add")]
|
||||
public async Task AddMenu(AddMenuInput input)
|
||||
{
|
||||
var isExist = await _sysMenuRep.DetachedEntities.AnyAsync(u => u.Code == input.Code); // u.Name == input.Name
|
||||
if (isExist)
|
||||
throw Oops.Oh(ErrorCode.D4000);
|
||||
|
||||
// 校验参数
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
// 校验参数
|
||||
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 != 0L)
|
||||
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.UpdateAsync(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,
|
||||
Weight = 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<long>();
|
||||
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,
|
||||
Weight = 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Api/Dilon.Core/Service/Monitor/IMachineService.cs
Normal file
11
Api/Dilon.Core/Service/Monitor/IMachineService.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
public interface IMachineService
|
||||
{
|
||||
Task<dynamic> GetMachineBaseInfo();
|
||||
Task<dynamic> GetMachineNetWorkInfo();
|
||||
Task<dynamic> GetMachineUseInfo();
|
||||
}
|
||||
}
|
||||
53
Api/Dilon.Core/Service/Monitor/MachineService.cs
Normal file
53
Api/Dilon.Core/Service/Monitor/MachineService.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using Furion.DependencyInjection;
|
||||
using Furion.DynamicApiController;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
60
Api/Dilon.Core/Service/Notice/Dto/NoticeBase.cs
Normal file
60
Api/Dilon.Core/Service/Notice/Dto/NoticeBase.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 通知公告参数
|
||||
/// </summary>
|
||||
public class NoticeBase
|
||||
{
|
||||
/// <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 long PublicUserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 发布人姓名
|
||||
/// </summary>
|
||||
public string PublicUserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 发布机构Id
|
||||
/// </summary>
|
||||
public long PublicOrgId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 发布机构名称
|
||||
/// </summary>
|
||||
public string PublicOrgName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 发布时间
|
||||
/// </summary>
|
||||
public DateTimeOffset PublicTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 撤回时间
|
||||
/// </summary>
|
||||
public DateTimeOffset CancelTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态(字典 0草稿 1发布 2撤回 3删除)
|
||||
/// </summary>
|
||||
public int Status { get; set; }
|
||||
}
|
||||
}
|
||||
44
Api/Dilon.Core/Service/Notice/Dto/NoticeDetailOutput.cs
Normal file
44
Api/Dilon.Core/Service/Notice/Dto/NoticeDetailOutput.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Dilon.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; }
|
||||
}
|
||||
|
||||
public class NoticeUserRead
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户Id
|
||||
/// </summary>
|
||||
public long UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户名称
|
||||
/// </summary>
|
||||
public string UserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态(字典 0未读 1已读)
|
||||
/// </summary>
|
||||
public int ReadStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 阅读时间
|
||||
/// </summary>
|
||||
public DateTimeOffset ReadTime { get; set; }
|
||||
}
|
||||
}
|
||||
101
Api/Dilon.Core/Service/Notice/Dto/NoticeInput.cs
Normal file
101
Api/Dilon.Core/Service/Notice/Dto/NoticeInput.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Dilon.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<long> 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<long> NoticeUserIdList { get; set; }
|
||||
}
|
||||
|
||||
public class DeleteNoticeInput
|
||||
{
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "通知公告Id不能为空")]
|
||||
public long Id { get; set; }
|
||||
}
|
||||
|
||||
public class UpdateNoticeInput : AddNoticeInput
|
||||
{
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "通知公告Id不能为空")]
|
||||
public long Id { get; set; }
|
||||
}
|
||||
|
||||
public class QueryNoticeInput : DeleteNoticeInput
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class ChangeStatusNoticeInput : DeleteNoticeInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 状态(字典 0草稿 1发布 2撤回 3删除)
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "状态不能为空")]
|
||||
public int Status { get; set; }
|
||||
}
|
||||
}
|
||||
25
Api/Dilon.Core/Service/Notice/Dto/NoticeReceiveOutput.cs
Normal file
25
Api/Dilon.Core/Service/Notice/Dto/NoticeReceiveOutput.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 通知公告接收参数
|
||||
/// </summary>
|
||||
public class NoticeReceiveOutput : NoticeBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 阅读状态(字典 0未读 1已读)
|
||||
/// </summary>
|
||||
public int ReadStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 阅读时间
|
||||
/// </summary>
|
||||
public DateTimeOffset ReadTime { get; set; }
|
||||
}
|
||||
}
|
||||
16
Api/Dilon.Core/Service/Notice/ISysNoticeService.cs
Normal file
16
Api/Dilon.Core/Service/Notice/ISysNoticeService.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.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);
|
||||
}
|
||||
}
|
||||
13
Api/Dilon.Core/Service/Notice/ISysNoticeUserService.cs
Normal file
13
Api/Dilon.Core/Service/Notice/ISysNoticeUserService.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.Core.Service.Notice
|
||||
{
|
||||
public interface ISysNoticeUserService
|
||||
{
|
||||
Task Add(long noticeId, List<long> noticeUserIdList, int noticeUserStatus);
|
||||
Task<List<SysNoticeUser>> GetNoticeUserListByNoticeId(long noticeId);
|
||||
Task Read(long noticeId, long userId, int status);
|
||||
Task Update(long noticeId, List<long> noticeUserIdList, int noticeUserStatus);
|
||||
}
|
||||
}
|
||||
224
Api/Dilon.Core/Service/Notice/SysNoticeService.cs
Normal file
224
Api/Dilon.Core/Service/Notice/SysNoticeService.cs
Normal file
@@ -0,0 +1,224 @@
|
||||
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.Threading.Tasks;
|
||||
|
||||
namespace Dilon.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;
|
||||
|
||||
public SysNoticeService(IRepository<SysNotice> sysNoticeRep,
|
||||
IRepository<SysNoticeUser> sysNoticeUserRep,
|
||||
IUserManager userManager,
|
||||
ISysNoticeUserService sysNoticeUserService)
|
||||
{
|
||||
_sysNoticeRep = sysNoticeRep;
|
||||
_sysNoticeUserRep = sysNoticeUserRep;
|
||||
_userManager = userManager;
|
||||
_sysNoticeUserService = sysNoticeUserService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分页查询通知公告
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("/sysNotice/page")]
|
||||
public async Task<dynamic> QueryNoticePageList([FromQuery] 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.PageNo, input.PageSize);
|
||||
return XnPageResult<SysNotice>.PageResult(notices);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增加通知公告
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("/sysNotice/add")]
|
||||
public async Task AddNotice(AddNoticeInput input)
|
||||
{
|
||||
if (input.Status != (int)NoticeStatus.DRAFT && input.Status != (int)NoticeStatus.PUBLIC)
|
||||
throw Oops.Oh(ErrorCode.D7000);
|
||||
|
||||
var notice = input.Adapt<SysNotice>();
|
||||
await UpdatePublicInfo(notice);
|
||||
// 如果是发布,则设置发布时间
|
||||
if (input.Status == (int)NoticeStatus.PUBLIC)
|
||||
notice.PublicTime = DateTimeOffset.Now;
|
||||
var newItem = await notice.InsertNowAsync();
|
||||
|
||||
// 通知到的人
|
||||
var noticeUserIdList = input.NoticeUserIdList;
|
||||
var noticeUserStatus = (int)NoticeUserStatus.UNREAD;
|
||||
await _sysNoticeUserService.Add(newItem.Entity.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.Status == (int)NoticeStatus.PUBLIC)
|
||||
{
|
||||
notice.PublicTime = DateTimeOffset.Now;
|
||||
await UpdatePublicInfo(notice);
|
||||
}
|
||||
await notice.UpdateAsync();
|
||||
|
||||
// 通知到的人
|
||||
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,
|
||||
UserName = _userManager.Name,
|
||||
ReadStatus = u.ReadStatus,
|
||||
ReadTime = u.ReadTime
|
||||
};
|
||||
noticeUserReadInfoList.Add(noticeUserRead);
|
||||
});
|
||||
}
|
||||
var noticeResult = notice.Adapt<NoticeDetailOutput>();
|
||||
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 = DateTimeOffset.Now;
|
||||
}
|
||||
else if (input.Status == (int)NoticeStatus.PUBLIC)
|
||||
{
|
||||
notice.PublicTime = DateTimeOffset.Now;
|
||||
}
|
||||
await notice.UpdateAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取接收的通知公告
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("/sysNotice/received")]
|
||||
public async Task<dynamic> ReceivedNoticePageList([FromQuery] NoticeInput input)
|
||||
{
|
||||
var searchValue = !string.IsNullOrEmpty(input.SearchValue?.Trim());
|
||||
var notices = await _sysNoticeRep.DetachedEntities.Join(_sysNoticeUserRep.DetachedEntities, u => u.Id, e => e.NoticeId, (u, e) => new { u, e })
|
||||
.Where(u => u.e.UserId == _userManager.UserId)
|
||||
.Where(searchValue, u => EF.Functions.Like(u.u.Title, $"%{input.SearchValue.Trim()}%") || EF.Functions.Like(u.u.Content, $"%{input.SearchValue.Trim()}%"))
|
||||
.Where(input.Type > 0, u => u.u.Type == input.Type)
|
||||
.Where(u => u.u.Status != (int)NoticeStatus.DELETED)
|
||||
.Select(u => u.u.Adapt<NoticeReceiveOutput>())
|
||||
.ToPagedListAsync(input.PageNo, input.PageSize);
|
||||
return XnPageResult<NoticeReceiveOutput>.PageResult(notices);
|
||||
}
|
||||
|
||||
/// <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;
|
||||
}
|
||||
}
|
||||
}
|
||||
90
Api/Dilon.Core/Service/Notice/SysNoticeUserService.cs
Normal file
90
Api/Dilon.Core/Service/Notice/SysNoticeUserService.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
using Furion.DatabaseAccessor;
|
||||
using Furion.DatabaseAccessor.Extensions;
|
||||
using Furion.DependencyInjection;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.Core.Service.Notice
|
||||
{
|
||||
/// <summary>
|
||||
/// 通知公告用户
|
||||
/// </summary>
|
||||
public class SysNoticeUserService : ISysNoticeUserService, ITransient
|
||||
{
|
||||
private readonly IRepository<SysNoticeUser> _sysNoticeUserRep; // 通知公告用户表仓储
|
||||
|
||||
public SysNoticeUserService(IRepository<SysNoticeUser> sysNoticeUserRep)
|
||||
{
|
||||
_sysNoticeUserRep = sysNoticeUserRep;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增加
|
||||
/// </summary>
|
||||
/// <param name="noticeId"></param>
|
||||
/// <param name="noticeUserIdList"></param>
|
||||
/// <param name="noticeUserStatus"></param>
|
||||
/// <returns></returns>
|
||||
public Task Add(long noticeId, List<long> noticeUserIdList, int noticeUserStatus)
|
||||
{
|
||||
noticeUserIdList.ForEach(u =>
|
||||
{
|
||||
new SysNoticeUser
|
||||
{
|
||||
NoticeId = noticeId,
|
||||
UserId = u,
|
||||
ReadStatus = noticeUserStatus
|
||||
}.InsertAsync();
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新
|
||||
/// </summary>
|
||||
/// <param name="noticeId"></param>
|
||||
/// <param name="noticeUserIdList"></param>
|
||||
/// <param name="noticeUserStatus"></param>
|
||||
/// <returns></returns>
|
||||
public async Task Update(long noticeId, List<long> 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(long 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(long noticeId, long userId, int status)
|
||||
{
|
||||
var noticeUser = await _sysNoticeUserRep.FirstOrDefaultAsync(u => u.NoticeId == noticeId && u.UserId == userId);
|
||||
if (noticeUser != null)
|
||||
{
|
||||
noticeUser.ReadStatus = status;
|
||||
noticeUser.ReadTime = DateTimeOffset.Now;
|
||||
await noticeUser.UpdateAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Api/Dilon.Core/Service/OAuth/ISysOauthService.cs
Normal file
12
Api/Dilon.Core/Service/OAuth/ISysOauthService.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.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 = "");
|
||||
}
|
||||
}
|
||||
68
Api/Dilon.Core/Service/OAuth/SysOauthService.cs
Normal file
68
Api/Dilon.Core/Service/OAuth/SysOauthService.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
using Dilon.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 Dilon.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("Dilon"));
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
93
Api/Dilon.Core/Service/Org/Dto/OrgInput.cs
Normal file
93
Api/Dilon.Core/Service/Org/Dto/OrgInput.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 组织机构参数
|
||||
/// </summary>
|
||||
public class OrgInput : XnInputBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 父Id
|
||||
/// </summary>
|
||||
public 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 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; }
|
||||
}
|
||||
|
||||
public class AddOrgInput : OrgInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "机构名称不能为空")]
|
||||
public override string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 编码
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "机构编码不能为空")]
|
||||
public override string Code { 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; }
|
||||
}
|
||||
}
|
||||
13
Api/Dilon.Core/Service/Org/Dto/OrgOutput.cs
Normal file
13
Api/Dilon.Core/Service/Org/Dto/OrgOutput.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 组织机构参数
|
||||
/// </summary>
|
||||
public class OrgOutput : OrgInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 机构Id
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
}
|
||||
}
|
||||
61
Api/Dilon.Core/Service/Org/Dto/OrgTreeNode.cs
Normal file
61
Api/Dilon.Core/Service/Org/Dto/OrgTreeNode.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 组织机构树
|
||||
/// </summary>
|
||||
public class OrgTreeNode : ITreeNode
|
||||
{
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 父Id
|
||||
/// </summary>
|
||||
public long 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<OrgTreeNode> Children { get; set; } = new List<OrgTreeNode>();
|
||||
|
||||
/// <summary>
|
||||
/// 上一级Id
|
||||
/// </summary>
|
||||
public long Pid { get; set; }
|
||||
|
||||
public long GetId()
|
||||
{
|
||||
return Id;
|
||||
}
|
||||
|
||||
public long GetPid()
|
||||
{
|
||||
return ParentId;
|
||||
}
|
||||
|
||||
public void SetChildren(IList children)
|
||||
{
|
||||
Children = (List<OrgTreeNode>)children;
|
||||
}
|
||||
}
|
||||
}
|
||||
19
Api/Dilon.Core/Service/Org/ISysOrgService.cs
Normal file
19
Api/Dilon.Core/Service/Org/ISysOrgService.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
public interface ISysOrgService
|
||||
{
|
||||
Task AddOrg(AddOrgInput input);
|
||||
Task DeleteOrg(DeleteOrgInput input);
|
||||
Task<List<long>> GetDataScopeListByDataScopeType(int dataScopeType, long orgId);
|
||||
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);
|
||||
Task<List<long>> GetUserDataScopeIdList();
|
||||
}
|
||||
}
|
||||
348
Api/Dilon.Core/Service/Org/SysOrgService.cs
Normal file
348
Api/Dilon.Core/Service/Org/SysOrgService.cs
Normal file
@@ -0,0 +1,348 @@
|
||||
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 Dilon.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>
|
||||
[HttpGet("/sysOrg/page")]
|
||||
public async Task<dynamic> QueryOrgPageList([FromQuery] PageOrgInput input)
|
||||
{
|
||||
var dataScopeList = GetDataScopeList(await GetUserDataScopeIdList());
|
||||
|
||||
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 == long.Parse(input.Id.Trim())), // 根据机构id查询
|
||||
(pId, u => EF.Functions.Like(u.Pids, $"%[{input.Pid.Trim()}]%")
|
||||
|| u.Id == long.Parse(input.Pid.Trim()))) // 根据父机构id查询
|
||||
.Where(dataScopeList.Count > 0, u => dataScopeList.Contains(u.Id)) // 非管理员范围限制
|
||||
.Where(u => u.Status != CommonStatus.DELETED).OrderBy(u => u.Sort)
|
||||
.Select(u => u.Adapt<OrgOutput>())
|
||||
.ToPagedListAsync(input.PageNo, input.PageSize);
|
||||
return XnPageResult<OrgOutput>.PageResult(orgs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// (非管理员)获取当前用户数据范围(机构Id)
|
||||
/// </summary>
|
||||
/// <param name="dataScopes"></param>
|
||||
/// <returns></returns>
|
||||
private List<long> GetDataScopeList(List<long> dataScopes)
|
||||
{
|
||||
var dataScopeList = new List<long>();
|
||||
// 如果是超级管理员则获取所有组织机构,否则只获取其数据范围的机构数据
|
||||
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(",").Select(u => long.Parse(u)).ToList();
|
||||
dataScopeList.AddRange(parentAndChildIdListWithSelf);
|
||||
});
|
||||
}
|
||||
return dataScopeList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取组织机构列表
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("/sysOrg/list")]
|
||||
public async Task<List<OrgOutput>> GetOrgList([FromQuery] OrgInput input)
|
||||
{
|
||||
var dataScopeList = GetDataScopeList(await GetUserDataScopeIdList());
|
||||
|
||||
var pId = !string.IsNullOrEmpty(input.Pid?.Trim());
|
||||
var orgs = await _sysOrgRep.DetachedEntities
|
||||
.Where(pId, u => u.Pid == long.Parse(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.Name == input.Name || 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 GetUserDataScopeIdList();
|
||||
if (dataScopes.Count < 1 || !dataScopes.Contains(long.Parse(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 == 0L)
|
||||
{
|
||||
sysOrg.Pids = "[" + 0 + "],";
|
||||
}
|
||||
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 == long.Parse(input.Id));
|
||||
|
||||
// 检测数据范围能不能操作这个机构
|
||||
var dataScopes = await GetUserDataScopeIdList();
|
||||
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 != "0" && !string.IsNullOrEmpty(input.Pid))
|
||||
{
|
||||
var org = await _sysOrgRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == long.Parse(input.Pid));
|
||||
_ = org ?? throw Oops.Oh(ErrorCode.D2000);
|
||||
}
|
||||
if (input.Id == input.Pid)
|
||||
throw Oops.Oh(ErrorCode.D2001);
|
||||
|
||||
// 如果是编辑,父id不能为自己的子节点
|
||||
var childIdListById = await GetChildIdListWithSelfById(long.Parse(input.Id));
|
||||
if (childIdListById.Contains(long.Parse(input.Pid)))
|
||||
throw Oops.Oh(ErrorCode.D2001);
|
||||
|
||||
var sysOrg = await _sysOrgRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == long.Parse(input.Id));
|
||||
|
||||
// 检测数据范围能不能操作这个机构
|
||||
var dataScopes = await GetUserDataScopeIdList();
|
||||
if (!_userManager.SuperAdmin && (dataScopes.Count < 1 || !dataScopes.Contains(sysOrg.Id)))
|
||||
throw Oops.Oh(ErrorCode.D2003);
|
||||
|
||||
var isExist = await _sysOrgRep.DetachedEntities.AnyAsync(u => (u.Name == input.Name || 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 == long.Parse(input.Id));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据节点Id获取所有子节点Id集合,包含自己
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<List<long>> GetChildIdListWithSelfById(long 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<long>();
|
||||
if (!_userManager.SuperAdmin)
|
||||
{
|
||||
var dataScopes = await GetUserDataScopeIdList();
|
||||
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)
|
||||
.Select(u => new OrgTreeNode
|
||||
{
|
||||
Id = u.Id,
|
||||
ParentId = u.Pid,
|
||||
Title = u.Name,
|
||||
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<long>> GetDataScopeListByDataScopeType(int dataScopeType, long orgId)
|
||||
{
|
||||
var orgIdList = new List<long>();
|
||||
if (orgId < 0)
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户数据范围(机构Id集合)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
public async Task<List<long>> GetUserDataScopeIdList()
|
||||
{
|
||||
return await App.GetService<ISysUserService>().GetUserDataScopeIdList();
|
||||
}
|
||||
}
|
||||
}
|
||||
83
Api/Dilon.Core/Service/Pos/Dto/PosInput.cs
Normal file
83
Api/Dilon.Core/Service/Pos/Dto/PosInput.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 职位参数
|
||||
/// </summary>
|
||||
public class PosInput
|
||||
{
|
||||
/// <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 long Id { get; set; }
|
||||
}
|
||||
|
||||
public class UpdatePosInput : AddPosInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 职位Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "职位Id不能为空")]
|
||||
public long Id { get; set; }
|
||||
}
|
||||
|
||||
public class QueryPosInput : DeletePosInput
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
15
Api/Dilon.Core/Service/Pos/ISysPosService.cs
Normal file
15
Api/Dilon.Core/Service/Pos/ISysPosService.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.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);
|
||||
}
|
||||
}
|
||||
130
Api/Dilon.Core/Service/Pos/SysPosService.cs
Normal file
130
Api/Dilon.Core/Service/Pos/SysPosService.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
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 Dilon.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>
|
||||
[HttpGet("/sysPos/page")]
|
||||
public async Task<dynamic> QueryPosPageList([FromQuery] 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)
|
||||
.ToPagedListAsync(input.PageNo, input.PageSize);
|
||||
return XnPageResult<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);
|
||||
}
|
||||
}
|
||||
}
|
||||
87
Api/Dilon.Core/Service/Role/Dto/RoleInput.cs
Normal file
87
Api/Dilon.Core/Service/Role/Dto/RoleInput.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 角色参数
|
||||
/// </summary>
|
||||
public class RoleInput : XnInputBase
|
||||
{
|
||||
/// <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 long Id { get; set; }
|
||||
}
|
||||
|
||||
public class UpdateRoleInput : AddRoleInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 角色Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessageResourceName = "角色Id不能为空")]
|
||||
public long Id { get; set; }
|
||||
}
|
||||
|
||||
public class QueryRoleInput : DeleteRoleInput
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class GrantRoleMenuInput : RoleInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 角色Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessageResourceName = "角色Id不能为空")]
|
||||
public long Id { get; set; }
|
||||
}
|
||||
|
||||
public class GrantRoleDataInput : GrantRoleMenuInput
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
23
Api/Dilon.Core/Service/Role/Dto/RoleOutput.cs
Normal file
23
Api/Dilon.Core/Service/Role/Dto/RoleOutput.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 登录用户角色参数
|
||||
/// </summary>
|
||||
public class RoleOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 编码
|
||||
/// </summary>
|
||||
public string Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
13
Api/Dilon.Core/Service/Role/ISysRoleDataScopeService.cs
Normal file
13
Api/Dilon.Core/Service/Role/ISysRoleDataScopeService.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
public interface ISysRoleDataScopeService
|
||||
{
|
||||
Task DeleteRoleDataScopeListByOrgIdList(List<long> orgIdList);
|
||||
Task DeleteRoleDataScopeListByRoleId(long roleId);
|
||||
Task<List<long>> GetRoleDataScopeIdList(List<long> roleIdList);
|
||||
Task GrantDataScope(GrantRoleDataInput input);
|
||||
}
|
||||
}
|
||||
13
Api/Dilon.Core/Service/Role/ISysRoleMenuService.cs
Normal file
13
Api/Dilon.Core/Service/Role/ISysRoleMenuService.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
public interface ISysRoleMenuService
|
||||
{
|
||||
Task DeleteRoleMenuListByMenuIdList(List<long> menuIdList);
|
||||
Task DeleteRoleMenuListByRoleId(long roleId);
|
||||
Task<List<long>> GetRoleMenuIdList(List<long> roleIdList);
|
||||
Task GrantMenu(GrantRoleMenuInput input);
|
||||
}
|
||||
}
|
||||
24
Api/Dilon.Core/Service/Role/ISysRoleService.cs
Normal file
24
Api/Dilon.Core/Service/Role/ISysRoleService.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
public interface ISysRoleService
|
||||
{
|
||||
Task AddRole(AddRoleInput input);
|
||||
Task DeleteRole(DeleteRoleInput input);
|
||||
Task<string> GetNameByRoleId(long roleId);
|
||||
Task<dynamic> GetRoleDropDown();
|
||||
Task<SysRole> GetRoleInfo([FromQuery] QueryRoleInput input);
|
||||
Task<dynamic> GetRoleList([FromQuery] RoleInput input);
|
||||
Task<List<long>> GetUserDataScopeIdList(List<long> roleIdList, long orgId);
|
||||
Task<List<RoleOutput>> GetUserRoleList(long userId);
|
||||
Task GrantData(GrantRoleDataInput input);
|
||||
Task GrantMenu(GrantRoleMenuInput input);
|
||||
Task<List<long>> OwnData([FromQuery] QueryRoleInput input);
|
||||
Task<List<long>> OwnMenu([FromQuery] QueryRoleInput input);
|
||||
Task<dynamic> QueryRolePageList([FromQuery] RoleInput input);
|
||||
Task UpdateRole(UpdateRoleInput input);
|
||||
}
|
||||
}
|
||||
87
Api/Dilon.Core/Service/Role/SysRoleDataScopeService.cs
Normal file
87
Api/Dilon.Core/Service/Role/SysRoleDataScopeService.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
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 Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 角色数据范围服务
|
||||
/// </summary>
|
||||
public class SysRoleDataScopeService : ISysRoleDataScopeService, ITransient
|
||||
{
|
||||
private readonly IRepository<SysRoleDataScope> _sysRoleDataScopeRep; // 角色数据范围表仓储
|
||||
|
||||
public SysRoleDataScopeService(IRepository<SysRoleDataScope> sysRoleDataScopeRep)
|
||||
{
|
||||
_sysRoleDataScopeRep = sysRoleDataScopeRep;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 授权角色数据范围
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[UnitOfWork]
|
||||
public async Task GrantDataScope(GrantRoleDataInput input)
|
||||
{
|
||||
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<long>> GetRoleDataScopeIdList(List<long> 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<long> 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(long roleId)
|
||||
{
|
||||
var dataScopes = await _sysRoleDataScopeRep.DetachedEntities.Where(u => u.SysRoleId == roleId).ToListAsync();
|
||||
dataScopes.ForEach(u =>
|
||||
{
|
||||
u.Delete();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
93
Api/Dilon.Core/Service/Role/SysRoleMenuService.cs
Normal file
93
Api/Dilon.Core/Service/Role/SysRoleMenuService.cs
Normal 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 Dilon.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<long>> GetRoleMenuIdList(List<long> 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<long> 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(long roleId)
|
||||
{
|
||||
var roleMenus = await _sysRoleMenuRep.DetachedEntities.Where(u => u.SysRoleId == roleId).ToListAsync();
|
||||
roleMenus.ForEach(u =>
|
||||
{
|
||||
u.Delete();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
305
Api/Dilon.Core/Service/Role/SysRoleService.cs
Normal file
305
Api/Dilon.Core/Service/Role/SysRoleService.cs
Normal file
@@ -0,0 +1,305 @@
|
||||
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 Dilon.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(long 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>
|
||||
[HttpGet("/sysRole/page")]
|
||||
public async Task<dynamic> QueryRolePageList([FromQuery] 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)
|
||||
.ToPagedListAsync(input.PageNo, input.PageSize);
|
||||
return XnPageResult<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<long>();
|
||||
|
||||
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 _sysOrgService.GetUserDataScopeIdList();
|
||||
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集合获取数据范围Id集合
|
||||
/// </summary>
|
||||
/// <param name="roleIdList"></param>
|
||||
/// <param name="orgId"></param>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
public async Task<List<long>> GetUserDataScopeIdList(List<long> roleIdList, long orgId)
|
||||
{
|
||||
// 定义角色中最大数据范围的类型,目前按最大范围策略来,如果你同时拥有ALL和SELF的权限,最后按ALL返回
|
||||
int strongerDataScopeType = (int)DataScopeType.SELF;
|
||||
|
||||
var customDataScopeRoleIdList = new List<long>();
|
||||
if (roleIdList != null && roleIdList.Count > 0)
|
||||
{
|
||||
var roles = await _sysRoleRep.DetachedEntities.Where(u => roleIdList.Contains(u.Id)).ToListAsync();
|
||||
roles.ForEach(u =>
|
||||
{
|
||||
if (u.DataScopeType == (int)DataScopeType.DEFINE)
|
||||
customDataScopeRoleIdList.Add(u.Id);
|
||||
else if (u.DataScopeType <= strongerDataScopeType)
|
||||
strongerDataScopeType = u.DataScopeType;
|
||||
});
|
||||
}
|
||||
|
||||
// 自定义数据范围的角色对应的数据范围
|
||||
var roleDataScopeIdList = await _sysRoleDataScopeService.GetRoleDataScopeIdList(customDataScopeRoleIdList);
|
||||
|
||||
// 角色中拥有最大数据范围类型的数据范围
|
||||
var dataScopeIdList = await _sysOrgService.GetDataScopeListByDataScopeType(strongerDataScopeType, orgId);
|
||||
|
||||
return roleDataScopeIdList.Concat(dataScopeIdList).Distinct().ToList(); //并集
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据角色Id获取角色名称
|
||||
/// </summary>
|
||||
/// <param name="roleId"></param>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
public async Task<string> GetNameByRoleId(long 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<long>> OwnMenu([FromQuery] QueryRoleInput input)
|
||||
{
|
||||
return await _sysRoleMenuService.GetRoleMenuIdList(new List<long> { input.Id });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取角色拥有数据Id集合
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("/sysRole/ownData")]
|
||||
public async Task<List<long>> OwnData([FromQuery] QueryRoleInput input)
|
||||
{
|
||||
return await _sysRoleDataScopeService.GetRoleDataScopeIdList(new List<long> { input.Id });
|
||||
}
|
||||
}
|
||||
}
|
||||
94
Api/Dilon.Core/Service/Tenant/Dto/TenantInput.cs
Normal file
94
Api/Dilon.Core/Service/Tenant/Dto/TenantInput.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Dilon.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 long Id { get; set; }
|
||||
}
|
||||
|
||||
public class UpdateTenantInput : TenantInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 租户Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "租户Id不能为空")]
|
||||
public long Id { get; set; }
|
||||
}
|
||||
|
||||
public class QueryTenantInput : DeleteTenantInput
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
53
Api/Dilon.Core/Service/Tenant/Dto/TenantOutput.cs
Normal file
53
Api/Dilon.Core/Service/Tenant/Dto/TenantOutput.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
namespace Dilon.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; }
|
||||
}
|
||||
}
|
||||
14
Api/Dilon.Core/Service/Tenant/ISysTenantService.cs
Normal file
14
Api/Dilon.Core/Service/Tenant/ISysTenantService.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.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);
|
||||
}
|
||||
}
|
||||
100
Api/Dilon.Core/Service/Tenant/SysTenantService.cs
Normal file
100
Api/Dilon.Core/Service/Tenant/SysTenantService.cs
Normal 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 Dilon.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>
|
||||
[HttpGet("/sysTenant/page")]
|
||||
public async Task<dynamic> QueryTenantPageList([FromQuery] 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.PageNo, input.PageSize);
|
||||
return XnPageResult<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);
|
||||
}
|
||||
}
|
||||
}
|
||||
109
Api/Dilon.Core/Service/Timer/Dto/JobInput.cs
Normal file
109
Api/Dilon.Core/Service/Timer/Dto/JobInput.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
using Furion.DataValidation;
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 任务调度参数
|
||||
/// </summary>
|
||||
public class JobInput : PageInputBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 任务名称
|
||||
/// </summary>
|
||||
/// <example>dilon</example>
|
||||
public string JobName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 任务分组
|
||||
/// </summary>
|
||||
/// <example>dilon</example>
|
||||
public string JobGroup { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 开始时间
|
||||
/// </summary>
|
||||
public DateTimeOffset BeginTime { get; set; } = DateTimeOffset.Now;
|
||||
|
||||
/// <summary>
|
||||
/// 结束时间
|
||||
/// </summary>
|
||||
/// <example>null</example>
|
||||
public DateTimeOffset? EndTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cron表达式
|
||||
/// </summary>
|
||||
/// <example></example>
|
||||
public string Cron { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 执行次数(默认无限循环)
|
||||
/// </summary>
|
||||
/// <example>10</example>
|
||||
public int? RunNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 执行间隔时间,单位秒(如果有Cron,则IntervalSecond失效)
|
||||
/// </summary>
|
||||
/// <example>5</example>
|
||||
public int? Interval { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 触发器类型
|
||||
/// </summary>
|
||||
public TriggerTypeEnum TriggerType { get; set; } = TriggerTypeEnum.Simple;
|
||||
|
||||
/// <summary>
|
||||
/// 请求url
|
||||
/// </summary>
|
||||
public string RequestUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求参数(Post,Put请求用)
|
||||
/// </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>
|
||||
public string Remark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 任务状态
|
||||
/// </summary>
|
||||
public string DisplayState { get; set; }
|
||||
}
|
||||
|
||||
public class DeleteJobInput : JobInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 任务Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "任务Id不能为空"), DataValidation(ValidationTypes.Numeric)]
|
||||
public long Id { get; set; }
|
||||
}
|
||||
|
||||
public class UpdateJobInput : DeleteJobInput
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class QueryJobInput : DeleteJobInput
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
96
Api/Dilon.Core/Service/Timer/Dto/JobOutput.cs
Normal file
96
Api/Dilon.Core/Service/Timer/Dto/JobOutput.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
using Quartz;
|
||||
using System;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 任务信息---任务详情
|
||||
/// </summary>
|
||||
public class JobOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// 任务名称
|
||||
/// </summary>
|
||||
public string JobName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 任务组名
|
||||
/// </summary>
|
||||
public string JobGroup { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 下次执行时间
|
||||
/// </summary>
|
||||
public DateTime? NextFireTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 上次执行时间
|
||||
/// </summary>
|
||||
public DateTime? PreviousFireTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 开始时间
|
||||
/// </summary>
|
||||
public DateTime BeginTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 结束时间
|
||||
/// </summary>
|
||||
public DateTime? EndTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 上次执行的异常信息
|
||||
/// </summary>
|
||||
public string LastErrMsg { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 任务状态
|
||||
/// </summary>
|
||||
public TriggerState TriggerState { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 描述
|
||||
/// </summary>
|
||||
public string Remark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 显示状态
|
||||
/// </summary>
|
||||
public string DisplayState
|
||||
{
|
||||
get
|
||||
{
|
||||
return TriggerState switch
|
||||
{
|
||||
TriggerState.Normal => "正常",
|
||||
TriggerState.Paused => "暂停",
|
||||
TriggerState.Complete => "完成",
|
||||
TriggerState.Error => "异常",
|
||||
TriggerState.Blocked => "阻塞",
|
||||
TriggerState.None => "不存在",
|
||||
_ => "未知",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 时间间隔
|
||||
/// </summary>
|
||||
public string Interval { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求地址
|
||||
/// </summary>
|
||||
public string RequestUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求类型
|
||||
/// </summary>
|
||||
public string RequestType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 已经执行的次数
|
||||
/// </summary>
|
||||
public string RunNumber { get; set; }
|
||||
}
|
||||
}
|
||||
68
Api/Dilon.Core/Service/Timer/HttpJob.cs
Normal file
68
Api/Dilon.Core/Service/Timer/HttpJob.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
using Furion.JsonSerialization;
|
||||
using Furion.RemoteRequest.Extensions;
|
||||
using Quartz;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
16
Api/Dilon.Core/Service/Timer/ISysTimerService.cs
Normal file
16
Api/Dilon.Core/Service/Timer/ISysTimerService.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
public interface ISysTimerService
|
||||
{
|
||||
Task AddJob(JobInput input);
|
||||
Task DeleteJob(DeleteJobInput input);
|
||||
Task<dynamic> GetJobPageList([FromQuery] JobInput input);
|
||||
Task<dynamic> GetTimer([FromQuery] QueryJobInput input);
|
||||
Task StopScheduleJobAsync(JobInput input);
|
||||
Task TriggerJobAsync(JobInput input);
|
||||
Task UpdateJob(UpdateJobInput input);
|
||||
}
|
||||
}
|
||||
336
Api/Dilon.Core/Service/Timer/SchedulerCenter.cs
Normal file
336
Api/Dilon.Core/Service/Timer/SchedulerCenter.cs
Normal file
@@ -0,0 +1,336 @@
|
||||
using Furion.DatabaseAccessor;
|
||||
using Furion.DependencyInjection;
|
||||
using Furion.FriendlyException;
|
||||
using Mapster;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Quartz;
|
||||
using Quartz.Impl;
|
||||
using Quartz.Impl.Matchers;
|
||||
using Quartz.Impl.Triggers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 任务调度中心
|
||||
/// </summary>
|
||||
public class SchedulerCenter : ISingleton
|
||||
{
|
||||
private IScheduler _scheduler = null;
|
||||
|
||||
public SchedulerCenter()
|
||||
{
|
||||
_ = StartScheduleAsync();
|
||||
|
||||
InitAllJob().GetAwaiter();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开启调度器
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task<bool> StartScheduleAsync()
|
||||
{
|
||||
if (_scheduler == null)
|
||||
{
|
||||
// 初始化Scheduler
|
||||
var schedulerFactory = new StdSchedulerFactory();
|
||||
_scheduler = await schedulerFactory.GetScheduler();
|
||||
|
||||
// 开启调度器
|
||||
if (_scheduler.InStandbyMode)
|
||||
await _scheduler.Start();
|
||||
}
|
||||
return _scheduler.InStandbyMode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止调度器
|
||||
/// </summary>
|
||||
private async Task<bool> StopScheduleAsync()
|
||||
{
|
||||
//判断调度是否已经关闭
|
||||
if (!_scheduler.InStandbyMode)
|
||||
{
|
||||
//等待任务运行完成
|
||||
await _scheduler.Standby(); // 注意:Shutdown后Start会报错,所以这里使用暂停。
|
||||
}
|
||||
return !_scheduler.InStandbyMode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个工作任务
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<dynamic> AddScheduleJobAsync(JobInput input)
|
||||
{
|
||||
// 检查任务是否已存在
|
||||
var jobKey = new JobKey(input.JobName, input.JobGroup);
|
||||
if (await _scheduler.CheckExists(jobKey))
|
||||
throw Oops.Oh("任务已存在");
|
||||
|
||||
// http请求配置
|
||||
var httpDir = new Dictionary<string, string>()
|
||||
{
|
||||
{ SchedulerDef.ENDAT, input.EndTime.ToString()},
|
||||
{ SchedulerDef.REQUESTURL, input.RequestUrl},
|
||||
{ SchedulerDef.HEADERS, input.Headers },
|
||||
{ SchedulerDef.REQUESTPARAMETERS, input.RequestParameters},
|
||||
{ SchedulerDef.REQUESTTYPE, ((int)input.RequestType).ToString()},
|
||||
{ SchedulerDef.RUNNUMBER, input.RunNumber.ToString()}
|
||||
};
|
||||
|
||||
// 定义这个工作,并将其绑定到我们的IJob实现类
|
||||
IJobDetail job = JobBuilder.Create<HttpJob>()
|
||||
.SetJobData(new JobDataMap(httpDir))
|
||||
.WithDescription(input.Remark)
|
||||
.WithIdentity(input.JobName, input.JobGroup)
|
||||
.Build();
|
||||
// 创建触发器
|
||||
ITrigger trigger = input.TriggerType == TriggerTypeEnum.Cron // && CronExpression.IsValidExpression(entity.Cron)
|
||||
? CreateCronTrigger(input)
|
||||
: CreateSimpleTrigger(input);
|
||||
|
||||
return await _scheduler.ScheduleJob(job, trigger);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 暂停任务
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public async Task StopScheduleJobAsync(JobInput input)
|
||||
{
|
||||
var jobKey = new JobKey(input.JobName, input.JobGroup);
|
||||
await _scheduler.PauseJob(jobKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除任务
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public async Task DeleteScheduleJobAsync(DeleteJobInput input)
|
||||
{
|
||||
var jobKey = new JobKey(input.JobName, input.JobGroup);
|
||||
await _scheduler.PauseJob(jobKey);
|
||||
await _scheduler.DeleteJob(jobKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 恢复运行暂停的任务
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("/sysTimer/resumeJob")]
|
||||
public async Task<dynamic> ResumeJobAsync(JobInput input)
|
||||
{
|
||||
//检查任务是否存在
|
||||
var jobKey = new JobKey(input.JobName, input.JobGroup);
|
||||
if (await _scheduler.CheckExists(jobKey))
|
||||
{
|
||||
var jobDetail = await _scheduler.GetJobDetail(jobKey);
|
||||
var endTime = jobDetail.JobDataMap.GetString(SchedulerDef.ENDAT);
|
||||
if (!string.IsNullOrWhiteSpace(endTime) && DateTime.Parse(endTime) <= DateTime.Now)
|
||||
{
|
||||
throw Oops.Oh("Job的结束时间已过期");
|
||||
}
|
||||
else
|
||||
{
|
||||
await _scheduler.ResumeJob(jobKey); // 任务已经存在则暂停任务
|
||||
}
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询任务
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<JobInput> QueryJobAsync(JobInput input)
|
||||
{
|
||||
var jobKey = new JobKey(input.JobName, input.JobGroup);
|
||||
var jobDetail = await _scheduler.GetJobDetail(jobKey);
|
||||
var triggersList = await _scheduler.GetTriggersOfJob(jobKey);
|
||||
var triggers = triggersList.AsEnumerable().FirstOrDefault();
|
||||
var intervalSeconds = (triggers as SimpleTriggerImpl)?.RepeatInterval.TotalSeconds;
|
||||
var endTime = jobDetail.JobDataMap.GetString(SchedulerDef.ENDAT);
|
||||
return new JobInput
|
||||
{
|
||||
BeginTime = triggers.StartTimeUtc.LocalDateTime,
|
||||
EndTime = !string.IsNullOrWhiteSpace(endTime) ? DateTime.Parse(endTime) : null,
|
||||
Interval = intervalSeconds.HasValue ? Convert.ToInt32(intervalSeconds.Value) : null,
|
||||
JobGroup = input.JobGroup,
|
||||
JobName = input.JobName,
|
||||
Cron = (triggers as CronTriggerImpl)?.CronExpressionString,
|
||||
RunNumber = (triggers as SimpleTriggerImpl)?.RepeatCount,
|
||||
TriggerType = triggers is SimpleTriggerImpl ? TriggerTypeEnum.Simple : TriggerTypeEnum.Cron,
|
||||
Remark = jobDetail.Description,
|
||||
RequestUrl = jobDetail.JobDataMap.GetString(SchedulerDef.REQUESTURL),
|
||||
RequestType = (RequestTypeEnum)int.Parse(jobDetail.JobDataMap.GetString(SchedulerDef.REQUESTTYPE)),
|
||||
RequestParameters = jobDetail.JobDataMap.GetString(SchedulerDef.REQUESTPARAMETERS),
|
||||
Headers = jobDetail.JobDataMap.GetString(SchedulerDef.HEADERS)
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 立即执行
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public async Task TriggerJobAsync(JobInput input)
|
||||
{
|
||||
var jobKey = new JobKey(input.JobName, input.JobGroup);
|
||||
await _scheduler.ResumeJob(jobKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取任务日志
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<string>> GetJobLogsAsync(JobInput input)
|
||||
{
|
||||
var jobKey = new JobKey(input.JobName, input.JobGroup);
|
||||
var jobDetail = await _scheduler.GetJobDetail(jobKey);
|
||||
return jobDetail.JobDataMap[SchedulerDef.LOGLIST] as List<string>;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取任务运行次数
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<long> GetRunNumberAsync(JobInput input)
|
||||
{
|
||||
var jobKey = new JobKey(input.JobName, input.JobGroup);
|
||||
var jobDetail = await _scheduler.GetJobDetail(jobKey);
|
||||
return jobDetail.JobDataMap.GetLong(SchedulerDef.RUNNUMBER);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有任务详情
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<List<JobOutput>> GetJobList()
|
||||
{
|
||||
var jobInfoList = new List<JobOutput>();
|
||||
var groupNames = await _scheduler.GetJobGroupNames();
|
||||
var jboKeyList = new List<JobKey>();
|
||||
foreach (var groupName in groupNames.OrderBy(t => t))
|
||||
{
|
||||
jboKeyList.AddRange(await _scheduler.GetJobKeys(GroupMatcher<JobKey>.GroupEquals(groupName)));
|
||||
//jobInfoList.Add(new JobOutput() { JobGroup = groupName });
|
||||
}
|
||||
foreach (var jobKey in jboKeyList.OrderBy(t => t.Name))
|
||||
{
|
||||
var jobDetail = await _scheduler.GetJobDetail(jobKey);
|
||||
var triggersList = await _scheduler.GetTriggersOfJob(jobKey);
|
||||
var triggers = triggersList.AsEnumerable().FirstOrDefault();
|
||||
|
||||
var interval = triggers is SimpleTriggerImpl
|
||||
? ((triggers as SimpleTriggerImpl)?.RepeatInterval.ToString())
|
||||
: ((triggers as CronTriggerImpl)?.CronExpressionString);
|
||||
|
||||
jobInfoList.Add(new JobOutput
|
||||
{
|
||||
JobName = jobKey.Name,
|
||||
JobGroup = jobKey.Group,
|
||||
LastErrMsg = jobDetail.JobDataMap.GetString(SchedulerDef.EXCEPTION),
|
||||
RequestUrl = jobDetail.JobDataMap.GetString(SchedulerDef.REQUESTURL),
|
||||
TriggerState = await _scheduler.GetTriggerState(triggers.Key),
|
||||
PreviousFireTime = triggers.GetPreviousFireTimeUtc()?.LocalDateTime,
|
||||
NextFireTime = triggers.GetNextFireTimeUtc()?.LocalDateTime,
|
||||
BeginTime = triggers.StartTimeUtc.LocalDateTime,
|
||||
Interval = interval,
|
||||
EndTime = triggers.EndTimeUtc?.LocalDateTime,
|
||||
Remark = jobDetail.Description,
|
||||
RequestType = jobDetail.JobDataMap.GetString(SchedulerDef.REQUESTTYPE),
|
||||
RunNumber = jobDetail.JobDataMap.GetString(SchedulerDef.RUNNUMBER)
|
||||
});
|
||||
}
|
||||
return jobInfoList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从数据库里面获取所有任务并初始化
|
||||
/// </summary>
|
||||
private async Task InitAllJob()
|
||||
{
|
||||
var jobList = Db.GetRepository<SysTimer>().DetachedEntities.Select(u => u.Adapt<JobInput>()).ToList();
|
||||
var jobTasks = new List<Task<dynamic>>();
|
||||
jobList.ForEach(u =>
|
||||
{
|
||||
jobTasks.Add(AddScheduleJobAsync(u));
|
||||
});
|
||||
await Task.WhenAll(jobTasks);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建类型Simple的触发器
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
private static ITrigger CreateSimpleTrigger(JobInput input)
|
||||
{
|
||||
//作业触发器
|
||||
if (input.RunNumber.HasValue && input.RunNumber > 0)
|
||||
{
|
||||
return TriggerBuilder.Create()
|
||||
.WithIdentity(input.JobName, input.JobGroup)
|
||||
.StartAt(input.BeginTime)//开始时间
|
||||
//.EndAt(entity.EndTime)//结束数据
|
||||
.WithSimpleSchedule(x =>
|
||||
{
|
||||
x.WithIntervalInSeconds(input.Interval.Value)//执行时间间隔,单位秒
|
||||
.WithRepeatCount(input.RunNumber.Value)//执行次数、默认从0开始
|
||||
.WithMisfireHandlingInstructionFireNow();
|
||||
})
|
||||
.ForJob(input.JobName, input.JobGroup)//作业名称
|
||||
.Build();
|
||||
}
|
||||
else
|
||||
{
|
||||
return TriggerBuilder.Create()
|
||||
.WithIdentity(input.JobName, input.JobGroup)
|
||||
.StartAt(input.BeginTime)//开始时间
|
||||
//.EndAt(entity.EndTime)//结束数据
|
||||
.WithSimpleSchedule(x =>
|
||||
{
|
||||
x.WithIntervalInSeconds(input.Interval.Value)//执行时间间隔,单位秒
|
||||
.RepeatForever()//无限循环
|
||||
.WithMisfireHandlingInstructionFireNow();
|
||||
})
|
||||
.ForJob(input.JobName, input.JobGroup)//作业名称
|
||||
.Build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建类型Cron的触发器
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
private static ITrigger CreateCronTrigger(JobInput input)
|
||||
{
|
||||
if (!CronExpression.IsValidExpression(input.Cron))
|
||||
throw Oops.Oh("Cron表达式错误");
|
||||
|
||||
// 作业触发器
|
||||
return TriggerBuilder.Create()
|
||||
|
||||
.WithIdentity(input.JobName, input.JobGroup)
|
||||
.StartAt(input.BeginTime) //开始时间
|
||||
//.EndAt(entity.EndTime) //结束时间
|
||||
.WithCronSchedule(input.Cron, cronScheduleBuilder => cronScheduleBuilder.WithMisfireHandlingInstructionFireAndProceed())//指定cron表达式
|
||||
.ForJob(input.JobName, input.JobGroup)//作业名称
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
63
Api/Dilon.Core/Service/Timer/SchedulerDef.cs
Normal file
63
Api/Dilon.Core/Service/Timer/SchedulerDef.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 任务调度相关常量
|
||||
/// </summary>
|
||||
public class SchedulerDef
|
||||
{
|
||||
/// <summary>
|
||||
/// 请求url RequestUrl
|
||||
/// </summary>
|
||||
public const string REQUESTURL = "RequestUrl";
|
||||
/// <summary>
|
||||
/// 请求参数 RequestParameters
|
||||
/// </summary>
|
||||
public const string REQUESTPARAMETERS = "RequestParameters";
|
||||
/// <summary>
|
||||
/// Headers(可以包含:Authorization授权认证)
|
||||
/// </summary>
|
||||
public const string HEADERS = "Headers";
|
||||
/// <summary>
|
||||
/// 请求类型 RequestType
|
||||
/// </summary>
|
||||
public const string REQUESTTYPE = "RequestType";
|
||||
/// <summary>
|
||||
/// 日志 LogList
|
||||
/// </summary>
|
||||
public const string LOGLIST = "LogList";
|
||||
/// <summary>
|
||||
/// 异常 Exception
|
||||
/// </summary>
|
||||
public const string EXCEPTION = "Exception";
|
||||
/// <summary>
|
||||
/// 执行次数
|
||||
/// </summary>
|
||||
public const string RUNNUMBER = "RunNumber";
|
||||
/// <summary>
|
||||
/// 任务结束时间
|
||||
/// </summary>
|
||||
public const string ENDAT = "EndAt";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// http请求类型
|
||||
/// </summary>
|
||||
public enum RequestTypeEnum
|
||||
{
|
||||
None = 0,
|
||||
Get = 1,
|
||||
Post = 2,
|
||||
Put = 3,
|
||||
Delete = 4
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 触发器类型
|
||||
/// </summary>
|
||||
public enum TriggerTypeEnum
|
||||
{
|
||||
None = 0,
|
||||
Simple = 1,
|
||||
Cron = 2
|
||||
}
|
||||
}
|
||||
145
Api/Dilon.Core/Service/Timer/SysTimerService.cs
Normal file
145
Api/Dilon.Core/Service/Timer/SysTimerService.cs
Normal file
@@ -0,0 +1,145 @@
|
||||
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 Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 任务调度服务
|
||||
/// </summary>
|
||||
[ApiDescriptionSettings(Name = "Timer", Order = 100)]
|
||||
public class SysTimerService : ISysTimerService, IDynamicApiController, IScoped
|
||||
{
|
||||
private readonly IRepository<SysTimer> _sysTimerRep; // 任务表仓储
|
||||
private readonly SchedulerCenter _schedulerCenter;
|
||||
|
||||
public SysTimerService(IRepository<SysTimer> sysTimerRep, SchedulerCenter schedulerCenter)
|
||||
{
|
||||
_sysTimerRep = sysTimerRep;
|
||||
_schedulerCenter = schedulerCenter;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分页获取任务列表
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("/sysTimers/page")]
|
||||
public async Task<dynamic> GetJobPageList([FromQuery] JobInput input)
|
||||
{
|
||||
var jobList = await _schedulerCenter.GetJobList();
|
||||
|
||||
var jobName = !string.IsNullOrEmpty(input.JobName?.Trim());
|
||||
var timers = await _sysTimerRep.DetachedEntities
|
||||
.Where((jobName, u => EF.Functions.Like(u.JobName, $"%{input.JobName.Trim()}%")))
|
||||
.Select(u => u.Adapt<JobInput>())
|
||||
.ToPagedListAsync(input.PageNo, input.PageSize);
|
||||
|
||||
timers.Items.ToList().ForEach(u =>
|
||||
{
|
||||
u.DisplayState = jobList.Find(m => m.JobName == u.JobName)?.DisplayState;
|
||||
});
|
||||
return XnPageResult<JobInput>.PageResult(timers);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增加任务
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("/sysTimers/add")]
|
||||
public async Task AddJob(JobInput input)
|
||||
{
|
||||
var isExist = await _sysTimerRep.AnyAsync(u => u.JobName == input.JobName, false);
|
||||
if (isExist)
|
||||
throw Oops.Oh(ErrorCode.D1100);
|
||||
|
||||
var timer = input.Adapt<SysTimer>();
|
||||
await _sysTimerRep.InsertAsync(timer);
|
||||
|
||||
// 添加到调度
|
||||
await _schedulerCenter.AddScheduleJobAsync(input);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除任务
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("/sysTimers/delete")]
|
||||
public async Task DeleteJob(DeleteJobInput input)
|
||||
{
|
||||
var timer = await _sysTimerRep.FirstOrDefaultAsync(u => u.Id == input.Id);
|
||||
if (timer == null)
|
||||
throw Oops.Oh(ErrorCode.D1101);
|
||||
|
||||
await timer.DeleteAsync();
|
||||
|
||||
// 从调度器里删除
|
||||
await _schedulerCenter.DeleteScheduleJobAsync(input);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 修改任务
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("/sysTimers/edit")]
|
||||
public async Task UpdateJob(UpdateJobInput input)
|
||||
{
|
||||
// 排除自己并且判断与其他是否相同
|
||||
var isExist = await _sysTimerRep.AnyAsync(u => u.JobName == input.JobName && u.Id != input.Id, false);
|
||||
if (isExist) throw Oops.Oh(ErrorCode.D1100);
|
||||
|
||||
var timer = input.Adapt<SysTimer>();
|
||||
await timer.UpdateAsync(ignoreNullValues: true);
|
||||
|
||||
// 先从调度器里删除
|
||||
var oldTimer = await _sysTimerRep.FirstOrDefaultAsync(u => u.Id == input.Id, false);
|
||||
await _schedulerCenter.DeleteScheduleJobAsync(oldTimer.Adapt<DeleteJobInput>());
|
||||
|
||||
// 再加到调度里
|
||||
await _schedulerCenter.AddScheduleJobAsync(timer.Adapt<JobInput>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查看任务
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("/sysTimers/detail")]
|
||||
public async Task<dynamic> GetTimer([FromQuery] QueryJobInput input)
|
||||
{
|
||||
return await _sysTimerRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == input.Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止任务
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("/sysTimers/stop")]
|
||||
public async Task StopScheduleJobAsync(JobInput input)
|
||||
{
|
||||
await _schedulerCenter.StopScheduleJobAsync(input);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动任务
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("/sysTimers/start")]
|
||||
public async Task TriggerJobAsync(JobInput input)
|
||||
{
|
||||
await _schedulerCenter.TriggerJobAsync(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
27
Api/Dilon.Core/Service/User/Dto/AuthToken.cs
Normal file
27
Api/Dilon.Core/Service/User/Dto/AuthToken.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// AuthToken参数
|
||||
/// </summary>
|
||||
public class AuthToken
|
||||
{
|
||||
public string AccessToken { get; set; }
|
||||
public int ExpireIn { get; set; }
|
||||
public string RefreshToken { get; set; }
|
||||
public string Uid { get; set; }
|
||||
public string OpenId { get; set; }
|
||||
public string AccessCode { get; set; }
|
||||
public string UnionId { get; set; }
|
||||
public string Scope { get; set; }
|
||||
public string TokenType { get; set; }
|
||||
public string IdToken { get; set; }
|
||||
public string MacAlgorithm { get; set; }
|
||||
public string MacKey { get; set; }
|
||||
public string Code { get; set; }
|
||||
public string OauthToken { get; set; }
|
||||
public string OauthTokenSecret { get; set; }
|
||||
public string UserId { get; set; }
|
||||
public string ScreenName { get; set; }
|
||||
public bool OauthCallbackConfirmed { get; set; }
|
||||
}
|
||||
}
|
||||
22
Api/Dilon.Core/Service/User/Dto/AuthUserInput.cs
Normal file
22
Api/Dilon.Core/Service/User/Dto/AuthUserInput.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
namespace Dilon.Core.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// OAuth用户参数
|
||||
/// </summary>
|
||||
public class AuthUserInput
|
||||
{
|
||||
public string Uuid { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string Nickname { get; set; }
|
||||
public string Avatar { get; set; }
|
||||
public string Blog { get; set; }
|
||||
public string Company { get; set; }
|
||||
public string Location { get; set; }
|
||||
public string Email { get; set; }
|
||||
public string Eemark { get; set; }
|
||||
public Gender Gender { get; set; }
|
||||
public string Source { get; set; }
|
||||
public AuthToken Token { get; set; }
|
||||
public string RawUserInfo { get; set; }
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user