diff --git a/README.md b/README.md index b7c512b..7845f55 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ * 后端采用Net5、Sqlsugar、MySQL。 * 权限认证使用Jwt,支持多终端认证系统。 * 支持加载动态权限菜单,多方式轻松权限控制 +* 提供了技术栈(Ant Design Vue)版[Ant Design Vue](https://gitee.com/billzh/mc-dull.git) * 七牛云通用云产品优惠券:[点我进入](https://s.qiniu.com/FzEfay)。 * 腾讯云秒杀场:[点我进入](https://curl.qcloud.com/4yEoRquq)。 * 腾讯云优惠券:[点我领取](https://curl.qcloud.com/5J4nag8D)。 diff --git a/ZR.Admin.WebApi/Controllers/CommonController.cs b/ZR.Admin.WebApi/Controllers/CommonController.cs index 9abc60c..d36dff1 100644 --- a/ZR.Admin.WebApi/Controllers/CommonController.cs +++ b/ZR.Admin.WebApi/Controllers/CommonController.cs @@ -100,7 +100,7 @@ namespace ZR.Admin.WebApi.Controllers { if (formFile == null) throw new CustomException(ResultCode.PARAM_ERROR, "上传文件不能为空"); - SysFile file = await SysFileService.SaveFileLocal(WebHostEnvironment.WebRootPath, fileName, fileDir, HttpContext.GetName(), formFile); + SysFile file = await SysFileService.SaveFileToLocal(WebHostEnvironment.WebRootPath, fileName, fileDir, HttpContext.GetName(), formFile); return SUCCESS(new { url = uploadType == 1 ? file.FileUrl : file.AccessUrl, @@ -121,10 +121,9 @@ namespace ZR.Admin.WebApi.Controllers [ActionPermissionFilter(Permission = "common")] public async Task UploadFileAliyun([FromForm(Name = "file")] IFormFile formFile, string fileName = "", string fileDir = "") { - if (fileDir.IsEmpty()) fileDir = "uploads"; if (formFile == null) throw new CustomException(ResultCode.PARAM_ERROR, "上传文件不能为空"); string fileExt = Path.GetExtension(formFile.FileName);//文件后缀 - double fileSize = formFile.Length / 1024.0;//文件大小KB + double fileSize = Math.Round(formFile.Length / 1024.0, 2);//文件大小KB string[] NotAllowedFileExtensions = new string[] { ".bat", ".exe", ".jar", ".js" }; int MaxContentLength = 15; if (NotAllowedFileExtensions.Contains(fileExt)) @@ -135,26 +134,20 @@ namespace ZR.Admin.WebApi.Controllers { return ToResponse(ResultCode.CUSTOM_ERROR, "上传文件过大,不能超过 " + MaxContentLength + " MB"); } - - (bool, string, string) result = new(); - await Task.Run(() => - { - result = SysFileService.SaveFile(fileDir, formFile, fileName, ""); - }); - if (!result.Item1) - { - return ToResponse(ApiResult.Error("阿里云连接失败")); - } - long id = await SysFileService.InsertFile(new(formFile.FileName, fileName, fileExt, fileSize + "kb", "", result.Item2, HttpContext.GetName()) + SysFile file = new(formFile.FileName, fileName, fileExt, fileSize + "kb", fileDir, "", HttpContext.GetName()) { StoreType = (int)Infrastructure.Enums.StoreType.ALIYUN, FileType = formFile.ContentType - }); + }; + file = await SysFileService.SaveFileToAliyun(file, formFile); + + if (file.Id <= 0) { return ToResponse(ApiResult.Error("阿里云连接失败")); } + return SUCCESS(new { - url = result.Item2, - fileName = result.Item3, - fileId = id + url = file.AccessUrl, + fileName = file.FileName, + fileId = file.Id.ToString() }); } #endregion diff --git a/ZR.Admin.WebApi/Controllers/System/SysLoginController.cs b/ZR.Admin.WebApi/Controllers/System/SysLoginController.cs index 3694650..2b89b4c 100644 --- a/ZR.Admin.WebApi/Controllers/System/SysLoginController.cs +++ b/ZR.Admin.WebApi/Controllers/System/SysLoginController.cs @@ -86,8 +86,8 @@ namespace ZR.Admin.WebApi.Controllers.System List permissions = permissionService.GetMenuPermission(user); LoginUser loginUser = new(user, roles, permissions); - CacheHelper.SetCache(GlobalConstant.UserPermKEY + user.UserId, loginUser); - return SUCCESS(JwtUtil.GenerateJwtToken(HttpContext.AddClaims(loginUser), jwtSettings.JwtSettings)); + CacheHelper.SetCache(GlobalConstant.UserPermKEY + user.UserId, permissions); + return SUCCESS(JwtUtil.GenerateJwtToken(JwtUtil.AddClaims(loginUser), jwtSettings.JwtSettings)); } /// @@ -103,11 +103,11 @@ namespace ZR.Admin.WebApi.Controllers.System // //注销登录的用户,相当于ASP.NET中的FormsAuthentication.SignOut // await HttpContext.SignOutAsync(); //}).Wait(); - var id = HttpContext.GetUId(); + var userid = HttpContext.GetUId(); var name = HttpContext.GetName(); - - CacheHelper.Remove(GlobalConstant.UserPermKEY + id); - return SUCCESS(new { name , id}); + + CacheHelper.Remove(GlobalConstant.UserPermKEY + userid); + return SUCCESS(new { name , id = userid }); } /// diff --git a/ZR.Admin.WebApi/Controllers/System/SysUserController.cs b/ZR.Admin.WebApi/Controllers/System/SysUserController.cs index 5f8420b..9f6b0a5 100644 --- a/ZR.Admin.WebApi/Controllers/System/SysUserController.cs +++ b/ZR.Admin.WebApi/Controllers/System/SysUserController.cs @@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Mvc; using System.Collections.Generic; using System.IO; using System.Linq; +using ZR.Admin.WebApi.Extensions; using ZR.Admin.WebApi.Filters; using ZR.Common; using ZR.Model; @@ -94,7 +95,7 @@ namespace ZR.Admin.WebApi.Controllers.System return ToResponse(ApiResult.Error($"新增用户 '{user.UserName}'失败,登录账号已存在")); } - user.Create_by = User.Identity.Name; + user.Create_by = HttpContext.GetName(); user.Password = NETCore.Encrypt.EncryptProvider.Md5(user.Password); return ToResponse(UserService.InsertUser(user)); @@ -112,7 +113,7 @@ namespace ZR.Admin.WebApi.Controllers.System { if (user == null || user.UserId <= 0) { return ToResponse(ApiResult.Error(101, "请求参数错误")); } - user.Update_by = User.Identity.Name; + user.Update_by = HttpContext.GetName(); int upResult = UserService.UpdateUser(user); return ToResponse(upResult); diff --git a/ZR.Admin.WebApi/Extensions/HttpContextExtension.cs b/ZR.Admin.WebApi/Extensions/HttpContextExtension.cs index 2df4734..2103a91 100644 --- a/ZR.Admin.WebApi/Extensions/HttpContextExtension.cs +++ b/ZR.Admin.WebApi/Extensions/HttpContextExtension.cs @@ -130,27 +130,6 @@ namespace ZR.Admin.WebApi.Extensions return context != null ? context.Request.Path.Value : ""; } - /// - ///组装Claims - /// - /// - /// - /// - public static List AddClaims(this HttpContext context, LoginUser user) - { - //1、创建Cookie保存用户信息,使用claim - var claims = new List() - { - new Claim(ClaimTypes.PrimarySid, user.UserId.ToString()), - new Claim(ClaimTypes.Name, user.UserName), - new Claim(ClaimTypes.UserData, JsonConvert.SerializeObject(user)) - }; - - //写入Cookie - //WhiteCookie(context, claims); - return claims; - } - private static void WhiteCookie(HttpContext context, List claims) { //2.创建声明主题 指定认证方式 这里使用cookie diff --git a/ZR.Admin.WebApi/Framework/JwtUtil.cs b/ZR.Admin.WebApi/Framework/JwtUtil.cs index 3af5a6f..eb37c83 100644 --- a/ZR.Admin.WebApi/Framework/JwtUtil.cs +++ b/ZR.Admin.WebApi/Framework/JwtUtil.cs @@ -10,6 +10,7 @@ using System.Linq; using System.Security.Claims; using System.Text; using ZR.Admin.WebApi.Extensions; +using ZR.Common; using ZR.Model.System; namespace ZR.Admin.WebApi.Framework @@ -129,8 +130,10 @@ namespace ZR.Admin.WebApi.Framework try { var userData = jwtToken.FirstOrDefault(x => x.Type == ClaimTypes.UserData).Value; - - LoginUser loginUser = JsonConvert.DeserializeObject(userData); + var loginUser = JsonConvert.DeserializeObject(userData); + var permissions = CacheHelper.GetCache(GlobalConstant.UserPermKEY + loginUser?.UserId); + if (permissions == null) return null; + loginUser.Permissions = (List)permissions; return loginUser; } catch (Exception ex) @@ -139,5 +142,27 @@ namespace ZR.Admin.WebApi.Framework return null; } } + + /// + ///组装Claims + /// + /// + /// + public static List AddClaims(LoginUser user) + { + user.Permissions = new List(); + //1、创建Cookie保存用户信息,使用claim + var claims = new List() + { + new Claim(ClaimTypes.PrimarySid, user.UserId.ToString()), + new Claim(ClaimTypes.Name, user.UserName), + new Claim(ClaimTypes.UserData, JsonConvert.SerializeObject(user)) + }; + + //写入Cookie + //WhiteCookie(context, claims); + return claims; + } + } } diff --git a/ZR.Model/System/Dto/SysFileQueryDto.cs b/ZR.Model/System/Dto/SysFileQueryDto.cs index fc860f8..b251f1e 100644 --- a/ZR.Model/System/Dto/SysFileQueryDto.cs +++ b/ZR.Model/System/Dto/SysFileQueryDto.cs @@ -10,15 +10,72 @@ namespace ZR.Model.System.Dto public class SysFileDto { public long Id { get; set; } + /// + /// 文件原名 + /// + public string RealName { get; set; } + /// + /// 文件类型 + /// + public string FileType { get; set; } + /// + /// 描述 : 存储文件名 + /// 空值 : true + /// public string FileName { get; set; } + /// + /// 描述 : 文件存储地址 eg:/uploads/20220202 + /// 空值 : true + /// public string FileUrl { get; set; } + /// + /// 描述 : 仓库位置 eg:/uploads + /// 空值 : true + /// public string StorePath { get; set; } + /// + /// 描述 : 文件大小 + /// 空值 : true + /// public string FileSize { get; set; } + /// + /// 描述 : 文件扩展名 + /// 空值 : true + /// public string FileExt { get; set; } + /// + /// 描述 : 创建人 + /// 空值 : true + /// public string Create_by { get; set; } + /// + /// 描述 : 上传时间 + /// 空值 : true + /// public DateTime? Create_time { get; set; } + /// + /// 描述 : 存储类型 + /// 空值 : true + /// public int? StoreType { get; set; } + /// + /// 描述 : 访问路径 + /// 空值 : true + /// public string AccessUrl { get; set; } + + public SysFileDto() { } + public SysFileDto(string originFileName, string fileName, string ext, string fileSize, string storePath, string accessUrl, string create_by) + { + StorePath = storePath; + RealName = originFileName; + FileName = fileName; + FileExt = ext; + FileSize = fileSize; + AccessUrl = accessUrl; + Create_by = create_by; + Create_time = DateTime.Now; + } } public class SysFileQueryDto : PagerInfo { diff --git a/ZR.Model/System/LoginUser.cs b/ZR.Model/System/LoginUser.cs index 9b5e797..013a9d1 100644 --- a/ZR.Model/System/LoginUser.cs +++ b/ZR.Model/System/LoginUser.cs @@ -24,7 +24,7 @@ namespace ZR.Model.System /// /// 权限集合 /// - public List Permissions { get; set; } + public List Permissions { get; set; } = new List(); public LoginUser() { } diff --git a/ZR.Model/System/SysFile.cs b/ZR.Model/System/SysFile.cs index 08a2fd4..501b9c0 100644 --- a/ZR.Model/System/SysFile.cs +++ b/ZR.Model/System/SysFile.cs @@ -18,7 +18,7 @@ namespace ZR.Model.System [SugarColumn(IsPrimaryKey = true)] public long Id { get; set; } /// - /// 文件真实名 + /// 文件原名 /// public string RealName { get; set; } /// @@ -26,17 +26,17 @@ namespace ZR.Model.System /// public string FileType { get; set; } /// - /// 描述 : 文件名 + /// 描述 : 存储文件名 /// 空值 : true /// public string FileName { get; set; } /// - /// 描述 : 文件存储地址 + /// 描述 : 文件存储地址 eg:/uploads/20220202 /// 空值 : true /// public string FileUrl { get; set; } /// - /// 描述 : 仓库位置 + /// 描述 : 仓库位置 eg:/uploads /// 空值 : true /// public string StorePath { get; set; } @@ -72,10 +72,10 @@ namespace ZR.Model.System public string AccessUrl { get; set; } public SysFile() { } - public SysFile(string realName, string fileName, string ext, string fileSize, string storePath, string accessUrl,string create_by) + public SysFile(string originFileName, string fileName, string ext, string fileSize, string storePath, string accessUrl,string create_by) { StorePath = storePath; - RealName = realName; + RealName = originFileName; FileName = fileName; FileExt = ext; FileSize = fileSize; diff --git a/ZR.Service/System/IService/ISysFileService.cs b/ZR.Service/System/IService/ISysFileService.cs index aa40fee..2482bc7 100644 --- a/ZR.Service/System/IService/ISysFileService.cs +++ b/ZR.Service/System/IService/ISysFileService.cs @@ -19,19 +19,21 @@ namespace ZR.Service.System.IService /// /// /// 文件对象 - Task SaveFileLocal(string rootPath, string fileName, string fileDir, string userName, IFormFile formFile); - (bool, string, string) SaveFile(string picdir, IFormFile formFile, string customFileName, string bucketName); + Task SaveFileToLocal(string rootPath, string fileName, string fileDir, string userName, IFormFile formFile); + + Task SaveFileToAliyun(SysFile file, IFormFile formFile); /// /// 按时间来创建文件夹 /// /// + /// /// eg: 2020/11/3 - string GetdirPath(string path = ""); + string GetdirPath(string path = "", bool byTimeStore = true); /// /// 取文件名的MD5值(16位) /// - /// 文件名,不包括扩展名 + /// 文件名,不包括扩展名 /// string HashFileName(string str = null); } diff --git a/ZR.Service/System/SysFileService.cs b/ZR.Service/System/SysFileService.cs index 7f3c1ab..415a21e 100644 --- a/ZR.Service/System/SysFileService.cs +++ b/ZR.Service/System/SysFileService.cs @@ -35,13 +35,12 @@ namespace ZR.Service.System /// 存储本地 /// /// - public async Task SaveFileLocal(string rootPath, string fileName, string fileDir, string userName, IFormFile formFile) + public async Task SaveFileToLocal(string rootPath, string fileName, string fileDir, string userName, IFormFile formFile) { string fileExt = Path.GetExtension(formFile.FileName); - string hashFileName = FileUtil.HashFileName(); - fileName = (fileName.IsEmpty() ? hashFileName : fileName) + fileExt; + fileName = (fileName.IsEmpty() ? HashFileName() : fileName) + fileExt; fileDir = fileDir.IsEmpty() ? "uploads" : fileDir; - string filePath = FileUtil.GetdirPath(fileDir); + string filePath = GetdirPath(fileDir); string finalFilePath = Path.Combine(rootPath, filePath, fileName); double fileSize = Math.Round(formFile.Length / 1024.0, 2); @@ -68,37 +67,39 @@ namespace ZR.Service.System /// /// 上传文件到阿里云 /// - /// 文件夹 + /// /// - /// 自定义文件名 - /// 存储桶 /// - public (bool, string, string) SaveFile(string picdir, IFormFile formFile, string customFileName, string bucketName) + public async Task SaveFileToAliyun(SysFile file, IFormFile formFile) { - // eg: uploads/2020/08/18 - //string dir = GetdirPath(picdir.ToString()); + file.FileName = (file.FileName.IsEmpty() ? HashFileName() : file.FileName) + file.FileExt; + file.StorePath = GetdirPath(file.StorePath); + string finalPath = Path.Combine(file.StorePath, file.FileName); + HttpStatusCode statusCode = AliyunOssHelper.PutObjectFromFile(formFile.OpenReadStream(), finalPath, ""); + if (statusCode != HttpStatusCode.OK) return file; - string tempName = customFileName.IsEmpty() ? HashFileName() : customFileName; - string fileExt = Path.GetExtension(formFile.FileName); - string fileName = tempName + fileExt; - string webUrl = string.Concat(domainUrl, "/", picdir, "/", fileName); + file.StorePath = file.StorePath; + file.FileUrl = finalPath; + file.AccessUrl = string.Concat(domainUrl, "/", file.StorePath.Replace("\\", "/"), "/", file.FileName); + file.Id = await InsertFile(file); - HttpStatusCode statusCode = AliyunOssHelper.PutObjectFromFile(formFile.OpenReadStream(), Path.Combine(picdir, fileName), bucketName); - - return (statusCode == HttpStatusCode.OK, webUrl, fileName); + return file; } - public string GetdirPath(string path = "") + + /// + /// 获取文件存储目录 + /// + /// + /// 是否按年月日存储 + /// + public string GetdirPath(string storePath = "", bool byTimeStore = true) { DateTime date = DateTime.Now; - int year = date.Year; - int month = date.Month; - int day = date.Day; - //int hour = date.Hour; + string timeDir = date.ToString("yyyyMMdd"); - string timeDir = $"{year}/{month}/{day}";// date.ToString("yyyyMM/dd/HH/"); - if (!string.IsNullOrEmpty(path)) + if (!string.IsNullOrEmpty(storePath)) { - timeDir = path + "/" + timeDir; + timeDir = Path.Combine(storePath, timeDir); } return timeDir; } diff --git a/ZR.Vue/src/components/Crontab/day.vue b/ZR.Vue/src/components/Crontab/day.vue new file mode 100644 index 0000000..fe3eaf0 --- /dev/null +++ b/ZR.Vue/src/components/Crontab/day.vue @@ -0,0 +1,161 @@ + + + diff --git a/ZR.Vue/src/components/Crontab/hour.vue b/ZR.Vue/src/components/Crontab/hour.vue new file mode 100644 index 0000000..4b1f1fc --- /dev/null +++ b/ZR.Vue/src/components/Crontab/hour.vue @@ -0,0 +1,114 @@ + + + diff --git a/ZR.Vue/src/components/Crontab/index.vue b/ZR.Vue/src/components/Crontab/index.vue new file mode 100644 index 0000000..8e39046 --- /dev/null +++ b/ZR.Vue/src/components/Crontab/index.vue @@ -0,0 +1,389 @@ + + + + diff --git a/ZR.Vue/src/components/Crontab/min.vue b/ZR.Vue/src/components/Crontab/min.vue new file mode 100644 index 0000000..43cab90 --- /dev/null +++ b/ZR.Vue/src/components/Crontab/min.vue @@ -0,0 +1,116 @@ + + + \ No newline at end of file diff --git a/ZR.Vue/src/components/Crontab/month.vue b/ZR.Vue/src/components/Crontab/month.vue new file mode 100644 index 0000000..fd0ac38 --- /dev/null +++ b/ZR.Vue/src/components/Crontab/month.vue @@ -0,0 +1,114 @@ + + + diff --git a/ZR.Vue/src/components/Crontab/result.vue b/ZR.Vue/src/components/Crontab/result.vue new file mode 100644 index 0000000..2ce2041 --- /dev/null +++ b/ZR.Vue/src/components/Crontab/result.vue @@ -0,0 +1,569 @@ + + + + \ No newline at end of file diff --git a/ZR.Vue/src/components/Crontab/second.vue b/ZR.Vue/src/components/Crontab/second.vue new file mode 100644 index 0000000..e7b7761 --- /dev/null +++ b/ZR.Vue/src/components/Crontab/second.vue @@ -0,0 +1,117 @@ + + + diff --git a/ZR.Vue/src/components/Crontab/week.vue b/ZR.Vue/src/components/Crontab/week.vue new file mode 100644 index 0000000..1cec700 --- /dev/null +++ b/ZR.Vue/src/components/Crontab/week.vue @@ -0,0 +1,202 @@ + + + diff --git a/ZR.Vue/src/components/Crontab/year.vue b/ZR.Vue/src/components/Crontab/year.vue new file mode 100644 index 0000000..5487a6c --- /dev/null +++ b/ZR.Vue/src/components/Crontab/year.vue @@ -0,0 +1,131 @@ + + + diff --git a/ZR.Vue/src/views/login.vue b/ZR.Vue/src/views/login.vue index 8d5cdea..5e3b75b 100644 --- a/ZR.Vue/src/views/login.vue +++ b/ZR.Vue/src/views/login.vue @@ -145,7 +145,7 @@ export default { }; -