diff --git a/ZR.Admin.WebApi/Controllers/UploadController.cs b/ZR.Admin.WebApi/Controllers/UploadController.cs index 3762e45..7702b11 100644 --- a/ZR.Admin.WebApi/Controllers/UploadController.cs +++ b/ZR.Admin.WebApi/Controllers/UploadController.cs @@ -5,7 +5,9 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; using System; using System.IO; +using System.Linq; using ZR.Admin.WebApi.Filters; +using ZR.Service.System.IService; namespace ZR.Admin.WebApi.Controllers { @@ -15,10 +17,12 @@ namespace ZR.Admin.WebApi.Controllers private NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); private OptionsSetting OptionsSetting; private IWebHostEnvironment WebHostEnvironment; - public UploadController(IOptions optionsSetting, IWebHostEnvironment webHostEnvironment) + private ISysFileService SysFileService; + public UploadController(IOptions optionsSetting, IWebHostEnvironment webHostEnvironment, ISysFileService fileService) { OptionsSetting = optionsSetting.Value; WebHostEnvironment = webHostEnvironment; + SysFileService = fileService; } /// /// 存储文件 @@ -26,8 +30,8 @@ namespace ZR.Admin.WebApi.Controllers /// /// [HttpPost] - [Verify] - [ActionPermissionFilter(Permission = "system")] + //[Verify] + //[ActionPermissionFilter(Permission = "system")] public IActionResult SaveFile([FromForm(Name = "file")] IFormFile formFile) { if (formFile == null) throw new CustomException(ResultCode.PARAM_ERROR, "上传图片不能为空"); @@ -35,7 +39,7 @@ namespace ZR.Admin.WebApi.Controllers string fileName = FileUtil.HashFileName(Guid.NewGuid().ToString()).ToLower() + fileExt; string finalFilePath = Path.Combine(WebHostEnvironment.WebRootPath, FileUtil.GetdirPath("uploads"), fileName); finalFilePath = finalFilePath.Replace("\\", "/").Replace("//", "/"); - + if (!Directory.Exists(Path.GetDirectoryName(finalFilePath))) { Directory.CreateDirectory(Path.GetDirectoryName(finalFilePath)); @@ -47,7 +51,36 @@ namespace ZR.Admin.WebApi.Controllers } string accessPath = $"{OptionsSetting.Upload.UploadUrl}/{FileUtil.GetdirPath("uploads").Replace("\\", " /")}{fileName}"; - return ToResponse(ResultCode.SUCCESS, new { accessPath, fullPath = finalFilePath }); + return ToResponse(ResultCode.SUCCESS, accessPath); + } + + /// + /// 存储文件到阿里云 + /// + /// + /// + [HttpPost] + //[Verify] + //[ActionPermissionFilter(Permission = "system")] + public IActionResult SaveFileAliyun([FromForm(Name = "file")] IFormFile formFile) + { + if (formFile == null) throw new CustomException(ResultCode.PARAM_ERROR, "上传文件不能为空"); + string fileExt = Path.GetExtension(formFile.FileName); + string[] AllowedFileExtensions = new string[] { ".jpg", ".gif", ".png", ".jpeg", ".webp", ".svga", ".xls" }; + int MaxContentLength = 1024 * 1024 * 4; + + if (!AllowedFileExtensions.Contains(fileExt)) + { + return ToResponse(ResultCode.CUSTOM_ERROR, "上传失败,未经允许上传类型"); + } + + if (formFile.Length > MaxContentLength) + { + return ToResponse(ResultCode.CUSTOM_ERROR, "上传文件过大,不能超过 " + (MaxContentLength / 1024).ToString() + " MB"); + } + (bool, string) result = SysFileService.SaveFile("", formFile); + + return ToResponse(ResultCode.SUCCESS, result.Item2); } } } diff --git a/ZR.Admin.WebApi/appsettings.json b/ZR.Admin.WebApi/appsettings.json index eaafb97..58dd587 100644 --- a/ZR.Admin.WebApi/appsettings.json +++ b/ZR.Admin.WebApi/appsettings.json @@ -24,10 +24,13 @@ "UploadDirectory": "/", "UploadUrl": "http://localhost:8888" }, - "QIQIU_OSS": { + //ƴ洢 + "ALIYUN_OSS": { "REGIONID": "cn-hangzhou", "KEY": "XX", - "SECRET": "XX" + "SECRET": "XX", + "bucketName": "bucketName", + "domainUrl": "http://xxx.xxx.com"//Դ }, "gen": { "conn": "server=LAPTOP-STKF2M8H\\SQLEXPRESS;user=zr;pwd=abc;database=ZrAdmin;Trusted_Connection=SSPI", diff --git a/ZR.CodeGenerator/CodeGenerateTemplate.cs b/ZR.CodeGenerator/CodeGenerateTemplate.cs index 3914017..1f97147 100644 --- a/ZR.CodeGenerator/CodeGenerateTemplate.cs +++ b/ZR.CodeGenerator/CodeGenerateTemplate.cs @@ -98,7 +98,8 @@ namespace ZR.CodeGenerator { sb.AppendLine($" //文件上传成功方法"); sb.AppendLine($" handleUpload{dbFieldInfo.CsharpField}Success(res, file) {{"); - sb.AppendLine($" this.form.{columnName} = URL.createObjectURL(file.raw);"); + sb.AppendLine($" this.form.{columnName} = res.data;"); + sb.AppendLine($" // this.form.{columnName} = URL.createObjectURL(file.raw);"); sb.AppendLine($" // this.$refs.upload.clearFiles();"); sb.AppendLine($" }},"); replaceDto.VueBeforeUpload = TplJsBeforeUpload(); @@ -346,7 +347,7 @@ namespace ZR.CodeGenerator { StringBuilder sb = new StringBuilder(); sb.AppendLine(@" //文件上传前判断方法"); - sb.AppendLine(@" uploadUrl: process.env.VUE_APP_BASE_API + ""/upload/SaveFile/"","); + sb.AppendLine(@" uploadUrl: process.env.VUE_APP_BASE_API + ""upload/SaveFile"","); return sb.ToString(); } diff --git a/ZR.CodeGenerator/CodeGeneratorTool.cs b/ZR.CodeGenerator/CodeGeneratorTool.cs index c70cac2..2275666 100644 --- a/ZR.CodeGenerator/CodeGeneratorTool.cs +++ b/ZR.CodeGenerator/CodeGeneratorTool.cs @@ -94,12 +94,12 @@ namespace ZR.CodeGenerator sb2.AppendLine($" this.{FirstLowerCase(dbFieldInfo.CsharpField)}Options = response.data;"); sb2.AppendLine(" })"); } - //引用组件 - if (dbFieldInfo.HtmlType == GenConstants.HTML_EDITOR) - { - replaceDto.VueComponent += "Editor,"; - replaceDto.VueComponentImport += "import Editor from '@/components/Editor';\n"; - } + //引用组件 已弃用、改用前端全局注册 + //if (dbFieldInfo.HtmlType == GenConstants.HTML_EDITOR) + //{ + // replaceDto.VueComponent += "Editor,"; + // replaceDto.VueComponentImport += "import Editor from '@/components/Editor';\n"; + //} CodeGenerateTemplate.GetQueryDtoProperty(dbFieldInfo, replaceDto); replaceDto.ModelProperty += CodeGenerateTemplate.GetModelTemplate(dbFieldInfo); diff --git a/ZR.Common/AliyunOssHelper.cs b/ZR.Common/AliyunOssHelper.cs new file mode 100644 index 0000000..8510317 --- /dev/null +++ b/ZR.Common/AliyunOssHelper.cs @@ -0,0 +1,47 @@ +using Aliyun.OSS; +using Aliyun.OSS.Common; +using Infrastructure; +using System; +using System.IO; + +namespace ZR.Common +{ + public class AliyunOssHelper + { + static string accessKeyId = ConfigUtils.Instance.GetConfig("ALIYUN_OSS:KEY"); + static string accessKeySecret = ConfigUtils.Instance.GetConfig("ALIYUN_OSS:SECRET"); + static string endpoint = ConfigUtils.Instance.GetConfig("ALIYUN_OSS:REGIONID"); + static string bucketName1 = ConfigUtils.Instance.GetConfig("ALIYUN_OSS:bucketName"); + + /// + /// 上传到阿里云 + /// + /// + /// 存储路径 eg: upload/2020/01/01/xxx.png + /// 存储桶 如果为空默认取配置文件 + public static System.Net.HttpStatusCode PutObjectFromFile(Stream filestreams, string dirPath, string bucketName = "") + { + OssClient client = new OssClient(endpoint, accessKeyId, accessKeySecret); + if (string.IsNullOrEmpty(bucketName)) { bucketName = bucketName1; } + try + { + dirPath = dirPath.Replace("\\", "/"); + PutObjectResult putObjectResult = client.PutObject(bucketName, dirPath, filestreams); + // Console.WriteLine("Put object:{0} succeeded", directory); + + return putObjectResult.HttpStatusCode; + } + catch (OssException ex) + { + Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}", + ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId); + } + catch (Exception ex) + { + Console.WriteLine("Failed with error info: {0}", ex.Message); + } + return System.Net.HttpStatusCode.BadRequest; + } + + } +} diff --git a/ZR.Common/ZR.Common.csproj b/ZR.Common/ZR.Common.csproj index 988d309..1bffb47 100644 --- a/ZR.Common/ZR.Common.csproj +++ b/ZR.Common/ZR.Common.csproj @@ -5,7 +5,12 @@ + + + + + diff --git a/ZR.Service/System/IService/ISysFileService.cs b/ZR.Service/System/IService/ISysFileService.cs index 99daf07..ff1b047 100644 --- a/ZR.Service/System/IService/ISysFileService.cs +++ b/ZR.Service/System/IService/ISysFileService.cs @@ -1,9 +1,24 @@ using Infrastructure.Attribute; -using ZR.Model.System; +using Microsoft.AspNetCore.Http; namespace ZR.Service.System.IService { public interface ISysFileService { + (bool, string) SaveFile(string picdir, IFormFile formFile); + + /// + /// 按时间来创建文件夹 + /// + /// + /// eg: 2020/11/3 + string GetdirPath(string path = ""); + + /// + /// 取文件名的MD5值(16位) + /// + /// 文件名,不包括扩展名 + /// + string HashFileName(string str = null); } } diff --git a/ZR.Service/System/SysFileService.cs b/ZR.Service/System/SysFileService.cs index 7a0741d..7a78c8b 100644 --- a/ZR.Service/System/SysFileService.cs +++ b/ZR.Service/System/SysFileService.cs @@ -1,6 +1,13 @@ using Infrastructure.Attribute; -using ZR.Model.System; +using Microsoft.AspNetCore.Http; +using System.IO; using ZR.Service.System.IService; +using ZR.Common; +using Infrastructure; +using System; +using System.Text; +using System.Security.Cryptography; +using System.Net; namespace ZR.Service.System { @@ -10,6 +17,57 @@ namespace ZR.Service.System [AppService(ServiceType = typeof(ISysFileService), ServiceLifetime = LifeTime.Transient)] public class SysFileService : ISysFileService { + private string domainUrl = ConfigUtils.Instance.GetConfig("ALIYUN_OSS:domainUrl"); + + /// + /// 上传文件到阿里云 + /// + /// + /// + /// + public (bool, string) SaveFile(string picdir, IFormFile formFile) + { + // eg: idcard/2020/08/18 + string dir = GetdirPath(picdir.ToString()); + string tempName = HashFileName(); + string fileExt = Path.GetExtension(formFile.FileName); + string fileName = $"{tempName}{fileExt}"; + string webUrl = $"{domainUrl}/{dir}/{fileName}"; + + HttpStatusCode statusCode = AliyunOssHelper.PutObjectFromFile(formFile.OpenReadStream(), Path.Combine(dir, fileName)); + + if (statusCode == HttpStatusCode.OK) + { + return (true, webUrl); + } + return (false, ""); + } + + public string GetdirPath(string path = "") + { + DateTime date = DateTime.Now; + int year = date.Year; + int month = date.Month; + int day = date.Day; + //int hour = date.Hour; + + string timeDir = $"{year}/{month}/{day}";// date.ToString("yyyyMM/dd/HH/"); + if (!string.IsNullOrEmpty(path)) + { + timeDir = path + "/" + timeDir; + } + return timeDir; + } + + public string HashFileName(string str = null) + { + if (string.IsNullOrEmpty(str)) + { + str = Guid.NewGuid().ToString(); + } + MD5CryptoServiceProvider md5 = new(); + return BitConverter.ToString(md5.ComputeHash(Encoding.Default.GetBytes(str)), 4, 8).Replace("-", ""); + } } } diff --git a/ZR.Vue/src/main.js b/ZR.Vue/src/main.js index 4bb5702..38f615a 100644 --- a/ZR.Vue/src/main.js +++ b/ZR.Vue/src/main.js @@ -21,6 +21,8 @@ import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, import Pagination from "@/components/Pagination"; //自定义表格工具扩展 import RightToolbar from "@/components/RightToolbar" +// 富文本组件 +import Editor from "@/components/Editor"; // 字典标签组件 import DictTag from '@/components/DictTag' // 字典数据组件 @@ -53,7 +55,7 @@ Vue.prototype.msgInfo = function(msg) { Vue.component('Pagination', Pagination) Vue.component('RightToolbar', RightToolbar) Vue.component('DictTag', DictTag) - +Vue.component('Editor', Editor) Vue.use(permission) Vue.use(Element, { diff --git a/ZR.Vue/src/views/business/gendemo/index.vue b/ZR.Vue/src/views/business/gendemo/index.vue index f543ac0..614f3ea 100644 --- a/ZR.Vue/src/views/business/gendemo/index.vue +++ b/ZR.Vue/src/views/business/gendemo/index.vue @@ -179,7 +179,7 @@ export default { // 用户性别选项列表 sexOptions: [], //文件上传前判断方法 - uploadUrl: process.env.VUE_APP_BASE_API + "/upload/SaveFile/", + uploadUrl: process.env.VUE_APP_BASE_API + "upload/SaveFile", // 数据列表 dataList: [], @@ -291,7 +291,8 @@ export default { }, //文件上传成功方法 handleUploadIconSuccess(res, file) { - this.form.icon = URL.createObjectURL(file.raw); + this.form.icon = res.data; + // this.form.icon = URL.createObjectURL(file.raw); // this.$refs.upload.clearFiles(); }, // 显示状态字典翻译 diff --git a/ZR.Vue/src/views/login.vue b/ZR.Vue/src/views/login.vue index 5bfdd0e..edfe6bc 100644 --- a/ZR.Vue/src/views/login.vue +++ b/ZR.Vue/src/views/login.vue @@ -107,7 +107,6 @@ export default { if (valid) { this.loading = true; if (this.loginForm.rememberMe) { - console.log(decrypt(this.loginForm.password)); Cookies.set("username", this.loginForm.username, { expires: 30 }); Cookies.set("password", this.loginForm.password, { expires: 30, diff --git a/ZR.Vue/src/views/system/notice/index.vue b/ZR.Vue/src/views/system/notice/index.vue index a2e73b4..05f9735 100644 --- a/ZR.Vue/src/views/system/notice/index.vue +++ b/ZR.Vue/src/views/system/notice/index.vue @@ -103,13 +103,9 @@ import { updateNotice, // exportNotice, } from "@/api/system/notice"; -import Editor from "@/components/Editor"; export default { name: "Notice", - components: { - Editor, - }, data() { return { // 遮罩层 diff --git a/ZR.Vue/src/views/tool/email/sendEmail.vue b/ZR.Vue/src/views/tool/email/sendEmail.vue index aa5413b..02bdb5e 100644 --- a/ZR.Vue/src/views/tool/email/sendEmail.vue +++ b/ZR.Vue/src/views/tool/email/sendEmail.vue @@ -28,11 +28,9 @@