diff --git a/Infrastructure/Helper/FileUtil.cs b/Infrastructure/Helper/FileUtil.cs index 1a3c000..d9bbb0a 100644 --- a/Infrastructure/Helper/FileUtil.cs +++ b/Infrastructure/Helper/FileUtil.cs @@ -12,7 +12,7 @@ namespace Infrastructure /// 按时间来创建文件夹 /// /// - /// eg: /{yourPath}/2020/11/3 + /// eg: /{yourPath}/2020/11/3/ public static string GetdirPath(string path = "") { DateTime date = DateTime.Now; @@ -21,7 +21,7 @@ namespace Infrastructure int day = date.Day; int hour = date.Hour; - string timeDir = $"{year}{month}{day}";// date.ToString("yyyyMM/dd/HH/"); + string timeDir = $"{year}{month}{day}/";// date.ToString("yyyyMM/dd/HH/"); if (!string.IsNullOrEmpty(path)) { diff --git a/ZR.Admin.WebApi/Controllers/CommonController.cs b/ZR.Admin.WebApi/Controllers/CommonController.cs index 14f1be7..b2b940f 100644 --- a/ZR.Admin.WebApi/Controllers/CommonController.cs +++ b/ZR.Admin.WebApi/Controllers/CommonController.cs @@ -9,8 +9,10 @@ using Newtonsoft.Json; using System; using System.IO; using System.Linq; +using ZR.Admin.WebApi.Extensions; using ZR.Admin.WebApi.Filters; using ZR.Common; +using ZR.Model.System; using ZR.Service.System.IService; namespace ZR.Admin.WebApi.Controllers @@ -82,17 +84,20 @@ namespace ZR.Admin.WebApi.Controllers /// 存储文件 /// /// + /// 存储目录 /// [HttpPost()] [Verify] [ActionPermissionFilter(Permission = "common")] - public IActionResult UploadFile([FromForm(Name = "file")] IFormFile formFile) + public IActionResult UploadFile([FromForm(Name = "file")] IFormFile formFile, string fileDir = "uploads") { if (formFile == null) throw new CustomException(ResultCode.PARAM_ERROR, "上传文件不能为空"); string fileExt = Path.GetExtension(formFile.FileName); string fileName = FileUtil.HashFileName(Guid.NewGuid().ToString()).ToLower() + fileExt; - string finalFilePath = Path.Combine(WebHostEnvironment.WebRootPath, FileUtil.GetdirPath("uploads"), fileName); + string filePath = FileUtil.GetdirPath(fileDir); + string finalFilePath = Path.Combine(WebHostEnvironment.WebRootPath, filePath, fileName); finalFilePath = finalFilePath.Replace("\\", "/").Replace("//", "/"); + double fileSize = formFile.Length / 1024; if (!Directory.Exists(Path.GetDirectoryName(finalFilePath))) { @@ -104,11 +109,24 @@ namespace ZR.Admin.WebApi.Controllers formFile.CopyTo(stream); } - string accessPath = $"{OptionsSetting.Upload.UploadUrl}/{FileUtil.GetdirPath("uploads").Replace("\\", " /")}{fileName}"; + string accessPath = $"{OptionsSetting.Upload.UploadUrl}/{filePath.Replace("\\", " /")}{fileName}"; + SysFile file = new() + { + AccessUrl = accessPath, + Create_by = HttpContext.GetName(), + FileExt = fileExt, + FileName = fileName, + FileSize = fileSize + "kb", + StoreType = 1, + FileUrl = finalFilePath, + Create_time = DateTime.Now + }; + long fileId = SysFileService.InsertFile(file); return ToResponse(ResultCode.SUCCESS, new { url = accessPath, - fileName + fileName, + fileId }); } @@ -127,7 +145,7 @@ namespace ZR.Admin.WebApi.Controllers string fileExt = Path.GetExtension(formFile.FileName); string[] AllowedFileExtensions = new string[] { ".jpg", ".gif", ".png", ".jpeg", ".webp", ".svga", ".xls" }; int MaxContentLength = 1024 * 1024 * 5; - + double fileSize = formFile.Length / 1024; if (!AllowedFileExtensions.Contains(fileExt)) { return ToResponse(ResultCode.CUSTOM_ERROR, "上传失败,未经允许上传类型"); @@ -138,11 +156,21 @@ namespace ZR.Admin.WebApi.Controllers return ToResponse(ResultCode.CUSTOM_ERROR, "上传文件过大,不能超过 " + (MaxContentLength / 1024).ToString() + " MB"); } (bool, string, string) result = SysFileService.SaveFile(fileDir, formFile); - + long fileId = SysFileService.InsertFile(new SysFile() + { + AccessUrl = result.Item2, + Create_by = HttpContext.GetName(), + FileExt = fileExt, + FileName = result.Item3, + FileSize = fileSize + "kb", + StoreType = 2, + StorePath = fileDir + }); return ToResponse(ResultCode.SUCCESS, new { url = result.Item2, - fileName = result.Item3 + fileName = result.Item3, + fileId }); } #endregion diff --git a/ZR.Admin.WebApi/Controllers/System/SysFileController.cs b/ZR.Admin.WebApi/Controllers/System/SysFileController.cs new file mode 100644 index 0000000..05f2537 --- /dev/null +++ b/ZR.Admin.WebApi/Controllers/System/SysFileController.cs @@ -0,0 +1,163 @@ +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using Infrastructure; +using Infrastructure.Attribute; +using Infrastructure.Enums; +using Infrastructure.Model; +using Mapster; +using ZR.Admin.WebApi.Extensions; +using ZR.Admin.WebApi.Filters; +using ZR.Common; +using ZR.Model.System; +using ZR.Service.System.IService; +using ZR.Model.System.Dto; + +namespace ZR.Admin.WebApi.Controllers +{ + /// + /// 文件存储Controller + /// + [Verify] + [Route("tool/file")] + public class SysFileController : BaseController + { + /// + /// 文件存储接口 + /// + private readonly ISysFileService _SysFileService; + + public SysFileController(ISysFileService SysFileService) + { + _SysFileService = SysFileService; + } + + /// + /// 查询文件存储列表 + /// + /// + /// + [HttpGet("list")] + [ActionPermissionFilter(Permission = "tool:file:list")] + public IActionResult QuerySysFile([FromQuery] SysFileQueryDto parm) + { + //开始拼装查询条件 + var predicate = Expressionable.Create(); + //搜索条件查询语法参考Sqlsugar + predicate = predicate.AndIF(parm.BeginCreate_time != null, it => it.Create_time >= parm.BeginCreate_time); + predicate = predicate.AndIF(parm.EndCreate_time != null, it => it.Create_time <= parm.EndCreate_time); + predicate = predicate.AndIF(parm.StoreType != null, m => m.StoreType == parm.StoreType); + + //搜索条件查询语法参考Sqlsugar + var response = _SysFileService.GetPages(predicate.ToExpression(), parm); + return SUCCESS(response); + } + + /// + /// 查询文件存储详情 + /// + /// + /// + [HttpGet("{Id}")] + [ActionPermissionFilter(Permission = "tool:file:query")] + public IActionResult GetSysFile(int Id) + { + var response = _SysFileService.GetFirst(x => x.Id == Id); + + return SUCCESS(response); + } + + /// + /// 添加文件存储 + /// + /// + [HttpPost] + [ActionPermissionFilter(Permission = "tool:file:add")] + [Log(Title = "文件存储", BusinessType = BusinessType.INSERT)] + public IActionResult AddSysFile([FromBody] SysFileDto parm) + { + if (parm == null) + { + throw new CustomException("请求参数错误"); + } + //从 Dto 映射到 实体 + var model = parm.Adapt().ToCreate(HttpContext); + + var response = _SysFileService.Insert(model, it => new + { + it.FileName, + it.FileUrl, + it.StorePath, + it.FileSize, + it.FileExt, + it.Create_by, + it.Create_time, + it.StoreType, + it.AccessUrl, + }); + return ToResponse(response); + } + + /// + /// 更新文件存储 + /// + /// + [HttpPut] + [ActionPermissionFilter(Permission = "tool:file:update")] + [Log(Title = "文件存储", BusinessType = BusinessType.UPDATE)] + public IActionResult UpdateSysFile([FromBody] SysFileDto parm) + { + if (parm == null) + { + throw new CustomException("请求实体不能为空"); + } + //从 Dto 映射到 实体 + var model = parm.Adapt().ToUpdate(HttpContext); + + var response = _SysFileService.Update(w => w.Id == model.Id, it => new SysFile() + { + //Update 字段映射 + FileUrl = model.FileUrl, + StorePath = model.StorePath, + FileSize = model.FileSize, + FileExt = model.FileExt, + StoreType = model.StoreType, + AccessUrl = model.AccessUrl, + }); + + return ToResponse(response); + } + + /// + /// 删除文件存储 + /// + /// + [HttpDelete("{ids}")] + [ActionPermissionFilter(Permission = "tool:file:delete")] + [Log(Title = "文件存储", BusinessType = BusinessType.DELETE)] + public IActionResult DeleteSysFile(string ids) + { + int[] idsArr = Tools.SpitIntArrary(ids); + if (idsArr.Length <= 0) { return ToResponse(ApiResult.Error($"删除失败Id 不能为空")); } + + var response = _SysFileService.Delete(idsArr); + //TODO 删除本地资源 + + return ToResponse(response); + } + + /// + /// 文件存储导出 + /// + /// + [Log(BusinessType = BusinessType.EXPORT, IsSaveResponseData = false, Title = "文件存储")] + [HttpGet("export")] + [ActionPermissionFilter(Permission = "tool:file:export")] + public IActionResult Export() + { + var list = _SysFileService.GetAll(); + + string sFileName = ExportExcel(list, "SysFile", "文件存储"); + return SUCCESS(new { path = "/export/" + sFileName, fileName = sFileName }); + } + } +} \ No newline at end of file diff --git a/ZR.Admin.WebApi/NLog.config b/ZR.Admin.WebApi/NLog.config index 4982ce8..95cb5ee 100644 --- a/ZR.Admin.WebApi/NLog.config +++ b/ZR.Admin.WebApi/NLog.config @@ -55,10 +55,9 @@ + - - diff --git a/ZR.Admin.WebApi/wwwroot/CodeGenTemplate/TplControllers.txt b/ZR.Admin.WebApi/wwwroot/CodeGenTemplate/TplControllers.txt index 0996ead..74c282b 100644 --- a/ZR.Admin.WebApi/wwwroot/CodeGenTemplate/TplControllers.txt +++ b/ZR.Admin.WebApi/wwwroot/CodeGenTemplate/TplControllers.txt @@ -42,6 +42,7 @@ namespace ${options.ApiControllerNamespace}.Controllers /// /// 查询${genTable.FunctionName}列表 /// + /// /// [HttpGet("list")] [ActionPermissionFilter(Permission = "${replaceDto.PermissionPrefix}:list")] diff --git a/ZR.Model/System/Dto/SysFileQueryDto.cs b/ZR.Model/System/Dto/SysFileQueryDto.cs index 868534d..4cfa45d 100644 --- a/ZR.Model/System/Dto/SysFileQueryDto.cs +++ b/ZR.Model/System/Dto/SysFileQueryDto.cs @@ -4,7 +4,26 @@ using System.Text; namespace ZR.Model.System.Dto { + /// + /// 文件存储输入对象 + /// + public class SysFileDto + { + public int Id { get; set; } + public string FileName { get; set; } + public string FileUrl { get; set; } + public string StorePath { get; set; } + public string FileSize { get; set; } + public string FileExt { get; set; } + public string Create_by { get; set; } + public DateTime? Create_time { get; set; } + public int? StoreType { get; set; } + public string AccessUrl { get; set; } + } public class SysFileQueryDto : PagerInfo { + public DateTime? BeginCreate_time { get; set; } + public DateTime? EndCreate_time { get; set; } + public int? StoreType { get; set; } } } diff --git a/ZR.Model/System/SysFile.cs b/ZR.Model/System/SysFile.cs index 569abb6..0bfc99f 100644 --- a/ZR.Model/System/SysFile.cs +++ b/ZR.Model/System/SysFile.cs @@ -9,14 +9,56 @@ namespace ZR.Model.System [SugarTable("sys_file")] public class SysFile { - public int Id { get; set; } - public string FilePath { get; set; } + /// + /// 描述 : 自增id + /// 空值 : false + /// + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public long Id { get; set; } + /// + /// 描述 : 文件名 + /// 空值 : true + /// public string FileName { get; set; } + /// + /// 描述 : 文件存储地址 + /// 空值 : true + /// + public string FileUrl { get; set; } + /// + /// 描述 : 仓库位置 + /// 空值 : true + /// public string StorePath { get; set; } - public string AccessPat { get; set; } - public int FileSize { get; set; } + /// + /// 描述 : 文件大小 + /// 空值 : true + /// + public string FileSize { get; set; } + /// + /// 描述 : 文件扩展名 + /// 空值 : true + /// public string FileExt { get; set; } - public DateTime? AddTime { 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; } } -} +} \ No newline at end of file diff --git a/ZR.Repository/System/SysFileRepository.cs b/ZR.Repository/System/SysFileRepository.cs new file mode 100644 index 0000000..867dd5f --- /dev/null +++ b/ZR.Repository/System/SysFileRepository.cs @@ -0,0 +1,21 @@ +using System; +using Infrastructure.Attribute; +using ZR.Repository.System; +using ZR.Model.Models; +using ZR.Model.System; + +namespace ZR.Repository.System +{ + /// + /// 文件存储仓储 + /// + /// @author zz + /// @date 2021-12-15 + /// + [AppService(ServiceLifetime = LifeTime.Transient)] + public class SysFileRepository : BaseRepository + { + #region 业务逻辑代码 + #endregion + } +} \ No newline at end of file diff --git a/ZR.Service/System/IService/ISysFileService.cs b/ZR.Service/System/IService/ISysFileService.cs index c4dc983..e3971a3 100644 --- a/ZR.Service/System/IService/ISysFileService.cs +++ b/ZR.Service/System/IService/ISysFileService.cs @@ -1,10 +1,14 @@ using Infrastructure.Attribute; using Microsoft.AspNetCore.Http; +using ZR.Model.Models; +using ZR.Model.System; namespace ZR.Service.System.IService { - public interface ISysFileService + public interface ISysFileService : IBaseService { + long InsertFile(SysFile file); + /// /// 上传文件 /// diff --git a/ZR.Service/System/SysFileService.cs b/ZR.Service/System/SysFileService.cs index bab5cb3..e189b0f 100644 --- a/ZR.Service/System/SysFileService.cs +++ b/ZR.Service/System/SysFileService.cs @@ -8,6 +8,8 @@ using System; using System.Text; using System.Security.Cryptography; using System.Net; +using ZR.Model.System; +using ZR.Repository.System; namespace ZR.Service.System { @@ -15,9 +17,15 @@ namespace ZR.Service.System /// 文件管理 /// [AppService(ServiceType = typeof(ISysFileService), ServiceLifetime = LifeTime.Transient)] - public class SysFileService : ISysFileService + public class SysFileService : BaseService, ISysFileService { private string domainUrl = ConfigUtils.Instance.GetConfig("ALIYUN_OSS:domainUrl"); + private readonly SysFileRepository SysFileRepository; + + public SysFileService(SysFileRepository repository) : base(repository) + { + SysFileRepository = repository; + } /// /// 上传文件到阿里云 @@ -65,5 +73,17 @@ namespace ZR.Service.System return BitConverter.ToString(md5.ComputeHash(Encoding.Default.GetBytes(str)), 4, 8).Replace("-", ""); } + public long InsertFile(SysFile file) + { + try + { + return InsertReturnBigIdentity(file); + } + catch (Exception ex) + { + Console.WriteLine("存储图片失败" + ex.Message); + } + return 1; + } } } diff --git a/ZR.Vue/.env.development b/ZR.Vue/.env.development index e3942d6..e3d7f72 100644 --- a/ZR.Vue/.env.development +++ b/ZR.Vue/.env.development @@ -2,7 +2,7 @@ ENV = 'development' # 页面标题 -VUE_APP_TITLE = ZrAdmin.NET管理系统 +VUE_APP_TITLE = 'ZrAdmin.NET后台管理' # 开发环境 VUE_APP_BASE_API = '/dev-api' diff --git a/ZR.Vue/.env.production b/ZR.Vue/.env.production index c615a61..d54f532 100644 --- a/ZR.Vue/.env.production +++ b/ZR.Vue/.env.production @@ -2,10 +2,10 @@ ENV = 'production' # 页面标题 -VUE_APP_TITLE = ZrAdmin.NET管理系统 +VUE_APP_TITLE = 'ZrAdmin.NET后台管理' # 生产环境 VUE_APP_BASE_API = '/prod-api' # 路由前缀 -VUE_APP_ROUTER_PREFIX = '/admin/' +VUE_APP_ROUTER_PREFIX = '/' diff --git a/ZR.Vue/.env.staging b/ZR.Vue/.env.staging index 6907d21..4504612 100644 --- a/ZR.Vue/.env.staging +++ b/ZR.Vue/.env.staging @@ -2,7 +2,7 @@ ENV = 'staging' # 页面标题 -VUE_APP_TITLE = ZrAdmin.NET管理系统 +VUE_APP_TITLE = 'ZrAdmin.NET后台管理' # 测试环境 VUE_APP_BASE_API = '/stage-api' diff --git a/ZR.Vue/package.json b/ZR.Vue/package.json index 0564ec4..c8b8421 100644 --- a/ZR.Vue/package.json +++ b/ZR.Vue/package.json @@ -1,6 +1,6 @@ { "name": "zradmin", - "description": "ZrAdmnin.NET管理系统", + "description": "ZrAdmnin.NET后台管理", "author": "ZR", "scripts": { "dev": "vue-cli-service serve", diff --git a/ZR.Vue/src/api/tool/file.js b/ZR.Vue/src/api/tool/file.js new file mode 100644 index 0000000..03b64a8 --- /dev/null +++ b/ZR.Vue/src/api/tool/file.js @@ -0,0 +1,69 @@ +import request from '@/utils/request' + +/** +* 文件存储分页查询 +* @param {查询条件} data +*/ +export function listSysfile(query) { + return request({ + url: 'tool/file/list', + method: 'get', + params: query, + }) +} + +/** +* 新增文件存储 +* @param data +*/ +export function addSysfile(data) { + return request({ + url: 'tool/file', + method: 'post', + data: data, + }) +} + +/** +* 修改文件存储 +* @param data +*/ +export function updateSysfile(data) { + return request({ + url: 'tool/file', + method: 'PUT', + data: data, + }) +} + +/** +* 获取文件存储详情 +* @param {Id} +*/ +export function getSysfile(id) { + return request({ + url: 'tool/file/' + id, + method: 'get' + }) +} + +/** +* 删除文件存储 +* @param {主键} pid +*/ +export function delSysfile(pid) { + return request({ + url: 'tool/file/' + pid, + method: 'delete' + }) +} + +// 导出文件存储 +export function exportSysfile(query) { + return request({ + url: 'tool/file/export', + method: 'get', + params: query + }) +} + diff --git a/ZR.Vue/src/components/FileUpload/index.vue b/ZR.Vue/src/components/FileUpload/index.vue index 9617600..b4f4adb 100644 --- a/ZR.Vue/src/components/FileUpload/index.vue +++ b/ZR.Vue/src/components/FileUpload/index.vue @@ -1,7 +1,7 @@