commit 5f40d38679be35faf7c1ee7de22755004f9b6194 Author: net <> Date: Fri Jun 2 21:15:33 2023 +0800 Initial commit diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..985e687 --- /dev/null +++ b/.gitignore @@ -0,0 +1,273 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +#*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc +/ARW.Admin.WebApi/appsettings.Stage.json +/CodeGenerate +/ARW.WebApi/appsettings.Production.json +/ARW.WebApi/wwwroot/uploads +/ARW.WebApi/wwwroot/Generatecode +/ARW.WebApi/wwwroot/export +/ARW.Vue/src/views/business/Gendemo.vue +/ARW.WebApi/Properties/launchSettings.json +/ARW.WebApi/ARWAdmin.xml +/ARW.WebApi/DataProtection +/Quartz.NET.WindowsService + diff --git a/.net_run.bat b/.net_run.bat new file mode 100644 index 0000000..bfd85fe --- /dev/null +++ b/.net_run.bat @@ -0,0 +1,10 @@ +"age": 10, +"classId": "1547502470350114800", +"className": "1班", +"sex": "1", +"studentDescribe": "

啊实打实大苏打实打实实打实上的

", +"studentId": 1548629251954184200, +"studentImg": "/url", +"studentName": "张思1", +"studentService": [{service_name: "特殊服务", service_price: "999"}], +"studentTag": "a,v,c" \ No newline at end of file diff --git a/ARW.CodeGenerator/ARW.CodeGenerator.csproj b/ARW.CodeGenerator/ARW.CodeGenerator.csproj new file mode 100644 index 0000000..e03b913 --- /dev/null +++ b/ARW.CodeGenerator/ARW.CodeGenerator.csproj @@ -0,0 +1,20 @@ + + + + net6.0 + ARW.CodeGenerator + ARW.CodeGenerator + + + + + + + + + + + + + + diff --git a/ARW.CodeGenerator/CodeGenerateOption.cs b/ARW.CodeGenerator/CodeGenerateOption.cs new file mode 100644 index 0000000..b7f4e3f --- /dev/null +++ b/ARW.CodeGenerator/CodeGenerateOption.cs @@ -0,0 +1,52 @@ +namespace ARW.CodeGenerator +{ + public class CodeGenerateOption + { + /// + /// 项目命名空间 + /// + public string BaseNamespace { get; set; } + /// + /// 下级命名空间 + /// + public string SubNamespace { get; set; } + /// + /// 数据实体命名空间 + /// + public string ModelsNamespace { get; set; } + /// + /// 输入输出数据实体名称空间 + /// + public string DtosNamespace { get; set; } + /// + /// 仓储接口命名空间 + /// + public string IRepositoriesNamespace { get; set; } + /// + /// 仓储实现名称空间 + /// + public string RepositoriesNamespace { get; set; } + /// + /// 服务接口命名空间 + /// + public string IServicsNamespace { get; set; } + /// + /// 服务接口实现命名空间 + /// + public string ServicesNamespace { get; set; } + + /// + /// Api控制器命名空间 + /// + public string ApiControllerNamespace { get; set; } + + /// + /// 去掉的表头字符 + /// + public string ReplaceTableNameStr { get; set; } + /// + /// 要生数据的表,用“,”分割 + /// + //public string TableList { get; set; } + } +} diff --git a/ARW.CodeGenerator/CodeGenerateTemplate.cs b/ARW.CodeGenerator/CodeGenerateTemplate.cs new file mode 100644 index 0000000..319ebf6 --- /dev/null +++ b/ARW.CodeGenerator/CodeGenerateTemplate.cs @@ -0,0 +1,52 @@ +using System; +using System.Linq; +using System.Text; +using ARW.Model.System.Generate; + +namespace ARW.CodeGenerator +{ + /// + /// 代码生成模板 + /// + public class CodeGenerateTemplate + { + //模板调用 + public static string QueryExp(string propertyName, string queryType) + { + if (queryType.Equals("EQ")) + { + return $"it => it.{ propertyName} == parm.{propertyName})"; + } + if (queryType.Equals("LIKE")) + { + return $"it => it.{propertyName}.Contains(parm.{propertyName}))"; + } + if (queryType.Equals("GTE")) + { + return $"it => it.{ propertyName} >= parm.{propertyName})"; + } + if (queryType.Equals("GT")) + { + return $"it => it.{ propertyName} > parm.{propertyName})"; + } + if (queryType.Equals("LT")) + { + return $"it => it.{ propertyName} < parm.{propertyName})"; + } + if (queryType.Equals("LTE")) + { + return $"it => it.{ propertyName} <= parm.{propertyName})"; + } + if (queryType.Equals("NE")) + { + return $"it => it.{ propertyName} != parm.{propertyName})"; + } + if (queryType.Equals("ARWKE")) + { + return $"it => it.{ propertyName}.Contains(parm.{propertyName}))"; + } + return $"it => it.{ propertyName} == parm.{propertyName})"; + } + + } +} diff --git a/ARW.CodeGenerator/CodeGeneratorTool.cs b/ARW.CodeGenerator/CodeGeneratorTool.cs new file mode 100644 index 0000000..6f34b58 --- /dev/null +++ b/ARW.CodeGenerator/CodeGeneratorTool.cs @@ -0,0 +1,805 @@ +using Infrastructure; +using Infrastructure.Extensions; +using JinianNet.JNTemplate; +using SqlSugar; +using SqlSugar.IOC; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using ARW.CodeGenerator.Model; +using ARW.Model.System.Generate; + +namespace ARW.CodeGenerator +{ + /// + /// 代码生成器 + /// + /// + public class CodeGeneratorTool + { + /// + /// 代码生成器配置 + /// + private static CodeGenerateOption _option = new CodeGenerateOption(); + + + #region 业务生成 + /// + /// 代码生成器入口方法 + /// + /// + public static void Generate(GenerateDto dto) + { + _option.BaseNamespace = dto.GenTable.BaseNameSpace; + _option.SubNamespace = dto.GenTable.ModuleName.FirstUpperCase(); + _option.DtosNamespace = _option.BaseNamespace + "Model"; + _option.ModelsNamespace = _option.BaseNamespace + "Model"; + _option.RepositoriesNamespace = _option.BaseNamespace + "Repository"; + _option.IRepositoriesNamespace = _option.BaseNamespace + "Repository"; + _option.IServicsNamespace = _option.BaseNamespace + "Service"; + _option.ServicesNamespace = _option.BaseNamespace + "Service"; + _option.ApiControllerNamespace = _option.BaseNamespace + "WebApi"; + + if (dto.GenTable.ModuleName.Contains('/')) dto.GenTable.ModuleName = dto.GenTable.ModuleName.Replace('/', '.'); + + if (dto.GenType == "1") + { + var vuePath = AppSettings.GetConfig("gen:vuePath"); + if (!vuePath.IsEmpty()) + { + dto.VueParentPath = vuePath; + } + } + else + { + string fullName = Path.Combine(dto.GenCodePath, "vue"); + + dto.VueParentPath = fullName; + } + dto.GenOptions = _option; + + string PKName = "Id"; + string PKType = "int"; + ReplaceDto replaceDto = new() + { + ModelTypeName = dto.GenTable.ClassName,//表名对应C# 实体类名 + PermissionPrefix = dto.GenTable?.Options?.PermissionPrefix, + Author = dto.GenTable.FunctionAuthor, + ShowBtnAdd = dto.GenTable.Options.CheckedBtn.Any(f => f == 1), + ShowBtnEdit = dto.GenTable.Options.CheckedBtn.Any(f => f == 2), + ShowBtnDelete = dto.GenTable.Options.CheckedBtn.Any(f => f == 3), + ShowBtnExport = dto.GenTable.Options.CheckedBtn.Any(f => f == 4), + ShowBtnView = dto.GenTable.Options.CheckedBtn.Any(f => f == 5), + ShowBtnImport = dto.GenTable.Options.CheckedBtn.Any(f => f == 6), + ShowBtnAudit = dto.GenTable.Options.CheckedBtn.Any(f => f == 7) + }; + + //循环表字段信息 + foreach (GenTableColumn dbFieldInfo in dto.GenTable.Columns.OrderBy(x => x.Sort)) + { + if (dbFieldInfo.IsPk || dbFieldInfo.IsIncrement) + { + PKName = dbFieldInfo.CsharpField; + PKType = dbFieldInfo.CsharpType; + } + if (dbFieldInfo.HtmlType.Equals(GenConstants.HTML_IMAGE_UPLOAD) || dbFieldInfo.HtmlType.Equals(GenConstants.HTML_FILE_UPLOAD)) + { + replaceDto.UploadFile = 1; + } + dbFieldInfo.CsharpFieldFl = dbFieldInfo.CsharpField.FirstLowerCase(); + } + + replaceDto.PKName = PKName; + replaceDto.PKType = PKType; + replaceDto.FistLowerPk = PKName.FirstLowerCase(); + InitJntTemplate(dto, replaceDto); + + GenerateModels(replaceDto, dto); + GenerateRepository(replaceDto, dto); + GenerateService(replaceDto, dto); + GenerateControllers(replaceDto, dto); + GenerateVue3Views(replaceDto, dto); + GenerateVueJs(replaceDto, dto); + GenerateSql(replaceDto, dto); + + if (dto.IsPreview) return; + + foreach (var item in dto.GenCodes) + { + item.Path = Path.Combine(dto.GenCodePath, item.Path); + FileHelper.WriteAndSave(item.Path, item.Content); + } + } + + #region 读取模板 + + /// + /// 生成实体类Model + /// + /// + /// 替换实体 + private static void GenerateModels(ReplaceDto replaceDto, GenerateDto generateDto) + { + + + string fullPath = Path.Combine(_option.ModelsNamespace, "Models", "Business", _option.SubNamespace, replaceDto.ModelTypeName + ".cs"); + string fullPathDto = Path.Combine(_option.ModelsNamespace, "Dto", "Business", _option.SubNamespace, $"{replaceDto.ModelTypeName}Dto.cs"); + string fullPathVo = Path.Combine(_option.ModelsNamespace, "Vo", "Business", _option.SubNamespace, $"{replaceDto.ModelTypeName}Vo.cs"); + + var tpl = FileHelper.ReadJtTemplate("TplModel.txt"); + var tplDto = FileHelper.ReadJtTemplate("TplDto.txt"); + var tplVo = FileHelper.ReadJtTemplate("TplVo.txt"); + + generateDto.GenCodes.Add(new GenCode(1, "Model.cs", fullPath, tpl.Render())); + generateDto.GenCodes.Add(new GenCode(2, "Dto.cs", fullPathDto, tplDto.Render())); + generateDto.GenCodes.Add(new GenCode(3, "Vo.cs", fullPathVo, tplVo.Render())); + } + + /// + /// 生成Repository层代码文件 + /// + /// + /// 替换实体 + private static void GenerateRepository(ReplaceDto replaceDto, GenerateDto generateDto) + { + var tpl = FileHelper.ReadJtTemplate("TplRepository.txt"); + var result = tpl.Render(); + var fullPath = Path.Combine(_option.RepositoriesNamespace, "Business", _option.SubNamespace, $"{replaceDto.ModelTypeName}Repository.cs"); + + generateDto.GenCodes.Add(new GenCode(3, "Repository.cs", fullPath, result)); + } + + /// + /// 生成Service文件 + /// + private static void GenerateService(ReplaceDto replaceDto, GenerateDto generateDto) + { + var tpl = FileHelper.ReadJtTemplate("TplService.txt"); + var tpl2 = FileHelper.ReadJtTemplate("TplIService.txt"); + var result = tpl.Render(); + var result2 = tpl2.Render(); + + var fullPath = Path.Combine(_option.ServicesNamespace, "Business", "BusinessService", _option.SubNamespace, $"{replaceDto.ModelTypeName}Service.cs"); + var fullPath2 = Path.Combine(_option.IServicsNamespace, "Business", "IBusinessService", _option.SubNamespace, $"I{replaceDto.ModelTypeName}Service.cs"); + + generateDto.GenCodes.Add(new GenCode(4, "Service.cs", fullPath, result)); + generateDto.GenCodes.Add(new GenCode(4, "IService.cs", fullPath2, result2)); + } + + /// + /// 生成控制器ApiControllers文件 + /// + private static void GenerateControllers(ReplaceDto replaceDto, GenerateDto generateDto) + { + var tpl = FileHelper.ReadJtTemplate("TplControllers.txt"); + tpl.Set("QueryCondition", replaceDto.QueryCondition); + var result = tpl.Render(); + + var fullPath = Path.Combine(_option.ApiControllerNamespace, "Controllers", "Business", _option.SubNamespace, $"{replaceDto.ModelTypeName}Controller.cs"); + generateDto.GenCodes.Add(new GenCode(5, "Controller.cs", fullPath, result)); + } + + /// + /// 生成Vue页面 + private static void GenerateVueViews(ReplaceDto replaceDto, GenerateDto generateDto) + { + string fileName = string.Empty; + switch (generateDto.GenTable.TplCategory) + { + case "tree": + fileName = "TplTreeVue.txt"; + break; + case "crud": + fileName = "TplVue.txt"; + break; + case "subNav": + fileName = "TplVue.txt"; + break; + case "subNavMore": + fileName = "TplVue.txt"; + break; + case "select": + fileName = "TplVueSelect.txt"; + break; + default: + break; + } + var tpl = FileHelper.ReadJtTemplate(fileName); + tpl.Set("vueQueryFormHtml", replaceDto.VueQueryFormHtml); + tpl.Set("VueViewFormContent", replaceDto.VueViewFormHtml);//添加、修改表单 + tpl.Set("VueViewListContent", replaceDto.VueViewListHtml);//查询 table列 + + var result = tpl.Render(); + var fullPath = Path.Combine("src", "views", generateDto.GenTable.ModuleName.FirstLowerCase(), $"{generateDto.GenTable.BusinessName.FirstUpperCase()}.vue"); + + generateDto.GenCodes.Add(new GenCode(6, "index.vue", fullPath, result)); + } + + /// + /// vue3 + /// + /// + /// + private static void GenerateVue3Views(ReplaceDto replaceDto, GenerateDto generateDto) + { + string fileName = generateDto.GenTable.TplCategory switch + { + "tree" => "TplVueIndex.txt", + "crud" => "TplVueIndex.txt", + //case "select": + // fileName = "TplVueSelect.txt"; + // break; + _ => "Vue.txt", + }; + //fileName = Path.Combine("v3", fileName); + var tpl = FileHelper.ReadJtTemplate(fileName); + var tplAdd = FileHelper.ReadJtTemplate("Add.txt"); + var tplEdit = FileHelper.ReadJtTemplate("Edit.txt"); + var tplDetail = FileHelper.ReadJtTemplate("Detail.txt"); + var tplUpload = FileHelper.ReadJtTemplate("Upload.txt"); + //tpl.Set("treeCode", generateDto.GenTable?.Options?.TreeCode?.FirstLowerCase()); + //tpl.Set("treeName", generateDto.GenTable?.Options?.TreeName?.FirstLowerCase()); + //tpl.Set("treeParentCode", generateDto.GenTable?.Options?.TreeParentCode?.FirstLowerCase()); + //tpl.Set("options", generateDto.GenTable?.Options); + + var result = tpl.Render(); + var Addresult = tplAdd.Render(); + var Editresult = tplEdit.Render(); + var Detailresult = tplDetail.Render(); + var Uploadresult = tplUpload.Render(); + + + + var fullPath = Path.Combine(generateDto.VueParentPath, "src", "views", "business", _option.SubNamespace, "index.vue"); + var AddfullPath = Path.Combine(generateDto.VueParentPath, "src", "views", "business", _option.SubNamespace , "components", "AddDialog.vue"); + var EditfullPath = Path.Combine(generateDto.VueParentPath, "src", "views", "business", _option.SubNamespace , "components", "EditDialog.vue"); + var DetailfullPath = Path.Combine(generateDto.VueParentPath, "src", "views", "business", _option.SubNamespace , "components", "DetailDialog.vue"); + if (replaceDto.ShowBtnImport) + { + var UploadfullPath = Path.Combine(generateDto.VueParentPath, "src", "views", "business", _option.SubNamespace , "components", "UploadDialog.vue"); + generateDto.GenCodes.Add(new GenCode(16, "UploadDialog.vue", UploadfullPath, Uploadresult)); + + } + generateDto.GenCodes.Add(new GenCode(16, "index.vue", fullPath, result)); + generateDto.GenCodes.Add(new GenCode(16, "AddDialog.vue", AddfullPath, Addresult)); + generateDto.GenCodes.Add(new GenCode(16, "EditDialog.vue", EditfullPath, Editresult)); + generateDto.GenCodes.Add(new GenCode(16, "DetailDialog.vue", DetailfullPath, Detailresult)); + } + /// + /// 生成vue页面api + /// + /// + /// + /// + public static void GenerateVueJs(ReplaceDto replaceDto, GenerateDto generateDto) + { + var tpl = FileHelper.ReadJtTemplate("TplVueApi.txt"); + var result = tpl.Render(); + + string fileName; + if (generateDto.VueVersion == 3) + { + fileName = generateDto.GenTable.BusinessName.ToLower() + ".js"; + } + else + { + fileName = generateDto.GenTable.BusinessName.FirstLowerCase() + ".js"; + } + string fullPath = Path.Combine(generateDto.VueParentPath, "src", "api", "business", _option.SubNamespace, fileName); + + generateDto.GenCodes.Add(new GenCode(7, "api.js", fullPath, result)); + + } + + /// + /// 生成SQL + /// + /// + /// + public static void GenerateSql(ReplaceDto replaceDto, GenerateDto generateDto) + { + var db = DbScoped.SugarScope; + //new MySql.Data.MySqlClient.MySqlConnection("server=47.242.159.172;Database=demo;Uid=demo;Pwd=demo;SslMode=none;CharSet=utf8mb4;AllowLoadLocalInfile=true;AllowUserVariables=true;").Open(); + + var str = AppSettings.GetConfig("gen:conn"); + + SqlSugarClient Db = new SqlSugarClient(new ConnectionConfig() + { + ConnectionString = str, + DbType = DbType.MySqlConnector, + IsAutoCloseConnection = true + }, + db => + { + + }); + + var tempName = ""; + switch (generateDto.DbType) + { + case 8: + tempName = "MySqlTemplate"; + break; + case 1: + tempName = "SqlTemplate"; + break; + default: + break; + } + var tpl = FileHelper.ReadJtTemplate($"{tempName}.txt"); + tpl.Set("parentId", generateDto.GenTable?.Options?.ParentMenuId ?? 0); + var result = tpl.Render(); + if (generateDto.GenType == "1") + { + db.Ado.ExecuteCommand(result); + } + else + { + string fullPath = Path.Combine(generateDto.GenCodePath, "sql", generateDto.GenTable.BusinessName + ".sql"); + generateDto.GenCodes.Add(new GenCode(8, "sql", fullPath, result)); + } + } + + /// + /// 生成vue页面查询form + /// + /// + public static string GenerateVueQueryForm() + { + var tpl = FileHelper.ReadJtTemplate("QueryForm.txt"); + var result = tpl.Render(); + return result; + } + /// + /// 生成vue页面table + /// + /// + public static string GenerateVueTableList() + { + var tpl = FileHelper.ReadJtTemplate("TableList.txt"); + var result = tpl.Render(); + + return result; + } + /// + /// 生成vue表单 + /// + /// + public static string GenerateCurdForm() + { + var tpl = FileHelper.ReadJtTemplate("CurdForm.txt"); + var result = tpl.Render(); + return result; + } + #endregion + + #region 帮助方法 + + /// + /// 如果有前缀替换将前缀替换成空,替换下划线"_"为空再将首字母大写 + /// 表名转换成C#类名 + /// + /// + /// + public static string GetClassName(string tableName) + { + bool autoRemovePre = AppSettings.GetAppConfig(GenConstants.Gen_autoPre, false); + string tablePrefix = AppSettings.GetAppConfig(GenConstants.Gen_tablePrefix); + + if (!string.IsNullOrEmpty(tablePrefix) && autoRemovePre) + { + string[] prefixList = tablePrefix.Split(",", StringSplitOptions.RemoveEmptyEntries); + for (int i = 0; i < prefixList.Length; i++) + { + if (!string.IsNullOrEmpty(prefixList[i].ToString())) + { + tableName = tableName.Replace(prefixList[i], "", StringComparison.OrdinalIgnoreCase); + } + } + } + + return tableName.UnderScoreToCamelCase(); + } + + /// + /// 获取前端标签名 + /// + /// + /// + /// + public static string GetLabelName(string columnDescription, string columnName) + { + return string.IsNullOrEmpty(columnDescription) ? columnName : columnDescription; + } + + /// + /// 首字母转小写,模板使用(勿删) + /// + /// + /// + public static string FirstLowerCase(string str) + { + try + { + return string.IsNullOrEmpty(str) ? str : str.Substring(0, 1).ToLower() + str[1..]; + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + return ""; + } + } + + /// + /// 获取C# 类型 + /// + /// + /// + public static string GetCSharpDatatype(string sDatatype) + { + sDatatype = sDatatype.ToLower(); + string sTempDatatype = sDatatype switch + { + "int" or "number" or "integer" or "smallint" => "int", + "bigint" => "long", + "tinyint" => "byte", + "numeric" or "real" or "float" => "float", + "decimal" or "numer(8,2)" or "numeric" => "decimal", + "bit" => "bool", + "date" or "datetime" or "datetime2" or "smalldatetime" or "timestamp" => "DateTime", + "money" or "smallmoney" => "decimal", + _ => "string", + }; + return sTempDatatype; + } + + public static bool IsNumber(string tableDataType) + { + string[] arr = new string[] { "int", "long" }; + return arr.Any(f => f.Contains(GetCSharpDatatype(tableDataType))); + } + #endregion + + #region 初始化信息 + + /// + /// 初始化表信息 + /// + /// + /// + /// + /// + /// + public static GenTable InitTable(string dbName, string userName, string tableName, string desc) + { + GenTable genTable = new() + { + DbName = dbName, + BaseNameSpace = "ARW.",//导入默认命名空间前缀 + ModuleName = GetClassName(tableName).FirstUpperCase() + "s",//导入默认模块名 + ClassName = GetClassName(tableName).FirstUpperCase(), + BusinessName = GetClassName(tableName).FirstUpperCase(), + FunctionAuthor = AppSettings.GetConfig(GenConstants.Gen_author), + TableName = tableName, + TableComment = desc, + FunctionName = desc, + Create_by = userName, + GenType = "1", + GenPath = "", + Options = new Options() + { + SortField = "Update_time", + SortType = "Desc", + CheckedBtn = new int[] { 1, 2, 3, 5 } + } + }; + genTable.Options.PermissionPrefix = $"business:{genTable.ClassName.ToLower()}";//权限 + + return genTable; + } + + /// + /// 初始化列属性字段数据 + /// + /// + /// + public static List InitGenTableColumn(GenTable genTable, List dbColumnInfos) + { + List genTableColumns = new(); + var index = 0; + foreach (var column in dbColumnInfos) + { + index++; + genTableColumns.Add(InitColumnField(genTable, column, index)); + } + return genTableColumns; + } + + /// + /// 初始化表字段数据 + /// + /// + /// + /// + private static GenTableColumn InitColumnField(GenTable genTable, DbColumnInfo column, int index) + { + GenTableColumn genTableColumn = new() + { + ColumnName = column.DbColumnName.FirstLowerCase(), + ColumnComment = column.ColumnDescription, + IsPk = column.IsPrimarykey, + ColumnType = column.DataType, + TableId = genTable.TableId, + TableName = genTable.TableName, + CsharpType = GetCSharpDatatype(column.DataType), + CsharpField = column.DbColumnName.ConvertToPascal("_"), + IsRequired = !column.IsNullable, + IsIncrement = column.IsIdentity, + Create_by = genTable.Create_by, + Create_time = DateTime.Now, + IsInsert = !column.IsIdentity || GenConstants.inputDtoNoField.Any(f => f.Contains(column.DbColumnName, StringComparison.OrdinalIgnoreCase)),//非自增字段都需要插入 + IsInit = GenConstants.inputDtoNoField.Any(f => column.DbColumnName.Contains(f)), + IsGuid = column.DbColumnName.Contains("guid"), + IsEdit = true, + IsQuery = false, + HtmlType = GenConstants.HTML_INPUT, + Sort = index + }; + + switch (genTableColumn.CsharpField) + { + case "CreateBy": + genTableColumn.CsharpField = "Create_by"; + break; + case "CreateTime": + genTableColumn.CsharpField = "Create_time"; + break; + case "UpdateBy": + genTableColumn.CsharpField = "Update_by"; + break; + case "UpdateTime": + genTableColumn.CsharpField = "Update_time"; + break; + default: + break; + } + + if (GenConstants.imageFiled.Any(f => column.DbColumnName.ToLower().Contains(f.ToLower()))) + { + genTableColumn.HtmlType = GenConstants.HTML_IMAGE_UPLOAD; + } + else if (GenConstants.COLUMNTYPE_TIME.Any(f => genTableColumn.CsharpType.ToLower().Contains(f.ToLower()))) + { + genTableColumn.HtmlType = GenConstants.HTML_DATETIME; + } + else if (GenConstants.radioFiled.Any(f => column.DbColumnName.EndsWith(f, StringComparison.OrdinalIgnoreCase)) || + GenConstants.radioFiled.Any(f => column.DbColumnName.StartsWith(f, StringComparison.OrdinalIgnoreCase))) + { + genTableColumn.HtmlType = GenConstants.HTML_RADIO; + } + else if (GenConstants.selectFiled.Any(f => column.DbColumnName == f) || + GenConstants.selectFiled.Any(f => column.DbColumnName.EndsWith(f, StringComparison.OrdinalIgnoreCase))) + { + genTableColumn.HtmlType = GenConstants.HTML_SELECT; + } + else if (column.Length > 500) + { + genTableColumn.HtmlType = GenConstants.HTML_TEXTAREA; + } + //编辑字段 + if (column.IsIdentity || column.IsPrimarykey || GenConstants.COLUMNNAME_NOT_EDIT.Any(f => column.DbColumnName.Contains(f))) + { + genTableColumn.IsEdit = false; + } + //列表字段 + if (!GenConstants.COLUMNNAME_NOT_ARWST.Any(f => column.DbColumnName.Contains(f) && !column.IsPrimarykey)) + { + genTableColumn.IsList = true; + } + //时间类型初始化between范围查询 + if (genTableColumn.CsharpType == GenConstants.TYPE_DATE) + { + genTableColumn.QueryType = "BETWEEN"; + } + + return genTableColumn; + } + + #endregion + + /// + /// 初始化Jnt模板 + /// + /// + /// + private static void InitJntTemplate(GenerateDto dto, ReplaceDto replaceDto) + { + Engine.Current.Clean(); + dto.GenTable.Columns = dto.GenTable.Columns.OrderBy(x => x.Sort).ToList(); + bool showCustomInput = dto.GenTable.Columns.Any(f => f.HtmlType.Equals(GenConstants.HTML_CUSTOM_INPUT, StringComparison.OrdinalIgnoreCase)); + //jnt模板引擎全局变量 + Engine.Configure((options) => + { + options.TagPrefix = "${"; + options.TagSuffix = "}"; + options.TagFlag = '$'; + options.OutMode = OutMode.Auto; + //options.DisableeLogogram = true;//禁用简写 + options.Data.Set("refs", "$");//特殊标签替换 + options.Data.Set("t", "$");//特殊标签替换 + options.Data.Set("modal", "$");//特殊标签替换 + options.Data.Set("index", "$");//特殊标签替换 + options.Data.Set("confirm", "$");//特殊标签替换 + options.Data.Set("nextTick", "$"); + options.Data.Set("replaceDto", replaceDto); + options.Data.Set("options", dto.GenOptions); + options.Data.Set("genTable", dto.GenTable); + options.Data.Set("btns", dto.CheckedBtn); + options.Data.Set("showCustomInput", showCustomInput); + options.Data.Set("tool", new CodeGeneratorTool()); + options.Data.Set("codeTool", new CodeGenerateTemplate()); + options.EnableCache = true; + //...其它数据 + }); + } + + #region 模板用 + /// + /// 模板用 + /// + /// + /// + public static bool CheckInputDtoNoField(string str) + { + return GenConstants.inputDtoNoField.Any(f => f.Contains(str, StringComparison.OrdinalIgnoreCase)); + } + public static bool CheckTree(GenTable genTable, string csharpField) + { + return (genTable.TplCategory.Equals("tree", StringComparison.OrdinalIgnoreCase) && genTable?.Options?.TreeParentCode != null && csharpField.Equals(genTable?.Options?.TreeParentCode)); + } + #endregion + + #endregion + + + + #region Api接口生成 + + /// + /// 代码生成器入口方法(Api) + /// + /// + public static void GenerateApi(GenerateDto dto) + { + _option.BaseNamespace = dto.GenTable.BaseNameSpace; + _option.SubNamespace = dto.GenTable.ModuleName.FirstUpperCase(); + _option.DtosNamespace = _option.BaseNamespace + "Model"; + _option.ModelsNamespace = _option.BaseNamespace + "Model"; + _option.RepositoriesNamespace = _option.BaseNamespace + "Repository"; + _option.IRepositoriesNamespace = _option.BaseNamespace + "Repository"; + _option.IServicsNamespace = _option.BaseNamespace + "Service"; + _option.ServicesNamespace = _option.BaseNamespace + "Service"; + _option.ApiControllerNamespace = _option.BaseNamespace + "WebApi"; + + if (dto.GenTable.ModuleName.Contains('/')) dto.GenTable.ModuleName = dto.GenTable.ModuleName.Replace('/', '.'); + + if (dto.GenType == "1") + { + var vuePath = AppSettings.GetConfig("gen:vuePath"); + if (!vuePath.IsEmpty()) + { + dto.VueParentPath = vuePath; + } + } + else + { + string fullName = Path.Combine(dto.GenCodePath, "vue"); + + dto.VueParentPath = fullName; + } + dto.GenOptions = _option; + + string PKName = "Id"; + string PKType = "int"; + ReplaceDto replaceDto = new() + { + ModelTypeName = dto.GenTable.ClassName,//表名对应C# 实体类名 + PermissionPrefix = dto.GenTable?.Options?.PermissionPrefix, + Author = dto.GenTable.FunctionAuthor, + ShowBtnAdd = dto.GenTable.Options.CheckedBtn.Any(f => f == 1), + ShowBtnEdit = dto.GenTable.Options.CheckedBtn.Any(f => f == 2), + ShowBtnDelete = dto.GenTable.Options.CheckedBtn.Any(f => f == 3), + ShowBtnExport = dto.GenTable.Options.CheckedBtn.Any(f => f == 4), + ShowBtnView = dto.GenTable.Options.CheckedBtn.Any(f => f == 5), + ShowBtnImport = dto.GenTable.Options.CheckedBtn.Any(f => f == 6) + }; + + //循环表字段信息 + foreach (GenTableColumn dbFieldInfo in dto.GenTable.Columns.OrderBy(x => x.Sort)) + { + if (dbFieldInfo.IsPk || dbFieldInfo.IsIncrement) + { + PKName = dbFieldInfo.CsharpField; + PKType = dbFieldInfo.CsharpType; + } + if (dbFieldInfo.HtmlType.Equals(GenConstants.HTML_IMAGE_UPLOAD) || dbFieldInfo.HtmlType.Equals(GenConstants.HTML_FILE_UPLOAD)) + { + replaceDto.UploadFile = 1; + } + dbFieldInfo.CsharpFieldFl = dbFieldInfo.CsharpField.FirstLowerCase(); + } + + replaceDto.PKName = PKName; + replaceDto.PKType = PKType; + replaceDto.FistLowerPk = PKName.FirstLowerCase(); + InitJntTemplate(dto, replaceDto); + + GenerateModelsApi(replaceDto, dto); + GenerateServiceApi(replaceDto, dto); + GenerateControllersApi(replaceDto, dto); + + if (dto.IsPreview) return; + + foreach (var item in dto.GenCodes) + { + item.Path = Path.Combine(dto.GenCodePath, item.Path); + FileHelper.WriteAndSave(item.Path, item.Content); + } + } + + + /// + /// 生成实体类Model(Api) + /// + /// + /// 替换实体 + private static void GenerateModelsApi(ReplaceDto replaceDto, GenerateDto generateDto) + { + var tplDto = FileHelper.ReadJtTemplate("TplDtoApi.txt"); + var tplVo = FileHelper.ReadJtTemplate("TplVoApi.txt"); + + string fullPathDto = Path.Combine(_option.ModelsNamespace, "Dto", "Api", _option.SubNamespace, $"{replaceDto.ModelTypeName}ApiDto.cs"); + string fullPathVo = Path.Combine(_option.ModelsNamespace, "Vo", "Api", _option.SubNamespace, $"{replaceDto.ModelTypeName}ApiVo.cs"); + + generateDto.GenCodes.Add(new GenCode(2, "DtoApi.cs", fullPathDto, tplDto.Render())); + generateDto.GenCodes.Add(new GenCode(3, "VoApi.cs", fullPathVo, tplVo.Render())); + } + + + /// + /// 生成Service文件(Api) + /// + private static void GenerateServiceApi(ReplaceDto replaceDto, GenerateDto generateDto) + { + var tpl = FileHelper.ReadJtTemplate("TplServiceApi.txt"); + var tpl2 = FileHelper.ReadJtTemplate("TplIServiceApi.txt"); + var result = tpl.Render(); + var result2 = tpl2.Render(); + + var fullPath = Path.Combine(_option.ServicesNamespace, "Api", "BusinessService", _option.SubNamespace, $"{replaceDto.ModelTypeName}ServiceApi.cs"); + var fullPath2 = Path.Combine(_option.IServicsNamespace, "Api", "IBusinessService", _option.SubNamespace, $"I{replaceDto.ModelTypeName}ServiceApi.cs"); + + generateDto.GenCodes.Add(new GenCode(4, "ServiceApi.cs", fullPath, result)); + generateDto.GenCodes.Add(new GenCode(4, "IServiceApi.cs", fullPath2, result2)); + } + + + /// + /// 生成控制器ApiControllers文件(Api) + /// + private static void GenerateControllersApi(ReplaceDto replaceDto, GenerateDto generateDto) + { + var tpl = FileHelper.ReadJtTemplate("TplControllersApi.txt"); + tpl.Set("QueryCondition", replaceDto.QueryCondition); + var result = tpl.Render(); + + var fullPath = Path.Combine(_option.ApiControllerNamespace, "Controllers", "Api", _option.SubNamespace, $"{replaceDto.ModelTypeName}ApiController.cs"); + generateDto.GenCodes.Add(new GenCode(5, "Controller.cs", fullPath, result)); + } + + #endregion + + + } +} diff --git a/ARW.CodeGenerator/DbProvider.cs b/ARW.CodeGenerator/DbProvider.cs new file mode 100644 index 0000000..2ebf84a --- /dev/null +++ b/ARW.CodeGenerator/DbProvider.cs @@ -0,0 +1,70 @@ +using Infrastructure; +using Infrastructure.Extensions; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace ARW.CodeGenerator +{ + /// + /// 代码生成数据库连接 + /// + public class DbProvider + { + protected static SqlSugarClient CodeDb; + + /// + /// 获取动态连接字符串 + /// + /// 数据库名 + /// + public SqlSugarClient GetSugarDbContext(string dbName = "") + { + string connStr = AppSettings.GetConfig(GenConstants.Gen_conn); + int dbType = AppSettings.GetAppConfig(GenConstants.Gen_conn_dbType, 0); + + if (!string.IsNullOrEmpty(dbName)) + { + string replaceStr = GetValue(connStr, "Database=", ";"); + string replaceStr2 = GetValue(connStr, "Initial Catalog=", ";"); + if (replaceStr.IsNotEmpty()) + { + connStr = connStr.Replace(replaceStr, dbName, StringComparison.OrdinalIgnoreCase); + } + if (replaceStr2.IsNotEmpty()) + { + connStr = connStr.Replace(replaceStr2, dbName, StringComparison.OrdinalIgnoreCase); + } + } + var db = new SqlSugarClient(new List() + { + new ConnectionConfig(){ + ConnectionString = connStr, + DbType = (DbType)dbType, + IsAutoCloseConnection = true,//开启自动释放模式和EF原理一样 + InitKeyType = InitKeyType.Attribute,//从特性读取主键和自增列信息 + }, + }); + + CodeDb = db; + return db; + } + + /// + /// 获得字符串中开始和结束字符串中间得值 + /// + /// 字符串 + /// 开始 + /// 结束 + /// + public static string GetValue(string str, string s, string e) + { + Regex rg = new Regex("(?<=(" + s + "))[.\\s\\S]*?(?=(" + e + "))", RegexOptions.Multiline | RegexOptions.Singleline); + return rg.Match(str).Value; + } + } +} diff --git a/ARW.CodeGenerator/FileHelper.cs b/ARW.CodeGenerator/FileHelper.cs new file mode 100644 index 0000000..d6ca974 --- /dev/null +++ b/ARW.CodeGenerator/FileHelper.cs @@ -0,0 +1,190 @@ +using JinianNet.JNTemplate; +using System; +using System.IO; +using System.IO.Compression; +using System.Runtime.InteropServices; + +namespace ARW.CodeGenerator +{ + public class FileHelper + { + /// + /// 创建文件夹 + /// + /// + /// + public static bool CreateDirectory(string path) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + path = path.Replace("\\", "/").Replace("//", "/"); + } + try + { + if (!Directory.Exists(path)) + { + DirectoryInfo info = Directory.CreateDirectory(path); + Console.WriteLine("不存在创建文件夹" + info); + } + } + catch (Exception ex) + { + Console.WriteLine($"创建文件夹出错了,{ex.Message}"); + return false; + } + return true; + } + + /// + /// 写文件 + /// + /// 完整路径带扩展名的 + /// + public static void WriteAndSave(string path, string content) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + path = path.Replace("\\", "/").Replace("//", "/"); + } + if (!Directory.Exists(Path.GetDirectoryName(path))) + { + Directory.CreateDirectory(Path.GetDirectoryName(path)); + } + Console.WriteLine("写入文件:" + path); + try + { + //实例化一个文件流--->与写入文件相关联 + using var fs = new FileStream(path, FileMode.Create, FileAccess.Write); + //实例化一个StreamWriter-->与fs相关联 + using var sw = new StreamWriter(fs); + //开始写入 + sw.Write(content); + //清空缓冲区 + sw.Flush(); + //关闭流 + sw.Close(); + fs.Close(); + } + catch (Exception ex) + { + Console.WriteLine("写入文件出错了:" + ex.Message); + } + } + + + /// + /// 从代码模板中读取内容 + /// + /// 模板名称,应包括文件扩展名称。比如:template.txt + /// + public static string ReadTemplate(string tplName) + { + string path = Environment.CurrentDirectory; + string fullName = Path.Combine(path, "wwwroot", "CodeGenTemplate", tplName); + + Console.WriteLine("开始读取模板=" + fullName); + string temp = fullName; + string str = ""; + if (!File.Exists(temp)) + { + return str; + } + StreamReader sr = null; + try + { + sr = new StreamReader(temp); + str = sr.ReadToEnd(); // 读取文件 + } + catch (Exception ex) + { + Console.WriteLine($"读取模板出错了{ex.Message}"); + } + sr?.Close(); + sr?.Dispose(); + return str; + } + + public static ITemplate ReadJtTemplate(string tplName) + { + string path = Environment.CurrentDirectory; + string fullName = Path.Combine(path, "wwwroot", "CodeGenTemplate", tplName); + if (File.Exists(fullName)) + { + return Engine.LoadTemplate(fullName); + } + return null; + } + + /// + /// 压缩代码 + /// + /// + /// + /// 压缩后的文件名 + /// + public static bool ZipGenCode(string zipPath, string genCodePath,string zipFileName) + { + if (string.IsNullOrEmpty(zipPath)) return false; + try + { + CreateDirectory(genCodePath); + string zipFileFullName = Path.Combine(zipPath, zipFileName); + if (File.Exists(zipFileFullName)) + { + File.Delete(zipFileFullName); + } + + ZipFile.CreateFromDirectory(genCodePath, zipFileFullName); + DeleteDirectory(genCodePath); + + return true; + } + catch (Exception ex) + { + Console.WriteLine("压缩文件出错。" + ex.Message); + return false; + } + } + + /// + /// 删除指定目录下的所有文件及文件夹(保留目录) + /// + /// 文件目录 + public static void DeleteDirectory(string file) + { + try + { + //判断文件夹是否还存在 + if (Directory.Exists(file)) + { + DirectoryInfo fileInfo = new DirectoryInfo(file); + //去除文件夹的只读属性 + fileInfo.Attributes = FileAttributes.Normal & FileAttributes.Directory; + foreach (string f in Directory.GetFileSystemEntries(file)) + { + if (File.Exists(f)) + { + //去除文件的只读属性 + File.SetAttributes(file, FileAttributes.Normal); + //如果有子文件删除文件 + File.Delete(f); + } + else + { + //循环递归删除子文件夹 + DeleteDirectory(f); + } + } + //删除空文件夹 + Directory.Delete(file); + } + + } + catch (Exception ex) // 异常处理 + { + Console.WriteLine("代码生成异常" + ex.Message); + } + } + + } +} diff --git a/ARW.CodeGenerator/GenConstants.cs b/ARW.CodeGenerator/GenConstants.cs new file mode 100644 index 0000000..87362b0 --- /dev/null +++ b/ARW.CodeGenerator/GenConstants.cs @@ -0,0 +1,144 @@ + + +namespace ARW.CodeGenerator +{ + /// + /// 代码生成常量 + /// + public class GenConstants + { + public static string Gen_conn = "gen:conn"; + public static string Gen_conn_dbType = "gen:dbType"; + public static string Gen_author = "gen:author"; + public static string Gen_autoPre = "gen:autoPre"; + public static string Gen_tablePrefix = "gen:tablePrefix"; + + /// + /// InputDto输入实体是不包含字段 + /// + public static readonly string[] inputDtoNoField = new string[] { "IsDelete", "create_time", "update_time", "create_by", "update_by" }; + /// + /// 图片字段 + /// + public static readonly string[] imageFiled = new string[] { "icon", "img", "image", "url", "pic", "photo", "avatar" }; + /// + /// 下拉框字段 + /// + public static readonly string[] selectFiled = new string[] { "status", "type", "state", "sex", "gender" }; + /// + /// 单选按钮字段 + /// + public static readonly string[] radioFiled = new string[] { "status", "state", "is"}; + + + /** 单表(增删改查) */ + public static string TPL_CRUD = "crud"; + + /** 树表(增删改查) */ + public static string TPL_TREE = "tree"; + + /** 主子表(增删改查) */ + public static string TPL_SUB = "sub"; + + /** 树编码字段 */ + public static string TREE_CODE = "treeCode"; + + /** 树父编码字段 */ + public static string TREE_PARENT_CODE = "treeParentCode"; + + /** 树名称字段 */ + public static string TREE_NAME = "treeName"; + + /** 上级菜单ID字段 */ + public static string PARENT_MENU_ID = "parentMenuId"; + + /** 上级菜单名称字段 */ + public static string PARENT_MENU_NAME = "parentMenuName"; + + /** 数据库字符串类型 */ + public static string[] COLUMNTYPE_STR = { "char", "varchar", "nvarchar", "varchar2" }; + + /** 数据库文本类型 */ + public static string[] COLUMNTYPE_TEXT = { "tinytext", "text", "mediumtext", "longtext" }; + + /** 数据库时间类型 */ + public static string[] COLUMNTYPE_TIME = { "datetime", "time", "date", "timestamp" }; + + /** 页面不需要编辑字段 */ + public static string[] COLUMNNAME_NOT_EDIT = { "id", "create_by", "create_time", "delFlag" }; + + /** 页面不需要显示的列表字段 */ + public static string[] COLUMNNAME_NOT_ARWST = { "create_by", "create_time", "delFlag", "update_by", + "update_time" , "password"}; + + /** 页面不需要查询字段 */ + public static string[] COLUMNNAME_NOT_QUERY = { "id", "create_by", "create_time", "delFlag", "update_by", + "update_time", "remark" }; + + /** Entity基类字段 */ + public static string[] BASE_ENTITY = { "createBy", "createTime", "updateBy", "updateTime", "remark" }; + + /** Tree基类字段 */ + public static string[] TREE_ENTITY = { "parentName", "parentId", "orderNum", "ancestors", "children" }; + + /** 文本框 */ + public static string HTML_INPUT = "input"; + /** 数字框 */ + public static string HTML_INPUT_NUMBER = "inputNumber"; + + /** 文本域 */ + public static string HTML_TEXTAREA = "textarea"; + + /** 下拉框 */ + public static string HTML_SELECT = "select"; + + /** 单选框 */ + public static string HTML_RADIO = "radio"; + + /** 复选框 */ + public static string HTML_CHECKBOX = "checkbox"; + + /** 日期控件 */ + public static string HTML_DATETIME = "datetime"; + + /** 图片上传控件 */ + public static string HTML_IMAGE_UPLOAD = "imageUpload"; + + /** 文件上传控件 */ + public static string HTML_FILE_UPLOAD = "fileUpload"; + + /** 富文本控件 */ + public static string HTML_EDITOR = "editor"; + // 自定义排序 + public static string HTML_SORT = "sort"; + /// + /// 自定义输入框 + /// + public static string HTML_CUSTOM_INPUT = "customInput"; + //颜色选择器 + public static string HTML_COLORPICKER = "colorPicker"; + //switch开关 + public static string HTML_SWITCH { get; set; } + + /** 字符串类型 */ + public static string TYPE_STRING = "string"; + + /** 整型 */ + public static string TYPE_INT = "int"; + + /** 长整型 */ + public static string TYPE_LONG = "long"; + + /** 浮点型 */ + public static string TYPE_DOUBLE = "Double"; + + /** 时间类型 */ + public static string TYPE_DATE = "DateTime"; + + /** 模糊查询 */ + public static string QUERY_ARWKE = "ARWKE"; + + /** 需要 */ + public static string REQUIRE = "1"; + } +} \ No newline at end of file diff --git a/ARW.CodeGenerator/Model/GenerateDto.cs b/ARW.CodeGenerator/Model/GenerateDto.cs new file mode 100644 index 0000000..029f8e7 --- /dev/null +++ b/ARW.CodeGenerator/Model/GenerateDto.cs @@ -0,0 +1,71 @@ +using System.Collections.Generic; +using ARW.Model.System.Generate; + +namespace ARW.CodeGenerator.Model +{ + public class GenerateDto + { + /// + /// vue版本 + /// + public int VueVersion { get; set; } + public long TableId { get; set; } + /// + /// 是否预览代码 + /// + public bool IsPreview { get; set; } + /// + /// 生成代码的数据库类型 0、mysql 1、sqlserver + /// + public int DbType { get; set; } + /// + /// 生成的按钮功能 + /// + public int[] CheckedBtn { get; set; } = System.Array.Empty(); + public GenTable GenTable { get; set; } + public CodeGenerateOption GenOptions { get; set; } + #region 存储路径 + /// + /// 代码模板预览存储路径存放 + /// + public List GenCodes { get; set; } = new List(); + /// + /// 代码生成路径 + /// + public string GenCodePath { get; set; } = string.Empty; + /// + /// 代码生成压缩包路径 + /// + public string ZipPath { get; set; } + /// + /// 代码生成压缩包名称 + /// + public string ZipFileName { get; set; } + /// + /// 生成代码方式(0zip压缩包 1自定义路径) + /// + public string GenType { get; set; } + public string GenPath { get; set; } = ""; + /// + /// vue代码路径 + /// + public string VueParentPath { get; set; } + #endregion + } + + public class GenCode + { + public int Type { get; set; } + public string Title { get; set; } + public string Path { get; set; } + public string Content { get; set; } + + public GenCode(int type, string title, string path, string content) + { + Type = type; + Title = title; + Path = path; + Content = content; + } + } +} diff --git a/ARW.CodeGenerator/Model/ReplaceDto.cs b/ARW.CodeGenerator/Model/ReplaceDto.cs new file mode 100644 index 0000000..9d5479c --- /dev/null +++ b/ARW.CodeGenerator/Model/ReplaceDto.cs @@ -0,0 +1,61 @@ +using System; + +namespace ARW.CodeGenerator.Model +{ + public class ReplaceDto + { + /// + /// 主键字段 + /// + public string PKName { get; set; } + /// + /// 首字母小写主键 + /// + public string FistLowerPk{ get; set; } + /// + /// 主键类型 + /// + public string PKType { get; set; } + /// + /// 控制器权限 + /// + public string PermissionPrefix { get; set; } + /// + /// C#类名 + /// + public string ModelTypeName { get; set; } + //vue、api + //public string VueViewFormResetHtml { get; set; } + /// + /// 前端列表查询html + /// + public string VueViewListHtml { get; set; } + /// + /// 前端添加、编辑表格html + /// + public string VueViewFormHtml { get; set; } + /// + /// 前端搜索表单html + /// + public string VueQueryFormHtml { get; set; } + + /// + /// 查询条件 + /// + public string QueryCondition { get; set; } = ""; + public bool ShowBtnExport { get; set; } + public bool ShowBtnImport { get; set; } + public bool ShowBtnAudit { get; set; } + public bool ShowBtnAdd { get; set; } + public bool ShowBtnEdit { get; set; } + public bool ShowBtnDelete { get; set; } + public bool ShowBtnView { get; set; } + /// + /// 上传URL data + /// + //public string VueUploadUrl { get; set; } + public int UploadFile { get; set; } = 0; + public string Author { get; set; } + public string AddTime { get; set; } = DateTime.Now.ToString("yyyy-MM-dd"); + } +} diff --git a/ARW.CodeGenerator/Service/CodeGeneraterService.cs b/ARW.CodeGenerator/Service/CodeGeneraterService.cs new file mode 100644 index 0000000..c820795 --- /dev/null +++ b/ARW.CodeGenerator/Service/CodeGeneraterService.cs @@ -0,0 +1,68 @@ +using SqlSugar; +using System.Collections.Generic; +using System.Linq; +using ARW.Model; + +namespace ARW.CodeGenerator.Service +{ + public class CodeGeneraterService : DbProvider + { + /// + /// 获取所有数据库名 + /// + /// + public List GetAllDataBases() + { + var db = GetSugarDbContext(); + var templist = db.DbMaintenance.GetDataBaseList(db); + + return templist; + } + + /// + /// 获取所有表 + /// + /// + /// + /// + /// + public List GetAllTables(string dbName, string tableName, PagerInfo pager) + { + var tableList = GetSugarDbContext(dbName).DbMaintenance.GetTableInfoList(true); + if (!string.IsNullOrEmpty(tableName)) + { + tableList = tableList.Where(f => f.Name.ToLower().Contains(tableName.ToLower())).ToList(); + } + //tableList = tableList.Where(f => !new string[] { "gen", "sys_" }.Contains(f.Name)).ToList(); + pager.TotalNum = tableList.Count; + return tableList.Skip(pager.PageSize * (pager.PageNum - 1)).Take(pager.PageSize).OrderBy(f => f.Name).ToList(); + } + + /// + /// 获取单表数据 + /// + /// + /// + /// + public DbTableInfo GetTableInfo(string dbName, string tableName) + { + var tableList = GetSugarDbContext(dbName).DbMaintenance.GetTableInfoList(true); + if (!string.IsNullOrEmpty(tableName)) + { + return tableList.Where(f => f.Name.Equals(tableName, System.StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); + } + + return null; + } + /// + /// 获取列信息 + /// + /// + /// + /// + public List GetColumnInfo(string dbName, string tableName) + { + return GetSugarDbContext(dbName).DbMaintenance.GetColumnInfosByTableName(tableName, true); + } + } +} diff --git a/ARW.Common/ARW.Common.csproj b/ARW.Common/ARW.Common.csproj new file mode 100644 index 0000000..e773da7 --- /dev/null +++ b/ARW.Common/ARW.Common.csproj @@ -0,0 +1,21 @@ + + + + net6.0 + ARW.Common + ARW.Common + + + + + + + + + + + + + + + diff --git a/ARW.Common/AliyunMsgHelper.cs b/ARW.Common/AliyunMsgHelper.cs new file mode 100644 index 0000000..7b4b863 --- /dev/null +++ b/ARW.Common/AliyunMsgHelper.cs @@ -0,0 +1,65 @@ +using Aliyun.OSS.Common; +using Aliyun.OSS; +using Org.BouncyCastle.Asn1.Ocsp; +using System; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Aliyun.Acs.Core.Exceptions; +using Aliyun.Acs.Core.Http; +using Aliyun.Acs.Core.Profile; +using Aliyun.Acs.Core; +using ClientException = Aliyun.Acs.Core.Exceptions.ClientException; +using Infrastructure; +using System.Collections.Generic; + +namespace ARW.Common +{ + public class AliyunMsgHelper + { + + public static void SendMsgCode(string phone) + { + var accessKeyId = AppSettings.GetConfig("AARWYUN_MSG:accessKeyId"); + var accessSecret = AppSettings.GetConfig("AARWYUN_MSG:accessSecret"); + var signName = AppSettings.GetConfig("AARWYUN_MSG:signName"); + var templateCode = AppSettings.GetConfig("AARWYUN_MSG:templateCode"); + + /*这里的*"cn-hangzhou":不需要更改, "":就是上面要求记录到本地的accessKeyId, "::就是上面要求记录到本地的accessSecret"*/ + IClientProfile profile = DefaultProfile.GetProfile("cn-hongkong", accessKeyId, accessSecret); + DefaultAcsClient client = new DefaultAcsClient(profile); + CommonRequest request = new CommonRequest(); + request.Method = MethodType.POST; + request.Domain = "dysmsapi.aliyuncs.com"; + request.Version = "2017-05-25"; + request.Action = "SendSms"; + // request.Protocol = ProtocolType.HTTP;1 + + request.AddQueryParameters("PhoneNumbers", phone); + request.AddQueryParameters("SignName", signName); + request.AddQueryParameters("TemplateCode", templateCode); + + Dictionary pairs = new Dictionary(); + pairs.Add("code", new Random().Next(100000, 1000000).ToString()); + string json = Newtonsoft.Json.JsonConvert.SerializeObject(pairs); + request.AddQueryParameters("TemplateParam", json); + + try + { + CommonResponse response = client.GetCommonResponse(request); + var status = response.HttpResponse; + } + catch (ServerException e) + { + Console.WriteLine(e); + } + catch (ClientException e) + { + Console.WriteLine(e); + } + + } + } + +} + diff --git a/ARW.Common/AliyunOssHelper.cs b/ARW.Common/AliyunOssHelper.cs new file mode 100644 index 0000000..9d774aa --- /dev/null +++ b/ARW.Common/AliyunOssHelper.cs @@ -0,0 +1,67 @@ +using Aliyun.OSS; +using Aliyun.OSS.Common; +using Infrastructure; +using System; +using System.IO; + +namespace ARW.Common +{ + public class AliyunOssHelper + { + static string accessKeyId = AppSettings.GetConfig("AARWYUN_OSS:KEY"); + static string accessKeySecret = AppSettings.GetConfig("AARWYUN_OSS:SECRET"); + static string endpoint = AppSettings.GetConfig("AARWYUN_OSS:REGIONID"); + static string bucketName1 = AppSettings.GetConfig("AARWYUN_OSS:bucketName"); + + /// + /// 上传到阿里云 + /// + /// + /// 存储路径 eg: upload/2020/01/01/xxx.png + /// 存储桶 如果为空默认取配置文件 + public static System.Net.HttpStatusCode PutObjectFromFile(Stream filestreams, string dirPath, string bucketName = "") + { + OssClient client = new(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; + } + + /// + /// 删除资源 + /// + /// + /// + /// + public static System.Net.HttpStatusCode DeleteFile(string dirPath, string bucketName = "") + { + if (string.IsNullOrEmpty(bucketName)) { bucketName = bucketName1; } + try + { + OssClient client = new(endpoint, accessKeyId, accessKeySecret); + DeleteObjectResult putObjectResult = client.DeleteObject(bucketName, dirPath); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + return System.Net.HttpStatusCode.BadRequest; + } + } +} diff --git a/ARW.Common/Cache/CacheHelper.cs b/ARW.Common/Cache/CacheHelper.cs new file mode 100644 index 0000000..8efe630 --- /dev/null +++ b/ARW.Common/Cache/CacheHelper.cs @@ -0,0 +1,111 @@ +using Microsoft.Extensions.Caching.Memory; +using System; + +namespace ARW.Common +{ + public class CacheHelper + { + public static MemoryCache Cache { get; set; } + static CacheHelper() + { + Cache = new MemoryCache(new MemoryCacheOptions + { + //SizeLimit = 1024 + }); + } + + /// + /// 获取缓存 + /// + /// + /// + /// + public static T GetCache(string key) where T : class + { + if (key == null) + throw new ArgumentNullException(nameof(key)); + //return Cache.Get(key) as T; //或者 + return Cache.Get(key); + } + + /// + /// 获取缓存 + /// + /// + /// + public static object GetCache(string CacheKey) + { + return Cache.Get(CacheKey); + } + + public static object Get(string CacheKey) + { + return Cache.Get(CacheKey); + } + + /// + /// 设置缓存,永久缓存 + /// + /// key + /// 值 + public static object SetCache(string CacheKey, object objObject) + { + return Cache.Set(CacheKey, objObject); + } + + /// + /// 设置缓存 + /// + /// key + /// 值 + /// 过期时间(分钟) + public static object SetCache(string CacheKey, object objObject, int Timeout) + { + return Cache.Set(CacheKey, objObject, DateTime.Now.AddMinutes(Timeout)); + } + + /// + /// 设置缓存(秒) + /// + /// key + /// 值 + /// 过期时间(秒) + public static void SetCaches(string CacheKey, object objObject, int Timeout) + { + Cache.Set(CacheKey, objObject, DateTime.Now.AddSeconds(Timeout)); + } + + /// + /// 设置缓存 + /// + /// key + /// 值 + /// 过期时间 + /// 过期时间间隔 + public static object SetCache(string CacheKey, object objObject, DateTime absoluteExpiration, TimeSpan slidingExpiration) + { + return Cache.Set(CacheKey, objObject, absoluteExpiration); + } + + /// + /// 设定绝对的过期时间 + /// + /// + /// + /// 超过多少秒后过期 + public static void SetCacheDateTime(string CacheKey, object objObject, long Seconds) + { + Cache.Set(CacheKey, objObject, DateTime.Now.AddSeconds(Seconds)); + } + + /// + /// 删除缓存 + /// + /// key + public static void Remove(string key) + { + Cache.Remove(key); + } + } +} + diff --git a/ARW.Common/Cache/RedisServer.cs b/ARW.Common/Cache/RedisServer.cs new file mode 100644 index 0000000..ce58b10 --- /dev/null +++ b/ARW.Common/Cache/RedisServer.cs @@ -0,0 +1,17 @@ +using CSRedis; +using Infrastructure; + +namespace ARW.Common.Cache +{ + public class RedisServer + { + public static CSRedisClient Cache; + public static CSRedisClient Session; + + public static void Initalize() + { + Cache = new CSRedisClient(AppSettings.GetConfig("RedisServer:Cache")); + Session = new CSRedisClient(AppSettings.GetConfig("RedisServer:Session")); + } + } +} diff --git a/ARW.Common/Common.cs b/ARW.Common/Common.cs new file mode 100644 index 0000000..b2fb4d7 --- /dev/null +++ b/ARW.Common/Common.cs @@ -0,0 +1,415 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using System.Text.RegularExpressions; //引用正则表达式 + +namespace ARW.Common +{ + /// + /// 常用公共类 + /// + public class Common + { + public static object _lock = new object(); + + public static int count = 1; + + + #region Stopwatch计时器 + /// + /// 计时器开始 + /// + /// + public static Stopwatch TimerStart() + { + Stopwatch watch = new Stopwatch(); + watch.Reset(); + watch.Start(); + return watch; + } + /// + /// 计时器结束 + /// + /// + /// + public static string TimerEnd(Stopwatch watch) + { + watch.Stop(); + double costtime = watch.ElapsedMilliseconds; + return costtime.ToString(); + } + #endregion + + #region 删除数组中的重复项 + /// + /// 删除数组中的重复项 + /// + /// + /// + public static string[] RemoveDup(string[] values) + { + List list = new List(); + for (int i = 0; i < values.Length; i++)//遍历数组成员 + { + if (!list.Contains(values[i])) + { + list.Add(values[i]); + }; + } + return list.ToArray(); + } + #endregion + + #region 自动生成编号 + /// + /// 表示全局唯一标识符 (GUID)。 + /// + /// + public static string GuId() + { + return Guid.NewGuid().ToString(); + } + /// + /// 自动生成编号 201008251145409865 + /// + /// + public static string CreateNo() + { + Random random = new Random(); + string strRandom = random.Next(1000, 10000).ToString(); //生成编号 + string code = DateTime.Now.ToString("yyyyMMddHHmmss") + strRandom;//形如 + return code; + } + + /// + /// 生成不重复的订单,净水器 + /// + /// + public static string CreateNo2() + { + lock (_lock) + { + if (count >= 10000) + { + count = 1; + } + + var number = DateTime.Now.ToString("yyMMddHHmmssfff") + count.ToString("0000"); + + count++; + + return number; + } + } + + /// + /// 生成不重复的订单,送芯 + /// + /// + public static string CreateNo3() + { + lock (_lock) + { + if (count >= 10000) + { + count = 1; + } + + var number = "C" + DateTime.Now.ToString("yyMMddHHmmssfff") + count.ToString("0000"); + + count++; + + return number; + } + } + + /// + /// 退款订单号生成 + /// + /// + public static string CreateNo_Recharge() + { + lock (_lock) + { + if (count >= 10000) + { + count = 1; + } + + var number = "R" + DateTime.Now.ToString("yyMMddHHmmssfff") + count.ToString("0000"); + + count++; + + return number; + } + } + + /// + /// 生成订单号 + /// + /// + public static string CreateNoQuery() + { + lock (_lock) + { + if (count >= 10000) + { + count = 1; + } + + var number = "Q" + DateTime.Now.ToString("yyMMddHHmmssfff") + count.ToString("0000"); + + count++; + + return number; + } + } + + + #endregion + + #region 生成0-9随机数 + /// + /// 生成0-9随机数 + /// + /// 生成长度 + /// + public static string RndNum(int codeNum) + { + StringBuilder sb = new StringBuilder(codeNum); + Random rand = new Random(); + for (int i = 1; i < codeNum + 1; i++) + { + int t = rand.Next(9); + sb.AppendFormat("{0}", t); + } + return sb.ToString(); + + } + #endregion + + #region 生成随机数 + /// + /// 生成随机数 + /// + /// 数据长度 + /// 生成类型,0:纯数字,1:纯字母, 2:数据字+字母 + /// + public static string GetRandomNo(int length, int CreateType) + { + char[] charlist = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'h', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; + string result = ""; + + Random rd = new Random(); + switch (CreateType) + { + case 0: //纯数字 + for (int i = 0; i < length; i++) + { + result = result + charlist[rd.Next(0, 10)]; + } + break; + case 1://纯字母 + for (int i = 0; i < length; i++) + { + result = result + charlist[rd.Next(10, 36)]; + } + break; + case 2://数据字+字母 + for (int i = 0; i < length; i++) + { + result = result + charlist[rd.Next(0, 36)]; + } + break; + } + + return result; + } + #endregion + + + #region 删除最后一个字符之后的字符 + /// + /// 删除最后结尾的一个逗号 + /// + public static string DelLastComma(string str) + { + return str.Substring(0, str.LastIndexOf(",")); + } + /// + /// 删除最后结尾的指定字符后的字符 + /// + public static string DelLastChar(string str, string strchar) + { + return str.Substring(0, str.LastIndexOf(strchar)); + } + /// + /// 删除最后结尾的长度 + /// + /// + /// + /// + public static string DelLastLength(string str, int Length) + { + if (string.IsNullOrEmpty(str)) + return ""; + str = str.Substring(0, str.Length - Length); + return str; + } + #endregion + + + #region 小写转大写 + /// + /// 转换人民币大小金额 + /// + /// 金额 + /// 返回大写形式 + public static string CmycurD(decimal num) + { + string str1 = "零壹贰叁肆伍陆柒捌玖"; //0-9所对应的汉字 + string str2 = "万仟佰拾亿仟佰拾万仟佰拾元角分"; //数字位所对应的汉字 + string str3 = ""; //从原num值中取出的值 + string str4 = ""; //数字的字符串形式 + string str5 = ""; //人民币大写金额形式 + int i; //循环变量 + int j; //num的值乘以100的字符串长度 + string ch1 = ""; //数字的汉语读法 + string ch2 = ""; //数字位的汉字读法 + int nzero = 0; //用来计算连续的零值是几个 + int temp; //从原num值中取出的值 + + num = Math.Round(Math.Abs(num), 2); //将num取绝对值并四舍五入取2位小数 + str4 = ((long)(num * 100)).ToString(); //将num乘100并转换成字符串形式 + j = str4.Length; //找出最高位 + if (j > 15) { return "溢出"; } + str2 = str2.Substring(15 - j); //取出对应位数的str2的值。如:200.55,j为5所以str2=佰拾元角分 + + //循环取出每一位需要转换的值 + for (i = 0; i < j; i++) + { + str3 = str4.Substring(i, 1); //取出需转换的某一位的值 + temp = Convert.ToInt32(str3); //转换为数字 + if (i != (j - 3) && i != (j - 7) && i != (j - 11) && i != (j - 15)) + { + //当所取位数不为元、万、亿、万亿上的数字时 + if (str3 == "0") + { + ch1 = ""; + ch2 = ""; + nzero = nzero + 1; + } + else + { + if (str3 != "0" && nzero != 0) + { + ch1 = "零" + str1.Substring(temp * 1, 1); + ch2 = str2.Substring(i, 1); + nzero = 0; + } + else + { + ch1 = str1.Substring(temp * 1, 1); + ch2 = str2.Substring(i, 1); + nzero = 0; + } + } + } + else + { + //该位是万亿,亿,万,元位等关键位 + if (str3 != "0" && nzero != 0) + { + ch1 = "零" + str1.Substring(temp * 1, 1); + ch2 = str2.Substring(i, 1); + nzero = 0; + } + else + { + if (str3 != "0" && nzero == 0) + { + ch1 = str1.Substring(temp * 1, 1); + ch2 = str2.Substring(i, 1); + nzero = 0; + } + else + { + if (str3 == "0" && nzero >= 3) + { + ch1 = ""; + ch2 = ""; + nzero = nzero + 1; + } + else + { + if (j >= 11) + { + ch1 = ""; + nzero = nzero + 1; + } + else + { + ch1 = ""; + ch2 = str2.Substring(i, 1); + nzero = nzero + 1; + } + } + } + } + } + if (i == (j - 11) || i == (j - 3)) + { + //如果该位是亿位或元位,则必须写上 + ch2 = str2.Substring(i, 1); + } + str5 = str5 + ch1 + ch2; + + if (i == j - 1 && str3 == "0") + { + //最后一位(分)为0时,加上“整” + str5 = str5 + '整'; + } + } + if (num == 0) + { + str5 = "零元整"; + } + return str5; + } + + #endregion + + #region 获取html所有Img标签src地址 + public static string[] GetHtmlImageUrlList(string sHtmlText) + { + // 定义正则表达式用来匹配 img 标签 + Regex regImg = new Regex(@"]*?\bsrc[\s\t\r\n]*=[\s\t\r\n]*[""']?[\s\t\r\n]*(?[^\s\t\r\n""'<>]*)[^<>]*?/?[\s\t\r\n]*>", RegexOptions.IgnoreCase); + + // 搜索匹配的字符串 + MatchCollection matches = regImg.Matches(sHtmlText); + int i = 0; + string[] sUrlList = new string[matches.Count]; + + // 取得匹配项列表 + foreach (Match match in matches) + sUrlList[i++] = match.Groups["imgUrl"].Value; + return sUrlList; + } + + #endregion + + #region 删除html标签 + public static string ReplaceHtmlTag(string html, int length = 0) + { + string strText = System.Text.RegularExpressions.Regex.Replace(html, "<[^>]+>", ""); + strText = System.Text.RegularExpressions.Regex.Replace(strText, "&[^;]+;", ""); + + if (length > 0 && strText.Length > length) + return strText.Substring(0, length); + + return strText; + } + #endregion + } +} diff --git a/ARW.Common/CrawlerHelper.cs b/ARW.Common/CrawlerHelper.cs new file mode 100644 index 0000000..3d9b33e --- /dev/null +++ b/ARW.Common/CrawlerHelper.cs @@ -0,0 +1,829 @@ +/// +/// 类说明:HttpHelper类,用来实现Http访问,Post或者Get方式的,直接访问,带Cookie的,带证书的等方式,可以设置代理 +/// 重要提示:请不要自行修改本类,如果因为你自己修改后将无法升级到新版本。如果确实有什么问题请到官方网站提建议, +/// 我们一定会及时修改 +/// 编码日期:2011-09-20 +/// 编 码 人:苏飞 +/// 联系方式:361983679 +/// 官方网址:http://www.sufeinet.com/thread-3-1-1.html +/// 修改日期:2018-11-06 +/// 版 本 号:1.9.9 +/// +using System; +using System.Collections.Generic; +using System.Text; +using System.Net; +using System.IO; +using System.Text.RegularExpressions; +using System.IO.Compression; +using System.Security.Cryptography.X509Certificates; +using System.Net.Security; +using System.Linq; +using System.Net.Cache; + +namespace ARW.Common +{ + /// + /// Http连接操作帮助类 + /// + public class CrawlerHelper + { + + #region 预定义方变量 + //默认的编码 + private Encoding encoding = Encoding.Default; + //Post数据编码 + private Encoding postencoding = Encoding.Default; + //HttpWebRequest对象用来发起请求 + private HttpWebRequest request = null; + //获取影响流的数据对象 + private HttpWebResponse response = null; + //设置本地的出口ip和端口 + private IPEndPoint _IPEndPoint = null; + #endregion + + #region Public + + /// + /// 根据相传入的数据,得到相应页面数据 + /// + /// 参数类对象 + /// 返回HttpResult类型 + public HttpResult GetHtml(HttpItem item) + { + //返回参数 + HttpResult result = new HttpResult(); + try + { + //准备参数 + SetRequest(item); + } + catch (Exception ex) + { + //配置参数时出错 + return new HttpResult() { Cookie = string.Empty, Header = null, Html = ex.Message, StatusDescription = "配置参数时出错:" + ex.Message }; + } + try + { + //请求数据 + using (response = (HttpWebResponse)request.GetResponse()) + { + GetData(item, result); + } + } + catch (WebException ex) + { + if (ex.Response != null) + { + using (response = (HttpWebResponse)ex.Response) + { + GetData(item, result); + } + } + else + { + result.Html = ex.Message; + } + } + catch (Exception ex) + { + result.Html = ex.Message; + } + if (item.IsToLower) result.Html = result.Html.ToLower(); + //重置request,response为空 + if (item.IsReset) + { + request = null; + response = null; + } + return result; + } + #endregion + + #region GetData + + /// + /// 获取数据的并解析的方法 + /// + /// + /// + private void GetData(HttpItem item, HttpResult result) + { + if (response == null) + { + return; + } + #region base + //获取StatusCode + result.StatusCode = response.StatusCode; + //获取StatusDescription + result.StatusDescription = response.StatusDescription; + //获取Headers + result.Header = response.Headers; + //获取最后访问的URl + result.ResponseUri = response.ResponseUri.ToString(); + //获取CookieCollection + if (response.Cookies != null) result.CookieCollection = response.Cookies; + //获取set-cookie + if (response.Headers["set-cookie"] != null) result.Cookie = response.Headers["set-cookie"]; + #endregion + + #region byte + + //处理网页Byte + byte[] ResponseByte = GetByte(); + + #endregion + + #region Html + if (ResponseByte != null && ResponseByte.Length > 0) + { + //设置编码 + SetEncoding(item, result, ResponseByte); + //得到返回的HTML + result.Html = encoding.GetString(ResponseByte); + } + else + { + //没有返回任何Html代码 + result.Html = string.Empty; + } + #endregion + } + /// + /// 设置编码 + /// + /// HttpItem + /// HttpResult + /// byte[] + private void SetEncoding(HttpItem item, HttpResult result, byte[] ResponseByte) + { + //是否返回Byte类型数据 + if (item.ResultType == ResultType.Byte) result.ResultByte = ResponseByte; + //从这里开始我们要无视编码了 + if (encoding == null) + { + Match meta = Regex.Match(Encoding.Default.GetString(ResponseByte), " 0) + { + c = meta.Groups[1].Value.ToLower().Trim(); + } + if (c.Length > 2) + { + try + { + encoding = Encoding.GetEncoding(c.Replace("\"", string.Empty).Replace("'", "").Replace(";", "").Replace("iso-8859-1", "gbk").Trim()); + } + catch + { + if (string.IsNullOrEmpty(response.CharacterSet)) + { + encoding = Encoding.UTF8; + } + else + { + encoding = Encoding.GetEncoding(response.CharacterSet); + } + } + } + else + { + if (string.IsNullOrEmpty(response.CharacterSet)) + { + encoding = Encoding.UTF8; + } + else + { + encoding = Encoding.GetEncoding(response.CharacterSet); + } + } + } + } + /// + /// 提取网页Byte + /// + /// + private byte[] GetByte() + { + byte[] ResponseByte = null; + using (MemoryStream _stream = new MemoryStream()) + { + //GZIIP处理 + if (response.ContentEncoding != null && response.ContentEncoding.Equals("gzip", StringComparison.InvariantCultureIgnoreCase)) + { + //开始读取流并设置编码方式 + new GZipStream(response.GetResponseStream(), CompressionMode.Decompress).CopyTo(_stream, 10240); + } + else + { + //开始读取流并设置编码方式 + response.GetResponseStream().CopyTo(_stream, 10240); + } + //获取Byte + ResponseByte = _stream.ToArray(); + } + return ResponseByte; + } + + + #endregion + + #region SetRequest + + /// + /// 为请求准备参数 + /// + ///参数列表 + private void SetRequest(HttpItem item) + { + + // 验证证书 + SetCer(item); + if (item.IPEndPoint != null) + { + _IPEndPoint = item.IPEndPoint; + //设置本地的出口ip和端口 + request.ServicePoint.BindIPEndPointDelegate = new BindIPEndPoint(BindIPEndPointCallback); + } + //设置Header参数 + if (item.Header != null && item.Header.Count > 0) foreach (string key in item.Header.AllKeys) + { + request.Headers.Add(key, item.Header[key]); + } + // 设置代理 + SetProxy(item); + if (item.ProtocolVersion != null) request.ProtocolVersion = item.ProtocolVersion; + request.ServicePoint.Expect100Continue = item.Expect100Continue; + //请求方式Get或者Post + request.Method = item.Method; + request.Timeout = item.Timeout; + request.KeepAlive = item.KeepAlive; + request.ReadWriteTimeout = item.ReadWriteTimeout; + if (!string.IsNullOrWhiteSpace(item.Host)) + { + request.Host = item.Host; + } + if (item.IfModifiedSince != null) request.IfModifiedSince = Convert.ToDateTime(item.IfModifiedSince); + //Accept + request.Accept = item.Accept; + //ContentType返回类型 + request.ContentType = item.ContentType; + //UserAgent客户端的访问类型,包括浏览器版本和操作系统信息 + request.UserAgent = item.UserAgent; + // 编码 + encoding = item.Encoding; + //设置安全凭证 + request.Credentials = item.ICredentials; + //设置Cookie + SetCookie(item); + //来源地址 + request.Referer = item.Referer; + //是否执行跳转功能 + request.AllowAutoRedirect = item.Allowautoredirect; + if (item.MaximumAutomaticRedirections > 0) + { + request.MaximumAutomaticRedirections = item.MaximumAutomaticRedirections; + } + //设置Post数据 + SetPostData(item); + //设置最大连接 + if (item.Connectionlimit > 0) request.ServicePoint.ConnectionLimit = item.Connectionlimit; + } + /// + /// 设置证书 + /// + /// + private void SetCer(HttpItem item) + { + if (!string.IsNullOrWhiteSpace(item.CerPath)) + { + //这一句一定要写在创建连接的前面。使用回调的方法进行证书验证。 + ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(CheckValidationResult); + //初始化对像,并设置请求的URL地址 + request = (HttpWebRequest)WebRequest.Create(item.URL); + SetCerList(item); + //将证书添加到请求里 + request.ClientCertificates.Add(new X509Certificate(item.CerPath)); + } + else + { + //初始化对像,并设置请求的URL地址 + request = (HttpWebRequest)WebRequest.Create(item.URL); + SetCerList(item); + } + } + /// + /// 设置多个证书 + /// + /// + private void SetCerList(HttpItem item) + { + if (item.ClentCertificates != null && item.ClentCertificates.Count > 0) + { + foreach (X509Certificate c in item.ClentCertificates) + { + request.ClientCertificates.Add(c); + } + } + } + /// + /// 设置Cookie + /// + /// Http参数 + private void SetCookie(HttpItem item) + { + if (!string.IsNullOrEmpty(item.Cookie)) request.Headers[HttpRequestHeader.Cookie] = item.Cookie; + //设置CookieCollection + if (item.ResultCookieType == ResultCookieType.CookieCollection) + { + request.CookieContainer = new CookieContainer(); + if (item.CookieCollection != null && item.CookieCollection.Count > 0) + request.CookieContainer.Add(item.CookieCollection); + } + } + /// + /// 设置Post数据 + /// + /// Http参数 + private void SetPostData(HttpItem item) + { + //验证在得到结果时是否有传入数据 + if (!request.Method.Trim().ToLower().Contains("get")) + { + if (item.PostEncoding != null) + { + postencoding = item.PostEncoding; + } + byte[] buffer = null; + //写入Byte类型 + if (item.PostDataType == PostDataType.Byte && item.PostdataByte != null && item.PostdataByte.Length > 0) + { + //验证在得到结果时是否有传入数据 + buffer = item.PostdataByte; + }//写入文件 + else if (item.PostDataType == PostDataType.FilePath && !string.IsNullOrWhiteSpace(item.Postdata)) + { + StreamReader r = new StreamReader(item.Postdata, postencoding); + buffer = postencoding.GetBytes(r.ReadToEnd()); + r.Close(); + } //写入字符串 + else if (!string.IsNullOrWhiteSpace(item.Postdata)) + { + buffer = postencoding.GetBytes(item.Postdata); + } + if (buffer != null) + { + request.ContentLength = buffer.Length; + request.GetRequestStream().Write(buffer, 0, buffer.Length); + } + else + { + request.ContentLength = 0; + } + } + } + /// + /// 设置代理 + /// + /// 参数对象 + private void SetProxy(HttpItem item) + { + bool isIeProxy = false; + if (!string.IsNullOrWhiteSpace(item.ProxyIp)) + { + isIeProxy = item.ProxyIp.ToLower().Contains("ieproxy"); + } + if (!string.IsNullOrWhiteSpace(item.ProxyIp) && !isIeProxy) + { + //设置代理服务器 + if (item.ProxyIp.Contains(":")) + { + string[] plist = item.ProxyIp.Split(':'); + WebProxy myProxy = new WebProxy(plist[0].Trim(), Convert.ToInt32(plist[1].Trim())); + //建议连接 + myProxy.Credentials = new NetworkCredential(item.ProxyUserName, item.ProxyPwd); + //给当前请求对象 + request.Proxy = myProxy; + } + else + { + WebProxy myProxy = new WebProxy(item.ProxyIp, false); + //建议连接 + myProxy.Credentials = new NetworkCredential(item.ProxyUserName, item.ProxyPwd); + //给当前请求对象 + request.Proxy = myProxy; + } + } + else if (isIeProxy) + { + //设置为IE代理 + } + else + { + request.Proxy = item.WebProxy; + } + } + + + #endregion + + #region private main + /// + /// 回调验证证书问题 + /// + /// 流对象 + /// 证书 + /// X509Chain + /// SslPolicyErrors + /// bool + private bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors) { return true; } + + /// + /// 通过设置这个属性,可以在发出连接的时候绑定客户端发出连接所使用的IP地址。 + /// + /// + /// + /// + /// + private IPEndPoint BindIPEndPointCallback(ServicePoint servicePoint, IPEndPoint remoteEndPoint, int retryCount) + { + return _IPEndPoint;//端口号 + } + #endregion + } + + #region public calss + /// + /// Http请求参考类 + /// + public class HttpItem + { + /// + /// 请求URL必须填写 + /// + public string URL { get; set; } + string _Method = "GET"; + /// + /// 请求方式默认为GET方式,当为POST方式时必须设置Postdata的值 + /// + public string Method + { + get { return _Method; } + set { _Method = value; } + } + int _Timeout = 100000; + /// + /// 默认请求超时时间 + /// + public int Timeout + { + get { return _Timeout; } + set { _Timeout = value; } + } + int _ReadWriteTimeout = 30000; + /// + /// 默认写入Post数据超时间 + /// + public int ReadWriteTimeout + { + get { return _ReadWriteTimeout; } + set { _ReadWriteTimeout = value; } + } + /// + /// 设置Host的标头信息 + /// + public string Host { get; set; } + Boolean _KeepAlive = true; + /// + /// 获取或设置一个值,该值指示是否与 Internet 资源建立持久性连接默认为true。 + /// + public Boolean KeepAlive + { + get { return _KeepAlive; } + set { _KeepAlive = value; } + } + string _Accept = "text/html, application/xhtml+xml, */*"; + /// + /// 请求标头值 默认为text/html, application/xhtml+xml, */* + /// + public string Accept + { + get { return _Accept; } + set { _Accept = value; } + } + string _ContentType = "text/html"; + /// + /// 请求返回类型默认 text/html + /// + public string ContentType + { + get { return _ContentType; } + set { _ContentType = value; } + } + string _UserAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)"; + /// + /// 客户端访问信息默认Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0) + /// + public string UserAgent + { + get { return _UserAgent; } + set { _UserAgent = value; } + } + /// + /// 返回数据编码默认为NUll,可以自动识别,一般为utf-8,gbk,gb2312 + /// + public Encoding Encoding { get; set; } + private PostDataType _PostDataType = PostDataType.String; + /// + /// Post的数据类型 + /// + public PostDataType PostDataType + { + get { return _PostDataType; } + set { _PostDataType = value; } + } + /// + /// Post请求时要发送的字符串Post数据 + /// + public string Postdata { get; set; } + /// + /// Post请求时要发送的Byte类型的Post数据 + /// + public byte[] PostdataByte { get; set; } + /// + /// Cookie对象集合 + /// + public CookieCollection CookieCollection { get; set; } + /// + /// 请求时的Cookie + /// + public string Cookie { get; set; } + /// + /// 来源地址,上次访问地址 + /// + public string Referer { get; set; } + /// + /// 证书绝对路径 + /// + public string CerPath { get; set; } + /// + /// 设置代理对象,不想使用IE默认配置就设置为Null,而且不要设置ProxyIp + /// + public WebProxy WebProxy { get; set; } + private Boolean isToLower = false; + /// + /// 是否设置为全文小写,默认为不转化 + /// + public Boolean IsToLower + { + get { return isToLower; } + set { isToLower = value; } + } + private Boolean allowautoredirect = false; + /// + /// 支持跳转页面,查询结果将是跳转后的页面,默认是不跳转 + /// + public Boolean Allowautoredirect + { + get { return allowautoredirect; } + set { allowautoredirect = value; } + } + private int connectionlimit = 1024; + /// + /// 最大连接数 + /// + public int Connectionlimit + { + get { return connectionlimit; } + set { connectionlimit = value; } + } + /// + /// 代理Proxy 服务器用户名 + /// + public string ProxyUserName { get; set; } + /// + /// 代理 服务器密码 + /// + public string ProxyPwd { get; set; } + /// + /// 代理 服务IP,如果要使用IE代理就设置为ieproxy + /// + public string ProxyIp { get; set; } + private ResultType resulttype = ResultType.String; + /// + /// 设置返回类型String和Byte + /// + public ResultType ResultType + { + get { return resulttype; } + set { resulttype = value; } + } + private WebHeaderCollection header = new WebHeaderCollection(); + /// + /// header对象 + /// + public WebHeaderCollection Header + { + get { return header; } + set { header = value; } + } + /// + // 获取或设置用于请求的 HTTP 版本。返回结果:用于请求的 HTTP 版本。默认为 System.Net.HttpVersion.Version11。 + /// + public Version ProtocolVersion { get; set; } + private Boolean _expect100continue = false; + /// + /// 获取或设置一个 System.Boolean 值,该值确定是否使用 100-Continue 行为。如果 POST 请求需要 100-Continue 响应,则为 true;否则为 false。默认值为 true。 + /// + public Boolean Expect100Continue + { + get { return _expect100continue; } + set { _expect100continue = value; } + } + /// + /// 设置509证书集合 + /// + public X509CertificateCollection ClentCertificates { get; set; } + /// + /// 设置或获取Post参数编码,默认的为Default编码 + /// + public Encoding PostEncoding { get; set; } + private ResultCookieType _ResultCookieType = ResultCookieType.String; + /// + /// Cookie返回类型,默认的是只返回字符串类型 + /// + public ResultCookieType ResultCookieType + { + get { return _ResultCookieType; } + set { _ResultCookieType = value; } + } + private ICredentials _ICredentials = CredentialCache.DefaultCredentials; + /// + /// 获取或设置请求的身份验证信息。 + /// + public ICredentials ICredentials + { + get { return _ICredentials; } + set { _ICredentials = value; } + } + /// + /// 设置请求将跟随的重定向的最大数目 + /// + public int MaximumAutomaticRedirections { get; set; } + private DateTime? _IfModifiedSince = null; + /// + /// 获取和设置IfModifiedSince,默认为当前日期和时间 + /// + public DateTime? IfModifiedSince + { + get { return _IfModifiedSince; } + set { _IfModifiedSince = value; } + } + #region ip-port + private IPEndPoint _IPEndPoint = null; + /// + /// 设置本地的出口ip和端口 + /// ] + /// + ///item.IPEndPoint = new IPEndPoint(IPAddress.Parse("192.168.1.1"),80); + /// + public IPEndPoint IPEndPoint + { + get { return _IPEndPoint; } + set { _IPEndPoint = value; } + } + #endregion + + private bool _isReset = false; + /// + /// 是否重置request,response的值,默认不重置,当设置为True时request,response将被设置为Null + /// + public bool IsReset + { + get { return _isReset; } + set { _isReset = value; } + } + } + /// + /// Http返回参数类 + /// + public class HttpResult + { + /// + /// Http请求返回的Cookie + /// + public string Cookie { get; set; } + /// + /// Cookie对象集合 + /// + public CookieCollection CookieCollection { get; set; } + private string _html = string.Empty; + /// + /// 返回的String类型数据 只有ResultType.String时才返回数据,其它情况为空 + /// + public string Html + { + get { return _html; } + set { _html = value; } + } + /// + /// 返回的Byte数组 只有ResultType.Byte时才返回数据,其它情况为空 + /// + public byte[] ResultByte { get; set; } + /// + /// header对象 + /// + public WebHeaderCollection Header { get; set; } + /// + /// 返回状态说明 + /// + public string StatusDescription { get; set; } + /// + /// 返回状态码,默认为OK + /// + public HttpStatusCode StatusCode { get; set; } + /// + /// 最后访问的URl + /// + public string ResponseUri { get; set; } + /// + /// 获取重定向的URl + /// + public string RedirectUrl + { + get + { + try + { + if (Header != null && Header.Count > 0) + { + if (Header.AllKeys.Any(k => k.ToLower().Contains("location"))) + { + string baseurl = Header["location"].ToString().Trim(); + string locationurl = baseurl.ToLower(); + if (!string.IsNullOrWhiteSpace(locationurl)) + { + bool b = locationurl.StartsWith("http://") || locationurl.StartsWith("https://"); + if (!b) + { + baseurl = new Uri(new Uri(ResponseUri), baseurl).AbsoluteUri; + } + } + return baseurl; + } + } + } + catch { } + return string.Empty; + } + } + } + /// + /// 返回类型 + /// + public enum ResultType + { + /// + /// 表示只返回字符串 只有Html有数据 + /// + String, + /// + /// 表示返回字符串和字节流 ResultByte和Html都有数据返回 + /// + Byte + } + /// + /// Post的数据格式默认为string + /// + public enum PostDataType + { + /// + /// 字符串类型,这时编码Encoding可不设置 + /// + String, + /// + /// Byte类型,需要设置PostdataByte参数的值编码Encoding可设置为空 + /// + Byte, + /// + /// 传文件,Postdata必须设置为文件的绝对路径,必须设置Encoding的值 + /// + FilePath + } + /// + /// Cookie返回类型 + /// + public enum ResultCookieType + { + /// + /// 只返回字符串类型的Cookie + /// + String, + /// + /// CookieCollection格式的Cookie集合同时也返回String类型的cookie + /// + CookieCollection + } + #endregion +} \ No newline at end of file diff --git a/ARW.Common/ExcelHelper.cs b/ARW.Common/ExcelHelper.cs new file mode 100644 index 0000000..e245f69 --- /dev/null +++ b/ARW.Common/ExcelHelper.cs @@ -0,0 +1,162 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using OfficeOpenXml; +namespace ARW.Common +{ + public class ExcelHelper where T : new() + { + /// + /// 导入数据 + /// + /// + /// + public static IEnumerable ImportData(Stream stream) + { + using ExcelPackage package = new(stream); + ExcelPackage.LicenseContext = LicenseContext.NonCommercial; + ExcelWorksheet worksheet = package.Workbook.Worksheets[0];//读取第1个sheet + //获取表格的列数和行数 + + int colStart = worksheet.Dimension.Start.Column; + int colEnd = worksheet.Dimension.End.Column; + int rowStart = worksheet.Dimension.Start.Row; + int rowEnd = worksheet.Dimension.End.Row; + //int rowCount = worksheet.Dimension.Rows; + //int ColCount = worksheet.Dimension.Columns; + + List resultList = new(); + List propertyInfos = new();// new(typeof(T).GetProperties()); + Dictionary dictHeader = new(); + for (int i = colStart; i <= colEnd; i++) + { + var name = worksheet.Cells[rowStart, i].Value.ToString(); + dictHeader[name] = i; + + PropertyInfo propertyInfo = MapPropertyInfo(name); + if (propertyInfo != null) + { + propertyInfos.Add(propertyInfo); + } + } + for (int row = rowStart + 1; row <= rowEnd; row++) + { + T result = new(); + + foreach (PropertyInfo p in propertyInfos) + { + try + { + foreach (var i in p.CustomAttributes) + { + foreach (var i2 in i.NamedArguments) + { + ExcelRange cell = worksheet.Cells[row, dictHeader[i2.TypedValue.Value.ToString()]]; + if (cell.Value == null) + { + continue; + } + switch (p.PropertyType.Name.ToLower()) + { + case "string": + p.SetValue(result, cell.GetValue()); + break; + case "int16": + p.SetValue(result, cell.GetValue()); break; + case "int32": + p.SetValue(result, cell.GetValue()); break; + case "int64": + p.SetValue(result, cell.GetValue()); break; + case "decimal": + p.SetValue(result, cell.GetValue()); + break; + case "double": + p.SetValue(result, cell.GetValue()); break; + case "datetime": + p.SetValue(result, cell.GetValue()); break; + case "boolean": + p.SetValue(result, cell.GetValue()); break; + case "char": + p.SetValue(result, cell.GetValue()); break; + default: + break; + } + } + } + } + catch (KeyNotFoundException ex) + { + Console.WriteLine("未找到该列将继续循环," + ex.Message); + continue; + } + } + resultList.Add(result); + } + + return resultList; + } + + /// + /// 查找Excel列名对应的实体属性 + /// + /// + /// + public static PropertyInfo MapPropertyInfo(string columnName) + { + PropertyInfo[] propertyList = GetProperties(typeof(T)); + //PropertyInfo propertyInfo = propertyList.Where(p => p.Name == columnName).FirstOrDefault(); + + foreach (var item in propertyList) + { + foreach (var i in item.CustomAttributes) + { + if (i.AttributeType.Name == "EpplusTableColumnAttribute") + { + foreach (var i2 in i.NamedArguments) + { + if (columnName == i2.TypedValue.Value.ToString()) + { + return item; + } + } + } + } + } + + return null; + } + + /// + /// 得到类里面的属性集合 + /// + /// + /// + /// + public static PropertyInfo[] GetProperties(Type type, string[] columns = null) + { + PropertyInfo[] properties = null; + properties = type.GetProperties(); + + if (columns != null && columns.Length > 0) + { + // 按columns顺序返回属性 + var columnPropertyList = new List(); + foreach (var column in columns) + { + var columnProperty = properties.Where(p => p.Name == column).FirstOrDefault(); + if (columnProperty != null) + { + columnPropertyList.Add(columnProperty); + } + } + return columnPropertyList.ToArray(); + } + else + { + return properties; + } + } + } +} diff --git a/ARW.Common/MailHelper.cs b/ARW.Common/MailHelper.cs new file mode 100644 index 0000000..4b69f51 --- /dev/null +++ b/ARW.Common/MailHelper.cs @@ -0,0 +1,174 @@ +using Infrastructure; +using MailKit.Net.Smtp; +using MimeKit; +using MimeKit.Text; +using System; +using System.Collections.Generic; +using System.IO; + +namespace ARW.Common +{ + public class MailHelper + { + /// + /// 发送人邮箱 + /// + public string FromEmail { get; set; } = ""; + /// + /// 发送人密码 + /// + public string FromPwd { get; set; } = ""; + /// + /// 发送协议 + /// + public string Smtp { get; set; } = "smtp.qq.com"; + /// + /// 协议端口 + /// + public int Port { get; set; } = 587; + /// + /// 邮件签名 + /// + public string Signature { get; set; } + /// + /// 是否使用SSL协议 + /// + public bool UseSsl { get; set; } = false; + private readonly MailOptions mailOptions = new(); + + public MailHelper() + { + AppSettings.Bind("MailOptions", mailOptions); + FromEmail = mailOptions.From; + Smtp = mailOptions.Smtp; + FromPwd = mailOptions.Password; + Port = mailOptions.Port; + } + public MailHelper(string fromEmail, string smtp, int port, string fromPwd) + { + FromEmail = fromEmail; + Smtp = smtp; + FromPwd = fromPwd; + Port = port; + } + + public MailHelper(string fromEmail, string fromPwd) + { + FromEmail = fromEmail; + FromPwd = fromPwd; + } + + /// + /// 发送一个 + /// + /// + /// + /// + /// + public void SendMail(string toAddress, string subject, string text, string path = "", string html = "") + { + IEnumerable mailboxes = new List() { + new MailboxAddress(toAddress, toAddress) + }; + + SendMail(mailboxes, subject, text, path, html); + } + + /// + /// 发送多个邮箱 + /// + /// + /// + /// + /// + public void SendMail(string[] toAddress, string subject, string text, string path = "", string html = "") + { + IList mailboxes = new List() { }; + foreach (var item in toAddress) + { + mailboxes.Add(new MailboxAddress(item, item)); + } + + SendMail(mailboxes, subject, text, path, html); + } + + /// + /// 发送邮件 + /// + /// + /// 主题 + /// + /// 附件url地址 + /// 网页HTML内容 + private void SendMail(IEnumerable toAddress, string subject, string text, string path = "", string html = "") + { + MimeMessage message = new MimeMessage(); + //发件人 + message.From.Add(new MailboxAddress(FromEmail, FromEmail)); + //收件人 + message.To.AddRange(toAddress); + message.Subject = subject; + message.Date = DateTime.Now; + + //创建附件Multipart + Multipart multipart = new Multipart("mixed"); + var alternative = new MultipartAlternative(); + //html内容 + if (!string.IsNullOrEmpty(html)) + { + var Html = new TextPart(TextFormat.Html) + { + Text = html + }; + alternative.Add(Html); + } + //文本内容 + //if (!string.IsNullOrEmpty(text)) + //{ + var plain = new TextPart(TextFormat.Plain) + { + Text = text + "\r\n\n\n" + mailOptions.Signature + }; + alternative.Add(plain); + //} + + //附件 + if (!string.IsNullOrEmpty(path)) + { + string[] files = path.Split(","); + foreach (var file in files) + { + MimePart attachment = new() + { + Content = new MimeContent(File.OpenRead(file), ContentEncoding.Default), + //读取文件,只能用绝对路径 + ContentDisposition = new ContentDisposition(ContentDisposition.Attachment), + ContentTransferEncoding = ContentEncoding.Base64, + //文件名字 + FileName = Path.GetFileName(path) + }; + alternative.Add(attachment); + } + } + multipart.Add(alternative); + //赋值邮件内容 + message.Body = multipart; + + //开始发送 + using var client = new SmtpClient(); + client.ServerCertificateValidationCallback = (s, c, h, e) => true; + + //Smtp服务器 + //client.Connect("smtp.qq.com", 587, false); + client.Connect(Smtp, Port, true); + //登录,发送 + //特别说明,对于服务器端的中文相应,Exception中有编码问题,显示乱码了 + client.Authenticate(FromEmail, FromPwd); + + client.Send(message); + //断开 + client.Disconnect(true); + Console.WriteLine($"发送邮件成功{DateTime.Now}"); + } + } +} \ No newline at end of file diff --git a/ARW.Common/Tools.cs b/ARW.Common/Tools.cs new file mode 100644 index 0000000..947ac4a --- /dev/null +++ b/ARW.Common/Tools.cs @@ -0,0 +1,191 @@ +using Newtonsoft.Json.Linq; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using System.Linq; + +namespace ARW.Common +{ + public class Tools + { + /// + /// 要分割的字符串 eg: 1,3,10,00 + /// + /// + /// 分割的字符串 + /// + public static long[] SpitLongArrary(string str, char split = ',') + { + if (string.IsNullOrEmpty(str)) { return Array.Empty(); } + str = str.TrimStart(split).TrimEnd(split); + string[] strIds = str.Split(split, (char)StringSplitOptions.RemoveEmptyEntries); + long[] infoIdss = Array.ConvertAll(strIds, s => long.Parse(s)); + return infoIdss; + } + + public static int[] SpitIntArrary(string str, char split = ',') + { + if (string.IsNullOrEmpty(str)) { return Array.Empty(); } + string[] strIds = str.Split(split, (char)StringSplitOptions.RemoveEmptyEntries); + int[] infoIdss = Array.ConvertAll(strIds, s => int.Parse(s)); + return infoIdss; + } + + public static string[] SpitStringArrary(string str, char split = ',') + { + if (string.IsNullOrEmpty(str)) { return Array.Empty(); } + string[] strIds = str.Split(split, (char)StringSplitOptions.RemoveEmptyEntries); + return strIds; + } + + /// + /// 根据日期获取星期几 + /// + public static string GetWeekByDate(DateTime dt) + { + var day = new[] { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" }; + return day[Convert.ToInt32(dt.DayOfWeek.ToString("d"))]; + } + + /// + /// 得到这个月的第几周 + /// + /// 年月日 + /// 传递过来的时间是第几周 + public static int GetWeekNumInMonth(DateTime daytime) + { + int dayInMonth = daytime.Day; + //本月第一天 + DateTime firstDay = daytime.AddDays(1 - daytime.Day); + //本月第一天是周几 + int weekday = (int)firstDay.DayOfWeek == 0 ? 7 : (int)firstDay.DayOfWeek; + //本月第一周有几天 + int firstWeekEndDay = 7 - (weekday - 1); + //当前日期和第一周之差 + int diffday = dayInMonth - firstWeekEndDay; + diffday = diffday > 0 ? diffday : 1; + //当前是第几周,如果整除7就减一天 + int weekNumInMonth = ((diffday % 7) == 0 + ? (diffday / 7 - 1) + : (diffday / 7)) + 1 + (dayInMonth > firstWeekEndDay ? 1 : 0); + return weekNumInMonth; + } + /// + /// 判断一个字符串是否为url + /// + /// + /// + public static bool IsUrl(string str) + { + try + { + string Url = @"^http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?$"; + return Regex.IsMatch(str, Url); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + return false; + } + } + + /// + /// 计算密码强度 + /// + /// 密码字符串 + /// + public static bool PasswordStrength(string password) + { + //空字符串强度值为0 + if (string.IsNullOrEmpty(password)) return false; + + //字符统计 + int iNum = 0, iLtt = 0, iSym = 0; + foreach (char c in password) + { + if (c >= '0' && c <= '9') iNum++; + else if (c >= 'a' && c <= 'z') iLtt++; + else if (c >= 'A' && c <= 'Z') iLtt++; + else iSym++; + } + + if (iLtt == 0 && iSym == 0) return false; //纯数字密码 + if (iNum == 0 && iLtt == 0) return false; //纯符号密码 + if (iNum == 0 && iSym == 0) return false; //纯字母密码 + + if (password.Length >= 6 && password.Length < 16) return true;//长度不大于6的密码 + + if (iLtt == 0) return true; //数字和符号构成的密码 + if (iSym == 0) return true; //数字和字母构成的密码 + if (iNum == 0) return true; //字母和符号构成的密码 + + return true; //由数字、字母、符号构成的密码 + } + + + public static string GetNumCode(int lenght) + { + Random random = new Random(); + StringBuilder stringBuilder = new StringBuilder(); + for (int i = 0; i < lenght; i++) + { + stringBuilder.Append(random.Next(1, 10)); + } + return stringBuilder.ToString(); + } + + // 通过地址获取经纬度 + public static (double? lng, double? lat, string country, string province, string city, string area, string addr) GetXY(string address, System.Net.Http.HttpClient client) + { + string gdkey = "ec7484f53ba7b557eac7efc6687e5c0d";//高德key + string bdkey = "bnPWCosxo6QwUC7DsfkGiunf4zBZ3ogy";//百度key + //高德API会把地址拆分成省市区和坐标返回,百度只返回坐标 + string url = String.Format("https://restapi.amap.com/v3/geocode/geo?address={0}&output=json&key={1}", address, gdkey); + //结果 + string result = client.GetStringAsync(url).Result; + var locationResult = (JObject)JsonConvert.DeserializeObject(result); + if (locationResult["status"].ToString() == "1" && locationResult["geocodes"].Count() > 0) + { + var coordinate = locationResult["geocodes"][0]["location"].ToString().Split(","); + var country = locationResult["geocodes"][0]["country"].ToString().Replace("[]", ""); + var province = locationResult["geocodes"][0]["province"].ToString().Replace("[]", ""); + var city = locationResult["geocodes"][0]["city"].ToString().Replace("[]", ""); + var district = locationResult["geocodes"][0]["district"].ToString().Replace("[]", ""); + var street = locationResult["geocodes"][0]["street"].ToString().Replace("[]", ""); + var number = locationResult["geocodes"][0]["number"].ToString().Replace("[]", ""); + double? lng = null, lat = null; + if (coordinate.Length == 2) + { + string lngStr = coordinate[0]; + string latStr = coordinate[1]; + lng = double.Parse(lngStr); + lat = double.Parse(latStr); + + } + return (lng, lat, country, province, city, district, street + number); + } + else + { + //百度API + url = String.Format("http://api.map.baidu.com/geocoding/v3/?address={0}&output=json&ak={1}", address, bdkey); + result = client.GetStringAsync(url).Result; + locationResult = (JObject)JsonConvert.DeserializeObject(result); + if (locationResult["status"].ToString() == "0") + { + string lngStr = locationResult["result"]["location"]["lng"].ToString(); + string latStr = locationResult["result"]["location"]["lat"].ToString(); + double lng = double.Parse(lngStr); + double lat = double.Parse(latStr); + return (lng, lat, "", "", "", "", ""); + } + else + { + return (null, null, "", "", "", "", ""); + } + } + } + + } +} diff --git a/ARW.Model/ARW.Model.csproj b/ARW.Model/ARW.Model.csproj new file mode 100644 index 0000000..ddbc471 --- /dev/null +++ b/ARW.Model/ARW.Model.csproj @@ -0,0 +1,31 @@ + + + + net6.0 + ARW.Model + ARW.Model + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ARW.Model/Dto/Business/Customers/CustomerDto.cs b/ARW.Model/Dto/Business/Customers/CustomerDto.cs new file mode 100644 index 0000000..0fb54dd --- /dev/null +++ b/ARW.Model/Dto/Business/Customers/CustomerDto.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using ARW.Model.Models.Business.Customers; + +namespace ARW.Model.Dto.Business.Customers +{ + /// + /// 小程序客户输入对象 + /// + public class CustomerDto + { + public int CustomerId { get; set; } + public long CustomerGuid { get; set; } + public string CustomerName { get; set; } + public string CustomerBirth { get; set; } + public string CustomerImg { get; set; } + public int? CustomerSex { get; set; } + public string CustomerPhone { get; set; } + public string CustomerXcxOpenid { get; set; } + public string CustomerXcxName { get; set; } + public string CustomerXcxImg { get; set; } + } + + + /// + /// 小程序客户查询对象 + /// + public class CustomerQueryDto : PagerInfo + { + public string CustomerName { get; set; } + public string CustomerXcxName { get; set; } + } +} diff --git a/ARW.Model/Dto/Business/Payments/PaymentDto.cs b/ARW.Model/Dto/Business/Payments/PaymentDto.cs new file mode 100644 index 0000000..e3f983a --- /dev/null +++ b/ARW.Model/Dto/Business/Payments/PaymentDto.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using ARW.Model.Models.Business.Payments; + +namespace ARW.Model.Dto.Business.Payments +{ + /// + /// 支付订单输入对象 + /// + public class PaymentDto + { + public int PaymentId { get; set; } + public long PaymentGuid { get; set; } + public string PaymentOvertimeNumber { get; set; } + [Required(ErrorMessage = "操作状态(1待支付 |2已支付 | 3已取消 | 4已退款)不能为空")] + public int PaymentStatus { get; set; } + public decimal PaymentMoney { get; set; } + public decimal PaymentBeforeMoney { get; set; } + public string PaymentRefundNumber { get; set; } + public string PaymentWeixinNumber { get; set; } + [Required(ErrorMessage = "系统订单号不能为空")] + public string PaymentNumber { get; set; } + [Required(ErrorMessage = "操作客户guid(外键)不能为空")] + public string CustomerGuid { get; set; } + public long? PaymentBusinessGuid { get; set; } + [Required(ErrorMessage = "购买类型(1| )不能为空")] + public int PaymentBuytype { get; set; } + } + + + /// + /// 支付订单查询对象 + /// + public class PaymentQueryDto : PagerInfo + { + public int? PaymentStatus { get; set; } + } +} diff --git a/ARW.Model/Dto/Business/SubscribeTasks/SubscribeTaskDto.cs b/ARW.Model/Dto/Business/SubscribeTasks/SubscribeTaskDto.cs new file mode 100644 index 0000000..a9b13b4 --- /dev/null +++ b/ARW.Model/Dto/Business/SubscribeTasks/SubscribeTaskDto.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using ARW.Model.Models.Business.SubscribeTasks; + +namespace ARW.Model.Dto.Business.SubscribeTasks +{ + /// + /// 订阅推送任务输入对象 + /// + public class SubscribeTaskDto + { + public int SubscribeTaskId { get; set; } + public long SubscribeTaskGuid { get; set; } + public long? CustomerGuid { get; set; } + public long? SubscribeTaskBusinessGuid { get; set; } + public int? SubscribeTaskType { get; set; } + public string TemplateId { get; set; } + public int? SubscribeTaskStatus { get; set; } + public string SubscribeTaskErrorMsg { get; set; } + } + + + /// + /// 订阅推送任务查询对象 + /// + public class SubscribeTaskQueryDto : PagerInfo + { + } +} diff --git a/ARW.Model/Models/Business/BusinessBase.cs b/ARW.Model/Models/Business/BusinessBase.cs new file mode 100644 index 0000000..6943b7c --- /dev/null +++ b/ARW.Model/Models/Business/BusinessBase.cs @@ -0,0 +1,52 @@ +using System; +using Newtonsoft.Json; +using SqlSugar; +using OfficeOpenXml.Attributes; + +namespace ARW.Model.Models.Business +{ + + [EpplusTable(PrintHeaders = true, AutofitColumns = true, AutoCalculate = true, ShowTotal = true)] + public class BusinessBase + { + [SugarColumn(IsOnlyIgnoreUpdate = true, IsNullable = true, ColumnName = "create_by", ColumnDescription = "创建者")]//设置后修改不会有此字段 + [JsonProperty(propertyName: "CreateBy")] + [EpplusIgnore] + public string Create_by { get; set; } + + [SugarColumn(IsOnlyIgnoreUpdate = true, IsNullable = true, ColumnName = "create_time", ColumnDescription = "创建时间")]//设置后修改不会有此字段 + [JsonProperty(propertyName: "CreateTime")] + [EpplusTableColumn(NumberFormat = "yyyy-MM-dd HH:mm:ss")] + public DateTime Create_time { get; set; } = DateTime.Now; + + [JsonIgnore] + [JsonProperty(propertyName: "UpdateBy")] + [SugarColumn(IsOnlyIgnoreInsert = true, IsNullable = true, ColumnName = "update_by", ColumnDescription = "更新者")] + [EpplusIgnore] + public string Update_by { get; set; } + + //[JsonIgnore] + [SugarColumn(IsOnlyIgnoreInsert = true, IsNullable = true, ColumnName = "update_time", ColumnDescription = "更新时间")]//设置后插入数据不会有此字段 + [JsonProperty(propertyName: "UpdateTime")] + [EpplusIgnore] + public DateTime? Update_time { get; set; } + + [SugarColumn(IsIgnore = true)] + [JsonIgnore] + [EpplusIgnore] + public DateTime? BeginTime { get; set; } + + /// + /// 用于搜索使用 + /// + [SugarColumn(IsIgnore = true)] + [JsonIgnore] + [EpplusIgnore] + public DateTime? EndTime { get; set; } + + [JsonProperty(propertyName: "IsDelete")] + [SugarColumn(IsNullable = true, ColumnDescription = "是否删除")] + [EpplusIgnore] + public bool IsDelete { get; set; } + } +} diff --git a/ARW.Model/Models/Business/Crawler/Crawl.cs b/ARW.Model/Models/Business/Crawler/Crawl.cs new file mode 100644 index 0000000..5cc5fda --- /dev/null +++ b/ARW.Model/Models/Business/Crawler/Crawl.cs @@ -0,0 +1,66 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OfficeOpenXml.Attributes; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ARW.Model.Models.Business.Crawler +{ + [SugarTable("crawl")] + public class Crawl: BusinessBase + { + [SugarColumn(IsPrimaryKey = true,IsIdentity =true)] + public int Id { get; set; } + + [SugarColumn(ColumnDescription = "名称", IsNullable = true)] + public string Name { get; set; } + + [SugarColumn(ColumnDescription = "简介", IsNullable = true)] + public string Intro { get; set; } + + [SugarColumn(ColumnDescription = "图片", IsNullable = true)] + public string Cover { get; set; } + + [SugarColumn(ColumnDescription = "链接", IsNullable = true)] + public string Link { get; set; } + + [SugarColumn(ColumnDescription = "类型", IsNullable = true)] + public string Type { get; set; } + + [SugarColumn(ColumnDescription = "上传时间", IsNullable = true)] + public DateTime PublishTime { get; set; } + + [JsonIgnore] + [SugarColumn(IsIgnore = true)] + public List DownResources { get; set; } + + [SugarColumn(ColumnDescription = "下载资源", IsNullable = true)] + public string Resources + { + get + { + if (this.DownResources != null) + { + return JToken.FromObject(this.DownResources).ToString(); + } + else + { + return "[]"; + } + + } + } + } + + public class Resource + { + public string Description { get; set; } + + public string Link { get; set; } + } + +} diff --git a/ARW.Model/Models/Business/Customers/Customer.cs b/ARW.Model/Models/Business/Customers/Customer.cs new file mode 100644 index 0000000..5b23b64 --- /dev/null +++ b/ARW.Model/Models/Business/Customers/Customer.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using SqlSugar; +using OfficeOpenXml.Attributes; +using Newtonsoft.Json; + +namespace ARW.Model.Models.Business.Customers +{ + /// + /// 小程序客户,数据实体对象 + /// + /// @author admin + /// @date 2022-12-06 + /// + [SugarTable("tb_customer")] + public class Customer : BusinessBase + { + + /// + /// 描述 : + /// 空值 : false + /// + [EpplusTableColumn(Header = "CustomerId")] + [SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnName = "customer_id")] + public int CustomerId { get; set; } + + /// + /// 描述 : + /// 空值 : false + /// + [EpplusTableColumn(Header = "CustomerGuid")] + [JsonConverter(typeof(ValueToStringConverter))] + [SugarColumn(IsPrimaryKey = true, IsIdentity = false, ColumnName = "customer_guid")] + public long CustomerGuid { get; set; } + + /// + /// 描述 :客户姓名 + /// 空值 : true + /// + [EpplusTableColumn(Header = "客户姓名")] + [SugarColumn(ColumnName = "customer_name")] + public string CustomerName { get; set; } + + /// + /// 描述 :客户生日 + /// 空值 : true + /// + [EpplusTableColumn(Header = "客户生日")] + [SugarColumn(ColumnName = "customer_birth")] + public string CustomerBirth { get; set; } + + /// + /// 描述 :客户头像 (人脸识别) + /// 空值 : true + /// + [EpplusTableColumn(Header = "客户头像 (人脸识别)")] + [SugarColumn(ColumnName = "customer_img")] + public string CustomerImg { get; set; } + + /// + /// 描述 :客户性别 1: 男 2: 女 + /// 空值 : true + /// + [EpplusTableColumn(Header = "客户性别 1: 男 2: 女")] + [SugarColumn(ColumnName = "customer_sex")] + public int? CustomerSex { get; set; } + + /// + /// 描述 :客户电话 + /// 空值 : true + /// + [EpplusTableColumn(Header = "客户电话")] + [SugarColumn(ColumnName = "customer_phone")] + public string CustomerPhone { get; set; } + + /// + /// 描述 :小程序openid + /// 空值 : true + /// + [EpplusTableColumn(Header = "小程序openid")] + [SugarColumn(ColumnName = "customer_xcx_openid")] + public string CustomerXcxOpenid { get; set; } + + /// + /// 描述 :小程序名称 + /// 空值 : true + /// + [EpplusTableColumn(Header = "小程序名称")] + [SugarColumn(ColumnName = "customer_xcx_name")] + public string CustomerXcxName { get; set; } + + /// + /// 描述 :小程序头像 + /// 空值 : true + /// + [EpplusTableColumn(Header = "小程序头像")] + [SugarColumn(ColumnName = "customer_xcx_img")] + public string CustomerXcxImg { get; set; } + } +} \ No newline at end of file diff --git a/ARW.Model/Models/Business/Payments/Payment.cs b/ARW.Model/Models/Business/Payments/Payment.cs new file mode 100644 index 0000000..af8ff0c --- /dev/null +++ b/ARW.Model/Models/Business/Payments/Payment.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using SqlSugar; +using OfficeOpenXml.Attributes; +using Newtonsoft.Json; + +namespace ARW.Model.Models.Business.Payments +{ + /// + /// 支付订单,数据实体对象 + /// + /// @author admin + /// @date 2022-12-15 + /// + [SugarTable("tb_payment")] + public class Payment : BusinessBase + { + + /// + /// 描述 : + /// 空值 : false + /// + [EpplusTableColumn(Header = "PaymentId")] + [SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnName = "payment_id")] + public int PaymentId { get; set; } + + /// + /// 描述 :支付订单guid + /// 空值 : false + /// + [EpplusTableColumn(Header = "支付订单guid")] + [JsonConverter(typeof(ValueToStringConverter))] + [SugarColumn(IsPrimaryKey = true, IsIdentity = false, ColumnName = "payment_guid")] + public long PaymentGuid { get; set; } + + /// + /// 描述 :超时付款订单号 + /// 空值 : true + /// + [EpplusTableColumn(Header = "超时付款订单号")] + [SugarColumn(ColumnName = "payment_overtime_number")] + public string PaymentOvertimeNumber { get; set; } + + /// + /// 描述 :操作状态(1待支付 |2已支付 | 3已取消 | 4已退款) + /// 空值 : false + /// + [EpplusTableColumn(Header = "操作状态(1待支付 |2已支付 | 3已取消 | 4已退款)")] + [SugarColumn(ColumnName = "payment_status")] + public int PaymentStatus { get; set; } + + /// + /// 描述 :核销后价格/操作金额 + /// 空值 : true + /// + [EpplusTableColumn(Header = "核销后价格/操作金额")] + [SugarColumn(ColumnName = "payment_money")] + public decimal PaymentMoney { get; set; } + + /// + /// 描述 :核销前价格 + /// 空值 : true + /// + [EpplusTableColumn(Header = "核销前价格")] + [SugarColumn(ColumnName = "payment_before_money")] + public decimal PaymentBeforeMoney { get; set; } + + /// + /// 描述 :退款订单号 + /// 空值 : true + /// + [EpplusTableColumn(Header = "退款订单号")] + [SugarColumn(ColumnName = "payment_refund_number")] + public string PaymentRefundNumber { get; set; } + + /// + /// 描述 :微信支付订单号 + /// 空值 : true + /// + [EpplusTableColumn(Header = "微信支付订单号")] + [SugarColumn(ColumnName = "payment_weixin_number")] + public string PaymentWeixinNumber { get; set; } + + /// + /// 描述 :系统订单号 + /// 空值 : false + /// + [EpplusTableColumn(Header = "系统订单号")] + [SugarColumn(ColumnName = "payment_number")] + public string PaymentNumber { get; set; } + + /// + /// 描述 :操作客户guid(外键) + /// 空值 : false + /// + [EpplusTableColumn(Header = "操作客户guid(外键)")] + [JsonConverter(typeof(ValueToStringConverter))] + [SugarColumn(ColumnName = "customer_guid")] + public long? CustomerGuid { get; set; } + + /// + /// 描述 :业务订单guid(外键) + /// 空值 : true + /// + [EpplusTableColumn(Header = "业务订单guid(外键)")] + [JsonConverter(typeof(ValueToStringConverter))] + [SugarColumn(ColumnName = "payment_business_guid")] + public long? PaymentBusinessGuid { get; set; } + + /// + /// 描述 :购买类型(1| ) + /// 空值 : false + /// + [EpplusTableColumn(Header = "购买类型(1| )")] + [SugarColumn(ColumnName = "payment_buytype")] + public int PaymentBuytype { get; set; } + } +} \ No newline at end of file diff --git a/ARW.Model/Models/Business/SubscribeTasks/SubscribeTask.cs b/ARW.Model/Models/Business/SubscribeTasks/SubscribeTask.cs new file mode 100644 index 0000000..a5ac25a --- /dev/null +++ b/ARW.Model/Models/Business/SubscribeTasks/SubscribeTask.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using SqlSugar; +using OfficeOpenXml.Attributes; +using Newtonsoft.Json; + +namespace ARW.Model.Models.Business.SubscribeTasks +{ + /// + /// 订阅推送任务,数据实体对象 + /// + /// @author admin + /// @date 2022-12-21 + /// + [SugarTable("tb_subscribe_task")] + public class SubscribeTask : BusinessBase + { + + /// + /// 描述 :推送任务id + /// 空值 : false + /// + [SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnName = "subscribe_task_id")] + public int SubscribeTaskId { get; set; } + + /// + /// 描述 :推送任务guid + /// 空值 : false + /// + [JsonConverter(typeof(ValueToStringConverter))] + [SugarColumn(IsPrimaryKey = true, IsIdentity = false, ColumnName = "subscribe_task_guid")] + public long SubscribeTaskGuid { get; set; } + + /// + /// 描述 :订阅客户guid(外键) + /// 空值 : true + /// + [JsonConverter(typeof(ValueToStringConverter))] + [SugarColumn(ColumnName = "customer_guid")] + public long? CustomerGuid { get; set; } + + /// + /// 描述 :订阅业务guid(外键) + /// 空值 : true + /// + [JsonConverter(typeof(ValueToStringConverter))] + [SugarColumn(ColumnName = "subscribe_task_business_guid")] + public long? SubscribeTaskBusinessGuid { get; set; } + + /// + /// 描述 :订阅类型( 1 | 预约门店健身提醒 ) + /// 空值 : true + /// + [SugarColumn(ColumnName = "subscribe_task_type")] + public int? SubscribeTaskType { get; set; } + + /// + /// 描述 :订阅推送模板ID + /// 空值 : true + /// + [SugarColumn(ColumnName = "template_id")] + public string TemplateId { get; set; } + + /// + /// 描述 :推送状态 (0 未推送 | 1 已推送 | 2 推送失败 ) + /// 空值 : true + /// + [SugarColumn(ColumnName = "subscribe_task_status")] + public int? SubscribeTaskStatus { get; set; } + + /// + /// 描述 :推送失败原因 + /// 空值 : true + /// + [SugarColumn(ColumnName = "subscribe_task_error_msg")] + public string SubscribeTaskErrorMsg { get; set; } + } +} \ No newline at end of file diff --git a/ARW.Model/PagedInfo.cs b/ARW.Model/PagedInfo.cs new file mode 100644 index 0000000..d696216 --- /dev/null +++ b/ARW.Model/PagedInfo.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ARW.Model +{ + /// + /// 分页参数 + /// + public class PagedInfo + { + /// + /// 每页行数 + /// + public int PageSize { get; set; } = 10; + /// + /// 当前页 + /// + public int PageIndex { get; set; } = 1; + /// + /// 总记录数 + /// + public int TotalNum { get; set; } + /// + /// 总页数 + /// + public int TotalPage + { + get + { + if (TotalNum > 0) + { + return TotalNum % this.PageSize == 0 ? TotalNum / this.PageSize : TotalNum / this.PageSize + 1; + } + else + { + return 0; + } + } + set { } + } + public List Result { get; set; } + public Dictionary Extra { get; set; } = new Dictionary(); + public PagedInfo() + { + } + } +} diff --git a/ARW.Model/PagerInfo.cs b/ARW.Model/PagerInfo.cs new file mode 100644 index 0000000..b185410 --- /dev/null +++ b/ARW.Model/PagerInfo.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ARW.Model +{ + public class PagerInfo + { + /// + /// 当前页码 + /// + public int PageNum { get; set; } + public int PageSize { get; set; } + /// + /// 总记录数 + /// + public int TotalNum { get; set; } + /// + /// 总页码 + /// + /// + /// 总页数 + /// + public int TotalPage + { + get + { + return TotalNum > 0 ? TotalNum % PageSize == 0 ? TotalNum / PageSize : TotalNum / PageSize + 1 : 0; + } + } + + /// + /// 排序字段 + /// + public string Sort { get; set; } = string.Empty; + /// + /// 排序类型,前端传入的是"ascending","descending" + /// + public string SortType { get; set; } = string.Empty; + public PagerInfo() + { + PageNum = 1; + PageSize = 10; + } + + public PagerInfo(int page = 1, int pageSize = 20) + { + PageNum = page; + PageSize = pageSize; + } + } +} diff --git a/ARW.Model/System/CommonLang.cs b/ARW.Model/System/CommonLang.cs new file mode 100644 index 0000000..d5fd9c7 --- /dev/null +++ b/ARW.Model/System/CommonLang.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using SqlSugar; +using OfficeOpenXml.Attributes; +using Newtonsoft.Json; + +namespace ARW.Model.Models +{ + /// + /// 多语言配置,数据实体对象 + /// + /// @author + /// + /// @date 2022-05-06 + /// + [Tenant("0")] + [SugarTable("sys_common_lang")] + public class CommonLang + { + /// + /// 描述 : id + /// 空值 : false + /// + [JsonConverter(typeof(ValueToStringConverter))] + [EpplusTableColumn(Header = "id")] + [SugarColumn(IsPrimaryKey = true)] + public long Id { get; set; } + + /// + /// 描述 : 语言code + /// 空值 : false + /// + [EpplusTableColumn(Header = "语言code")] + [SugarColumn(ColumnName = "lang_code")] + public string LangCode { get; set; } + + /// + /// 描述 : 语言key + /// 空值 : true + /// + [EpplusTableColumn(Header = "语言key")] + [SugarColumn(ColumnName = "lang_key")] + public string LangKey { get; set; } + + /// + /// 描述 : 名称 + /// 空值 : false + /// + [EpplusTableColumn(Header = "名称")] + [SugarColumn(ColumnName = "lang_name")] + public string LangName { get; set; } + + /// + /// 描述 : 添加时间 + /// 空值 : true + /// + [EpplusTableColumn(Header = "添加时间", NumberFormat = "yyyy-MM-dd HH:mm:ss")] + public DateTime? Addtime { get; set; } + } +} \ No newline at end of file diff --git a/ARW.Model/System/Dto/CommonLangDto.cs b/ARW.Model/System/Dto/CommonLangDto.cs new file mode 100644 index 0000000..9f28e07 --- /dev/null +++ b/ARW.Model/System/Dto/CommonLangDto.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace ARW.Model.Dto +{ + /// + /// 多语言配置输入对象 + /// + public class CommonLangDto + { + //[Required(ErrorMessage = "id不能为空")] + public long Id { get; set; } + //[Required(ErrorMessage = "语言code不能为空")] + public string LangCode { get; set; } + public string LangKey { get; set; } + //[Required(ErrorMessage = "名称不能为空")] + public string LangName { get; set; } + public List LangList { get; set; } + } + + /// + /// 多语言配置查询对象 + /// + public class CommonLangQueryDto : PagerInfo + { + public string LangCode { get; set; } + public string LangKey { get; set; } + public DateTime? BeginAddtime { get; set; } + public DateTime? EndAddtime { get; set; } + public int ShowMode { get; set; } + } +} diff --git a/ARW.Model/System/Dto/GenTableDto.cs b/ARW.Model/System/Dto/GenTableDto.cs new file mode 100644 index 0000000..514b7e5 --- /dev/null +++ b/ARW.Model/System/Dto/GenTableDto.cs @@ -0,0 +1,81 @@ +using System.Collections.Generic; +using ARW.Model.System.Generate; + +namespace ARW.Model.System.Dto +{ + public class GenTableDto + { + public int TableId { get; set; } + public string TableName { get; set; } + public string TableComment { get; set; } + public string SubTableName { get; set; } + public string SubTableFkName { get; set; } + public string ClassName { get; set; } + public string TplCategory { get; set; } + public string BaseNameSpace { get; set; } + public string ModuleName { get; set; } + public string BusinessName { get; set; } + public string FunctionName { get; set; } + public string FunctionAuthor { get; set; } + public string GenType { get; set; } + public string GenPath { get; set; } + //public string PermissionPrefix { get; set; } + public string Remark { get; set; } + /// + /// 额外参数 + /// + public Options Params { get; set; } + public List Columns { get; set; } + } + + /// + /// 额外参数 + /// ****注意里面参数统一首字母小写***** + /// + public class Params + { + public string TreeCode { get; set; } + public string TreeName { get; set; } + public string TreeParentCode { get; set; } + public int? ParentMenuId { get; set; } + public string SortField { get; set; } + public string SortType { get; set; } + /// + /// 额外参数字符串 + /// + public string CheckedBtn { get; set; } + public string PermissionPrefix { get; set; } + } + public class GenTableColumnDto + { + public int ColumnId { get; set; } + public int TableId { get; set; } + public string ColumnComment { get; set; } + public string CsharpType { get; set; } + public string CsharpField { get; set; } + public bool IsInsert { get; set; } + public bool IsEdit { get; set; } + public bool IsList { get; set; } + public bool IsQuery { get; set; } + public bool IsSort { get; set; } + public bool IsRequired { get; set; } + /// + /// 显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件) + /// + public string HtmlType { get; set; } + /// + /// 查询类型(等于、不等于、大于、小于、范围) + /// + public string QueryType { get; set; } = "EQ"; + public int Sort { get; set; } + /// + /// 字典类型 + /// + public string DictType { get; set; } + /// + /// 备注 + /// + public string Remark { get; set; } + } + +} diff --git a/ARW.Model/System/Dto/LoginBodyDto.cs b/ARW.Model/System/Dto/LoginBodyDto.cs new file mode 100644 index 0000000..00d06c1 --- /dev/null +++ b/ARW.Model/System/Dto/LoginBodyDto.cs @@ -0,0 +1,45 @@ +using System.ComponentModel.DataAnnotations; + +namespace ARW.Model.System.Dto +{ + public class LoginBodyDto + { + /// + /// 用户名 + /// + [Required(ErrorMessage = "用户名不能为空")] + public string Username { get; set; } + + /// + /// 用户密码 + /// + [Required(ErrorMessage = "密码不能为空")] + public string Password { get; set; } + + /** + * 验证码 + */ + public string Code { get; set; } + + /** + * 唯一标识 + */ + public string Uuid { get; set; } = ""; + public string LoginIP { get; set; } + } + + public class PostEmailDto + { + public string Email { get; set; } + } + + public class ChangePwByEmailDto + { + public string Email { get; set; } + + public string code { get; set; } + + public string Password { get; set; } + + } +} diff --git a/ARW.Model/System/Dto/MenuDto.cs b/ARW.Model/System/Dto/MenuDto.cs new file mode 100644 index 0000000..58e0c5d --- /dev/null +++ b/ARW.Model/System/Dto/MenuDto.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Text; + +namespace ARW.Model.System.Dto +{ + public class MenuDto + { + //{"parentId":0,"menuName":"aaa","icon":"documentation","menuType":"M","orderNum":999,"visible":0,"status":0,"path":"aaa"} + [Required(ErrorMessage = "菜单id不能为空")] + public int MenuId { get; set; } + public string MenuName { get; set; } + /// + /// 父菜单ID + /// + public long? parentId { get; set; } + + /// + /// 显示顺序 + /// + public int orderNum { get; set; } + + /// + /// 路由地址 + /// + public string path { get; set; } = "#"; + + /// + /// 组件路径 + /// + public string component { get; set; } + + /// + /// 是否缓存(1缓存 0不缓存) + /// + [Required(ErrorMessage = "是否缓存不能为空")] + public string isCache { get; set; } + /// + /// 是否外链 1、是 0、否 + /// + public string isFrame { get; set; } + + /// + /// 类型(M目录 C菜单 F按钮 L链接) + /// + [Required(ErrorMessage = "菜单类型不能为空")] + public string menuType { get; set; } + + /// + /// 显示状态(0显示 1隐藏) + /// + [Required(ErrorMessage = "显示状态不能为空")] + public string visible { get; set; } + + /// + /// 菜单状态(0正常 1停用) + /// + [Required(ErrorMessage = "菜单状态不能为空")] + public string status { get; set; } + + /// + /// 权限字符串 + /// + public string perms { get; set; } + + /// + /// 菜单图标 + /// + public string icon { get; set; } = string.Empty; + /// + /// 翻译key + /// + public string MenuNameKey { get; set; } + } + + public class MenuQueryDto + { + public string MenuName { get; set; } + public string Visible { get; set; } + public string Status { get; set; } + public string MenuTypeIds { get; set; } = string.Empty; + public int? ParentId { get; set; } + public string[] MenuTypeIdArr + { + get + { + return MenuTypeIds.Split(',', StringSplitOptions.RemoveEmptyEntries); + } + } + } +} diff --git a/ARW.Model/System/Dto/RegisterDto.cs b/ARW.Model/System/Dto/RegisterDto.cs new file mode 100644 index 0000000..38159c2 --- /dev/null +++ b/ARW.Model/System/Dto/RegisterDto.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Text; + +namespace ARW.Model.System.Dto +{ + public class RegisterDto + { + /// + /// 用户名 + /// + [Required(ErrorMessage = "用户名不能为空")] + public string Username { get; set; } + + /// + /// 用户密码 + /// + [Required(ErrorMessage = "密码不能为空")] + public string Password { get; set; } + [Required(ErrorMessage = "确认密码不能为空")] + public string ConfirmPassword { get; set; } + /** + * 验证码 + */ + public string Code { get; set; } + + /** + * 唯一标识 + */ + public string Uuid { get; set; } = ""; + } +} diff --git a/ARW.Model/System/Dto/RoleUserDto.cs b/ARW.Model/System/Dto/RoleUserDto.cs new file mode 100644 index 0000000..f8b9e35 --- /dev/null +++ b/ARW.Model/System/Dto/RoleUserDto.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Text; + +namespace ARW.Model.System.Dto +{ + public class RoleUserQueryDto : PagerInfo + { + public long RoleId { get; set; } + + public string UserName { get; set; } + } + + public class RoleUsersCreateDto + { + /// + /// 描述 : 角色id + /// 空值 : False + /// 默认 : + /// + [Display(Name = "角色id")] + [Required(ErrorMessage = "roleId 不能为空")] + public long RoleId { get; set; } + + /// + /// 描述 : 用户编码 [1,2,3,4] + /// 空值 : False + /// 默认 : + /// + [Display(Name = "用户编码 [1,2,3,4]")] + public List UserIds { get; set; } + } +} diff --git a/ARW.Model/System/Dto/SysConfigDto.cs b/ARW.Model/System/Dto/SysConfigDto.cs new file mode 100644 index 0000000..4c985ef --- /dev/null +++ b/ARW.Model/System/Dto/SysConfigDto.cs @@ -0,0 +1,30 @@ +using System; + +namespace ARW.Model.System.Dto +{ + /// + /// 参数配置输入对象模型 + /// + public class SysConfigDto + { + public int ConfigId { get; set; } + public string ConfigName { get; set; } + public string ConfigKey { get; set; } + public string ConfigValue { get; set; } + public string ConfigType { get; set; } + public string Remark { get; set; } + } + + /// + /// 参数配置查询对象模型 + /// + public class SysConfigQueryDto : PagerInfo + { + public string ConfigName { get; set; } + public string ConfigKey { get; set; } + public string ConfigValue { get; set; } + public string ConfigType { get; set; } + public DateTime? BeginTime { get; set; } + public DateTime? EndTime { get; set; } + } +} diff --git a/ARW.Model/System/Dto/SysFileQueryDto.cs b/ARW.Model/System/Dto/SysFileQueryDto.cs new file mode 100644 index 0000000..879e612 --- /dev/null +++ b/ARW.Model/System/Dto/SysFileQueryDto.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ARW.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 + { + public DateTime? BeginCreate_time { get; set; } + public DateTime? EndCreate_time { get; set; } + public int? StoreType { get; set; } + public long? FileId { get; set; } + } +} diff --git a/ARW.Model/System/Dto/SysLogininfoDto.cs b/ARW.Model/System/Dto/SysLogininfoDto.cs new file mode 100644 index 0000000..5a0f25d --- /dev/null +++ b/ARW.Model/System/Dto/SysLogininfoDto.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ARW.Model.System; + +namespace ARW.Model.System.Dto +{ + public class SysLogininfoDto : SysBase + { + public int pageNum { get; set; } + /// + /// IP 地址 + /// + public string Ipaddr { get; set; } + /// + /// 登录状态 0成功 1失败 + /// + public string Status { get; set; } + /// + /// 用户名 + /// + public string UserName { get; set; } + + } +} diff --git a/ARW.Model/System/Dto/SysNoticeDto.cs b/ARW.Model/System/Dto/SysNoticeDto.cs new file mode 100644 index 0000000..7fef20f --- /dev/null +++ b/ARW.Model/System/Dto/SysNoticeDto.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using Newtonsoft.Json; +using ARW.Model.Models; + +namespace ARW.Model.System.Dto +{ + /// + /// 通知公告表输入对象 + /// + public class SysNoticeDto + { + public int NoticeId { get; set; } + public string NoticeTitle { get; set; } + public string NoticeType { get; set; } + public string NoticeContent { get; set; } + public string Status { get; set; } + public string Remark { get; set; } + } + + /// + /// 通知公告表查询对象 + /// + public class SysNoticeQueryDto : PagerInfo + { + public string NoticeTitle { get; set; } + public string NoticeType { get; set; } + public string CreateBy { get; set; } + public string Status { get; set; } + } +} diff --git a/ARW.Model/System/Dto/SysOperLogDto.cs b/ARW.Model/System/Dto/SysOperLogDto.cs new file mode 100644 index 0000000..9cccbcd --- /dev/null +++ b/ARW.Model/System/Dto/SysOperLogDto.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ARW.Model.System; + +namespace ARW.Model.System.Dto +{ + public class SysOperLogDto : SysBase + { + /// + /// 页码 + /// + public int pageNum { get; set; } + public int PageSize { get; set; } + /// + /// 操作人员 + /// + public string operName { get; set; } + /// + /// 业务类型 0=其它,1=新增,2=修改,3=删除,4=授权,5=导出,6=导入,7=强退,8=生成代码,9=清空数据 + /// + public int BusinessType { get; set; } = -1; + /// + /// 状态 + /// + public int Status { get; set; } = -1; + /// + /// 操作模块 + /// + public string Title { get; set; } + } +} diff --git a/ARW.Model/System/Dto/SysRoleDto.cs b/ARW.Model/System/Dto/SysRoleDto.cs new file mode 100644 index 0000000..59df3e9 --- /dev/null +++ b/ARW.Model/System/Dto/SysRoleDto.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ARW.Model.System; + +namespace ARW.Model.System.Dto +{ + public class SysRoleDto: SysBase + { + public long RoleId { get; set; } + /// + /// 角色分配菜单 + /// + public List MenuIds { get; set; } = new List(); + public string RoleName { get; set; } + public string RoleKey { get; set; } + public int RoleSort { get; set; } + public string Status { get; set; } + } +} diff --git a/ARW.Model/System/Dto/SysUserDto.cs b/ARW.Model/System/Dto/SysUserDto.cs new file mode 100644 index 0000000..ddcacc4 --- /dev/null +++ b/ARW.Model/System/Dto/SysUserDto.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ARW.Model.System; + +namespace ARW.Model.System.Dto +{ + public class SysUserDto + { + public long UserId { get; set; } + public string UserName { get; set; } + public string NickName { get; set; } + public string Email { get; set; } + public string Remark { get; set; } + public string Phonenumber { get; set; } + /// + /// '用户性别(0男 1女 2未知)', + /// + public int Sex { get; set; } + } +} diff --git a/ARW.Model/System/Dto/SysdictDataDto.cs b/ARW.Model/System/Dto/SysdictDataDto.cs new file mode 100644 index 0000000..3490829 --- /dev/null +++ b/ARW.Model/System/Dto/SysdictDataDto.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ARW.Model.System.Dto +{ + public class SysdictDataDto + { + public string DictType { get; set; } + public string ColumnName { get; set; } + public List List { get; set; } + } +} diff --git a/ARW.Model/System/Dto/TasksDto.cs b/ARW.Model/System/Dto/TasksDto.cs new file mode 100644 index 0000000..95811ad --- /dev/null +++ b/ARW.Model/System/Dto/TasksDto.cs @@ -0,0 +1,233 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Text; + +namespace ARW.Model.System.Dto +{ + public class TasksQueryDto + { + /// + /// 描述 : 查询字符串 + /// 空值 : False + /// 默认 : + /// + [Display(Name = "查询字符串")] + public string QueryText { get; set; } + } + + /// + /// 添加任务 + /// + public class TasksCreateDto + { + /// + /// 描述 : 任务名称 + /// 空值 : False + /// 默认 : + /// + [Display(Name = "任务名称")] + [Required(ErrorMessage = "任务名称不能为空")] + public string Name { get; set; } + + /// + /// 描述 : 任务分组 + /// 空值 : False + /// 默认 : + /// + [Display(Name = "任务分组")] + [Required(ErrorMessage = "任务分组不能为空")] + public string JobGroup { get; set; } + + /// + /// 描述 : 运行时间表达式 + /// 空值 : False + /// 默认 : + /// + [Display(Name = "运行时间表达式")] + public string Cron { get; set; } + + /// + /// 描述 : 程序集名称 + /// 空值 : False + /// 默认 : + /// + [Display(Name = "程序集名称")] + //[Required(ErrorMessage = "程序集名称不能为空")] + public string AssemblyName { get; set; } + + /// + /// 描述 : 任务所在类 + /// 空值 : False + /// 默认 : + /// + [Display(Name = "任务所在类")] + //[Required(ErrorMessage = "任务所在类不能为空")] + public string ClassName { get; set; } + + /// + /// 描述 : 任务描述 + /// 空值 : True + /// 默认 : + /// + [Display(Name = "任务描述")] + public string Remark { get; set; } + + /// + /// 描述 : 开始时间 + /// 空值 : True + /// 默认 : + /// + [Display(Name = "开始时间")] + public DateTime? BeginTime { get; set; } + + /// + /// 描述 : 结束时间 + /// 空值 : True + /// 默认 : + /// + [Display(Name = "结束时间")] + public DateTime? EndTime { get; set; } + + /// + /// 描述 : 触发器类型(0、simple 1、cron) + /// 空值 : False + /// 默认 : + /// + [Display(Name = "触发器类型(0、simple 1、cron)")] + public int TriggerType { get; set; } + + /// + /// 描述 : 执行间隔时间(单位:秒) + /// 空值 : False + /// 默认 : 0 + /// + [Display(Name = "执行间隔时间(单位:秒)")] + public int IntervalSecond { get; set; } + + /// + /// 描述 : 传入参数 + /// 空值 : True + /// 默认 : + /// + [Display(Name = "传入参数")] + public string JobParams { get; set; } + public string ApiUrl { get; set; } + /// + /// 1、程序集任务 2、apiUrl任务 + /// + public int TaskType { get; set; } + } + + /// + /// 更新任务 + /// + public class TasksUpdateDto + { + /// + /// 描述 : UID + /// 空值 : False + /// 默认 : + /// + [Display(Name = "UID")] + [Required(ErrorMessage = "UID不能为空")] + public string ID { get; set; } + + /// + /// 描述 : 任务名称 + /// 空值 : False + /// 默认 : + /// + [Display(Name = "任务名称")] + [Required(ErrorMessage = "任务名称不能为空")] + public string Name { get; set; } + + /// + /// 描述 : 任务分组 + /// 空值 : False + /// 默认 : + /// + [Display(Name = "任务分组")] + [Required(ErrorMessage = "任务分组不能为空")] + public string JobGroup { get; set; } + + /// + /// 描述 : 运行时间表达式 + /// 空值 : False + /// 默认 : + /// + [Display(Name = "运行时间表达式")] + public string Cron { get; set; } + + /// + /// 描述 : 程序集名称 + /// 空值 : False + /// 默认 : + /// + [Display(Name = "程序集名称")] + [Required(ErrorMessage = "程序集名称不能为空")] + public string AssemblyName { get; set; } + + /// + /// 描述 : 任务所在类 + /// 空值 : False + /// 默认 : + /// + [Display(Name = "任务所在类")] + [Required(ErrorMessage = "任务所在类不能为空")] + public string ClassName { get; set; } + + /// + /// 描述 : 任务描述 + /// 空值 : True + /// 默认 : + /// + [Display(Name = "任务描述")] + public string Remark { get; set; } + + /// + /// 描述 : 开始时间 + /// 空值 : True + /// 默认 : + /// + [Display(Name = "开始时间")] + public DateTime? BeginTime { get; set; } + + /// + /// 描述 : 结束时间 + /// 空值 : True + /// 默认 : + /// + [Display(Name = "结束时间")] + public DateTime? EndTime { get; set; } + + /// + /// 描述 : 触发器类型(0、simple 1、cron) + /// 空值 : False + /// 默认 : + /// + [Display(Name = "触发器类型(0、simple 1、cron)")] + public int TriggerType { get; set; } + + /// + /// 描述 : 执行间隔时间(单位:秒) + /// 空值 : False + /// 默认 : 0 + /// + [Display(Name = "执行间隔时间(单位:秒)")] + public int IntervalSecond { get; set; } + + /// + /// 描述 : 传入参数 + /// 空值 : True + /// 默认 : + /// + [Display(Name = "传入参数")] + public string JobParams { get; set; } + public string ApiUrl { get; set; } + /// + /// 1、程序集任务 2、apiUrl任务 + /// + public int TaskType { get; set; } + } +} diff --git a/ARW.Model/System/Dto/TasksLogDto.cs b/ARW.Model/System/Dto/TasksLogDto.cs new file mode 100644 index 0000000..9899216 --- /dev/null +++ b/ARW.Model/System/Dto/TasksLogDto.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ARW.Model.System.Dto +{ + public class TasksLogQueryDto + { + /// + /// 描述 : 查询字符串 + /// 空值 : False + /// 默认 : + /// + //[Display(Name = "查询字符串")] + public string Name{ get; set; } + public string JobName { get; set; } + public string JobId { get; set; } + public string JobGroup { get; set; } + public string Status { get; set; } + public DateTime? BeginTime { get; set; } + public DateTime? EndTime { get; set; } + } + + public class TasksLogDto + { + + } +} diff --git a/ARW.Model/System/Generate/GenTable.cs b/ARW.Model/System/Generate/GenTable.cs new file mode 100644 index 0000000..db2dc81 --- /dev/null +++ b/ARW.Model/System/Generate/GenTable.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ARW.Model.System.Generate +{ + /// + /// 代码生成表 + /// + [SqlSugar.SugarTable("gen_table")] + [SqlSugar.Tenant("0")] + public class GenTable : SysBase + { + /// + /// 表id + /// + [SqlSugar.SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public int TableId { get; set; } + /// + /// 数据库名 + /// + public string DbName { get; set; } + /// + /// 表名 + /// + public string TableName { get; set; } + /// + /// 表描述 + /// + public string TableComment { get; set; } + /// + /// 关联父表的表名 + /// + public string SubTableName { get; set; } + /// + /// 本表关联父表的外键名 + /// + public string SubTableFkName { get; set; } + /// + /// csharp类名 + /// + public string ClassName { get; set; } + /// + /// 使用的模板(crud单表操作 tree树表操作 sub主子表操作) + /// + public string TplCategory { get; set; } + /// + /// 基本命名空间前缀 + /// + public string BaseNameSpace { get; set; } + /// + /// 生成模块名 + /// + public string ModuleName { get; set; } + /// + /// 生成业务名 + /// + public string BusinessName { get; set; } + /// + /// 生成功能名 + /// + public string FunctionName { get; set; } + /// + /// 生成作者名 + /// + public string FunctionAuthor { get; set; } + /// + /// 生成代码方式(0zip压缩包 1自定义路径) + /// + public string GenType { get; set; } + public string GenPath { get; set; } + /// + /// 其他生成选项 + /// + [SqlSugar.SugarColumn(IsJson = true, ColumnDataType = "nvarchar(4000)")] + public Options Options { get; set; } + + #region 表额外字段 + /** 表列信息 */ + [SqlSugar.SugarColumn(IsIgnore = true)] + public List Columns { get; set; } + + /// + /// 字表信息 + /// + [SqlSugar.SugarColumn(IsIgnore = true)] + public GenTable SubTable { get; set; } + #endregion + } + + public class Options + { + public long ParentMenuId { get; set; } = 0; + public string SortType { get; set; } = "asc"; + public string SortField { get; set; } = string.Empty; + public string TreeCode { get; set; } = string.Empty; + public string TreeName { get; set; } = string.Empty; + public string TreeParentCode { get; set; } = string.Empty; + public string PermissionPrefix { get; set; }= string.Empty; + /// + /// 额外参数字符串 + /// + public int[] CheckedBtn { get; set; } = new int[] { 1, 2, 3 }; + /// + /// 列大小 12,24 + /// + public int ColNum { get; set; } = 12; + } +} diff --git a/ARW.Model/System/Generate/GenTableColumn.cs b/ARW.Model/System/Generate/GenTableColumn.cs new file mode 100644 index 0000000..36b60c7 --- /dev/null +++ b/ARW.Model/System/Generate/GenTableColumn.cs @@ -0,0 +1,139 @@ +using SqlSugar; +using System; +using System.Linq; + +namespace ARW.Model.System.Generate +{ + /// + /// 代码生成表字段 + /// + [SugarTable("gen_table_column")] + [Tenant("0")] + public class GenTableColumn : SysBase + { + [SugarColumn(IsIdentity = true, IsPrimaryKey = true)] + public int ColumnId { get; set; } + /// + /// 导入代码生成表列名 首字母转了小写 + /// + public string ColumnName { get; set; } + [SugarColumn(IsOnlyIgnoreUpdate = true)] + public int TableId { get; set; } + + [SugarColumn(IsOnlyIgnoreUpdate = true)] + public string TableName { get; set; } + /// + /// 列说明 + /// + public string ColumnComment { get; set; } = string.Empty; + /// + /// 数据库列类型 + /// + + [SugarColumn(IsOnlyIgnoreUpdate = true)] + public string ColumnType { get; set; } + /// + /// C#类型 + /// + public string CsharpType { get; set; } + /// + /// C# 字段名 首字母大写 + /// + public string CsharpField { get; set; } + /// + /// 是否主键(1是) + /// + [SugarColumn(IsOnlyIgnoreUpdate = true)] + public bool IsPk { get; set; } + /// + /// 是否必填(1是) + /// + public bool IsRequired { get; set; } + /// + /// 是否自增(1是) + /// + [SugarColumn(IsOnlyIgnoreUpdate = true)] + public bool IsIncrement { get; set; } + /// + /// 是否插入(1是) + /// + public bool IsInsert { get; set; } + /// + /// 是否需要编辑(1是) + /// + public bool IsEdit { get; set; } + /// + /// 是否显示列表(1是) + /// + public bool IsList { get; set; } + /// + /// 是否查询(1是) + /// + public bool IsQuery { get; set; } + /// + /// 是否排序(1是) + /// + public bool IsSort { get; set; } + /// + /// 是否初始化字段(1是) + /// + public bool IsInit { get; set; } + /// + /// 是否Guid(1是) + /// + public bool IsGuid { get; set; } + /// + /// 显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件) + /// + public string HtmlType { get; set; } + /// + /// 查询类型(等于、不等于、大于、小于、范围) + /// + public string QueryType { get; set; } = "EQ"; + public int Sort { get; set; } + /// + /// 字典类型 + /// + public string DictType { get; set; } = ""; + + #region 额外字段 + [SugarColumn(IsIgnore = true)] + public string RequiredStr + { + get + { + string[] arr = new string[] { "int", "long" }; + return (!IsRequired && (arr.Any(f => f.Contains(CsharpType))) || typeof(DateTime).Name == CsharpType) ? "?" : ""; + } + } + /// + /// 前端排序字符串 + /// + [SugarColumn(IsIgnore = true)] + public string SortStr + { + get + { + return IsSort ? " sortable" : ""; + } + } + /// + /// C# 字段名 首字母小写,用于前端 + /// + [SugarColumn(IsIgnore = true)] + public string CsharpFieldFl { get; set; } + /// + /// 前端 只读字段 + /// + [SugarColumn(IsIgnore = true)] + public string DisabledStr + { + get + { + return (((!IsInsert && !IsEdit) || IsPk) && !IsRequired) ? " :disabled=\"true\"" : ""; + } + } + + #endregion + } +} diff --git a/ARW.Model/System/LoginUser.cs b/ARW.Model/System/LoginUser.cs new file mode 100644 index 0000000..75b8f4d --- /dev/null +++ b/ARW.Model/System/LoginUser.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace ARW.Model.System +{ + /// + /// 登录用户信息存储 + /// + public class LoginUser + { + public long UserId { get; set; } + public long DeptId { get; set; } + public string UserName { get; set; } + + public bool IsApi { get; set; } + + /// + /// 角色集合 + /// + public List RoleIds { get; set; } + /// + /// 角色集合(数据权限过滤使用) + /// + public List Roles { get; set; } + /// + /// 权限集合 + /// + public List Permissions { get; set; } = new List(); + public LoginUser() + { + } + + public LoginUser(SysUser user, List roles, List permissions) + { + UserId = user.UserId; + UserName = user.UserName; + DeptId = user.DeptId; + Roles = roles; + RoleIds = roles.Select(f => f.RoleKey).ToList(); + Permissions = permissions; + } + } +} diff --git a/ARW.Model/System/SysBase.cs b/ARW.Model/System/SysBase.cs new file mode 100644 index 0000000..840c44b --- /dev/null +++ b/ARW.Model/System/SysBase.cs @@ -0,0 +1,65 @@ +//using Dapper.Contrib.Extensions; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Text; +using SqlSugar; +using OfficeOpenXml.Attributes; + +namespace ARW.Model.System +{ + [EpplusTable(PrintHeaders = true, AutofitColumns = true, AutoCalculate = true, ShowTotal = true)] + public class SysBase + { + [SugarColumn(IsOnlyIgnoreUpdate = true)]//设置后修改不会有此字段 + [JsonProperty(propertyName: "CreateBy")] + [EpplusIgnore] + public string Create_by { get; set; } + + [SugarColumn(IsOnlyIgnoreUpdate = true)]//设置后修改不会有此字段 + [JsonProperty(propertyName: "CreateTime")] + [EpplusTableColumn(NumberFormat = "yyyy-MM-dd HH:mm:ss")] + public DateTime Create_time { get; set; } = DateTime.Now; + + [JsonIgnore] + [JsonProperty(propertyName: "UpdateBy")] + [SugarColumn(IsOnlyIgnoreInsert = true)] + [EpplusIgnore] + public string Update_by { get; set; } + + //[JsonIgnore] + [SugarColumn(IsOnlyIgnoreInsert = true)]//设置后插入数据不会有此字段 + [JsonProperty(propertyName: "UpdateTime")] + [EpplusIgnore] + public DateTime? Update_time { get; set; } + + public string Remark { get; set; } + + /// + /// 搜索时间起始时间 + /// + /// + /// Write:需穿一个bool值,false时insert,update等操作会忽略此列(和Computed的作用差不多,看了源码也没发现与Computed有什么不一样的地方,有了解的朋友可以赐教下哈) + /// ExplicitKey:指定此列为主键(不自动增长类型例如guid,ExplicitKey与Key地区别下面会详细讲) + /// Key:指定此列为主键(自动增长主键),可忽略,忽略后默认查找 + /// [Computed]计算属性,打上此标签,对象地insert,update等操作会忽略此列 + /// + [SugarColumn(IsIgnore = true)] + [JsonIgnore] + [EpplusIgnore] + public DateTime? BeginTime { get; set; } + + /// + /// 用于搜索使用 + /// + [SugarColumn(IsIgnore = true)] + [JsonIgnore] + [EpplusIgnore] + public DateTime? EndTime { get; set; } + + [JsonProperty(propertyName: "IsDelete")] + [SugarColumn(IsNullable = true)] + [EpplusIgnore] + public bool IsDelete { get; set; } + } +} diff --git a/ARW.Model/System/SysConfig.cs b/ARW.Model/System/SysConfig.cs new file mode 100644 index 0000000..c38d7f1 --- /dev/null +++ b/ARW.Model/System/SysConfig.cs @@ -0,0 +1,46 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Text; + +namespace ARW.Model.System +{ + /// + /// 参数配置,数据实体对象 + /// + /// @author zhaorui + /// @date 2021-09-29 + /// + [SugarTable("sys_config")] + [Tenant("0")] + public class SysConfig: SysBase + { + /// + /// 描述 : + /// 空值 :False + /// + [SqlSugar.SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public int ConfigId { get; set; } + /// + /// 描述 : + /// 空值 :True + /// + public string ConfigName { get; set; } + /// + /// 描述 : + /// 空值 :True + /// + public string ConfigKey { get; set; } + /// + /// 描述 : + /// 空值 :True + /// + public string ConfigValue { get; set; } + /// + /// 描述 : + /// 空值 :True + /// + public string ConfigType { get; set; } + + } +} diff --git a/ARW.Model/System/SysDept.cs b/ARW.Model/System/SysDept.cs new file mode 100644 index 0000000..f5abb93 --- /dev/null +++ b/ARW.Model/System/SysDept.cs @@ -0,0 +1,58 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Text; + +namespace ARW.Model.System +{ + /// + /// 部门表 + /// + [SugarTable("sys_dept")] + [Tenant("0")] + public class SysDept: SysBase + { + /** 部门ID */ + [SqlSugar.SugarColumn(IsIdentity = true, IsPrimaryKey = true)] + public long DeptId { get; set; } + + /** 父部门ID */ + public long ParentId { get; set; } + + /** 祖级列表 */ + public string Ancestors { get; set; } + + /** 部门名称 */ + public string DeptName { get; set; } + + /** 显示顺序 */ + public int OrderNum { get; set; } + + /** 负责人 */ + public string Leader { get; set; } + + /** 联系电话 */ + public string Phone { get; set; } + + /** 邮箱 */ + public string Email { get; set; } + + /** 部门状态:0正常,1停用 */ + public string Status { get; set; } + + /// + /// 删除标志(0代表存在 2代表删除) + /// + [SugarColumn(IsOnlyIgnoreInsert = true)] + public string DelFlag { get; set; } + + /** 父部门名称 */ + //[SugarColumn(IsIgnore = true)] + //public string ParentName { get; set; } + + /// + /// 子菜单 + /// + public List children = new List(); + } +} diff --git a/ARW.Model/System/SysDictData.cs b/ARW.Model/System/SysDictData.cs new file mode 100644 index 0000000..31fa5a2 --- /dev/null +++ b/ARW.Model/System/SysDictData.cs @@ -0,0 +1,31 @@ +//using Dapper.Contrib.Extensions; +using System; +using System.Collections.Generic; +using System.Text; +using SqlSugar; + +namespace ARW.Model.System +{ + /// + /// 字典数据表 + /// + [Tenant("0")] + [SugarTable("sys_dict_data")] + public class SysDictData: SysBase + { + //[Key] + /// + /// 字典主键 + /// + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]//主键并且自增 (string不能设置自增) + public long DictCode{ get; set; } + public int DictSort { get; set; } + public string DictLabel { get; set; } + public string DictValue { get; set; } + public string DictType { get; set; } + public string CssClass { get; set; } = string.Empty; + public string ListClass { get; set; } = string.Empty; + public string IsDefault { get; set; } + public string Status { get; set; } + } +} diff --git a/ARW.Model/System/SysDictType.cs b/ARW.Model/System/SysDictType.cs new file mode 100644 index 0000000..d8a35a2 --- /dev/null +++ b/ARW.Model/System/SysDictType.cs @@ -0,0 +1,36 @@ +using OfficeOpenXml.Attributes; +using SqlSugar; + +namespace ARW.Model.System +{ + /// + /// 字典类型表 + /// + [SugarTable("sys_dict_type")] + [Tenant("0")] + public class SysDictType : SysBase + { + /// + /// 字典主键 + /// + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]//主键并且自增 (string不能设置自增) + public long DictId { get; set; } + /// + /// 字典名称 + /// + public string DictName { get; set; } + /// + /// 字典类型 + /// + public string DictType { get; set; } + /// + /// 状态 0、正常 1、停用 + /// + [EpplusIgnore] + public string Status { get; set; } + /// + /// 系统内置 Y是 N否 + /// + public string Type { get; set; } + } +} diff --git a/ARW.Model/System/SysFile.cs b/ARW.Model/System/SysFile.cs new file mode 100644 index 0000000..36bfb0b --- /dev/null +++ b/ARW.Model/System/SysFile.cs @@ -0,0 +1,90 @@ +using Newtonsoft.Json; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Text; + +namespace ARW.Model.System +{ + [Tenant("0")] + [SugarTable("sys_file")] + public class SysFile + { + /// + /// 描述 : 自增id + /// 空值 : false + /// + [JsonConverter(typeof(ValueToStringConverter))] + [SugarColumn(IsPrimaryKey = true)] + 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; } + + [JsonProperty(propertyName: "IsDelete")] + [SugarColumn(IsNullable = true)] + public bool IsDelete { get; set; } + + public SysFile() { } + public SysFile(string originFileName, string fileName, string ext, string fileSize, string storePath, string create_by) + { + StorePath = storePath; + RealName = originFileName; + FileName = fileName; + FileExt = ext; + FileSize = fileSize; + Create_by = create_by; + Create_time = DateTime.Now; + } + } +} \ No newline at end of file diff --git a/ARW.Model/System/SysLogininfor.cs b/ARW.Model/System/SysLogininfor.cs new file mode 100644 index 0000000..0f407be --- /dev/null +++ b/ARW.Model/System/SysLogininfor.cs @@ -0,0 +1,64 @@ +//using Dapper.Contrib.Extensions; +using OfficeOpenXml.Attributes; +using SqlSugar; +using System; + +namespace ARW.Model.System +{ + /// + /// sys_logininfor 表 + /// + [SugarTable("sys_logininfor")] + [Tenant("0")] + public class SysLogininfor + { + //[Key] + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public long infoId { get; set; } + + /// + /// 用户账号 + /// + public string userName { get; set; } + + /// + /// 登录状态 0成功 1失败 + /// + [SugarColumn(Length = 1)] + public string status { get; set; } + + /// + /// 登录IP地址 + /// + public string ipaddr { get; set; } + + /// + /// 登录地点 + /// + public string loginLocation { get; set; } + + /// + /// 浏览器类型 + /// + public string browser { get; set; } + + /** 操作系统 */ + //@Excel(name = "操作系统") + public string os { get; set; } + + /// + /// 提示消息 + /// + public string msg { get; set; } + + /// + /// 访问时间 + /// + [EpplusTableColumn(NumberFormat = "yyyy-MM-dd HH:mm:ss")] + public DateTime loginTime { get; set; } = DateTime.Now; + [SugarColumn(IsIgnore = true)] + public DateTime? BeginTime { get; set; } + [SugarColumn(IsIgnore = true)] + public DateTime? EndTime { get; set; } + } +} diff --git a/ARW.Model/System/SysMenu.cs b/ARW.Model/System/SysMenu.cs new file mode 100644 index 0000000..cb50b46 --- /dev/null +++ b/ARW.Model/System/SysMenu.cs @@ -0,0 +1,107 @@ +using SqlSugar; +using System.Collections.Generic; + +namespace ARW.Model.System +{ + /// + /// Sys_menu表 + /// + [SugarTable("sys_menu")] + [Tenant("0")] + public class SysMenu : SysBase + { + /// + /// 菜单ID + /// + //[Key]//非自动增长主键时使用ExplicitKey + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public long MenuId { get; set; } + /// + /// 菜单名称 + /// + public string MenuName { get; set; } + + /// + /// 父菜单ID + /// + public long parentId { get; set; } + + /// + /// 显示顺序 + /// + public int orderNum { get; set; } + + /// + /// 路由地址 + /// + public string path { get; set; } = "#"; + + /// + /// 组件路径 + /// + [SugarColumn(IsNullable = true)] + public string component { get; set; } + + /// + /// 是否缓存(1缓存 0不缓存) + /// + public string isCache { get; set; } + /// + /// 是否外链 1、是 0、否 + /// + public string isFrame { get; set; } + + /// + /// 类型(M目录 C菜单 F按钮 L链接) + /// + public string menuType { get; set; } + + /// + /// 显示状态(0显示 1隐藏) + /// + public string visible { get; set; } + + /// + /// 菜单状态(0正常 1停用) + /// + public string status { get; set; } + + /// + /// 权限字符串 + /// + [SugarColumn(IsNullable = true)] + public string perms { get; set; } + + /// + /// 菜单图标 + /// + [SugarColumn(IsNullable = true)] + public string icon { get; set; } = string.Empty; + /// + /// 菜单名key + /// + [SugarColumn(ColumnName = "menuName_key", IsNullable = true)] + public string MenuNameKey { get; set; } + /// + /// 子菜单 + /// + [SugarColumn(IsIgnore = true)] + public List children { get; set; } = new List(); + /// + /// 子菜单个数 + /// + [SugarColumn(IsIgnore = true)] + public int SubNum { get; set; } + /// + /// 是否包含子节点,前端用 + /// + [SugarColumn(IsIgnore = true)] + public bool HasChildren + { + get + { + return SubNum > 0 || children.Count > 0; + } + } + } +} diff --git a/ARW.Model/System/SysNotice.cs b/ARW.Model/System/SysNotice.cs new file mode 100644 index 0000000..a91b285 --- /dev/null +++ b/ARW.Model/System/SysNotice.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using SqlSugar; + +namespace ARW.Model.System +{ + /// + /// 通知公告表,数据实体对象 + /// + /// @author zr + /// @date 2021-12-15 + /// + [SugarTable("sys_notice")] + [Tenant(0)] + public class SysNotice : SysBase + { + /// + /// 描述 : 公告ID + /// 空值 : true + /// + [SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnName = "notice_id")] + public int NoticeId { get; set; } + /// + /// 描述 : 公告标题 + /// 空值 : true + /// + [SugarColumn(ColumnName = "notice_title")] + public string NoticeTitle { get; set; } + /// + /// 描述 : 公告类型 (1通知 2公告) + /// 空值 : true + /// + [SugarColumn(ColumnName = "notice_type")] + public string NoticeType { get; set; } + /// + /// 描述 : 公告内容 + /// 空值 : true + /// + [SugarColumn(ColumnName = "notice_content")] + public string NoticeContent { get; set; } + /// + /// 描述 : 公告状态 (0正常 1关闭) + /// 空值 : true + /// + public string Status { get; set; } + } +} \ No newline at end of file diff --git a/ARW.Model/System/SysOperLog.cs b/ARW.Model/System/SysOperLog.cs new file mode 100644 index 0000000..871baa5 --- /dev/null +++ b/ARW.Model/System/SysOperLog.cs @@ -0,0 +1,92 @@ +using Newtonsoft.Json; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Text; +using OfficeOpenXml.Attributes; + +namespace ARW.Model.System +{ + [SugarTable("sys_oper_log")] + [Tenant("0")] + public class SysOperLog + { + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public long OperId { get; set; } + /** 操作模块 */ + //@Excel(name = "操作模块") + [SugarColumn(IsNullable = true)] + public string title { get; set; } + + /** 业务类型(0其它 1新增 2修改 3删除) */ + //@Excel(name = "业务类型", readConverterExp = "0=其它,1=新增,2=修改,3=删除,4=授权,5=导出,6=导入,7=强退,8=生成代码,9=清空数据") + public int businessType { get; set; } + + /** 业务类型数组 */ + [SugarColumn(IsIgnore = true)] + public int[] businessTypes { get; set; } + + /** 请求方法 */ + //@Excel(name = "请求方法") + [SugarColumn(IsNullable = true)] + public string method { get; set; } + + /** 请求方式 */ + //@Excel(name = "请求方式") + public string requestMethod { get; set; } + + /** 操作类别(0其它 1后台用户 2手机端用户) */ + //@Excel(name = "操作类别", readConverterExp = "0=其它,1=后台用户,2=手机端用户") + public int operatorType { get; set; } + + /** 操作人员 */ + //@Excel(name = "操作人员") + [SugarColumn(IsNullable = true)] + public string operName { get; set; } + + /** 部门名称 */ + //@Excel(name = "部门名称") + [SugarColumn(IsNullable = true)] + public string deptName { get; set; } + + /** 请求url */ + //@Excel(name = "请求地址") + public string operUrl { get; set; } + + /** 操作地址 */ + //@Excel(name = "操作地址") + public string operIp { get; set; } + + /** 操作地点 */ + //@Excel(name = "操作地点") + public string operLocation { get; set; } + + /** 请求参数 */ + //@Excel(name = "请求参数") + public string operParam { get; set; } + + /** 返回参数 */ + //@Excel(name = "返回参数") + public string jsonResult { get; set; } + + /** 操作状态(0正常 1异常) */ + //@Excel(name = "状态", readConverterExp = "0=正常,1=异常") + public int status { get; set; } + + /// + /// 错误消息 + /// + [EpplusTableColumn(Header = "错误消息")] + public string errorMsg { get; set; } + + /// + /// 操作时间 + /// + [EpplusTableColumn(Header = "操作时间", NumberFormat = "yyyy-MM-dd HH:mm:ss")] + public DateTime? operTime { get; set; } + /// + /// 操作用时 + /// + public long Elapsed { get; set; } + } +} diff --git a/ARW.Model/System/SysPost.cs b/ARW.Model/System/SysPost.cs new file mode 100644 index 0000000..4bfd544 --- /dev/null +++ b/ARW.Model/System/SysPost.cs @@ -0,0 +1,22 @@ +using OfficeOpenXml.Attributes; +using SqlSugar; + +namespace ARW.Model.System +{ + [SugarTable("sys_post")] + [Tenant("0")] + public class SysPost : SysBase + { + /// + /// 岗位Id + /// + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public long PostId { get; set; } + public string PostCode { get; set; } + public string PostName { get; set; } + [EpplusIgnore] + public int PostSort { get; set; } + [EpplusIgnore] + public string Status { get; set; } + } +} diff --git a/ARW.Model/System/SysRole.cs b/ARW.Model/System/SysRole.cs new file mode 100644 index 0000000..f8e9523 --- /dev/null +++ b/ARW.Model/System/SysRole.cs @@ -0,0 +1,94 @@ +using Newtonsoft.Json; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Text; + +namespace ARW.Model.System +{ + /// + /// 角色表 sys_role + /// + [SugarTable("sys_role")] + [Tenant("0")] + public class SysRole : SysBase + { + /// + /// 角色ID + /// + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public long RoleId { get; set; } + + /// + /// 角色名称 + /// + public string RoleName { get; set; } + + /// + /// 角色权限 + /// + public string RoleKey { get; set; } + + /// + /// 角色排序 + /// + public int RoleSort { get; set; } + + /// + /// 帐号状态(0正常 1停用) + /// + public string Status { get; set; } + + /// + /// 删除标志(0代表存在 2代表删除) + /// + [SugarColumn(IsOnlyIgnoreInsert = true, IsOnlyIgnoreUpdate = true)] + public string DelFlag { get; set; } + /// + /// 数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)) + /// + public string DataScope { get; set; } + /// + /// 菜单树选择项是否关联显示 + /// + [SugarColumn(ColumnName = "menu_check_strictly")] + public bool MenuCheckStrictly { get; set; } + /// + /// 部门树选择项是否关联显示 + /// + [SugarColumn(ColumnName = "dept_check_strictly")] + public bool DeptCheckStrictly { get; set; } + /// + /// 菜单组 + /// + [SugarColumn(IsIgnore = true)] + public long[] MenuIds { get; set; } + /// + /// 部门组(数据权限) + /// + [SugarColumn(IsIgnore = true)] + public long[] DeptIds { get; set; } + /// + /// 用户个数 + /// + [SugarColumn(IsIgnore = true)] + public int UserNum { get; set; } + + public SysRole() { } + + public SysRole(long roleId) + { + RoleId = roleId; + } + + public bool IsAdmin() + { + return IsAdmin(RoleId); + } + + public static bool IsAdmin(long roleId) + { + return 1 == roleId; + } + } +} diff --git a/ARW.Model/System/SysRoleDept.cs b/ARW.Model/System/SysRoleDept.cs new file mode 100644 index 0000000..4b5629b --- /dev/null +++ b/ARW.Model/System/SysRoleDept.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ARW.Model.System +{ + [SqlSugar.SugarTable("sys_role_dept")] + [SqlSugar.Tenant(0)] + public class SysRoleDept + { + public long RoleId { get; set; } + public long DeptId { get; set; } + } +} diff --git a/ARW.Model/System/SysRoleMenu.cs b/ARW.Model/System/SysRoleMenu.cs new file mode 100644 index 0000000..fc09ce0 --- /dev/null +++ b/ARW.Model/System/SysRoleMenu.cs @@ -0,0 +1,25 @@ +using Newtonsoft.Json; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Text; + +namespace ARW.Model.System +{ + /// + /// 角色菜单 + /// + [SugarTable("sys_role_menu")] + [Tenant("0")] + public class SysRoleMenu + { + [JsonProperty("roleId")] + [SugarColumn(IsPrimaryKey = true)] + public long Role_id { get; set; } + [JsonProperty("menuId")] + [SugarColumn(IsPrimaryKey = true)] + public long Menu_id { get; set; } + public DateTime Create_time { get; set; } + public string Create_by { get; set; } + } +} diff --git a/ARW.Model/System/SysRolePost.cs b/ARW.Model/System/SysRolePost.cs new file mode 100644 index 0000000..47fd843 --- /dev/null +++ b/ARW.Model/System/SysRolePost.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Text; +using SqlSugar; + +namespace ARW.Model.System +{ + /// + /// 角色部门 + /// + [SugarTable("sys_role_post")] + [Tenant("0")] + public class SysRolePost + { + public long RoleId { get; set; } + public long DeptId { get; set; } + } +} diff --git a/ARW.Model/System/SysTasksLog.cs b/ARW.Model/System/SysTasksLog.cs new file mode 100644 index 0000000..3e8bece --- /dev/null +++ b/ARW.Model/System/SysTasksLog.cs @@ -0,0 +1,54 @@ +using Newtonsoft.Json; +using OfficeOpenXml.Attributes; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Text; + +namespace ARW.Model.System +{ + /// + /// 任务日志 + /// + [SugarTable("sys_tasks_log")] + [Tenant("0")] + public class SysTasksLog + { + /// + /// 日志Id + /// + [JsonConverter(typeof(ValueToStringConverter))] + [SugarColumn(IsIdentity = true, IsPrimaryKey = true)] + public long JobLogId { get; set; } + /// + /// 任务Id + /// + public string JobId { get; set; } + public string JobName { get; set; } + public string JobGroup { get; set; } + /// + /// 执行状态(0正常 1失败) + /// + public string Status { get; set; } + /// + /// 异常 + /// + public string Exception { get; set; } + /// + /// + /// + public string JobMessage { get; set; } + /// + /// 调用目标字符串 + /// + public string InvokeTarget { get; set; } + + [EpplusTableColumn(NumberFormat = "yyyy-MM-dd HH:mm:ss")] + public DateTime CreateTime { get; set; } + /// + /// 执行用时,毫秒 + /// + //[SqlSugar.SugarColumn(IsIgnore = true)] + public double Elapsed { get; set; } + } +} diff --git a/ARW.Model/System/SysTasksQz.cs b/ARW.Model/System/SysTasksQz.cs new file mode 100644 index 0000000..6374782 --- /dev/null +++ b/ARW.Model/System/SysTasksQz.cs @@ -0,0 +1,170 @@ +using Newtonsoft.Json; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Text; + +namespace ARW.Model.System +{ + /// + ///计划任务 + /// + [SugarTable("sys_tasks")] + [Tenant("0")] + public class SysTasksQz + { + public SysTasksQz() + { + } + + /// + /// 描述 : UID + /// 空值 : False + /// 默认 : + /// + [Display(Name = "UID")] + [JsonConverter(typeof(ValueToStringConverter))] + [SugarColumn(IsPrimaryKey = true,IsIdentity =true)] + public int ID { get; set; } + + /// + /// 描述 : 任务名称 + /// 空值 : False + /// 默认 : + /// + [Display(Name = "任务名称")] + public string Name { get; set; } + + /// + /// 描述 : 任务分组 + /// 空值 : False + /// 默认 : + /// + [Display(Name = "任务分组")] + public string JobGroup { get; set; } + + /// + /// 描述 : 运行时间表达式 + /// 空值 : False + /// 默认 : + /// + [Display(Name = "运行时间表达式")] + public string Cron { get; set; } + + /// + /// 描述 : 程序集名称 + /// 空值 : False + /// 默认 : + /// + [Display(Name = "程序集名称")] + public string AssemblyName { get; set; } + + /// + /// 描述 : 任务所在类 + /// 空值 : False + /// 默认 : + /// + [Display(Name = "任务所在类")] + public string ClassName { get; set; } + + /// + /// 描述 : 任务描述 + /// 空值 : True + /// 默认 : + /// + [Display(Name = "任务描述")] + public string Remark { get; set; } + + /// + /// 描述 : 执行次数 + /// 空值 : False + /// 默认 : 0 + /// + [Display(Name = "执行次数")] + public int RunTimes { get; set; } + + /// + /// 描述 : 开始时间 + /// 空值 : True + /// 默认 : + /// + [Display(Name = "开始时间")] + public DateTime? BeginTime { get; set; } + + /// + /// 描述 : 结束时间 + /// 空值 : True + /// 默认 : + /// + [Display(Name = "结束时间")] + public DateTime? EndTime { get; set; } + + /// + /// 描述 : 触发器类型(0、simple 1、cron) + /// 空值 : False + /// 默认 : 1 + /// + [Display(Name = "触发器类型(0、simple 1、cron)")] + public int TriggerType { get; set; } + + /// + /// 描述 : 执行间隔时间(单位:秒) + /// 空值 : False + /// 默认 : 0 + /// + [Display(Name = "执行间隔时间(单位:秒)")] + public int IntervalSecond { get; set; } + + /// + /// 描述 : 是否启动 + /// 空值 : False + /// 默认 : 0 + /// + [Display(Name = "是否启动")] + public bool IsStart { get; set; } + + /// + /// 描述 : 传入参数 + /// 空值 : True + /// 默认 : + /// + [Display(Name = "传入参数")] + public string JobParams { get; set; } + + [SugarColumn(IsOnlyIgnoreUpdate = true)]//设置后修改不会有此字段 + [JsonProperty(propertyName: "CreateBy")] + public string Create_by { get; set; } + + /// + /// 描述 : 创建时间 + /// 空值 : False + /// 默认 : + /// + //[Display(Name = "创建时间")] + [SugarColumn(IsOnlyIgnoreUpdate = true)]//设置后修改不会有此字段 + [JsonProperty(propertyName: "CreateTime")] + public DateTime Create_time { get; set; } = DateTime.Now; + + [JsonIgnore] + [JsonProperty(propertyName: "UpdateBy")] + [SugarColumn(IsOnlyIgnoreInsert = true)] + public string Update_by { get; set; } + + [SugarColumn(IsOnlyIgnoreInsert = true)]//设置后插入数据不会有此字段 + [JsonProperty(propertyName: "UpdateTime")] + public DateTime Update_time { get; set; } = DateTime.Now; + /// + /// 最后运行时间 + /// + public DateTime? LastRunTime { get; set; } + /// + /// api执行地址 + /// + public string ApiUrl { get; set; } + /// + /// 任务类型 1程序集2网络请求 + /// + public int TaskType { get; set; } + } +} diff --git a/ARW.Model/System/SysUser.cs b/ARW.Model/System/SysUser.cs new file mode 100644 index 0000000..890016f --- /dev/null +++ b/ARW.Model/System/SysUser.cs @@ -0,0 +1,144 @@ +using Newtonsoft.Json; +using OfficeOpenXml.Attributes; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Text; + +namespace ARW.Model.System +{ + /// + /// 用户表 + /// + [SugarTable("sys_user")] + [Tenant("0")] + public class SysUser : SysBase + { + /// + /// 用户id + /// + [SugarColumn(IsIdentity = true, IsPrimaryKey = true)] + public long UserId { get; set; } + //[Duplication]//校验模板类该列数据是否重复 + public string UserName { get; set; } + public string NickName { get; set; } + /// + /// '用户类型(00系统用户)', + /// + //[JsonProperty(propertyName: "userType")] + //public string User_type { get; set; } = ""; + [SugarColumn(IsOnlyIgnoreInsert = true)] + [EpplusIgnore] + public string Avatar { get; set; } + public string Email { get; set; } + + //[JsonIgnore] + [EpplusIgnore] + public string Password { get; set; } + /// + /// 手机号 + /// + public string Phonenumber { get; set; } + /// + /// 用户性别(0男 1女 2未知) + /// + public string Sex { get; set; } + + /// + /// 帐号状态(0正常 1停用) + /// + [EpplusIgnore] + public string Status { get; set; } + + /// + /// 删除标志(0代表存在 2代表删除) + /// + [SugarColumn(IsOnlyIgnoreInsert = true)] + public string DelFlag { get; set; } + + /// + /// 最后登录IP + /// + [SugarColumn(IsOnlyIgnoreInsert = true)] + public string LoginIP { get; set; } + + /// + /// 最后登录时间 + /// + [SugarColumn(IsOnlyIgnoreInsert = true)] + [EpplusTableColumn(NumberFormat = "yyyy-MM-dd HH:mm:ss")] + public DateTime LoginDate { get; set; } + + /// + /// 部门Id + /// + public long DeptId { get; set; } + + #region 表额外字段 + public bool IsAdmin() + { + return IsAdmin(UserId); + } + public static bool IsAdmin(long userId) + { + return 1 == userId; + } + + /// + /// 拥有角色个数 + /// + //[SugarColumn(IsIgnore = true)] + //public int RoleNum { get; set; } + [SugarColumn(IsIgnore = true)] + public string DeptName { get; set; } + /// + /// 角色id集合 + /// + [SugarColumn(IsIgnore = true)] + [EpplusIgnore] + public long[] RoleIds { get; set; } + /// + /// 岗位集合 + /// + [SugarColumn(IsIgnore = true)] + [EpplusIgnore] + public int[] PostIds { get; set; } + + [SugarColumn(IsIgnore = true)] + [EpplusIgnore] + public List Roles { get; set; } + [SugarColumn(IsIgnore = true)] + public string WelcomeMessage + { + get + { + int now = DateTime.Now.Hour; + + if (now > 0 && now <= 6) + { + return "午夜好"; + } + else if (now > 6 && now <= 11) + { + return "早上好"; + } + else if (now > 11 && now <= 14) + { + return "中午好"; + } + else if (now > 14 && now <= 18) + { + return "下午好"; + } + else + { + return "晚上好"; + } + } + } + [SugarColumn(IsIgnore = true)] + public string WelcomeContent { get; set; } + + #endregion + } +} diff --git a/ARW.Model/System/SysUserPost.cs b/ARW.Model/System/SysUserPost.cs new file mode 100644 index 0000000..7ec3b59 --- /dev/null +++ b/ARW.Model/System/SysUserPost.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; +using SqlSugar; + +namespace ARW.Model.System +{ + + /// + /// 用户岗位 + /// + [SugarTable("sys_user_post")] + [Tenant("0")] + public class SysUserPost + { + public long UserId { get; set; } + public long PostId { get; set; } + } +} diff --git a/ARW.Model/System/SysUserRole.cs b/ARW.Model/System/SysUserRole.cs new file mode 100644 index 0000000..eb80472 --- /dev/null +++ b/ARW.Model/System/SysUserRole.cs @@ -0,0 +1,21 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Text; + +namespace ARW.Model.System +{ + /// + /// 用户角色关联表 用户N-1 角色 + /// + [SqlSugar.SugarTable("sys_user_role")] + [Tenant("0")] + public class SysUserRole + { + [SqlSugar.SugarColumn(ColumnName = "user_id", IsPrimaryKey = true)] + public long UserId { get; set; } + + [SqlSugar.SugarColumn(ColumnName = "role_id", IsPrimaryKey = true)] + public long RoleId { get; set; } + } +} diff --git a/ARW.Model/System/UserConstants.cs b/ARW.Model/System/UserConstants.cs new file mode 100644 index 0000000..ead0d74 --- /dev/null +++ b/ARW.Model/System/UserConstants.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ARW.Model.System +{ + public class UserConstants + { + /** + * 平台内系统用户的唯一标志 + */ + public static string SYS_USER = "SYS_USER"; + + /** 正常状态 */ + public static string NORMAL = "0"; + + /** 异常状态 */ + public static string EXCEPTION = "1"; + + /** 用户封禁状态 */ + public static string USER_DISABLE = "1"; + + /** 角色封禁状态 */ + public static string ROLE_DISABLE = "1"; + + /** 部门正常状态 */ + public static string DEPT_NORMAL = "0"; + + /** 部门停用状态 */ + public static string DEPT_DISABLE = "1"; + + /** 字典正常状态 */ + public static string DICT_NORMAL = "0"; + + /** 是否为系统默认(是) */ + public static string YES = "Y"; + + /** 是否菜单外链(是) */ + public static string YES_FRAME = "1"; + + /** 是否菜单外链(否) */ + public static string NO_FRAME = "0"; + + /** 菜单类型(目录) */ + public static string TYPE_DIR = "M"; + + /** 菜单类型(菜单) */ + public static string TYPE_MENU = "C"; + + /** 菜单类型(按钮) */ + public static string TYPE_BUTTON = "F"; + /** 菜单类型(链接) */ + //public static string TYPE_ARWNK = "L"; + + /** Layout组件标识 */ + public static string LAYOUT = "Layout"; + /** ParentView组件标识 */ + public static string PARENT_VIEW = "ParentView"; + /** InnerLink组件标识 */ + public static string INNER_ARWNK = "InnerLink"; + /** 校验返回结果码 */ + public static string UNIQUE = "0"; + public static string NOT_UNIQUE = "1"; + + /// + /// http请求 + /// + public static string HTTP = "http://"; + + /// + /// https请求 + /// + public static string HTTPS = "https://"; + } +} diff --git a/ARW.Model/System/Vo/LangVo.cs b/ARW.Model/System/Vo/LangVo.cs new file mode 100644 index 0000000..2479012 --- /dev/null +++ b/ARW.Model/System/Vo/LangVo.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ARW.Model.System.Vo +{ + public class LangVo + { + + } +} diff --git a/ARW.Model/System/Vo/RouterVo.cs b/ARW.Model/System/Vo/RouterVo.cs new file mode 100644 index 0000000..4bb9441 --- /dev/null +++ b/ARW.Model/System/Vo/RouterVo.cs @@ -0,0 +1,70 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Text; + +namespace ARW.Model.System.Vo +{ + /// + /// 路由展示 + /// + public class RouterVo + { + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public bool AlwaysShow { get; set; } + private string component; + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public bool Hidden { get; set; } + public string Name { get; set; } + public string Path { get; set; } + public string Redirect { get; set; } + public Meta Meta { get; set; } + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public List Children { get; set; } + public string Component { get => component; set => component = value; } + } + + public class Meta + { + /// + /// 设置该路由在侧边栏和面包屑中展示的名字 + /// + public string Title { get; set; } + /// + /// 设置该路由的图标,对应路径src/assets/icons/svg + /// + public string Icon { get; set; } + /// + /// 设置为true,则不会被 缓存 + /// + public bool NoCache { get; set; } + public string TitleKey { get; set; } = string.Empty; + public string Link { get; set; } = string.Empty; + + public Meta(string title, string icon) + { + Title = title; + Icon = icon; + } + public Meta(string title, string icon, string path) + { + Title = title; + Icon = icon; + Link = path; + } + public Meta(string title, string icon, bool noCache) + { + Title = title; + Icon = icon; + NoCache = noCache; + } + public Meta(string title, string icon, bool noCache, string titleKey, string path) + { + Title = title; + Icon = icon; + NoCache = noCache; + TitleKey = titleKey; + Link = path; + } + } +} diff --git a/ARW.Model/System/Vo/TreeSelectVo.cs b/ARW.Model/System/Vo/TreeSelectVo.cs new file mode 100644 index 0000000..75234c2 --- /dev/null +++ b/ARW.Model/System/Vo/TreeSelectVo.cs @@ -0,0 +1,58 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Text; +using ARW.Model.System; + +namespace ARW.Model.System.Vo +{ + /// + /// Treeselect树结构实体类 + /// + public class TreeSelectVo + { + /// + /// 节点Id + /// + public long Id { get; set; } + /// + /// 节点名称 + /// + public string Label { get; set; } + + public TreeSelectVo() { } + + public TreeSelectVo(SysMenu menu) + { + Id = menu.MenuId; + Label = menu.MenuName; + + //menu.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList()); java写法 + List child = new List(); + foreach (var item in menu.children) + { + child.Add(new TreeSelectVo(item)); + } + + Children = child; + } + + public TreeSelectVo(SysDept dept) + { + Id = dept.DeptId; + Label = dept.DeptName; + + //menu.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList()); java写法 + List child = new List(); + foreach (var item in dept.children) + { + child.Add(new TreeSelectVo(item)); + } + + Children = child; + } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public List Children { get; set; } + } +} diff --git a/ARW.Model/Vo/Business/Crawler/CrawlVo.cs b/ARW.Model/Vo/Business/Crawler/CrawlVo.cs new file mode 100644 index 0000000..cfaeab6 --- /dev/null +++ b/ARW.Model/Vo/Business/Crawler/CrawlVo.cs @@ -0,0 +1,51 @@ +using Newtonsoft.Json; +using OfficeOpenXml.Attributes; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ARW.Model.Models.Business; +using ARW.Model.Models.Business.Crawler; +using Newtonsoft.Json.Linq; + +namespace ARW.Model.Vo.Crawler +{ + public class CrawlVo + { + public long Id { get; set; } + + public string Name { get; set; } + + public string Intro { get; set; } + + public string Cover { get; set; } + + public string Link { get; set; } + + public string Type { get; set; } + + public DateTime PublishTime { get; set; } + + [JsonIgnore] + public List DownResources { get; set; } + + public string Resources + { + get + { + if (this.DownResources != null) + { + return JToken.FromObject(this.DownResources).ToString(); + } + else + { + return "[]"; + } + + } + } + } + +} diff --git a/ARW.Model/Vo/Business/Customers/CustomerVo.cs b/ARW.Model/Vo/Business/Customers/CustomerVo.cs new file mode 100644 index 0000000..ba94d75 --- /dev/null +++ b/ARW.Model/Vo/Business/Customers/CustomerVo.cs @@ -0,0 +1,42 @@ +using Newtonsoft.Json; +using OfficeOpenXml.Attributes; +using SqlSugar; + +namespace ARW.Model.Vo.Business.Customers +{ + /// + /// 小程序客户展示对象 + /// + public class CustomerVo + { + + [EpplusIgnore] + [EpplusTableColumn(Header = "CustomerId")] + public int CustomerId { get; set; } + + [EpplusIgnore] + [JsonConverter(typeof(ValueToStringConverter))] + [EpplusTableColumn(Header = "CustomerGuid")] + public long CustomerGuid { get; set; } + [EpplusTableColumn(Header = "客户姓名")] + public string CustomerName { get; set; } + + [EpplusTableColumn(Header = "客户生日")] + public string CustomerBrithday { get; set; } + + [EpplusTableColumn(Header = "客户性别")] + public int? CustomerSex { get; set; } + + [EpplusTableColumn(Header = "客户图片")] + public string CustomerImg { get; set; } + + [EpplusTableColumn(Header = "客户电话")] + public string CustomerPhone { get; set; } + [EpplusTableColumn(Header = "小程序openid")] + public string CustomerXcxOpenid { get; set; } + [EpplusTableColumn(Header = "小程序名称")] + public string CustomerXcxName { get; set; } + [EpplusTableColumn(Header = "小程序头像")] + public string CustomerXcxImg { get; set; } + } +} diff --git a/ARW.Model/Vo/Business/Payments/PaymentVo.cs b/ARW.Model/Vo/Business/Payments/PaymentVo.cs new file mode 100644 index 0000000..2250cad --- /dev/null +++ b/ARW.Model/Vo/Business/Payments/PaymentVo.cs @@ -0,0 +1,34 @@ +using Newtonsoft.Json; +using OfficeOpenXml.Attributes; +using SqlSugar; + +namespace ARW.Model.Vo.Business.Payments +{ + /// + /// 支付订单展示对象 + /// + public class PaymentVo + { + + [EpplusIgnore] + [EpplusTableColumn(Header = "PaymentId")] + public int PaymentId { get; set; } + + [EpplusIgnore] + [JsonConverter(typeof(ValueToStringConverter))] + [EpplusTableColumn(Header = "支付订单guid")] + public long PaymentGuid { get; set; } + [EpplusTableColumn(Header = "操作状态(1待支付 |2已支付 | 3已取消 | 4已退款)")] + public int PaymentStatus { get; set; } + [EpplusTableColumn(Header = "核销后价格/操作金额")] + public decimal PaymentMoney { get; set; } + [EpplusTableColumn(Header = "系统订单号")] + public string PaymentNumber { get; set; } + [EpplusTableColumn(Header = "操作客户guid(外键)")] + public long? CustomerGuid { get; set; } + [EpplusTableColumn(Header = "业务订单guid(外键)")] + public long? PaymentBusinessGuid { get; set; } + [EpplusTableColumn(Header = "购买类型(1| )")] + public int PaymentBuytype { get; set; } + } +} diff --git a/ARW.Model/Vo/Business/SubscribeTasks/SubscribeTaskVo.cs b/ARW.Model/Vo/Business/SubscribeTasks/SubscribeTaskVo.cs new file mode 100644 index 0000000..467487f --- /dev/null +++ b/ARW.Model/Vo/Business/SubscribeTasks/SubscribeTaskVo.cs @@ -0,0 +1,27 @@ +using Newtonsoft.Json; +using OfficeOpenXml.Attributes; +using SqlSugar; +using System; + +namespace ARW.Model.Vo.Business.SubscribeTasks +{ + /// + /// 订阅推送任务展示对象 + /// + public class SubscribeTaskVo + { + + [EpplusIgnore] + public int SubscribeTaskId { get; set; } + + [EpplusIgnore] + [JsonConverter(typeof(ValueToStringConverter))] + public long SubscribeTaskGuid { get; set; } + public string OpenId { get; set; } + public DateTime EndTime { get; set; } + public int? SubscribeTaskType { get; set; } + public string TemplateId { get; set; } + public int? SubscribeTaskStatus { get; set; } + public string SubscribeTaskErrorMsg { get; set; } + } +} diff --git a/ARW.Repository/ARW.Repository.csproj b/ARW.Repository/ARW.Repository.csproj new file mode 100644 index 0000000..cda6fdc --- /dev/null +++ b/ARW.Repository/ARW.Repository.csproj @@ -0,0 +1,23 @@ + + + + net6.0 + ARW.Repository + ARW.Repository + + + + + + + + + + + + + + + + + diff --git a/ARW.Repository/BaseRepository.cs b/ARW.Repository/BaseRepository.cs new file mode 100644 index 0000000..69fc9b7 --- /dev/null +++ b/ARW.Repository/BaseRepository.cs @@ -0,0 +1,416 @@ +using SqlSugar; +using SqlSugar.IOC; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq.Expressions; +using System.Reflection; +using ARW.Model; +using ARW.Model.Models.Business.Crawler; +using System.Threading.Tasks; + +namespace ARW.Repository +{ + /// + /// + /// + /// + public class BaseRepository : SimpleClient where T : class, new() + { + public ITenant itenant = null;//多租户事务 + public BaseRepository(ISqlSugarClient context = null) : base(context) + { + //通过特性拿到ConfigId + var configId = typeof(T).GetCustomAttribute()?.configId; + if (configId != null) + { + Context = DbScoped.SugarScope.GetConnectionScope(configId);//根据类传入的ConfigId自动选择 + } + else + { + Context = context ?? DbScoped.SugarScope.GetConnectionScope(0);//没有默认db0 + } + //Context = DbScoped.SugarScope.GetConnectionScopeWithAttr(); + itenant = DbScoped.SugarScope;//设置租户接口 + } + + #region add + + /// + /// 插入实体 + /// + /// + /// + public int Add(T t) + { + return Context.Insertable(t).IgnoreColumns(true).ExecuteCommand(); + } + + public int Insert(List t) + { + return Context.Insertable(t).ExecuteCommand(); + } + public int Insert(T parm, Expression> iClumns = null, bool ignoreNull = true) + { + return Context.Insertable(parm).InsertColumns(iClumns).IgnoreColumns(ignoreNullColumn: ignoreNull).ExecuteCommand(); + } + public IInsertable Insertable(T t) + { + return Context.Insertable(t); + } + #endregion add + + #region update + public IUpdateable Updateable(T entity) + { + return Context.Updateable(entity); + } + public int Update(T entity, bool ignoreNullColumns = false) + { + return Context.Updateable(entity).IgnoreColumns(ignoreNullColumns).ExecuteCommand(); + } + + public int Update(T entity, Expression> expression, bool ignoreAllNull = false) + { + return Context.Updateable(entity).UpdateColumns(expression).IgnoreColumns(ignoreAllNull).ExecuteCommand(); + } + + /// + /// 根据实体类更新指定列 eg:Update(dept, it => new { it.Status }, f => depts.Contains(f.DeptId));只更新Status列,条件是包含 + /// + /// + /// + /// + /// + public int Update(T entity, Expression> expression, Expression> where) + { + return Context.Updateable(entity).UpdateColumns(expression).Where(where).ExecuteCommand(); + } + + public int Update(SqlSugarClient client, T entity, Expression> expression, Expression> where) + { + return client.Updateable(entity).UpdateColumns(expression).Where(where).ExecuteCommand(); + } + + /// + /// + /// + /// + /// + /// 默认为true + /// + public int Update(T entity, List list = null, bool isNull = true) + { + if (list == null) + { + list = new List() + { + "Create_By", + "Create_time" + }; + } + return Context.Updateable(entity).IgnoreColumns(isNull).IgnoreColumns(list.ToArray()).ExecuteCommand(); + } + + //public bool Update(List entity) + //{ + // var result = base.Context.Ado.UseTran(() => + // { + // base.Context.Updateable(entity).ExecuteCommand(); + // }); + // return result.IsSuccess; + //} + + /// + /// 更新指定列 eg:Update(w => w.NoticeId == model.NoticeId, it => new SysNotice(){ Update_time = DateTime.Now, Title = "通知标题" }); + /// + /// + /// + /// + public int Update(Expression> where, Expression> columns) + { + return Context.Updateable().SetColumns(columns).Where(where).RemoveDataCache().ExecuteCommand(); + } + #endregion update + + public DbResult UseTran(Action action) + { + try + { + var result = Context.Ado.UseTran(() => action()); + return result; + } + catch (Exception ex) + { + Context.Ado.RollbackTran(); + Console.WriteLine(ex.Message); + throw; + } + } + + + public async Task> UseTranAsync(Func action) + { + try + { + var result = await Context.Ado.UseTranAsync(() => action()); + return result; + } + catch (Exception ex) + { + Context.Ado.RollbackTran(); + Console.WriteLine(ex.Message); + throw; + } + } + + + //public bool UseTran3(Action action) + //{ + // try + // { + // Context.Ado.BeginTran();//老版本用Context.Ado.BeginTran()新版本用了MySqlConnector必须要用异步事务 + + // action(); + // Context.Ado.CommitTran(); + // return true; + // } + // catch (Exception) + // { + // Context.Ado.RollbackTran(); + // } + // return false; + //} + + public IStorageable Storageable(T t) + { + return Context.Storageable(t); + } + public IStorageable Storageable(List t) + { + return Context.Storageable(t); + } + /// + /// + /// + /// + /// 增删改查方法 + /// + public DbResult UseTran(SqlSugarClient client, Action action) + { + try + { + var result = client.AsTenant().UseTran(() => action()); + return result; + } + catch (Exception ex) + { + client.AsTenant().RollbackTran(); + Console.WriteLine(ex.Message); + throw; + } + } + + public bool UseTran2(Action action) + { + var result = Context.Ado.UseTran(() => action()); + return result.IsSuccess; + } + + #region delete + public IDeleteable Deleteable() + { + return Context.Deleteable(); + } + + /// + /// 批量删除 + /// + /// + /// + public int Delete(object[] obj) + { + return Context.Deleteable().In(obj).ExecuteCommand(); + } + public int Delete(object id) + { + return Context.Deleteable(id).IsLogic().ExecuteCommand(); + } + public int DeleteTable() + { + return Context.Deleteable().ExecuteCommand(); + } + + #endregion delete + + #region query + + public bool Any(Expression> expression) + { + return Context.Queryable().Where(expression).Any(); + } + + public ISugarQueryable Queryable() + { + return Context.Queryable(); + } + + public (List, int) QueryableToPage(Expression> expression, int pageIndex = 0, int pageSize = 10) + { + int totalNumber = 0; + var list = Context.Queryable().Where(expression).ToPageList(pageIndex, pageSize, ref totalNumber); + return (list, totalNumber); + } + + public (List, int) QueryableToPage(Expression> expression, string order, int pageIndex = 0, int pageSize = 10) + { + int totalNumber = 0; + var list = Context.Queryable().Where(expression).OrderBy(order).ToPageList(pageIndex, pageSize, ref totalNumber); + return (list, totalNumber); + } + + public (List, int) QueryableToPage(Expression> expression, Expression> orderFiled, string orderBy, int pageIndex = 0, int pageSize = 10) + { + int totalNumber = 0; + + if (orderBy.Equals("DESC", StringComparison.OrdinalIgnoreCase)) + { + var list = Context.Queryable().Where(expression).OrderBy(orderFiled, OrderByType.Desc).ToPageList(pageIndex, pageSize, ref totalNumber); + return (list, totalNumber); + } + else + { + var list = Context.Queryable().Where(expression).OrderBy(orderFiled, OrderByType.Asc).ToPageList(pageIndex, pageSize, ref totalNumber); + return (list, totalNumber); + } + } + + public List SqlQueryToList(string sql, object obj = null) + { + return Context.Ado.SqlQuery(sql, obj); + } + + /// + /// 根据主值查询单条数据 + /// + /// 主键值 + /// 泛型实体 + public T GetId(object pkValue) + { + return Context.Queryable().InSingle(pkValue); + } + /// + /// 根据条件查询分页数据 + /// + /// + /// + /// + public PagedInfo GetPages(Expression> where, PagerInfo parm) + { + var source = Context.Queryable().Where(where); + + return source.ToPage(parm); + } + + public PagedInfo GetPages(Expression> where, PagerInfo parm, Expression> order, OrderByType orderEnum = OrderByType.Asc) + { + var source = Context.Queryable().Where(where).OrderByIF(orderEnum == OrderByType.Asc, order, OrderByType.Asc).OrderByIF(orderEnum == OrderByType.Desc, order, OrderByType.Desc); + + return source.ToPage(parm); + } + + public PagedInfo GetPages(Expression> where, PagerInfo parm, Expression> order, string orderByType) + { + return GetPages(where, parm, order, orderByType == "desc" ? OrderByType.Desc : OrderByType.Asc); + } + + /// + /// 查询所有数据(无分页,请慎用) + /// + /// + public List GetAll(bool useCache = false, int cacheSecond = 3600) + { + return Context.Queryable().WithCacheIF(useCache, cacheSecond).ToList(); + } + + #endregion query + + /// + /// 此方法不带output返回值 + /// var list = new List(); + /// list.Add(new SugarParameter(ParaName, ParaValue)); input + /// + /// + /// + /// + public DataTable UseStoredProcedureToDataTable(string procedureName, List parameters) + { + return Context.Ado.UseStoredProcedure().GetDataTable(procedureName, parameters); + } + + /// + /// 带output返回值 + /// var list = new List(); + /// list.Add(new SugarParameter(ParaName, ParaValue, true)); output + /// list.Add(new SugarParameter(ParaName, ParaValue)); input + /// + /// + /// + /// + public (DataTable, List) UseStoredProcedureToTuple(string procedureName, List parameters) + { + var result = (Context.Ado.UseStoredProcedure().GetDataTable(procedureName, parameters), parameters); + return result; + } + } + + /// + /// 分页查询扩展 + /// + public static class QueryableExtension + { + /// + /// 读取列表 + /// + /// + /// 查询表单式 + /// 分页参数 + /// + public static PagedInfo ToPage(this ISugarQueryable source, PagerInfo parm) + { + var page = new PagedInfo(); + var total = 0; + page.PageSize = parm.PageSize; + page.PageIndex = parm.PageNum; + + page.Result = source.OrderByIF(!string.IsNullOrEmpty(parm.Sort), $"{parm.Sort} {(parm.SortType.Contains("desc") ? "desc" : "asc")}") + .ToPageList(parm.PageNum, parm.PageSize, ref total); + page.TotalNum = total; + return page; + } + + /// + /// 读取列表(异步) + /// + /// + /// 查询表单式 + /// 分页参数 + /// + public static async Task> ToPageAsync(this ISugarQueryable source, PagerInfo parm) + { + var page = new PagedInfo(); + var total = 0; + page.PageSize = parm.PageSize; + page.PageIndex = parm.PageNum; + + page.Result = await source.OrderByIF(!string.IsNullOrEmpty(parm.Sort), $"{parm.Sort} {(parm.SortType.Contains("desc") ? "desc" : "asc")}") + .ToPageListAsync(parm.PageNum, parm.PageSize); + page.TotalNum = total; + return page; + } + + } + + + +} diff --git a/ARW.Repository/Business/Crawler/CrawlRepository.cs b/ARW.Repository/Business/Crawler/CrawlRepository.cs new file mode 100644 index 0000000..58fa0b3 --- /dev/null +++ b/ARW.Repository/Business/Crawler/CrawlRepository.cs @@ -0,0 +1,143 @@ +using Infrastructure.Attribute; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ARW.Model.Models.Business.Crawler; +using AngleSharp.Html.Parser; +using RestSharp; + +namespace ARW.Repository.Business +{ + /// + /// 爬虫仓储服务 + /// + [AppService(ServiceLifetime = LifeTime.Transient)] + public class CrawlRepository : BaseRepository + { + protected static HtmlParser htmlParser = new HtmlParser(); + + + // 不羞涩 + public string LoadBuxiuseHTML(string url) + { + try + { + var client = new RestClient(url); + var request = new RestRequest("https://www.buxiuse.com/", Method.Get); + request.AddHeader("cookie", "SESSION=YmNhNjgxNTctNzk3MS00YTVkLThmM2YtMDBjYzhjZDNiNzNm; Hm_lvt_479b5d690f3b5d1eae450ce953f78480=1660291808,1660530399; Hm_lpvt_479b5d690f3b5d1eae450ce953f78480=1660530399"); + request.AddHeader("accept-encoding", "gzip, deflate, br"); + request.AddHeader("accept", "application/json, text/javascript, */*; q=0.01"); + request.AddHeader("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36"); + request.AddHeader("upgrade-insecure-requests", "1"); + request.AddHeader("referer", "https://www.buxiuse.com/"); + request.AddHeader("cache-control", "max-age=0,no-cache"); + request.AddHeader("authority", "www.buxiuse.com"); + RestResponse response = client.Execute(request); + return response.IsSuccessful ? response.Content : ""; + + } + catch (Exception ex) + { + Console.WriteLine($"LoadHTML fail,url:{url},ex:{ex.ToString()}"); + + return string.Empty; + } + } + public int ParseBuxiusePic(string html) + { + var dom = htmlParser.ParseDocument(html); + var movies = new List(); + var lis = dom.QuerySelectorAll(".panel-body li"); + foreach (var li in lis) + { + + var onlineURL = "https://www.buxiuse.com" + li.QuerySelector("a").GetAttribute("href"); + var movie = new Crawl() + { + Name = li.QuerySelector("img").GetAttribute("title"), + Cover = li.QuerySelector("img").GetAttribute("src"), + Link = onlineURL, + Type = "图片", + PublishTime = DateTime.Now, + }; + //Context.Insertable(movie).ExecuteReturnIdentity(); + Add(movie); + movies.Add(movie); + } + + if (movies.Count == 0) + return 0; + else + return 1; + } + + + // Yellow + public string LoadYellowHTML(string url) + { + try + { + var client = new RestClient(url); + var request = new RestRequest(url, Method.Get); + request.AddHeader("cookie", "Hm_lvt_07f2c7e5bd9592209d606f0184fc3d8f=1660568257; recente=%5B%7B%22vod_name%22%3A%22%E5%9B%BD%E4%BA%A7AV%E5%89%A7%E6%83%85-%E4%B8%88%E5%A4%AB%E7%9A%84%22%2C%22vod_url%22%3A%22https%3A%2F%2Frra5ii1x6k3in.com%3A58002%2Findex.php%2Fvod%2Fplay%2Fid%2F138577%2Fsid%2F1%2Fnid%2F1.html%22%2C%22vod_part%22%3A%22%E7%AC%AC1%E9%9B%86%22%7D%5D; Hm_lvt_36ab7abfe863c7133f2af34068ebfc82=1660568383; Hm_lpvt_36ab7abfe863c7133f2af34068ebfc82=1660568383; Hm_lpvt_07f2c7e5bd9592209d606f0184fc3d8f=1660570678"); + request.AddHeader("accept-encoding", "gzip, deflate, br"); + request.AddHeader("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"); + request.AddHeader("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36"); + request.AddHeader("upgrade-insecure-requests", "1"); + request.AddHeader("referer", url); + request.AddHeader("cache-control", "max-age=0"); + RestResponse response = client.Execute(request); + return response.IsSuccessful ? response.Content : ""; + } + catch (Exception ex) + { + Console.WriteLine($"LoadHTML fail,url:{url},ex:{ex.ToString()}"); + + return string.Empty; + } + } + public int ParseYellowPic(string html) + { + var dom = htmlParser.ParseDocument(html); + var movies = new List(); + var lis = dom.QuerySelectorAll(".stui-pannel_bd")?.SelectMany(div => div.QuerySelectorAll("li")); + foreach (var li in lis) + { + var onlineURL = "https://x4dgjgj002d5c.com:58002/" + li.QuerySelector("a").GetAttribute("href"); + var name = li.QuerySelector("a").GetAttribute("title"); + + string[] arr = { "福利姬","swag","丝" ,"jk","可爱","制服","网红"}; + + foreach (var item in arr) + { + if (name.Contains(item) == true) + { + var movie = new Crawl() + { + Name = name, + Link = onlineURL, + Type = "Yellow", + Cover = li.QuerySelector("a").GetAttribute("data-original"), + }; + Add(movie); + movies.Add(movie); + } + else + { + continue; + } + } + + } + + if (movies.Count == 0) + return 0; + else + return 1; + } + + + } +} diff --git a/ARW.Repository/Business/Customers/CustomerRepository.cs b/ARW.Repository/Business/Customers/CustomerRepository.cs new file mode 100644 index 0000000..8534664 --- /dev/null +++ b/ARW.Repository/Business/Customers/CustomerRepository.cs @@ -0,0 +1,20 @@ +using System; +using Infrastructure.Attribute; +using ARW.Repository.System; +using ARW.Model.Models.Business.Customers; + +namespace ARW.Repository.Business.Customers +{ + /// + /// 小程序客户仓储 + /// + /// @author admin + /// @date 2022-12-06 + /// + [AppService(ServiceLifetime = LifeTime.Transient)] + public class CustomerRepository : BaseRepository + { + #region 业务逻辑代码 + #endregion + } +} \ No newline at end of file diff --git a/ARW.Repository/Business/Payments/PaymentRepository.cs b/ARW.Repository/Business/Payments/PaymentRepository.cs new file mode 100644 index 0000000..e407a75 --- /dev/null +++ b/ARW.Repository/Business/Payments/PaymentRepository.cs @@ -0,0 +1,20 @@ +using System; +using Infrastructure.Attribute; +using ARW.Repository.System; +using ARW.Model.Models.Business.Payments; + +namespace ARW.Repository.Business.Payments +{ + /// + /// 支付订单仓储 + /// + /// @author admin + /// @date 2022-12-15 + /// + [AppService(ServiceLifetime = LifeTime.Transient)] + public class PaymentRepository : BaseRepository + { + #region 业务逻辑代码 + #endregion + } +} \ No newline at end of file diff --git a/ARW.Repository/Business/SubscribeTasks/SubscribeTaskRepository.cs b/ARW.Repository/Business/SubscribeTasks/SubscribeTaskRepository.cs new file mode 100644 index 0000000..8ae0f35 --- /dev/null +++ b/ARW.Repository/Business/SubscribeTasks/SubscribeTaskRepository.cs @@ -0,0 +1,20 @@ +using System; +using Infrastructure.Attribute; +using ARW.Repository.System; +using ARW.Model.Models.Business.SubscribeTasks; + +namespace ARW.Repository.Business.SubscribeTasks +{ + /// + /// 订阅推送任务仓储 + /// + /// @author admin + /// @date 2022-12-21 + /// + [AppService(ServiceLifetime = LifeTime.Transient)] + public class SubscribeTaskRepository : BaseRepository + { + #region 业务逻辑代码 + #endregion + } +} \ No newline at end of file diff --git a/ARW.Repository/IBaseRepository.cs b/ARW.Repository/IBaseRepository.cs new file mode 100644 index 0000000..a8ccc88 --- /dev/null +++ b/ARW.Repository/IBaseRepository.cs @@ -0,0 +1,93 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq.Expressions; +using ARW.Model; + +namespace ARW.Repository +{ + public interface IBaseRepository : ISimpleClient where T : class, new() + { + #region add + int Add(T t); + + int Insert(List t); + int Insert(T parm, Expression> iClumns = null, bool ignoreNull = true); + + IInsertable Insertable(T t); + #endregion add + + #region update + IUpdateable Updateable(T entity); + int Update(T entity, bool ignoreNullColumns = false); + + /// + /// 只更新表达式的值 + /// + /// + /// + /// + int Update(T entity, Expression> expression, bool ignoreAllNull = false); + + int Update(T entity, Expression> expression, Expression> where); + + int Update(SqlSugarClient client, T entity, Expression> expression, Expression> where); + + int Update(Expression> where, Expression> columns); + + #endregion update + IStorageable Storageable(T t); + IStorageable Storageable(List t); + DbResult UseTran(Action action); + + DbResult UseTran(SqlSugarClient client, Action action); + + bool UseTran2(Action action); + + #region delete + IDeleteable Deleteable(); + int Delete(object[] obj); + int Delete(object id); + int DeleteTable(); + + #endregion delete + + #region query + /// + /// 根据条件查询分页数据 + /// + /// + /// + /// + PagedInfo GetPages(Expression> where, PagerInfo parm); + + PagedInfo GetPages(Expression> where, PagerInfo parm, Expression> order, OrderByType orderEnum = OrderByType.Asc); + PagedInfo GetPages(Expression> where, PagerInfo parm, Expression> order, string orderByType); + + bool Any(Expression> expression); + + ISugarQueryable Queryable(); + List GetAll(bool useCache = false, int cacheSecond = 3600); + + (List, int) QueryableToPage(Expression> expression, int pageIndex = 0, int pageSize = 10); + + (List, int) QueryableToPage(Expression> expression, string order, int pageIndex = 0, int pageSize = 10); + + (List, int) QueryableToPage(Expression> expression, Expression> orderFiled, string orderBy, int pageIndex = 0, int pageSize = 10); + + List SqlQueryToList(string sql, object obj = null); + + T GetId(object pkValue); + + #endregion query + + #region Procedure + + DataTable UseStoredProcedureToDataTable(string procedureName, List parameters); + + (DataTable, List) UseStoredProcedureToTuple(string procedureName, List parameters); + + #endregion Procedure + } +} diff --git a/ARW.Repository/System/CommonLangRepository.cs b/ARW.Repository/System/CommonLangRepository.cs new file mode 100644 index 0000000..435e6bf --- /dev/null +++ b/ARW.Repository/System/CommonLangRepository.cs @@ -0,0 +1,20 @@ +using System; +using Infrastructure.Attribute; +using ARW.Repository.System; +using ARW.Model.Models; + +namespace ARW.Repository +{ + /// + /// 多语言配置仓储 + /// + /// @author zr + /// @date 2022-05-06 + /// + [AppService(ServiceLifetime = LifeTime.Transient)] + public class CommonLangRepository : BaseRepository + { + #region 业务逻辑代码 + #endregion + } +} \ No newline at end of file diff --git a/ARW.Repository/System/GenTableRepository.cs b/ARW.Repository/System/GenTableRepository.cs new file mode 100644 index 0000000..f6020fb --- /dev/null +++ b/ARW.Repository/System/GenTableRepository.cs @@ -0,0 +1,91 @@ +using Infrastructure.Attribute; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ARW.Model.System.Generate; + +namespace ARW.Repository.System +{ + [AppService(ServiceLifetime = LifeTime.Transient)] + public class GenTableRepository : BaseRepository + { + + } + [AppService(ServiceLifetime = LifeTime.Transient)] + public class GenTableColumnRepository : BaseRepository + { + /// + /// 根据表id批量删除表字段 + /// + /// + /// + public int DeleteGenTableColumn(long[] tableId) + { + return Context.Deleteable().Where(f => tableId.Contains(f.TableId)).ExecuteCommand(); + } + + /// + /// 根据表名删除字段 + /// + /// + /// + public int DeleteGenTableColumnByTableName(string tableName) + { + return Context.Deleteable().Where(f => f.TableName == tableName).ExecuteCommand(); + } + + /// + /// 获取表所有字段 + /// + /// + /// + public List GenTableColumns(long tableId) + { + return Context.Queryable().Where(f => f.TableId == tableId).OrderBy(x => x.Sort,OrderByType.Asc).ToList(); + } + + /// + /// 插入表字段 + /// + /// + /// + public int InsertGenTableColumn(List tableColumn) + { + return Context.Insertable(tableColumn).IgnoreColumns(x => new { x.Remark }).ExecuteCommand(); + } + + /// + /// 批量更新表字段 + /// + /// + /// + public int UpdateGenTableColumn(List tableColumn) + { + return Context.Updateable(tableColumn) + .WhereColumns(it => new { it.ColumnId, it.TableId}) + .UpdateColumns(it => new + { + it.ColumnComment, + it.CsharpField, + it.CsharpType, + it.IsQuery, + it.IsEdit, + it.IsInsert, + it.IsList, + it.QueryType, + it.HtmlType, + it.IsRequired, + it.Sort, + it.Update_time, + it.DictType, + it.Update_by, + it.Remark, + it.IsSort + }) + .ExecuteCommand(); + } + } +} diff --git a/ARW.Repository/System/SysConfigRepository.cs b/ARW.Repository/System/SysConfigRepository.cs new file mode 100644 index 0000000..89af844 --- /dev/null +++ b/ARW.Repository/System/SysConfigRepository.cs @@ -0,0 +1,19 @@ +using System; +using Infrastructure.Attribute; +using ARW.Model.System; + +namespace ARW.Repository +{ + /// + /// 参数配置仓储接口的实现 + /// + /// @author zhaorui + /// @date 2021-09-29 + /// + [AppService(ServiceLifetime = LifeTime.Transient)] + public class SysConfigRepository : BaseRepository + { + #region 业务逻辑代码 + #endregion + } +} \ No newline at end of file diff --git a/ARW.Repository/System/SysDeptRepository.cs b/ARW.Repository/System/SysDeptRepository.cs new file mode 100644 index 0000000..438b52b --- /dev/null +++ b/ARW.Repository/System/SysDeptRepository.cs @@ -0,0 +1,48 @@ +using Infrastructure.Attribute; +using System.Collections.Generic; +using ARW.Model.System; + +namespace ARW.Repository.System +{ + /// + /// 部门管理 + /// + [AppService(ServiceLifetime = LifeTime.Transient)] + public class SysDeptRepository : BaseRepository + { + /// + /// + /// + /// + /// + public List SelectChildrenDeptById(long deptId) + { + string sql = "select * from sys_dept where find_in_set(@deptId, ancestors)"; + + return Context.SqlQueryable(sql).AddParameters(new { @deptId = deptId }).ToList(); + } + + public int UdateDeptChildren(List dept) + { + return Context.Updateable(dept).WhereColumns(f => new { f.DeptId }) + .UpdateColumns(it => new { it.Ancestors }).ExecuteCommand(); + } + } + + /// + /// 角色部门 + /// + [AppService(ServiceLifetime = LifeTime.Transient)] + public class SysRoleDeptRepository : BaseRepository + { + /// + /// 根据角色获取菜单id + /// + /// + /// + public List SelectRoleDeptByRoleId(long roleId) + { + return Context.Queryable().Where(it => it.RoleId == roleId).ToList(); + } + } +} diff --git a/ARW.Repository/System/SysDictDataRepository.cs b/ARW.Repository/System/SysDictDataRepository.cs new file mode 100644 index 0000000..0c5e3b6 --- /dev/null +++ b/ARW.Repository/System/SysDictDataRepository.cs @@ -0,0 +1,126 @@ +using Infrastructure.Attribute; +using Infrastructure.Model; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using ARW.Model; +using ARW.Model.System; + +namespace ARW.Repository.System +{ + /// + /// 字典数据 + /// + [AppService(ServiceLifetime = LifeTime.Transient)] + public class SysDictDataRepository : BaseRepository + { + /// + /// 字典类型数据搜索 + /// + /// + /// + /// + public PagedInfo SelectDictDataList(SysDictData dictData, PagerInfo pagerInfo) + { + var exp = Expressionable.Create(); + exp.AndIF(!string.IsNullOrEmpty(dictData.DictLabel), it => it.DictLabel.Contains(dictData.DictLabel)); + exp.AndIF(!string.IsNullOrEmpty(dictData.Status), it => it.Status == dictData.Status); + exp.AndIF(!string.IsNullOrEmpty(dictData.DictType), it => it.DictType == dictData.DictType); + return GetPages(exp.ToExpression(), pagerInfo); + } + + /// + /// 根据字典类型查询 + /// + /// + /// + public List SelectDictDataByType(string dictType) + { + return Context.Queryable().Where(f => f.Status == "0" && f.DictType == dictType) + .OrderBy(it => it.DictSort) + .ToList(); + } + + /// + /// 根据字典类型查询 + /// + /// + /// + public List SelectDictDataByTypes(string[] dictTypes) + { + return Context.Queryable().Where(f => f.Status == "0" && dictTypes.Contains(f.DictType)) + .OrderBy(it => it.DictSort) + .ToList(); + } + /// + /// 新增保存字典数据信息 + /// + /// + /// + public long InsertDictData(SysDictData dict) + { + var result = Context.Insertable(dict).ExecuteReturnBigIdentity(); + return result; + } + + /// + /// 修改数据 + /// + /// + /// + public long UpdateDictData(SysDictData dict) + { + return Context.Updateable() + .SetColumns(t => new SysDictData() + { + Remark = dict.Remark, + Update_time = DateTime.Now, + DictSort = dict.DictSort, + DictLabel = dict.DictLabel, + DictValue = dict.DictValue, + Status = dict.Status, + CssClass = dict.CssClass, + ListClass = dict.ListClass + }) + .Where(f => f.DictCode == dict.DictCode).ExecuteCommand(); + } + + /// + /// 批量删除字典数据信息 + /// + /// + /// + public int DeleteDictDataByIds(long[] dictCodes) + { + return Delete(dictCodes); + } + + /// + /// 同步修改字典类型 + /// + /// 旧字典类型 + /// 新字典类型 + /// + public int UpdateDictDataType(string old_dictType, string new_dictType) + { + //只更新DictType字段根据where条件 + return Context.Updateable() + .SetColumns(t => new SysDictData() { DictType = new_dictType }) + .Where(f => f.DictType == old_dictType) + .ExecuteCommand(); + } + + /// + /// 获取字典信息名称 + /// + /// + public string GetDictNameByName(string name, string value) + { + var dictData = Context.Queryable().Where(s => s.DictType == name).ToList(); + var res = dictData.Where(s => s.DictValue == value).First(); + return res.DictLabel; + } + + } +} diff --git a/ARW.Repository/System/SysDictRepository.cs b/ARW.Repository/System/SysDictRepository.cs new file mode 100644 index 0000000..7754291 --- /dev/null +++ b/ARW.Repository/System/SysDictRepository.cs @@ -0,0 +1,56 @@ +using Infrastructure.Attribute; +using SqlSugar; +using System.Collections.Generic; +using ARW.Model; +using ARW.Model.System; + +namespace ARW.Repository.System +{ + /// + /// 字典 + /// + [AppService(ServiceLifetime = LifeTime.Transient)] + public class SysDictRepository : BaseRepository + { + public List GetAll() + { + return Context.Queryable().ToList(); + } + + /// + /// 查询字段类型列表 + /// + /// 实体模型 + /// + public PagedInfo SelectDictTypeList(SysDictType dictType, PagerInfo pager) + { + var exp = Expressionable.Create(); + exp.AndIF(!string.IsNullOrEmpty(dictType.DictName), it => it.DictName.Contains(dictType.DictName)); + exp.AndIF(!string.IsNullOrEmpty(dictType.Status), it => it.Status == dictType.Status); + exp.AndIF(!string.IsNullOrEmpty(dictType.DictType), it => it.DictType.Contains(dictType.DictType)); + exp.AndIF(!string.IsNullOrEmpty(dictType.Type), it => it.Type.Equals(dictType.Type)); + + return GetPages(exp.ToExpression(), pager, f => f.DictId, OrderByType.Desc); + } + + /// + /// 批量删除 + /// + /// + /// + public int DeleteDictTypeByIds(long[] id) + { + return Context.Deleteable().In(id).ExecuteCommand(); + } + + /// + /// 修改 + /// + /// + /// + public int UpdateDictType(SysDictType dictType) + { + return Context.Updateable(dictType).IgnoreColumns(it => new { dictType.Create_by }).ExecuteCommand(); + } + } +} diff --git a/ARW.Repository/System/SysFileRepository.cs b/ARW.Repository/System/SysFileRepository.cs new file mode 100644 index 0000000..aa2eda1 --- /dev/null +++ b/ARW.Repository/System/SysFileRepository.cs @@ -0,0 +1,21 @@ +using System; +using Infrastructure.Attribute; +using ARW.Repository.System; +using ARW.Model.Models; +using ARW.Model.System; + +namespace ARW.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/ARW.Repository/System/SysLogininfoRepository.cs b/ARW.Repository/System/SysLogininfoRepository.cs new file mode 100644 index 0000000..c065a5b --- /dev/null +++ b/ARW.Repository/System/SysLogininfoRepository.cs @@ -0,0 +1,89 @@ +using Infrastructure.Attribute; +using Infrastructure.Extensions; +using System.Collections.Generic; +using ARW.Model; +using ARW.Model.System.Dto; +using ARW.Model.System; +using SqlSugar; + +namespace ARW.Repository.System +{ + [AppService(ServiceLifetime = LifeTime.Transient)] + public class SysLogininfoRepository : BaseRepository + { + /// + /// 查询登录日志 + /// + /// + /// + /// + public PagedInfo GetLoginLog(SysLogininfor logininfoDto, PagerInfo pager) + { + var exp = Expressionable.Create(); + exp.And(it => it.loginTime >= logininfoDto.BeginTime && it.loginTime <= logininfoDto.EndTime); + exp.AndIF(logininfoDto.ipaddr.IfNotEmpty(), f => f.ipaddr == logininfoDto.ipaddr); + exp.AndIF(logininfoDto.userName.IfNotEmpty(), f => f.userName.Contains(logininfoDto.userName)); + exp.AndIF(logininfoDto.status.IfNotEmpty(), f => f.status == logininfoDto.status); + var query = Context.Queryable() + .Where(exp.ToExpression()) + .OrderBy(it => it.infoId, OrderByType.Desc); + + return query.ToPage(pager); + } + + /// + /// 登录日志记录 + /// + /// + /// + public void AddLoginInfo(SysLogininfor sysLogininfor) + { + int result = Context.Insertable(sysLogininfor) + .ExecuteReturnIdentity(); + } + + /// + /// 清空登录日志 + /// + public void TruncateLogininfo() + { + string sql = "truncate table sys_logininfor"; + + Context.Ado.ExecuteCommand(sql); + } + + /// + /// 删除登录日志 + /// + /// + /// + public int DeleteLogininforByIds(long[] ids) + { + return Context.Deleteable().In(ids).ExecuteCommand(); + } + + /// + /// 登录 + /// + /// 登录实体 + /// + public SysUser Login(LoginBodyDto user) + { + return Context.Queryable().First(it => it.UserName == user.Username && it.Password == user.Password); + } + + /// + /// 修改登录信息 + /// + /// + /// + /// + public void UpdateLoginInfo(LoginBodyDto user, long userId) + { + var db = Context; + db.Updateable(new SysUser() { LoginIP = user.LoginIP, LoginDate = db.GetDate(), UserId = userId }) + .UpdateColumns(it => new { it.LoginIP, it.LoginDate }) + .ExecuteCommand(); + } + } +} diff --git a/ARW.Repository/System/SysMenuRepository.cs b/ARW.Repository/System/SysMenuRepository.cs new file mode 100644 index 0000000..66b5e1e --- /dev/null +++ b/ARW.Repository/System/SysMenuRepository.cs @@ -0,0 +1,198 @@ +using Infrastructure.Attribute; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using ARW.Model.System.Dto; +using ARW.Model.System; + +namespace ARW.Repository.System +{ + /// + /// 系统菜单 + /// + [AppService(ServiceLifetime = LifeTime.Transient)] + public class SysMenuRepository : BaseRepository + { + /// + /// 获取所有菜单(菜单管理) + /// + /// + public List SelectTreeMenuList(MenuQueryDto menu) + { + return Context.Queryable() + .WhereIF(!string.IsNullOrEmpty(menu.MenuName), it => it.MenuName.Contains(menu.MenuName)) + .WhereIF(!string.IsNullOrEmpty(menu.Visible), it => it.visible == menu.Visible) + .WhereIF(!string.IsNullOrEmpty(menu.Status), it => it.status == menu.Status) + .WhereIF(!string.IsNullOrEmpty(menu.MenuTypeIds), it => menu.MenuTypeIdArr.Contains(it.menuType)) + .OrderBy(it => new { it.parentId, it.orderNum }) + .ToTree(it => it.children, it => it.parentId, 0); + } + + /// + /// 根据用户查询系统菜单列表 + /// + /// + /// 用户角色集合 + /// + public List SelectTreeMenuListByRoles(MenuQueryDto menu, List roles) + { + var roleMenus = Context.Queryable() + .Where(r => roles.Contains(r.Role_id)) + .Select(f => f.Menu_id).Distinct().ToList(); + + return Context.Queryable() + .Where(c => roleMenus.Contains(c.MenuId)) + .WhereIF(!string.IsNullOrEmpty(menu.MenuName), (c) => c.MenuName.Contains(menu.MenuName)) + .WhereIF(!string.IsNullOrEmpty(menu.Visible), (c) => c.visible == menu.Visible) + .WhereIF(!string.IsNullOrEmpty(menu.Status), (c) => c.status == menu.Status) + .WhereIF(!string.IsNullOrEmpty(menu.MenuTypeIds), c => menu.MenuTypeIdArr.Contains(c.menuType)) + .OrderBy((c) => new { c.parentId, c.orderNum }) + .Select(c => c) + .ToTree(it => it.children, it => it.parentId, 0); + } + + /// + /// 获取所有菜单 + /// + /// + public List SelectMenuList(MenuQueryDto menu) + { + return Context.Queryable() + .WhereIF(!string.IsNullOrEmpty(menu.MenuName), it => it.MenuName.Contains(menu.MenuName)) + .WhereIF(!string.IsNullOrEmpty(menu.Visible), it => it.visible == menu.Visible) + .WhereIF(!string.IsNullOrEmpty(menu.Status), it => it.status == menu.Status) + .WhereIF(menu.ParentId != null, it => it.parentId == menu.ParentId) + .OrderBy(it => new { it.parentId, it.orderNum }) + .ToList(); + } + + /// + /// 根据用户查询系统菜单列表 + /// + /// + /// 用户角色集合 + /// + public List SelectMenuListByRoles(MenuQueryDto sysMenu, List roles) + { + var roleMenus = Context.Queryable() + .Where(r => roles.Contains(r.Role_id)); + + return Context.Queryable() + .InnerJoin(roleMenus, (c, j) => c.MenuId == j.Menu_id) + .Where((c, j) => c.status == "0") + .WhereIF(!string.IsNullOrEmpty(sysMenu.MenuName), (c, j) => c.MenuName.Contains(sysMenu.MenuName)) + .WhereIF(!string.IsNullOrEmpty(sysMenu.Visible), (c, j) => c.visible == sysMenu.Visible) + .OrderBy((c, j) => new { c.parentId, c.orderNum }) + .Select(c => c) + .ToList(); + } + + /// + /// 获取菜单详情 + /// + /// + /// + public SysMenu SelectMenuById(int menuId) + { + return Context.Queryable().Where(it => it.MenuId == menuId).Single(); + } + + /// + /// 添加菜单 + /// + /// + /// + public int AddMenu(SysMenu menu) + { + var Db = Context; + menu.Create_time = Db.GetDate(); + menu.MenuId = Db.Insertable(menu).ExecuteReturnIdentity(); + return 1; + } + + /// + /// 编辑菜单 + /// + /// + /// + public int EditMenu(SysMenu menu) + { + return Context.Updateable(menu).ExecuteCommand(); + } + + /// + /// 删除菜单 + /// + /// + /// + public int DeleteMenuById(int menuId) + { + return Context.Deleteable().Where(it => it.MenuId == menuId).ExecuteCommand(); + } + + /// + /// 菜单排序 + /// + /// 菜单Dto + /// + public int ChangeSortMenu(MenuDto menuDto) + { + var result = Context.Updateable(new SysMenu() { MenuId = menuDto.MenuId, orderNum = menuDto.orderNum }) + .UpdateColumns(it => new { it.orderNum }).ExecuteCommand(); + return result; + } + + /// + /// 查询菜单权限 + /// + /// + /// + public List SelectMenuPermsByUserId(long userId) + { + return Context.Queryable((m, rm, ur, r) => new JoinQueryInfos( + JoinType.Left, m.MenuId == rm.Menu_id, + JoinType.Left, rm.Role_id == ur.RoleId, + JoinType.Left, ur.RoleId == r.RoleId + )) + //.Distinct() + .Where((m, rm, ur, r) => m.status == "0" && r.Status == "0" && ur.UserId == userId) + .Select((m, rm, ur, r) => m).ToList(); + } + + /// + /// 校验菜单名称是否唯一 + /// + /// + /// + public SysMenu CheckMenuNameUnique(SysMenu menu) + { + return Context.Queryable() + .Where(it => it.MenuName == menu.MenuName && it.parentId == menu.parentId).Single(); + } + + /// + /// 是否存在菜单子节点 + /// + /// + /// + public int HasChildByMenuId(long menuId) + { + return Context.Queryable().Where(it => it.parentId == menuId).Count(); + } + + #region RoleMenu + + /// + /// 查询菜单使用数量 + /// + /// + /// + public int CheckMenuExistRole(long menuId) + { + return Context.Queryable().Where(it => it.Menu_id == menuId).Count(); + } + + #endregion + } +} diff --git a/ARW.Repository/System/SysNoticeRepository.cs b/ARW.Repository/System/SysNoticeRepository.cs new file mode 100644 index 0000000..ac991f2 --- /dev/null +++ b/ARW.Repository/System/SysNoticeRepository.cs @@ -0,0 +1,21 @@ +using System; +using Infrastructure.Attribute; +using ARW.Repository.System; +using ARW.Model.Models; +using ARW.Model.System; + +namespace ARW.Repository.System +{ + /// + /// 通知公告表仓储 + /// + /// @author zr + /// @date 2021-12-15 + /// + [AppService(ServiceLifetime = LifeTime.Transient)] + public class SysNoticeRepository : BaseRepository + { + #region 业务逻辑代码 + #endregion + } +} \ No newline at end of file diff --git a/ARW.Repository/System/SysOperLogRepository.cs b/ARW.Repository/System/SysOperLogRepository.cs new file mode 100644 index 0000000..06378d0 --- /dev/null +++ b/ARW.Repository/System/SysOperLogRepository.cs @@ -0,0 +1,72 @@ +using Infrastructure.Attribute; +using Infrastructure.Extensions; +using System.Collections.Generic; +using ARW.Model; +using ARW.Model.System.Dto; +using ARW.Model.System; +using SqlSugar; +using Infrastructure.Model; + +namespace ARW.Repository.System +{ + [AppService(ServiceLifetime = LifeTime.Transient)] + public class SysOperLogRepository : BaseRepository + { + /// + /// 查询操作日志 + /// + /// + /// 分页数据 + /// + public PagedInfo GetSysOperLog(SysOperLogDto sysOper, PagerInfo pagerInfo) + { + var exp = Expressionable.Create(); + exp.And(it => it.operTime >= sysOper.BeginTime && it.operTime <= sysOper.EndTime); + exp.AndIF(sysOper.Title.IfNotEmpty(), it => it.title.Contains(sysOper.Title)); + exp.AndIF(sysOper.operName.IfNotEmpty(), it => it.operName.Contains(sysOper.operName)); + exp.AndIF(sysOper.BusinessType != -1, it => it.businessType == sysOper.BusinessType); + exp.AndIF(sysOper.Status != -1, it => it.status == sysOper.Status); + + return GetPages(exp.ToExpression(), pagerInfo, x => x.OperId, OrderByType.Desc); + } + + /// + /// 添加操作日志 + /// + /// + /// + public void AddSysOperLog(SysOperLog sysOperLog) + { + Context.Insertable(sysOperLog).ExecuteCommandAsync(); + } + + /// + /// 清空日志 + /// + public void ClearOperLog() + { + string sql = "truncate table sys_oper_log"; + Context.Ado.ExecuteCommand(sql); + } + + /// + /// 删除操作日志 + /// + /// + /// + public int DeleteOperLogByIds(long[] operIds) + { + return Context.Deleteable().In(operIds).ExecuteCommand(); + } + + /// + /// 查询操作日志 + /// + /// + /// + public SysOperLog SelectOperLogById(long operId) + { + return Context.Queryable().InSingle(operId); + } + } +} diff --git a/ARW.Repository/System/SysPostRepository.cs b/ARW.Repository/System/SysPostRepository.cs new file mode 100644 index 0000000..39854a3 --- /dev/null +++ b/ARW.Repository/System/SysPostRepository.cs @@ -0,0 +1,15 @@ +using Infrastructure.Attribute; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ARW.Model.System; + +namespace ARW.Repository.System +{ + [AppService(ServiceLifetime = LifeTime.Transient)] + public class SysPostRepository : BaseRepository + { + } +} diff --git a/ARW.Repository/System/SysRoleRepository.cs b/ARW.Repository/System/SysRoleRepository.cs new file mode 100644 index 0000000..79687dc --- /dev/null +++ b/ARW.Repository/System/SysRoleRepository.cs @@ -0,0 +1,211 @@ +using Infrastructure.Attribute; +using Infrastructure.Model; +using SqlSugar; +using System.Collections.Generic; +using System.Linq; +using ARW.Model; +using ARW.Model.System; + +namespace ARW.Repository.System +{ + /// + /// 角色操作类 + /// + [AppService(ServiceLifetime = LifeTime.Transient)] + public class SysRoleRepository : BaseRepository + { + /// + /// 查询所有角色数据 + /// + /// + public List SelectRoleList() + { + return Context.Queryable() + .Where(role => role.DelFlag == "0") + .OrderBy(role => role.RoleSort) + .ToList(); + } + /// + /// 根据条件分页查询角色数据 + /// + /// + /// + /// + public PagedInfo SelectRoleList(SysRole sysRole, PagerInfo pager) + { + var exp = Expressionable.Create(); + exp.And(role => role.DelFlag == "0"); + exp.AndIF(!string.IsNullOrEmpty(sysRole.RoleName), role => role.RoleName.Contains(sysRole.RoleName)); + exp.AndIF(!string.IsNullOrEmpty(sysRole.Status), role => role.Status == sysRole.Status); + exp.AndIF(!string.IsNullOrEmpty(sysRole.RoleKey), role => role.RoleKey == sysRole.RoleKey); + + var query = Context.Queryable() + .Where(exp.ToExpression()) + .OrderBy(x => x.RoleSort) + .Select((role) => new SysRole + { + RoleId = role.RoleId.SelectAll(), + UserNum = SqlFunc.Subqueryable().Where(f => f.RoleId == role.RoleId).Count() + }); + + return query.ToPage(pager); + } + + /// + /// 根据用户查询 + /// + /// + /// + public List SelectRolePermissionByUserId(long userId) + { + return Context.Queryable() + .Where(role => role.DelFlag == "0") + .Where(it => SqlFunc.Subqueryable().Where(s => s.UserId == userId).Any()) + .OrderBy(role => role.RoleSort) + .ToList(); + } + + /// + /// 通过角色ID查询角色 + /// + /// 角色编号 + /// + public SysRole SelectRoleById(long roleId) + { + return Context.Queryable().InSingle(roleId); + } + + /// + /// 通过角色ID删除角色 + /// + /// + /// + public int DeleteRoleByRoleIds(long[] roleId) + { + return Context.Deleteable().In(roleId).ExecuteCommand(); + } + + /// + /// 获取用户所有角色信息 + /// + /// + /// + public List SelectUserRoleListByUserId(long userId) + { + return Context.Queryable((ur, r) => new JoinQueryInfos( + JoinType.Left, ur.RoleId == r.RoleId + )).Where((ur, r) => ur.UserId == userId) + .Select((ur, r) => r).ToList(); + } + + #region 用户角色对应菜单 用户N-1角色 + + /// + /// 根据角色获取菜单id + /// + /// + /// + public List SelectRoleMenuByRoleId(long roleId) + { + return Context.Queryable().Where(it => it.Role_id == roleId).ToList(); + } + + /// + /// 根据用户所有角色获取菜单 + /// + /// + /// + public List SelectRoleMenuByRoleIds(long[] roleIds) + { + return Context.Queryable().Where(it => roleIds.Contains(it.Role_id)).ToList(); + } + + /// + /// 批量插入用户菜单 + /// + /// + /// + public int AddRoleMenu(List sysRoleMenus) + { + return Context.Insertable(sysRoleMenus).ExecuteCommand(); + } + + /// + /// 删除角色与菜单关联 + /// + /// + /// + public int DeleteRoleMenuByRoleId(long roleId) + { + return Context.Deleteable().Where(it => it.Role_id == roleId).ExecuteCommand(); + } + + #endregion + + /// + /// 添加角色 + /// + /// + /// + public long InsertRole(SysRole sysRole) + { + sysRole.Create_time = Context.GetDate(); + return Context.Insertable(sysRole).ExecuteReturnBigIdentity(); + } + + /// + /// 修改用户角色 + /// + /// + /// + public int UpdateSysRole(SysRole sysRole) + { + var db = Context; + sysRole.Update_time = db.GetDate(); + + return db.Updateable() + .SetColumns(it => it.Update_time == sysRole.Update_time) + .SetColumns(it => it.DataScope == sysRole.DataScope) + .SetColumns(it => it.Remark == sysRole.Remark) + .SetColumns(it => it.Update_by == sysRole.Update_by) + //.SetColumns(it => it.MenuCheckStrictly == sysRole.MenuCheckStrictly) + .SetColumns(it => it.DeptCheckStrictly == sysRole.DeptCheckStrictly) + .SetColumnsIF(!string.IsNullOrEmpty(sysRole.RoleName), it => it.RoleName == sysRole.RoleName) + .SetColumnsIF(!string.IsNullOrEmpty(sysRole.RoleKey), it => it.RoleKey == sysRole.RoleKey) + .SetColumnsIF(sysRole.RoleSort >= 0, it => it.RoleSort == sysRole.RoleSort) + .Where(it => it.RoleId == sysRole.RoleId) + .ExecuteCommand(); + } + + /// + /// 更改角色权限状态 + /// + /// + /// + /// + public int UpdateRoleStatus(SysRole role) + { + return Context.Updateable(role).UpdateColumns(t => new { t.Status }).ExecuteCommand(); + } + + /// + /// 检查角色权限是否存在 + /// + /// 角色权限 + /// + public SysRole CheckRoleKeyUnique(string roleKey) + { + return Context.Queryable().Where(it => it.RoleKey == roleKey).Single(); + } + + /// + /// 校验角色名称是否唯一 + /// + /// 角色名称 + /// + public SysRole CheckRoleNameUnique(string roleName) + { + return Context.Queryable().Where(it => it.RoleName == roleName).Single(); + } + } +} diff --git a/ARW.Repository/System/SysTasksQzRepository.cs b/ARW.Repository/System/SysTasksQzRepository.cs new file mode 100644 index 0000000..9814c16 --- /dev/null +++ b/ARW.Repository/System/SysTasksQzRepository.cs @@ -0,0 +1,15 @@ +using Infrastructure.Attribute; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ARW.Model.System; + +namespace ARW.Repository.System +{ + [AppService(ServiceLifetime = LifeTime.Transient)] + public class SysTasksQzRepository: BaseRepository + { + } +} diff --git a/ARW.Repository/System/SysUserPostRepository.cs b/ARW.Repository/System/SysUserPostRepository.cs new file mode 100644 index 0000000..677ae4f --- /dev/null +++ b/ARW.Repository/System/SysUserPostRepository.cs @@ -0,0 +1,27 @@ +using Infrastructure.Attribute; +using SqlSugar; +using System.Collections.Generic; +using ARW.Model.System; + +namespace ARW.Repository.System +{ + /// + /// 用户岗位 + /// + [AppService(ServiceLifetime = LifeTime.Transient)] + public class SysUserPostRepository : BaseRepository + { + /// + /// 获取用户岗位 + /// + /// + /// + public List SelectPostsByUserId(long userId) + { + return Context.Queryable((p, up) => new JoinQueryInfos( + JoinType.Left, up.PostId == p.PostId + )).Where((p, up) => up.UserId == userId) + .Select().ToList(); + } + } +} diff --git a/ARW.Repository/System/SysUserRepository.cs b/ARW.Repository/System/SysUserRepository.cs new file mode 100644 index 0000000..d826514 --- /dev/null +++ b/ARW.Repository/System/SysUserRepository.cs @@ -0,0 +1,165 @@ +using Infrastructure.Attribute; +using Infrastructure.Extensions; +using SqlSugar; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using ARW.Model; +using ARW.Model.System; + +namespace ARW.Repository.System +{ + /// + /// 用户管理 + /// + [AppService(ServiceLifetime = LifeTime.Transient)] + public class SysUserRepository : BaseRepository + { + /// + /// 根据条件分页查询用户列表 + /// + /// + /// + /// + public PagedInfo SelectUserList(SysUser user, PagerInfo pager) + { + var exp = Expressionable.Create(); + exp.AndIF(!string.IsNullOrEmpty(user.UserName), u => u.UserName.Contains(user.UserName)); + exp.AndIF(!string.IsNullOrEmpty(user.Status), u => u.Status == user.Status); + exp.AndIF(user.BeginTime != DateTime.MinValue && user.BeginTime != null, u => u.Create_time >= user.BeginTime); + exp.AndIF(user.EndTime != DateTime.MinValue && user.EndTime != null, u => u.Create_time <= user.EndTime); + exp.AndIF(!user.Phonenumber.IsEmpty(), u => u.Phonenumber == user.Phonenumber); + exp.And(u => u.DelFlag == "0"); + + if (user.DeptId != 0) + { + List depts = Context.Queryable().ToList(); + + var newDepts = depts.FindAll(delegate (SysDept dept) + { + string[] parentDeptId = dept.Ancestors.Split(",", StringSplitOptions.RemoveEmptyEntries); + return parentDeptId.Contains(user.DeptId.ToString()); + }); + string[] deptArr = newDepts.Select(x => x.DeptId.ToString()).ToArray(); + exp.AndIF(user.DeptId != 0, u => u.DeptId == user.DeptId || deptArr.Contains(u.DeptId.ToString())); + } + var query = Context.Queryable() + .LeftJoin((u, dept) => u.DeptId == dept.DeptId) + .Where(exp.ToExpression()) + .Select((u, dept) => new SysUser + { + UserId = u.UserId.SelectAll(), + DeptName = dept.DeptName, + }); + + return query.ToPage(pager); + } + + /// + /// 通过用户ID查询用户 + /// + /// + /// + public SysUser SelectUserById(long userId) + { + return Context.Queryable().Filter(null, true).Where(f => f.UserId == userId).First(); + } + + /// + /// 校验用户名是否存在 + /// + /// + /// + public int CheckUserNameUnique(string userName) + { + return Context.Queryable().Where(it => it.UserName == userName).Count(); + } + + /// + /// 添加用户 + /// + /// + /// + public int AddUser(SysUser sysUser) + { + sysUser.Create_time = DateTime.Now; + return Context.Insertable(sysUser).ExecuteReturnIdentity(); + } + + /// + /// 重置密码 + /// + /// + /// + /// + public int ResetPwd(long userid, string password) + { + return Context.Updateable(new SysUser() { UserId = userid, Password = password }) + .UpdateColumns(it => new { it.Password }).ExecuteCommand(); + } + + /// + /// 改变用户状态 + /// + /// + /// + public int ChangeUserStatus(SysUser user) + { + return Context.Updateable(user).UpdateColumns(t => new { t.Status }) + .ExecuteCommand(); + } + + /// + /// 删除用户(软删除) + /// + /// 用户id + /// + public int DeleteUser(long userid) + { + return Context.Updateable(new SysUser() { UserId = userid, DelFlag = "2" }) + .UpdateColumns(t => t.DelFlag) + .ExecuteCommand(); + } + + /// + /// 修改用户信息 + /// + /// + /// + public int UpdateUser(SysUser user) + { + return Context.Updateable(user) + .UpdateColumns(t => new + { + t.NickName, + t.Email, + t.Phonenumber, + t.DeptId, + t.Status, + t.Sex, + t.PostIds, + t.Remark, + t.Update_by, + t.Update_time + }) + .IgnoreColumns(ignoreAllNullColumns: true)//忽略所有为null + .Where(f => f.UserId == user.UserId).ExecuteCommand(); + } + + /// + /// 修改用户头像 + /// + /// + /// + public int UpdatePhoto(SysUser user) + { + return Context.Updateable() + .SetColumns(t => new SysUser() + { + Avatar = user.Avatar + }) + .Where(f => f.UserId == user.UserId).ExecuteCommand(); + } + } +} diff --git a/ARW.Repository/System/SysUserRoleRepository.cs b/ARW.Repository/System/SysUserRoleRepository.cs new file mode 100644 index 0000000..f3ec81b --- /dev/null +++ b/ARW.Repository/System/SysUserRoleRepository.cs @@ -0,0 +1,112 @@ +using Infrastructure.Attribute; +using Infrastructure.Extensions; +using SqlSugar; +using System.Collections.Generic; +using ARW.Model; +using ARW.Model.System; +using ARW.Model.System.Dto; + +namespace ARW.Repository.System +{ + [AppService(ServiceLifetime = LifeTime.Transient)] + public class SysUserRoleRepository : BaseRepository + { + /// + /// 删除用户角色 + /// + /// + /// + public int DeleteUserRoleByUserId(int userId) + { + return Context.Deleteable().Where(it => it.UserId == userId).ExecuteCommand(); + } + + /// + /// 批量删除角色对应用户 + /// + /// 角色id + /// 用户id集合 + /// + public int DeleteRoleUserByUserIds(long roleId, List userIds) + { + return Context.Deleteable().Where(it => it.RoleId == roleId && userIds.Contains(it.UserId)) + .ExecuteCommand(); + } + + /// + /// 添加用户角色 + /// + /// + /// + public int AddUserRole(List sysUsers) + { + return Context.Insertable(sysUsers).ExecuteCommand(); + } + + /// + /// 删除角色关联的用户 + /// + /// + /// + public int DeleteUserRoleByRoleId(int roleId) + { + return Context.Deleteable().In(roleId).ExecuteCommand(); + } + + /// + /// 获取角色分配个数 + /// + /// + /// + public int CountUserRoleByRoleId(long roleId) + { + return Context.Queryable().Where(it => it.RoleId == roleId).Count(); + } + + /// + /// 获取用户数据根据角色id + /// + /// + /// + public List GetSysUsersByRoleId(long roleId) + { + return Context.Queryable((t1, u) => new JoinQueryInfos( + JoinType.Left, t1.UserId == u.UserId)) + .Where((t1, u) => t1.RoleId == roleId && u.DelFlag == "0") + .Select((t1, u) => u) + .ToList(); + } + + /// + /// 获取用户数据根据角色id + /// + /// + /// + public PagedInfo GetSysUsersByRoleId(RoleUserQueryDto roleUserQueryDto) + { + var query = Context.Queryable((t1, u) => new JoinQueryInfos( + JoinType.Left, t1.UserId == u.UserId)) + .Where((t1, u) => t1.RoleId == roleUserQueryDto.RoleId && u.DelFlag == "0"); + if (!string.IsNullOrEmpty(roleUserQueryDto.UserName)) + { + query = query.Where((t1, u) => u.UserName.Contains(roleUserQueryDto.UserName)); + } + return query.Select((t1, u) => u).ToPage(roleUserQueryDto); + } + + /// + /// 获取尚未指派的用户数据根据角色id + /// + /// + /// + public PagedInfo GetExcludedSysUsersByRoleId(RoleUserQueryDto roleUserQueryDto) + { + var query = Context.Queryable() + .Where(it => it.DelFlag == "0") + .Where(it => SqlFunc.Subqueryable().Where(s => s.UserId == it.UserId && s.RoleId == roleUserQueryDto.RoleId).NotAny()) + .WhereIF(roleUserQueryDto.UserName.IsNotEmpty(), it => it.UserName.Contains(roleUserQueryDto.UserName)); + + return query.ToPage(roleUserQueryDto); + } + } +} diff --git a/ARW.Service/ARW.Service.csproj b/ARW.Service/ARW.Service.csproj new file mode 100644 index 0000000..96fad4d --- /dev/null +++ b/ARW.Service/ARW.Service.csproj @@ -0,0 +1,24 @@ + + + + net6.0 + ARW.Service + ARW.Service + + + + + + + + + + + + + + + + + + diff --git a/ARW.Service/BaseService.cs b/ARW.Service/BaseService.cs new file mode 100644 index 0000000..6a75151 --- /dev/null +++ b/ARW.Service/BaseService.cs @@ -0,0 +1,19 @@ +using ARW.Repository; + +namespace ARW.Service +{ + /// + /// 基础服务定义 + /// + /// + public class BaseService : BaseRepository where T : class, new() + { + //public IBaseRepository baseRepository; + + //public BaseService(IBaseRepository repository) + //{ + // this.baseRepository = repository ?? throw new ArgumentNullException(nameof(repository)); + //} + + } +} diff --git a/ARW.Service/Business/BusinessService/Customers/CustomerService.cs b/ARW.Service/Business/BusinessService/Customers/CustomerService.cs new file mode 100644 index 0000000..2c4e718 --- /dev/null +++ b/ARW.Service/Business/BusinessService/Customers/CustomerService.cs @@ -0,0 +1,71 @@ +using Infrastructure.Attribute; +using Microsoft.AspNetCore.Http; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ARW.Model; +using ARW.Repository; +using ARW.Repository.Business.Customers; +using ARW.Service.Business.IBusinessService.Customers; +using ARW.Model.Dto.Business.Customers; +using ARW.Model.Models.Business.Customers; +using ARW.Model.Vo.Business.Customers; + +namespace ARW.Service.Business.BusinessService.Customers +{ + /// + /// 小程序客户接口实现类 + /// + [AppService(ServiceType = typeof(ICustomerService), ServiceLifetime = LifeTime.Transient)] + public class CustomerServiceImpl : BaseService, ICustomerService + { + private readonly CustomerRepository _CustomerRepository; + + public CustomerServiceImpl(CustomerRepository CustomerRepository) + { + this._CustomerRepository = CustomerRepository; + } + + #region 业务逻辑代码 + + /// + /// 查询小程序客户列表 + /// + /// + /// + public Task> GetCustomerList(CustomerQueryDto parm) + { + //开始拼装查询条件d + var predicate = Expressionable.Create(); + + predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.CustomerName), it => it.CustomerName.Contains(parm.CustomerName)); + predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.CustomerXcxName), it => it.CustomerXcxName.Contains(parm.CustomerXcxName)); + var query = _CustomerRepository + .Queryable() + .Where(predicate.ToExpression()) + .OrderBy(s => s.Create_time,OrderByType.Desc) + .Select(s => new CustomerVo + { + CustomerId = s.CustomerId, + CustomerGuid = s.CustomerGuid, + CustomerName = s.CustomerName, + CustomerPhone = s.CustomerPhone, + CustomerBrithday = s.CustomerBirth, + CustomerImg = s.CustomerImg, + CustomerSex = s.CustomerSex, + CustomerXcxOpenid = s.CustomerXcxOpenid, + CustomerXcxName = s.CustomerXcxName, + CustomerXcxImg = s.CustomerXcxImg, + }); + + + return query.ToPageAsync(parm); + } + + #endregion + + } +} diff --git a/ARW.Service/Business/BusinessService/Payments/PaymentService.cs b/ARW.Service/Business/BusinessService/Payments/PaymentService.cs new file mode 100644 index 0000000..c8fda56 --- /dev/null +++ b/ARW.Service/Business/BusinessService/Payments/PaymentService.cs @@ -0,0 +1,67 @@ +using Infrastructure.Attribute; +using Microsoft.AspNetCore.Http; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ARW.Model; +using ARW.Repository; +using ARW.Repository.Business.Payments; +using ARW.Service.Business.IBusinessService.Payments; +using ARW.Model.Dto.Business.Payments; +using ARW.Model.Models.Business.Payments; +using ARW.Model.Vo.Business.Payments; + +namespace ARW.Service.Business.BusinessService.Payments +{ + /// + /// 支付订单接口实现类 + /// + [AppService(ServiceType = typeof(IPaymentService), ServiceLifetime = LifeTime.Transient)] + public class PaymentServiceImpl : BaseService, IPaymentService + { + private readonly PaymentRepository _PaymentRepository; + + public PaymentServiceImpl(PaymentRepository PaymentRepository) + { + this._PaymentRepository = PaymentRepository; + } + + #region 业务逻辑代码 + + /// + /// 查询支付订单列表 + /// + /// + /// + public Task> GetPaymentList(PaymentQueryDto parm) + { + //开始拼装查询条件d + var predicate = Expressionable.Create(); + + predicate = predicate.AndIF(parm.PaymentStatus != null, it => it.PaymentStatus == parm.PaymentStatus); + var query = _PaymentRepository + .Queryable() + .Where(predicate.ToExpression()) + .Select(s => new PaymentVo + { + PaymentId = s.PaymentId, + PaymentGuid = s.PaymentGuid, + PaymentStatus = s.PaymentStatus, + PaymentMoney = s.PaymentMoney, + PaymentNumber = s.PaymentNumber, + CustomerGuid = s.CustomerGuid, + PaymentBusinessGuid = s.PaymentBusinessGuid, + PaymentBuytype = s.PaymentBuytype, + }); + + + return query.ToPageAsync(parm); + } + + #endregion + + } +} diff --git a/ARW.Service/Business/BusinessService/SubscribeTasks/SubscribeTaskService.cs b/ARW.Service/Business/BusinessService/SubscribeTasks/SubscribeTaskService.cs new file mode 100644 index 0000000..55142f5 --- /dev/null +++ b/ARW.Service/Business/BusinessService/SubscribeTasks/SubscribeTaskService.cs @@ -0,0 +1,68 @@ +using Infrastructure.Attribute; +using Microsoft.AspNetCore.Http; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ARW.Model; +using ARW.Repository; +using ARW.Repository.Business.SubscribeTasks; +using ARW.Service.Business.IBusinessService.SubscribeTasks; +using ARW.Model.Dto.Business.SubscribeTasks; +using ARW.Model.Models.Business.SubscribeTasks; +using ARW.Model.Vo.Business.SubscribeTasks; +using ARW.Model.Models.Business.Customers; + +namespace ARW.Service.Business.BusinessService.SubscribeTasks +{ + /// + /// 订阅推送任务接口实现类 + /// + [AppService(ServiceType = typeof(ISubscribeTaskService), ServiceLifetime = LifeTime.Transient)] + public class SubscribeTaskServiceImpl : BaseService, ISubscribeTaskService + { + private readonly SubscribeTaskRepository _SubscribeTaskRepository; + + public SubscribeTaskServiceImpl(SubscribeTaskRepository SubscribeTaskRepository) + { + this._SubscribeTaskRepository = SubscribeTaskRepository; + } + + #region 业务逻辑代码 + + /// + /// 查询订阅推送任务列表 + /// + /// + /// + public List GetSubscribeTaskList() + { + //开始拼装查询条件d + var predicate = Expressionable.Create(); + + var query = _SubscribeTaskRepository + .Queryable() + .Where(predicate.ToExpression()) + .Where(s => s.SubscribeTaskStatus == 0) + .LeftJoin((s,f) => s.CustomerGuid == f.CustomerGuid) + .OrderBy(s => s.Create_time, OrderByType.Desc) + .Select((s,f) => new SubscribeTaskVo + { + SubscribeTaskId = s.SubscribeTaskId, + SubscribeTaskGuid = s.SubscribeTaskGuid, + OpenId = f.CustomerXcxOpenid, + SubscribeTaskType = s.SubscribeTaskType, + TemplateId = s.TemplateId, + SubscribeTaskStatus = s.SubscribeTaskStatus, + SubscribeTaskErrorMsg = s.SubscribeTaskErrorMsg, + }); + + return query.ToList(); + } + + #endregion + + } +} diff --git a/ARW.Service/Business/IBusinessService/Customers/ICustomerService.cs b/ARW.Service/Business/IBusinessService/Customers/ICustomerService.cs new file mode 100644 index 0000000..d602216 --- /dev/null +++ b/ARW.Service/Business/IBusinessService/Customers/ICustomerService.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ARW.Model; +using ARW.Model.Dto.Business.Customers; +using ARW.Model.Models.Business.Customers; +using ARW.Model.Vo.Business.Customers; + +namespace ARW.Service.Business.IBusinessService.Customers +{ + public interface ICustomerService : IBaseService + { + /// + /// 获取小程序客户分页列表 + /// + /// + /// + Task> GetCustomerList(CustomerQueryDto parm); + + } +} diff --git a/ARW.Service/Business/IBusinessService/Payments/IPaymentService.cs b/ARW.Service/Business/IBusinessService/Payments/IPaymentService.cs new file mode 100644 index 0000000..f482d7c --- /dev/null +++ b/ARW.Service/Business/IBusinessService/Payments/IPaymentService.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ARW.Model; +using ARW.Model.Dto.Business.Payments; +using ARW.Model.Models.Business.Payments; +using ARW.Model.Vo.Business.Payments; + +namespace ARW.Service.Business.IBusinessService.Payments +{ + public interface IPaymentService : IBaseService + { + /// + /// 获取支付订单分页列表 + /// + /// + /// + Task> GetPaymentList(PaymentQueryDto parm); + + } +} diff --git a/ARW.Service/Business/IBusinessService/SubscribeTasks/ISubscribeTaskService.cs b/ARW.Service/Business/IBusinessService/SubscribeTasks/ISubscribeTaskService.cs new file mode 100644 index 0000000..34ed07e --- /dev/null +++ b/ARW.Service/Business/IBusinessService/SubscribeTasks/ISubscribeTaskService.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ARW.Model; +using ARW.Model.Dto.Business.SubscribeTasks; +using ARW.Model.Models.Business.SubscribeTasks; +using ARW.Model.Vo.Business.SubscribeTasks; + +namespace ARW.Service.Business.IBusinessService.SubscribeTasks +{ + public interface ISubscribeTaskService : IBaseService + { + /// + /// 获取订阅推送任务分页列表 + /// + /// + /// + List GetSubscribeTaskList(); + + } +} diff --git a/ARW.Service/IBaseService.cs b/ARW.Service/IBaseService.cs new file mode 100644 index 0000000..fcb1c49 --- /dev/null +++ b/ARW.Service/IBaseService.cs @@ -0,0 +1,24 @@ +using ARW.Model.Models.Business.Crawler; +using ARW.Repository; +using System; +using System.Collections.Generic; + +namespace ARW.Service +{ + /// + /// 基础服务定义 + /// + /// + public interface IBaseService : IBaseRepository where T : class, new() + { + public virtual string LoadHTML(string url) + { + throw new NotImplementedException(); + } + + public virtual int ParseMovies(string html) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/ARW.Service/System/CacheService.cs b/ARW.Service/System/CacheService.cs new file mode 100644 index 0000000..5b9c4d6 --- /dev/null +++ b/ARW.Service/System/CacheService.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ARW.Common; + +namespace ARW.Service.System +{ + public class CacheService + { + #region 用户权限 缓存 + public static List GetUserPerms(string key) + { + return (List)CacheHelper.GetCache(key); + } + + public static void SetUserPerms(string key, object data) + { + CacheHelper.SetCache(key, data); + } + public static void RemoveUserPerms(string key) + { + CacheHelper.Remove(key); + } + #endregion + } +} diff --git a/ARW.Service/System/CommonLangService.cs b/ARW.Service/System/CommonLangService.cs new file mode 100644 index 0000000..a52da06 --- /dev/null +++ b/ARW.Service/System/CommonLangService.cs @@ -0,0 +1,124 @@ +using Infrastructure.Attribute; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using ARW.Model; +using ARW.Model.Dto; +using ARW.Model.Models; +using ARW.Repository; +using ARW.Service.System.IService; + +namespace ARW.Service.System +{ + /// + /// 多语言配置Service业务层处理 + /// + /// @author li + /// @date 2022-05-06 + /// + [AppService(ServiceType = typeof(ICommonLangService), ServiceLifetime = LifeTime.Transient)] + public class CommonLangService : BaseService, ICommonLangService + { + private readonly CommonLangRepository _CommonLangrepository; + public CommonLangService(CommonLangRepository repository) + { + _CommonLangrepository = repository; + } + + #region 业务逻辑代码 + + /// + /// 查询多语言配置列表 + /// + /// + /// + public PagedInfo GetList(CommonLangQueryDto parm) + { + //开始拼装查询条件 + var predicate = Expressionable.Create(); + + //搜索条件查询语法参考Sqlsugar + predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.LangCode), it => it.LangCode == parm.LangCode); + predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.LangKey), it => it.LangKey.Contains(parm.LangKey)); + predicate = predicate.AndIF(parm.BeginAddtime != null, it => it.Addtime >= parm.BeginAddtime && it.Addtime <= parm.EndAddtime); + var response = _CommonLangrepository + .Queryable() + .Where(predicate.ToExpression()) + .ToPage(parm); + return response; + } + + /// + /// 行转列 + /// + /// + /// + public dynamic GetListToPivot(CommonLangQueryDto parm) + { + //开始拼装查询条件 + var predicate = Expressionable.Create(); + + //搜索条件查询语法参考Sqlsugar + predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.LangCode), it => it.LangCode == parm.LangCode); + predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.LangKey), it => it.LangKey.Contains(parm.LangKey)); + predicate = predicate.AndIF(parm.BeginAddtime != null, it => it.Addtime >= parm.BeginAddtime && it.Addtime <= parm.EndAddtime); + var response = _CommonLangrepository + .Queryable() + .Where(predicate.ToExpression()) + .ToPivotList(it => it.LangCode, it => it.LangKey, it => it.Max(f => f.LangName)); + return response; + } + + public List GetLangList(CommonLangQueryDto parm) + { + //开始拼装查询条件 + var predicate = Expressionable.Create(); + + //搜索条件查询语法参考Sqlsugar + predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.LangCode), it => it.LangCode == parm.LangCode); + //predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.LangKey), it => it.LangKey.Contains(parm.LangKey)); + var response = _CommonLangrepository + .Queryable() + .Where(predicate.ToExpression()) + .ToList(); + return response; + } + + public void StorageCommonLang(CommonLangDto parm) + { + List langs = new(); + foreach (var item in parm.LangList) + { + langs.Add(new CommonLang() + { + Addtime = DateTime.Now, + LangKey = parm.LangKey, + LangCode = item.LangCode, + LangName = item.LangName, + }); + } + var storage = _CommonLangrepository.Storageable(langs) + .WhereColumns(it => new { it.LangKey, it.LangCode }) + .ToStorage(); + + storage.AsInsertable.ExecuteReturnSnowflakeIdList();//执行插入 + storage.AsUpdateable.UpdateColumns(it => new { it.LangName }).ExecuteCommand();//执行修改 + } + + public Dictionary SetLang(List msgList) + { + Dictionary dic = new(); + + foreach (var item in msgList) + { + if (!dic.ContainsKey(item.LangKey)) + { + dic.Add(item.LangKey, item.LangName); + } + } + return dic; + } + #endregion + } +} \ No newline at end of file diff --git a/ARW.Service/System/GenTableService.cs b/ARW.Service/System/GenTableService.cs new file mode 100644 index 0000000..70096f2 --- /dev/null +++ b/ARW.Service/System/GenTableService.cs @@ -0,0 +1,222 @@ +using Infrastructure.Attribute; +using Infrastructure.Extensions; +using Newtonsoft.Json; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using ARW.Common; +using ARW.Model; +using ARW.Model.System.Generate; +using ARW.Repository.System; +using ARW.Service.System.IService; + +namespace ARW.Service.System +{ + /// + /// 代码生成表 + /// + [AppService(ServiceType = typeof(IGenTableService), ServiceLifetime = LifeTime.Transient)] + public class GenTableService : BaseService, IGenTableService + { + private GenTableRepository GenTableRepository; + private IGenTableColumnService GenTableColumnService; + public GenTableService(IGenTableColumnService genTableColumnService, GenTableRepository genTableRepository) + { + GenTableColumnService = genTableColumnService; + GenTableRepository = genTableRepository; + } + + /// + /// 删除表 + /// + /// 需要删除的表id + /// + public int DeleteGenTableByIds(long[] tableIds) + { + GenTableRepository.Delete(f => tableIds.Contains(f.TableId)); + return GenTableColumnService.DeleteGenTableColumn(tableIds); + } + + /// + /// 删除表根据表名 + /// + /// + /// + public int DeleteGenTableByTbName(string tableName) + { + return GenTableRepository.Delete(f => f.TableName == tableName) ? 1 : 0; + } + + /// + /// 获取表信息 + /// + /// + /// + public GenTable GetGenTableInfo(long tableId) + { + var info = GenTableRepository.GetId(tableId); + if (info != null && !info.SubTableName.IsEmpty()) + { + info.SubTable = GenTableRepository.Queryable().Where(f => f.TableName == info.SubTableName).First(); + } + return info; + } + + /// + /// 获取所有代码生成表 + /// + /// + public List GetGenTableAll() + { + return GenTableRepository.GetAll(); + } + + /// + /// 查询代码生成表信息 + /// + /// + /// + /// + public PagedInfo GetGenTables(GenTable genTable, PagerInfo pagerInfo) + { + var predicate = Expressionable.Create(); + predicate = predicate.AndIF(genTable.TableName.IfNotEmpty(), it => it.TableName.Contains(genTable.TableName)); + + return GenTableRepository.GetPages(predicate.ToExpression(), pagerInfo, x => x.TableId, OrderByType.Desc); + } + + /// + /// 插入代码生成表 + /// + /// + /// + public int ImportGenTable(GenTable table) + { + table.Create_time = DateTime.Now; + //导入前删除现有表 + //DeleteGenTableByIds(new long[] { table.TableId }); + DeleteGenTableByTbName(table.TableName); + + return GenTableRepository.Context.Insertable(table).IgnoreColumns(ignoreNullColumn: true).ExecuteReturnIdentity(); + } + + /// + /// 获取表数据 + /// + /// + /// + public List SelectDbTableListByNamess(string[] tableNames) + { + throw new NotImplementedException(); + } + + public int UpdateGenTable(GenTable genTable) + { + var db = GenTableRepository.Context; + genTable.Update_time = db.GetDate(); + return db.Updateable(genTable).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommand(); + } + + /// + /// 同步数据库 + /// + /// 表id + /// + /// + public void SynchDb(long tableId, GenTable genTable, List dbTableColumns) + { + List tableColumns = GenTableColumnService.GenTableColumns(tableId); + List tableColumnNames = tableColumns.Select(f => f.ColumnName).ToList(); + List dbTableColumneNames = dbTableColumns.Select(f => f.ColumnName).ToList(); + + List insertColumns = new(); + foreach (var column in dbTableColumns) + { + if (!tableColumnNames.Contains(column.ColumnName)) + { + insertColumns.Add(column); + } + } + GenTableColumnService.Insert(insertColumns); + + List delColumns = tableColumns.FindAll(column => !dbTableColumneNames.Contains(column.ColumnName)); + if (delColumns != null && delColumns.Count > 0) + { + GenTableColumnService.Delete(delColumns.Select(f => f.ColumnId).ToList()); + } + } + } + + /// + /// 代码生成表列 + /// + [AppService(ServiceType = typeof(IGenTableColumnService), ServiceLifetime = LifeTime.Transient)] + public class GenTableColumnService : BaseService, IGenTableColumnService + { + + private GenTableColumnRepository GetTableColumnRepository; + public GenTableColumnService(GenTableColumnRepository genTableColumnRepository) + { + GetTableColumnRepository = genTableColumnRepository; + } + /// + /// 删除表字段 + /// + /// + /// + public int DeleteGenTableColumn(long tableId) + { + return GetTableColumnRepository.DeleteGenTableColumn(new long[] { tableId }); + } + /// + /// 根据表id批量删除表字段 + /// + /// + /// + public int DeleteGenTableColumn(long[] tableId) + { + return GetTableColumnRepository.DeleteGenTableColumn(tableId); + } + + /// + /// 根据表名删除字段 + /// + /// + /// + public int DeleteGenTableColumnByTableName(string tableName) + { + return GetTableColumnRepository.DeleteGenTableColumnByTableName(tableName); + } + + /// + /// 获取表所有字段 + /// + /// + /// + public List GenTableColumns(long tableId) + { + return GetTableColumnRepository.GenTableColumns(tableId); + } + + /// + /// 插入表字段 + /// + /// + /// + public int InsertGenTableColumn(List tableColumn) + { + return GetTableColumnRepository.InsertGenTableColumn(tableColumn); + } + + /// + /// 批量更新表字段 + /// + /// + /// + public int UpdateGenTableColumn(List tableColumn) + { + return GetTableColumnRepository.UpdateGenTableColumn(tableColumn); + } + } +} diff --git a/ARW.Service/System/IService/ICommonLangService.cs b/ARW.Service/System/IService/ICommonLangService.cs new file mode 100644 index 0000000..9a69092 --- /dev/null +++ b/ARW.Service/System/IService/ICommonLangService.cs @@ -0,0 +1,24 @@ +using System; +using ARW.Model; +using ARW.Model.Dto; +using ARW.Model.Models; +using System.Collections.Generic; + +namespace ARW.Service.System.IService +{ + /// + /// 多语言配置service接口 + /// + /// @author + /// + /// @date 2022-05-06 + /// + public interface ICommonLangService : IBaseService + { + PagedInfo GetList(CommonLangQueryDto parm); + List GetLangList(CommonLangQueryDto parm); + dynamic GetListToPivot(CommonLangQueryDto parm); + void StorageCommonLang(CommonLangDto parm); + Dictionary SetLang(List msgList); + } +} diff --git a/ARW.Service/System/IService/IGenTableService.cs b/ARW.Service/System/IService/IGenTableService.cs new file mode 100644 index 0000000..16ef667 --- /dev/null +++ b/ARW.Service/System/IService/IGenTableService.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using ARW.Model; +using ARW.Model.System.Generate; + +namespace ARW.Service.System.IService +{ + public interface IGenTableService : IBaseService + { + List SelectDbTableListByNamess(string[] tableNames); + + int ImportGenTable(GenTable tables); + + int DeleteGenTableByIds(long[] tableIds); + int DeleteGenTableByTbName(string tableName); + PagedInfo GetGenTables(GenTable genTable, PagerInfo pagerInfo); + GenTable GetGenTableInfo(long tableId); + void SynchDb(long tableId, GenTable genTable, List dbTableColumns); + List GetGenTableAll(); + int UpdateGenTable(GenTable genTable); + } + + public interface IGenTableColumnService : IBaseService + { + int InsertGenTableColumn(List tableColumn); + + int DeleteGenTableColumn(long tableId); + int DeleteGenTableColumn(long[] tableIds); + int DeleteGenTableColumnByTableName(string tableName); + List GenTableColumns(long tableId); + int UpdateGenTableColumn(List tableColumn); + } +} diff --git a/ARW.Service/System/IService/ISysConfigService.cs b/ARW.Service/System/IService/ISysConfigService.cs new file mode 100644 index 0000000..6272bf8 --- /dev/null +++ b/ARW.Service/System/IService/ISysConfigService.cs @@ -0,0 +1,16 @@ +using System; +using ARW.Model.System; + +namespace ARW.Service.System +{ + /// + /// 参数配置service接口 + /// + /// @author zhaorui + /// @date 2021-09-29 + /// + public interface ISysConfigService : IBaseService + { + SysConfig GetSysConfigByKey(string key); + } +} diff --git a/ARW.Service/System/IService/ISysDeptService.cs b/ARW.Service/System/IService/ISysDeptService.cs new file mode 100644 index 0000000..836bd77 --- /dev/null +++ b/ARW.Service/System/IService/ISysDeptService.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ARW.Model.System; +using ARW.Model.System.Vo; + +namespace ARW.Service.System.IService +{ + public interface ISysDeptService : IBaseService + { + List GetSysDepts(SysDept dept); + string CheckDeptNameUnique(SysDept dept); + int InsertDept(SysDept dept); + int UpdateDept(SysDept dept); + void UpdateDeptChildren(long deptId, string newAncestors, string oldAncestors); + List GetChildrenDepts(List depts, long deptId); + List BuildDeptTree(List depts); + List BuildDeptTreeSelect(List depts); + List SelectRoleDeptByRoleId(long roleId); + + List SelectRoleDepts(long roleId); + bool DeleteRoleDeptByRoleId(long roleId); + int InsertRoleDepts(SysRole role); + } +} diff --git a/ARW.Service/System/IService/ISysDictDataService.cs b/ARW.Service/System/IService/ISysDictDataService.cs new file mode 100644 index 0000000..ac50b5e --- /dev/null +++ b/ARW.Service/System/IService/ISysDictDataService.cs @@ -0,0 +1,20 @@ +using Infrastructure.Model; +using System; +using System.Collections.Generic; +using System.Text; +using ARW.Model; +using ARW.Model.System; + +namespace ARW.Service.System.IService +{ + public interface ISysDictDataService + { + public PagedInfo SelectDictDataList(SysDictData dictData, PagerInfo pagerInfo); + public List SelectDictDataByType(string dictType); + public List SelectDictDataByTypes(string[] dictTypes); + public SysDictData SelectDictDataById(long dictCode); + public long InsertDictData(SysDictData dict); + public long UpdateDictData(SysDictData dict); + public int DeleteDictDataByIds(long[] dictCodes); + } +} diff --git a/ARW.Service/System/IService/ISysDictService.cs b/ARW.Service/System/IService/ISysDictService.cs new file mode 100644 index 0000000..e392592 --- /dev/null +++ b/ARW.Service/System/IService/ISysDictService.cs @@ -0,0 +1,53 @@ +using System.Collections.Generic; +using System.Text; +using ARW.Model; +using ARW.Model.System; + +namespace ARW.Service.System.IService +{ + /// + /// + /// + public interface ISysDictService + { + public List GetAll(); + public PagedInfo SelectDictTypeList(SysDictType dictType, Model.PagerInfo pager); + + /// + /// 校验字典类型称是否唯一 + /// + /// 字典类型 + /// + public string CheckDictTypeUnique(SysDictType dictType); + + /// + /// 批量删除字典数据信息 + /// + /// + /// + public int DeleteDictTypeByIds(long[] dictIds); + + /// + /// 插入字典类型 + /// + /// + /// + public long InsertDictType(SysDictType sysDictType); + + /// + /// 修改字典类型 + /// + /// + /// + public int UpdateDictType(SysDictType sysDictType); + + /// + /// 获取字典信息 + /// + /// + /// + SysDictType GetInfo(long dictId); + + + } +} diff --git a/ARW.Service/System/IService/ISysFileService.cs b/ARW.Service/System/IService/ISysFileService.cs new file mode 100644 index 0000000..916ac66 --- /dev/null +++ b/ARW.Service/System/IService/ISysFileService.cs @@ -0,0 +1,40 @@ +using Infrastructure.Attribute; +using Microsoft.AspNetCore.Http; +using System.Threading.Tasks; +using ARW.Model.Models; +using ARW.Model.System; + +namespace ARW.Service.System.IService +{ + public interface ISysFileService : IBaseService + { + Task InsertFile(SysFile file); + + /// + /// 上传文件 + /// + /// + /// + /// + /// + /// + /// 文件对象 + 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 = "", bool byTimeStore = true); + + /// + /// 取文件名的MD5值(16位) + /// + /// 文件名,不包括扩展名 + /// + string HashFileName(string str = null); + } +} diff --git a/ARW.Service/System/IService/ISysLoginService.cs b/ARW.Service/System/IService/ISysLoginService.cs new file mode 100644 index 0000000..5a99eef --- /dev/null +++ b/ARW.Service/System/IService/ISysLoginService.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ARW.Model; +using ARW.Model.System.Dto; +using ARW.Model.System; + +namespace ARW.Service.System.IService +{ + public interface ISysLoginService: IBaseService + { + /// + /// 登录 + /// + /// + /// + /// + public SysUser Login(LoginBodyDto loginBody, SysLogininfor logininfor); + + /// + /// 查询操作日志 + /// + /// + /// 分页 + /// + public PagedInfo GetLoginLog(SysLogininfor logininfoDto, PagerInfo pager); + + /// + /// 记录登录日志 + /// + /// + /// + public void AddLoginInfo(SysLogininfor sysLogininfor); + + /// + /// 清空登录日志 + /// + public void TruncateLogininfo(); + + /// + /// 删除登录日志 + /// + /// + /// + public int DeleteLogininforByIds(long[] ids); + } +} diff --git a/ARW.Service/System/IService/ISysMenuService.cs b/ARW.Service/System/IService/ISysMenuService.cs new file mode 100644 index 0000000..f53eae7 --- /dev/null +++ b/ARW.Service/System/IService/ISysMenuService.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using ARW.Model.System.Dto; +using ARW.Model.System; +using ARW.Model.System.Vo; + +namespace ARW.Service.System.IService +{ + public interface ISysMenuService + { + //List SelectMenuList(long userId); + + List SelectMenuList(MenuQueryDto menu, long userId); + List SelectTreeMenuList(MenuQueryDto menu, long userId); + + SysMenu GetMenuByMenuId(int menuId); + List GetMenusByMenuId(int menuId); + int AddMenu(SysMenu menu); + + int EditMenu(SysMenu menu); + + int DeleteMenuById(int menuId); + + string CheckMenuNameUnique(SysMenu menu); + + int ChangeSortMenu(MenuDto menuDto); + + bool HasChildByMenuId(long menuId); + List SelectChildByMenuId(long menuId); + + List SelectMenuTreeByUserId(long userId); + + List SelectMenuPermsListByUserId(long userId); + + List SelectMenuPermsByUserId(long userId); + + bool CheckMenuExistRole(long menuId); + + List BuildMenus(List menus); + + List BuildMenuTreeSelect(List menus); + } +} diff --git a/ARW.Service/System/IService/ISysNoticeService.cs b/ARW.Service/System/IService/ISysNoticeService.cs new file mode 100644 index 0000000..02fcb5c --- /dev/null +++ b/ARW.Service/System/IService/ISysNoticeService.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using ARW.Model.System; + +namespace ARW.Service.System.IService +{ + /// + /// 通知公告表service接口 + /// + /// @author + /// + /// @date 2021-12-15 + /// + public interface ISysNoticeService: IBaseService + { + List GetSysNotices(); + } +} diff --git a/ARW.Service/System/IService/ISysOperLogService.cs b/ARW.Service/System/IService/ISysOperLogService.cs new file mode 100644 index 0000000..5cd03c2 --- /dev/null +++ b/ARW.Service/System/IService/ISysOperLogService.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using ARW.Model; +using ARW.Model.System.Dto; +using ARW.Model.System; +using ARW.Service.System; +using Infrastructure.Model; + +namespace ARW.Service.System.IService +{ + public interface ISysOperLogService + { + public void InsertOperlog(SysOperLog operLog); + + /// + /// 查询系统操作日志集合 + /// + /// 操作日志对象 + /// + /// 操作日志集合 + public PagedInfo SelectOperLogList(SysOperLogDto operLog, PagerInfo pager); + + /// + /// 清空操作日志 + /// + public void CleanOperLog(); + + /// + /// 批量删除系统操作日志 + /// + /// 需要删除的操作日志ID + /// 结果 + public int DeleteOperLogByIds(long[] operIds); + + /// + /// 查询操作日志详细 + /// + /// 操作ID + /// 操作日志对象 + public SysOperLog SelectOperLogById(long operId); + } +} diff --git a/ARW.Service/System/IService/ISysPermissionService.cs b/ARW.Service/System/IService/ISysPermissionService.cs new file mode 100644 index 0000000..074c44a --- /dev/null +++ b/ARW.Service/System/IService/ISysPermissionService.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ARW.Model.System; + +namespace ARW.Service.System.IService +{ + public interface ISysPermissionService + { + public List GetRolePermission(SysUser user); + public List GetMenuPermission(SysUser user); + } +} diff --git a/ARW.Service/System/IService/ISysPostService.cs b/ARW.Service/System/IService/ISysPostService.cs new file mode 100644 index 0000000..1226d04 --- /dev/null +++ b/ARW.Service/System/IService/ISysPostService.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ARW.Model.System; +using ARW.Repository; + +namespace ARW.Service.System.IService +{ + public interface ISysPostService : IBaseService + { + string CheckPostNameUnique(SysPost sysPost); + string CheckPostCodeUnique(SysPost sysPost); + List GetAll(); + } +} diff --git a/ARW.Service/System/IService/ISysRoleService.cs b/ARW.Service/System/IService/ISysRoleService.cs new file mode 100644 index 0000000..866d337 --- /dev/null +++ b/ARW.Service/System/IService/ISysRoleService.cs @@ -0,0 +1,141 @@ +using System.Collections.Generic; +using ARW.Model; +using ARW.Model.System; + +namespace ARW.Service.System.IService +{ + public interface ISysRoleService : IBaseService + { + /// + /// 根据条件分页查询角色数据 + /// + /// 角色信息 + /// + /// 角色数据集合信息 + public PagedInfo SelectRoleList(SysRole role, PagerInfo pager); + + /// + /// 查询所有角色 + /// + /// + /// + public List SelectRoleAll(); + + /// + /// 根据用户查询 + /// + /// + /// + public List SelectRolePermissionByUserId(long userId); + + /// + /// 通过角色ID查询角色 + /// + /// 角色ID + /// 角色对象信息 + public SysRole SelectRoleById(long roleId); + + /// + /// 批量删除角色信息 + /// + /// 需要删除的角色ID + /// + public int DeleteRoleByRoleId(long[] roleIds); + + /// + /// 更改角色权限状态 + /// + /// + /// + public int UpdateRoleStatus(SysRole roleDto); + + /// + /// 校验角色权限是否唯一 + /// + /// 角色信息 + /// + public string CheckRoleKeyUnique(SysRole sysRole); + + /// + /// 校验角色是否允许操作 + /// + /// + public void CheckRoleAllowed(SysRole role); + + /// + /// 新增保存角色信息 + /// + /// 角色信息 + /// + public long InsertRole(SysRole sysRole); + + /// + /// 通过角色ID删除角色和菜单关联 + /// + /// 角色ID + /// + public int DeleteRoleMenuByRoleId(long roleId); + + /// + /// 授权数据范围 + /// + /// + /// + bool AuthDataScope(SysRole role); + #region Service + + + /// + /// 新增角色菜单信息 + /// + /// + /// + public int InsertRoleMenu(SysRole sysRoleDto); + + /// + /// 判断是否是管理员 + /// + /// + /// + public bool IsAdmin(long userid); + + /// + /// 获取角色菜单id集合 + /// + /// + /// + public List SelectUserRoleMenus(long roleId); + List SelectRoleMenuByRoleIds(long[] roleIds); + /// + /// 获取用户角色列表 + /// + /// + /// + public List SelectUserRoleListByUserId(long userId); + + /// + /// 获取用户权限集合 + /// + /// + /// + public List SelectUserRoles(long userId); + + /// + /// 获取用户权限字符串集合 + /// + /// + /// + public List SelectUserRoleKeys(long userId); + + public List SelectUserRoleNames(long userId); + + #endregion + + /// + /// 修改保存角色信息 + /// + /// 角色信息 + /// + public int UpdateRole(SysRole sysRole); + } +} diff --git a/ARW.Service/System/IService/ISysTasksLogService.cs b/ARW.Service/System/IService/ISysTasksLogService.cs new file mode 100644 index 0000000..a11cb31 --- /dev/null +++ b/ARW.Service/System/IService/ISysTasksLogService.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using ARW.Model.System; +using ARW.Repository; + +namespace ARW.Service.System.IService +{ + public interface ISysTasksLogService : IBaseService + { + /// + /// 记录任务执行日志 + /// + /// + //public int AddTaskLog(string jobId); + Task AddTaskLog(string jobId, SysTasksLog tasksLog); + } +} diff --git a/ARW.Service/System/IService/ISysTasksQzService.cs b/ARW.Service/System/IService/ISysTasksQzService.cs new file mode 100644 index 0000000..29a6be6 --- /dev/null +++ b/ARW.Service/System/IService/ISysTasksQzService.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ARW.Model.System; + +namespace ARW.Service.System.IService +{ + public interface ISysTasksQzService : IBaseService + { + //SysTasksQz GetId(object id); + } +} diff --git a/ARW.Service/System/IService/ISysUserPostService.cs b/ARW.Service/System/IService/ISysUserPostService.cs new file mode 100644 index 0000000..feeeb63 --- /dev/null +++ b/ARW.Service/System/IService/ISysUserPostService.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using ARW.Model.System; + +namespace ARW.Service.System.IService +{ + public interface ISysUserPostService + { + public void InsertUserPost(SysUser user); + + public List GetUserPostsByUserId(long userId); + + public string GetPostsStrByUserId(long userId); + bool Delete(long userId); + } +} diff --git a/ARW.Service/System/IService/ISysUserRoleService.cs b/ARW.Service/System/IService/ISysUserRoleService.cs new file mode 100644 index 0000000..467955f --- /dev/null +++ b/ARW.Service/System/IService/ISysUserRoleService.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ARW.Model; +using ARW.Model.System.Dto; +using ARW.Model.System; + +namespace ARW.Service.System.IService +{ + public interface ISysUserRoleService + { + public int CountUserRoleByRoleId(long roleId); + + /// + /// 删除用户角色 + /// + /// + /// + public int DeleteUserRoleByUserId(int userId); + + /// + /// 批量删除角色对应用户 + /// + /// + /// + /// + public int DeleteRoleUserByUserIds(long roleId, List userIds); + + /// + /// 添加用户角色 + /// + /// + /// + public int AddUserRole(List sysUsers); + + /// + /// 获取用户数据根据角色id + /// + /// + /// + public List GetSysUsersByRoleId(long roleId); + + /// + /// 获取用户数据根据角色id + /// + /// + /// + public PagedInfo GetSysUsersByRoleId(RoleUserQueryDto roleUserQueryDto); + + /// + /// 获取尚未指派的用户数据根据角色id + /// + /// + /// + public PagedInfo GetExcludedSysUsersByRoleId(RoleUserQueryDto roleUserQueryDto); + + /// + /// 新增用户角色信息 + /// + /// + /// + public int InsertUserRole(SysUser user); + + /// + /// 新增加角色用户 + /// + /// 角色id + /// 用户ids + /// + public int InsertRoleUser(RoleUsersCreateDto roleUsersCreateDto); + } +} diff --git a/ARW.Service/System/IService/ISysUserService.cs b/ARW.Service/System/IService/ISysUserService.cs new file mode 100644 index 0000000..64755db --- /dev/null +++ b/ARW.Service/System/IService/ISysUserService.cs @@ -0,0 +1,82 @@ +using ARW.Model; +using ARW.Model.System; +using ARW.Model.System.Dto; + +namespace ARW.Service.System.IService +{ + public interface ISysUserService : IBaseService + { + public PagedInfo SelectUserList(SysUser user, PagerInfo pager); + + /// + /// 通过用户ID查询用户 + /// + /// + /// + public SysUser SelectUserById(long userId); + + /// + /// 通过邮箱查找用户 + /// + /// + /// + public SysUser SelectUserByEmail(string email); + + + /// + /// 校验用户名称是否唯一 + /// + /// + /// + public string CheckUserNameUnique(string userName); + + /// + /// 新增保存用户信息 + /// + /// + /// + public long InsertUser(SysUser sysUser); + + /// + /// 修改用户信息 + /// + /// + /// + public int UpdateUser(SysUser user); + + public int ChangeUser(SysUser user); + + /// + /// 重置密码 + /// + /// + /// + /// + public int ResetPwd(long userid, string password); + + public int ChangeUserStatus(SysUser user); + + /// + /// 删除用户 + /// + /// + /// + public int DeleteUser(long userid); + + /// + /// 修改用户头像 + /// + /// + /// + public int UpdatePhoto(SysUser user); + + /// + /// 注册 + /// + /// + /// + SysUser Register(RegisterDto dto); + void CheckUserAllowed(SysUser user); + void CheckUserDataScope(long userid, long loginUserId); + } +} diff --git a/ARW.Service/System/SysConfigService.cs b/ARW.Service/System/SysConfigService.cs new file mode 100644 index 0000000..636773d --- /dev/null +++ b/ARW.Service/System/SysConfigService.cs @@ -0,0 +1,28 @@ +using Infrastructure.Attribute; +using ARW.Model.System; +using ARW.Repository; + +namespace ARW.Service.System +{ + /// + /// 参数配置Service业务层处理 + /// + [AppService(ServiceType = typeof(ISysConfigService), ServiceLifetime = LifeTime.Transient)] + public class SysConfigService : BaseService, ISysConfigService + { + private readonly SysConfigRepository _SysConfigrepository; + public SysConfigService(SysConfigRepository repository) + { + _SysConfigrepository = repository; + } + + #region 业务逻辑代码 + + public SysConfig GetSysConfigByKey(string key) + { + return _SysConfigrepository.Queryable().First(f => f.ConfigKey == key); + } + + #endregion + } +} \ No newline at end of file diff --git a/ARW.Service/System/SysDeptService.cs b/ARW.Service/System/SysDeptService.cs new file mode 100644 index 0000000..fa084e2 --- /dev/null +++ b/ARW.Service/System/SysDeptService.cs @@ -0,0 +1,288 @@ +using Infrastructure; +using Infrastructure.Attribute; +using Infrastructure.Extensions; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ARW.Common; +using ARW.Model.System; +using ARW.Model.System.Vo; +using ARW.Repository.System; +using ARW.Service.System.IService; + +namespace ARW.Service.System +{ + /// + /// 部门管理 + /// + [AppService(ServiceType = typeof(ISysDeptService), ServiceLifetime = LifeTime.Transient)] + public class SysDeptService : BaseService, ISysDeptService + { + public SysDeptRepository DeptRepository; + public SysRoleDeptRepository RoleDeptRepository; + public SysDeptService(SysDeptRepository deptRepository, SysRoleDeptRepository roleDeptRepository) + { + DeptRepository = deptRepository; + RoleDeptRepository = roleDeptRepository; + } + + /// + /// 查询部门管理数据 + /// + /// + /// + public List GetSysDepts(SysDept dept) + { + //开始拼装查询条件 + var predicate = Expressionable.Create(); + predicate = predicate.And(it => it.DelFlag == "0"); + predicate = predicate.AndIF(dept.DeptName.IfNotEmpty(), it => it.DeptName.Contains(dept.DeptName)); + predicate = predicate.AndIF(dept.Status.IfNotEmpty(), it => it.Status == dept.Status); + + var response = DeptRepository.GetList(predicate.ToExpression()); + + return response; + } + + /// + /// 校验部门名称是否唯一 + /// + /// + /// + public string CheckDeptNameUnique(SysDept dept) + { + long deptId = dept.DeptId == 0 ? -1L : dept.DeptId; + SysDept info = DeptRepository.GetFirst(it => it.DeptName == dept.DeptName && it.ParentId == dept.ParentId); + if (info != null && info.DeptId != deptId) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /// + /// 新增保存部门信息 + /// + /// + /// + public int InsertDept(SysDept dept) + { + SysDept info = DeptRepository.GetFirst(it => it.DeptId == dept.ParentId); + //如果父节点不为正常状态,则不允许新增子节点 + if (info != null && !UserConstants.DEPT_NORMAL.Equals(info?.Status)) + { + throw new CustomException("部门停用,不允许新增"); + } + dept.Ancestors = ""; + if (info != null) + { + dept.Ancestors = info.Ancestors + "," + dept.ParentId; + } + return DeptRepository.Add(dept); + } + + /// + /// 修改保存部门信息 + /// + /// + /// + public int UpdateDept(SysDept dept) + { + SysDept newParentDept = DeptRepository.GetFirst(it => it.DeptId == dept.ParentId); + SysDept oldDept = DeptRepository.GetFirst(m => m.DeptId == dept.DeptId); + if (newParentDept != null && oldDept != null) + { + string newAncestors = newParentDept.Ancestors + "," + newParentDept.DeptId; + string oldAncestors = oldDept.Ancestors; + dept.Ancestors = newAncestors; + UpdateDeptChildren(dept.DeptId, newAncestors, oldAncestors); + } + int result = DeptRepository.Context.Updateable(dept).ExecuteCommand(); + if (UserConstants.DEPT_NORMAL.Equals(dept.Status) && dept.Ancestors.IfNotEmpty() + && !"0".Equals(dept.Ancestors)) + { + // 如果该部门是启用状态,则启用该部门的所有上级部门 + UpdateParentDeptStatusNormal(dept); + } + return result; + } + + /// + /// 修改该部门的父级部门状态 + /// + /// 当前部门 + private void UpdateParentDeptStatusNormal(SysDept dept) + { + long[] depts = Tools.SpitLongArrary(dept.Ancestors); + dept.Status = "0"; + dept.Update_time = DateTime.Now; + + DeptRepository.Update(dept, it => new { it.Update_by, it.Update_time, it.Status }, f => depts.Contains(f.DeptId)); + } + + /// + /// 修改子元素关系 + /// + /// 被修改的部门ID + /// 新的父ID集合 + /// 旧的父ID集合 + public void UpdateDeptChildren(long deptId, string newAncestors, string oldAncestors) + { + List children = GetChildrenDepts(GetSysDepts(new SysDept()), deptId); + + foreach (var child in children) + { + string ancestors = child.Ancestors.ReplaceFirst(oldAncestors, newAncestors); + long[] ancestorsArr = Tools.SpitLongArrary(ancestors).Distinct().ToArray(); + child.Ancestors = string.Join(",", ancestorsArr); + } + if (children.Any()) + { + DeptRepository.UdateDeptChildren(children); + } + } + + /// + /// 获取所有子部门 + /// + /// + /// + /// + public List GetChildrenDepts(List depts, long deptId) + { + return depts.FindAll(delegate (SysDept item) + { + long[] pid = Tools.SpitLongArrary(item.Ancestors); + return pid.Contains(deptId); + }); + } + + /// + /// 构建前端所需要树结构 + /// + /// 部门列表 + /// + public List BuildDeptTree(List depts) + { + List returnList = new List(); + List tempList = depts.Select(f => f.DeptId).ToList(); + foreach (var dept in depts) + { + // 如果是顶级节点, 遍历该父节点的所有子节点 + if (!tempList.Contains(dept.ParentId)) + { + RecursionFn(depts, dept); + returnList.Add(dept); + } + } + + if (!returnList.Any()) + { + returnList = depts; + } + return returnList; + } + + /// + /// 构建前端所需下拉树结构 + /// + /// + /// + public List BuildDeptTreeSelect(List depts) + { + List menuTrees = BuildDeptTree(depts); + List treeMenuVos = new List(); + foreach (var item in menuTrees) + { + treeMenuVos.Add(new TreeSelectVo(item)); + } + return treeMenuVos; + } + + /// + /// 递归列表 + /// + /// + /// + private void RecursionFn(List list, SysDept t) + { + //得到子节点列表 + List childList = GetChildList(list, t); + t.children = childList; + foreach (var item in childList) + { + if (GetChildList(list, item).Count() > 0) + { + RecursionFn(list, item); + } + } + } + /// + /// 递归获取子菜单 + /// + /// 所有菜单 + /// + /// + private List GetChildList(List list, SysDept dept) + { + return list.Where(p => p.ParentId == dept.DeptId).ToList(); + } + + #region 角色部门 + + /// + /// 根据角色获取菜单id + /// + /// + /// + public List SelectRoleDeptByRoleId(long roleId) + { + return RoleDeptRepository.SelectRoleDeptByRoleId(roleId); + } + + /// + /// 获取角色部门id集合 + /// + /// + /// + public List SelectRoleDepts(long roleId) + { + var list = SelectRoleDeptByRoleId(roleId); + + return list.Select(x => x.DeptId).Distinct().ToList(); + } + + /// + /// 删除角色部门数据 + /// + /// + /// + public bool DeleteRoleDeptByRoleId(long roleId) + { + return RoleDeptRepository.Delete(f => f.RoleId == roleId); + } + + /// + /// 批量插入角色部门 + /// + /// + /// + public int InsertRoleDepts(SysRole role) + { + int rows = 1; + List list = new(); + foreach (var item in role.DeptIds) + { + list.Add(new SysRoleDept() { DeptId = item, RoleId = role.RoleId }); + } + if (list.Count > 0) + { + rows = RoleDeptRepository.Insert(list); + } + return rows; + } + #endregion + } +} diff --git a/ARW.Service/System/SysDictDataService.cs b/ARW.Service/System/SysDictDataService.cs new file mode 100644 index 0000000..fef9a06 --- /dev/null +++ b/ARW.Service/System/SysDictDataService.cs @@ -0,0 +1,110 @@ +using Infrastructure.Attribute; +using Infrastructure.Model; +using System; +using System.Collections.Generic; +using System.Text; +using ARW.Common; +using ARW.Model; +using ARW.Model.System; +using ARW.Repository.System; +using ARW.Service.System.IService; + +namespace ARW.Service.System +{ + /// + /// 字典数据类 + /// + [AppService(ServiceType = typeof(ISysDictDataService), ServiceLifetime = LifeTime.Transient)] + public class SysDictDataService : BaseService, ISysDictDataService + { + + private readonly SysDictDataRepository SysDictDataRepository; + public SysDictDataService(SysDictDataRepository sysDictDataRepository) + { + SysDictDataRepository = sysDictDataRepository; + } + + /// + /// 查询字典数据 + /// + /// + /// + public PagedInfo SelectDictDataList(SysDictData dictData, PagerInfo pagerInfo) + { + return SysDictDataRepository.SelectDictDataList(dictData, pagerInfo); + } + + /// + /// 根据字典类型查询 + /// + /// + /// + public List SelectDictDataByType(string dictType) + { + string CK = $"SelectDictDataByType_{dictType}"; + if (CacheHelper.GetCache(CK) is not List list) + { + list = SysDictDataRepository.SelectDictDataByType(dictType); + CacheHelper.SetCache(CK, list, 30); + } + return list; + } + public List SelectDictDataByTypes(string[] dictTypes) + { + string CK = $"SelectDictDataByTypes_{dictTypes}"; + if (CacheHelper.GetCache(CK) is not List list) + { + list = SysDictDataRepository.SelectDictDataByTypes(dictTypes); + //CacheHelper.SetCache(CK, list, 30); + } + return list; + } + /// + /// 根据字典数据ID查询信息 + /// + /// + /// + public SysDictData SelectDictDataById(long dictCode) + { + string CK = $"SelectDictDataByCode_{dictCode}"; + if (CacheHelper.GetCache(CK) is not SysDictData list) + { + list = SysDictDataRepository.GetFirst(f => f.DictCode == dictCode); + CacheHelper.SetCache(CK, list, 5); + } + return list; + } + + /// + /// 插入数据 + /// + /// + /// + public long InsertDictData(SysDictData dict) + { + return SysDictDataRepository.InsertDictData(dict); + } + + /// + /// 修改数据 + /// + /// + /// + public long UpdateDictData(SysDictData dict) + { + var result = SysDictDataRepository.UpdateDictData(dict); + CacheHelper.Remove($"SelectDictDataByCode_{dict.DictCode}"); + return result; + } + + /// + /// 批量删除字典数据信息 + /// + /// + /// + public int DeleteDictDataByIds(long[] dictCodes) + { + return SysDictDataRepository.DeleteDictDataByIds(dictCodes); + } + } +} diff --git a/ARW.Service/System/SysDictService.cs b/ARW.Service/System/SysDictService.cs new file mode 100644 index 0000000..b3f817c --- /dev/null +++ b/ARW.Service/System/SysDictService.cs @@ -0,0 +1,117 @@ +using Infrastructure; +using Infrastructure.Attribute; +using System.Collections.Generic; +using System.Text; +using ARW.Model; +using ARW.Model.System; +using ARW.Repository.System; +using ARW.Service.System.IService; + +namespace ARW.Service.System +{ + /// + /// 字典类型 + /// + [AppService(ServiceType = typeof(ISysDictService), ServiceLifetime = LifeTime.Transient)] + public class SysDictService : BaseService, ISysDictService + { + private SysDictRepository DictRepository; + private SysDictDataRepository DictDataRepository; + + public SysDictService(SysDictRepository sysDictRepository, SysDictDataRepository dictDataRepository) + { + this.DictRepository = sysDictRepository; + this.DictDataRepository = dictDataRepository; + } + public List GetAll() + { + return DictRepository.GetAll(); + } + + /// + /// 查询字段类型列表 + /// + /// 实体模型 + /// + public PagedInfo SelectDictTypeList(SysDictType dictType, Model.PagerInfo pager) + { + return DictRepository.SelectDictTypeList(dictType, pager); + } + + /// + /// 校验字典类型称是否唯一 + /// + /// 字典类型 + /// + public string CheckDictTypeUnique(SysDictType dictType) + { + SysDictType sysDictType = DictRepository.GetFirst(f => f.DictType == dictType.DictType); + if (sysDictType != null && sysDictType.DictId != dictType.DictId) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /// + /// 批量删除字典数据信息 + /// + /// + /// + public int DeleteDictTypeByIds(long[] dictIds) + { + foreach (var dictId in dictIds) + { + SysDictType dictType = DictRepository.GetFirst(x => x.DictId == dictId); + if (DictDataRepository.Count(f => f.DictType == dictType.DictType) > 0) + { + throw new CustomException($"{dictType.DictName}已分配,不能删除"); + } + } + int count = DictRepository.DeleteDictTypeByIds(dictIds); + //if (count > 0) + //{ + // DictUtils.clearDictCache(); + //} + return count; + } + + /// + /// 插入字典类型 + /// + /// + /// + public long InsertDictType(SysDictType sysDictType) + { + return DictRepository.InsertReturnBigIdentity(sysDictType); + } + + /// + /// 修改字典类型 + /// + /// + /// + public int UpdateDictType(SysDictType sysDictType) + { + SysDictType oldDict = DictRepository.GetFirst(x => x.DictId == sysDictType.DictId); + if (sysDictType.DictType != oldDict.DictType) + { + //同步修改 dict_data表里面的DictType值 + DictDataRepository.UpdateDictDataType(oldDict.DictType, sysDictType.DictType); + } + return DictRepository.UpdateDictType(sysDictType); + } + + /// + /// 获取字典信息 + /// + /// + /// + public SysDictType GetInfo(long dictId) + { + return DictRepository.GetFirst(f => f.DictId == dictId); + } + + + } +} diff --git a/ARW.Service/System/SysFileService.cs b/ARW.Service/System/SysFileService.cs new file mode 100644 index 0000000..0d46da6 --- /dev/null +++ b/ARW.Service/System/SysFileService.cs @@ -0,0 +1,247 @@ +using Infrastructure; +using Infrastructure.Attribute; +using Infrastructure.Extensions; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; +using System; +using System.IO; +using System.Net; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; +using ARW.Common; +using ARW.Model.System; +using ARW.Service.System.IService; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.Drawing; +using Encoder = System.Drawing.Imaging.Encoder; + +namespace ARW.Service.System +{ + /// + /// 文件管理 + /// + [AppService(ServiceType = typeof(ISysFileService), ServiceLifetime = LifeTime.Transient)] + public class SysFileService : BaseService, ISysFileService + { + private string domainUrl = AppSettings.GetConfig("AARWYUN_OSS:domainUrl"); + private readonly ISysConfigService SysConfigService; + private OptionsSetting OptionsSetting; + public SysFileService(ISysConfigService sysConfigService, IOptions options) + { + SysConfigService = sysConfigService; + OptionsSetting = options.Value; + } + + /// + /// 存储本地 + /// + /// 存储文件夹 + /// 存储根目录 + /// 自定文件名 + /// 上传的文件流 + /// + /// + public async Task SaveFileToLocal(string rootPath, string fileName, string fileDir, string userName, IFormFile formFile) + { + string fileExt = Path.GetExtension(formFile.FileName); + fileName = (fileName.IsEmpty() ? HashFileName() : fileName) + fileExt; + + string filePath = GetdirPath(fileDir); + string finalFilePath = Path.Combine(rootPath, filePath, fileName); + double fileSize = Math.Round(formFile.Length / 1024.0, 2); + + if (!Directory.Exists(Path.GetDirectoryName(finalFilePath))) + { + Directory.CreateDirectory(Path.GetDirectoryName(finalFilePath)); + } + + using (var stream = new FileStream(finalFilePath, FileMode.Create)) + { + if (fileSize > 100) + { + GetPicThumbnail(formFile, 0, 0, 90, stream); + } + else + { + await formFile.CopyToAsync(stream); + } + } + + var fs = File.OpenRead(@finalFilePath); + fileSize = Math.Round(fs.Length / 1024.0, 2); + + string uploadUrl = OptionsSetting.Upload.UploadUrl; + string accessPath = string.Concat(uploadUrl, "/", filePath.Replace("\\", "/"), "/", fileName); + SysFile file = new(formFile.FileName, fileName, fileExt, fileSize + "kb", filePath, userName) + { + StoreType = (int)Infrastructure.Enums.StoreType.LOCAL, + FileType = formFile.ContentType, + FileUrl = finalFilePath.Replace("\\", "/"), + AccessUrl = accessPath + }; + file.Id = await InsertFile(file); + return file; + } + + /// + /// 上传文件到阿里云 + /// + /// + /// + /// + public async Task SaveFileToAliyun(SysFile file, IFormFile formFile) + { + 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; + + file.StorePath = file.StorePath; + file.FileUrl = finalPath; + file.AccessUrl = string.Concat(domainUrl, "/", file.StorePath.Replace("\\", "/"), "/", file.FileName); + file.Id = await InsertFile(file); + + return file; + } + + /// + /// 获取文件存储目录 + /// + /// + /// 是否按年月日存储 + /// + public string GetdirPath(string storePath = "", bool byTimeStore = true) + { + DateTime date = DateTime.Now; + string timeDir = date.ToString("yyyyMMdd"); + + if (!string.IsNullOrEmpty(storePath)) + { + timeDir = Path.Combine(storePath, timeDir); + } + return timeDir; + } + + public string HashFileName(string str = null) + { + if (string.IsNullOrEmpty(str)) + { + str = Guid.NewGuid().ToString(); + } + MD5 md5 = MD5.Create(); + return BitConverter.ToString(md5.ComputeHash(Encoding.Default.GetBytes(str)), 4, 8).Replace("-", ""); + } + + public Task InsertFile(SysFile file) + { + try + { + return Insertable(file).ExecuteReturnSnowflakeIdAsync();//单条插入返回雪花ID; + } + catch (Exception ex) + { + Console.WriteLine("存储图片失败" + ex.Message); + throw new Exception(ex.Message); + } + } + + #region GetPicThumbnail + public static bool GetPicThumbnail(IFormFile stream, int dHeight, int dWidth, int flag, Stream outstream) + { + //可以直接从流里边得到图片,这样就可以不先存储一份了 + Image iSource = Image.FromStream(stream.OpenReadStream()); + + //如果为参数为0就保持原图片 + if (dHeight == 0) + { + dHeight = iSource.Height; + } + if (dWidth == 0) + { + dWidth = iSource.Width; + } + + + ImageFormat tFormat = iSource.RawFormat; + int sW = 0, sH = 0; + + //按比例缩放 + Size tem_size = new Size(iSource.Width, iSource.Height); + + if (tem_size.Width > dHeight || tem_size.Width > dWidth) + { + if ((tem_size.Width * dHeight) > (tem_size.Width * dWidth)) + { + sW = dWidth; + sH = (dWidth * tem_size.Height) / tem_size.Width; + } + else + { + sH = dHeight; + sW = (tem_size.Width * dHeight) / tem_size.Height; + } + } + else + { + sW = tem_size.Width; + sH = tem_size.Height; + } + + Bitmap ob = new Bitmap(dWidth, dHeight); + Graphics g = Graphics.FromImage(ob); + + g.Clear(Color.WhiteSmoke); + g.CompositingQuality = CompositingQuality.HighQuality; + g.SmoothingMode = SmoothingMode.HighQuality; + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + + g.DrawImage(iSource, new Rectangle((dWidth - sW) / 2, (dHeight - sH) / 2, sW, sH), 0, 0, iSource.Width, iSource.Height, GraphicsUnit.Pixel); + + g.Dispose(); + //以下代码为保存图片时,设置压缩质量 + EncoderParameters ep = new EncoderParameters(); + long[] qy = new long[1]; + qy[0] = flag;//设置压缩的比例1-100 + EncoderParameter eParam = new EncoderParameter(Encoder.Quality, qy); + ep.Param[0] = eParam; + try + { + ImageCodecInfo[] arrayICI = ImageCodecInfo.GetImageEncoders(); + ImageCodecInfo jpegICIinfo = null; + for (int x = 0; x < arrayICI.Length; x++) + { + if (arrayICI[x].FormatDescription.Equals("JPEG")) + { + jpegICIinfo = arrayICI[x]; + break; + } + } + if (jpegICIinfo != null) + { + //可以存储在流里边; + ob.Save(outstream, jpegICIinfo, ep); + + } + else + { + ob.Save(outstream, tFormat); + } + return true; + } + catch + { + return false; + } + finally + { + iSource.Dispose(); + ob.Dispose(); + } + } + #endregion + + } +} diff --git a/ARW.Service/System/SysLoginService.cs b/ARW.Service/System/SysLoginService.cs new file mode 100644 index 0000000..da44a4b --- /dev/null +++ b/ARW.Service/System/SysLoginService.cs @@ -0,0 +1,106 @@ +using Infrastructure; +using Infrastructure.Attribute; +using System; +using System.Collections.Generic; +using ARW.Common; +using ARW.Model; +using ARW.Model.System.Dto; +using ARW.Model.System; +using ARW.Repository.System; +using ARW.Service.System.IService; + +namespace ARW.Service.System +{ + /// + /// 登录 + /// + [AppService(ServiceType = typeof(ISysLoginService), ServiceLifetime = LifeTime.Transient)] + public class SysLoginService: BaseService, ISysLoginService + { + private SysLogininfoRepository SysLogininfoRepository; + + public SysLoginService(SysLogininfoRepository sysLogininfo) + { + SysLogininfoRepository = sysLogininfo; + } + + /// + /// 登录验证 + /// + /// + /// + public SysUser Login(LoginBodyDto loginBody, SysLogininfor logininfor) + { + //密码md5 + loginBody.Password = NETCore.Encrypt.EncryptProvider.Md5(loginBody.Password); + + SysUser user = SysLogininfoRepository.Login(loginBody); + logininfor.userName = loginBody.Username; + logininfor.status = "1"; + logininfor.loginTime = DateTime.Now; + + if (user == null || user.UserId <= 0) + { + logininfor.msg = "用户名或密码错误"; + AddLoginInfo(logininfor); + throw new CustomException(ResultCode.LOGIN_ERROR ,logininfor.msg); + } + if (user.Status == "1") + { + logininfor.msg = "该用户已禁用"; + AddLoginInfo(logininfor); + throw new CustomException(ResultCode.LOGIN_ERROR, logininfor.msg); + } + + logininfor.status = "0"; + logininfor.msg = "登录成功"; + AddLoginInfo(logininfor); + SysLogininfoRepository.UpdateLoginInfo(loginBody, user.UserId); + return user; + } + + + /// + /// 查询操作日志 + /// + /// + /// 分页 + /// + public PagedInfo GetLoginLog(SysLogininfor logininfoDto, PagerInfo pager) + { + logininfoDto.BeginTime = DateTimeHelper.GetBeginTime(logininfoDto.BeginTime, -1); + logininfoDto.EndTime = DateTimeHelper.GetBeginTime(logininfoDto.EndTime, 1); + + var list = SysLogininfoRepository.GetLoginLog(logininfoDto, pager); + return list; + } + + /// + /// 记录登录日志 + /// + /// + /// + public void AddLoginInfo(SysLogininfor sysLogininfor) + { + SysLogininfoRepository.AddLoginInfo(sysLogininfor); + } + + /// + /// 清空登录日志 + /// + public void TruncateLogininfo() + { + SysLogininfoRepository.TruncateLogininfo(); + } + + /// + /// 删除登录日志 + /// + /// + /// + public int DeleteLogininforByIds(long[] ids) + { + return SysLogininfoRepository.DeleteLogininforByIds(ids); + } + } +} diff --git a/ARW.Service/System/SysMenuService.cs b/ARW.Service/System/SysMenuService.cs new file mode 100644 index 0000000..59c0fd2 --- /dev/null +++ b/ARW.Service/System/SysMenuService.cs @@ -0,0 +1,496 @@ +using Infrastructure.Attribute; +using System.Collections.Generic; +using System.Linq; +using ARW.Model.System.Dto; +using ARW.Model.System; +using ARW.Model.System.Vo; +using ARW.Repository.System; +using ARW.Service.System.IService; +using ARW.Common; +using Infrastructure.Extensions; + +namespace ARW.Service +{ + /// + /// 菜单 + /// + [AppService(ServiceType = typeof(ISysMenuService), ServiceLifetime = LifeTime.Transient)] + public class SysMenuService : BaseService, ISysMenuService + { + public SysMenuRepository MenuRepository; + public ISysRoleService SysRoleService; + + public SysMenuService( + SysMenuRepository menuRepository, + ISysRoleService sysRoleService) + { + MenuRepository = menuRepository; + SysRoleService = sysRoleService; + } + + /// + /// 获取所有菜单数(菜单管理) + /// + /// + public List SelectTreeMenuList(MenuQueryDto menu, long userId) + { + List menuList; + if (SysRoleService.IsAdmin(userId)) + { + menuList = MenuRepository.SelectTreeMenuList(menu); + } + else + { + var userRoles = SysRoleService.SelectUserRoles(userId); + menuList = MenuRepository.SelectTreeMenuListByRoles(menu, userRoles); + } + return menuList; + } + + /// + /// 获取所有菜单列表 + /// + /// + public List SelectMenuList(MenuQueryDto menu, long userId) + { + List menuList; + if (SysRoleService.IsAdmin(userId)) + { + menuList = MenuRepository.SelectMenuList(menu); + } + else + { + var userRoles = SysRoleService.SelectUserRoles(userId); + menuList = MenuRepository.SelectMenuListByRoles(menu, userRoles); + } + return menuList; + } + + /// + /// 获取菜单详情 + /// + /// + /// + public SysMenu GetMenuByMenuId(int menuId) + { + return MenuRepository.SelectMenuById(menuId); + } + + /// + /// 根据菜单id获取菜单列表 + /// + /// + /// + public List GetMenusByMenuId(int menuId) + { + var list = MenuRepository.GetList(f => f.parentId == menuId).OrderBy(f => f.orderNum).ToList(); + Context.ThenMapper(list, item => + { + item.SubNum = Context.Queryable().SetContext(x => x.parentId, () => item.MenuId, item).Count; + }); + return list; + } + + /// + /// 添加菜单 + /// + /// + /// + public int AddMenu(SysMenu menu) + { + return MenuRepository.AddMenu(menu); + } + + /// + /// 编辑菜单 + /// + /// + /// + public int EditMenu(SysMenu menu) + { + menu.icon = string.IsNullOrEmpty(menu.icon) ? "" : menu.icon; + return MenuRepository.EditMenu(menu); + } + + /// + /// 删除菜单管理信息 + /// + /// + /// + public int DeleteMenuById(int menuId) + { + return MenuRepository.DeleteMenuById(menuId); + } + + /// + /// 校验菜单名称是否唯一 + /// + /// + /// + public string CheckMenuNameUnique(SysMenu menu) + { + long menuId = menu.MenuId == 0 ? -1 : menu.MenuId; + SysMenu info = MenuRepository.CheckMenuNameUnique(menu); + + //if (info != null && menuId != info.menuId && menu.menuName.Equals(info.menuName)) + //{ + // return UserConstants.NOT_UNIQUE; + //} + if (info != null && info.MenuId != menu.MenuId) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /// + /// 菜单排序 + /// + /// + /// + public int ChangeSortMenu(MenuDto menuDto) + { + return MenuRepository.ChangeSortMenu(menuDto); + } + + /// + /// 是否存在菜单子节点 + /// + /// + /// + public bool HasChildByMenuId(long menuId) + { + return MenuRepository.HasChildByMenuId(menuId) > 0; + } + + /// + /// 获取子级菜单 + /// + /// + /// + public List SelectChildByMenuId(long menuId) + { + return MenuRepository.GetList(it => it.parentId == menuId); + } + + /// + /// 获取左边导航栏菜单树 + /// + /// + /// + public List SelectMenuTreeByUserId(long userId) + { + MenuQueryDto dto = new() { Status = "0", MenuTypeIds = "M,C" }; + if (SysRoleService.IsAdmin(userId)) + { + return MenuRepository.SelectTreeMenuList(dto); + } + else + { + List roleIds = SysRoleService.SelectUserRoles(userId); + return MenuRepository.SelectTreeMenuListByRoles(dto, roleIds); + } + } + + /// + /// 查询菜单权限 + /// + /// + /// + public List SelectMenuPermsListByUserId(long userId) + { + return MenuRepository.SelectMenuPermsByUserId(userId); + } + + /// + /// 查询精确到按钮的操作权限 + /// + /// + /// + public List SelectMenuPermsByUserId(long userId) + { + var menuList = SelectMenuPermsListByUserId(userId).Where(f => !string.IsNullOrEmpty(f.perms)); + + return menuList.Select(x => x.perms).Distinct().ToList(); + } + + #region RoleMenu + + /// + /// 查询菜单使用数量 + /// + /// + /// + public bool CheckMenuExistRole(long menuId) + { + return MenuRepository.CheckMenuExistRole(menuId) > 0; + } + + #endregion + + #region 方法 + + ///// + ///// 根据父节点的ID获取所有子节点 + ///// + ///// 分类表 + ///// 传入的父节点ID + ///// + //public List GetChildPerms(List list, int parentId) + //{ + // List returnList = new List(); + // var data = list.FindAll(f => f.parentId == parentId); + + // foreach (var item in data) + // { + // RecursionFn(list, item); + + // returnList.Add(item); + // } + // return returnList; + //} + + /// + /// 递归列表 + /// + /// + /// + private void RecursionFn(List list, SysMenu t) + { + //得到子节点列表 + List childList = GetChildList(list, t); + t.children = childList; + foreach (var item in childList) + { + if (GetChildList(list, item).Count() > 0) + { + RecursionFn(list, item); + } + } + } + + /// + /// 递归获取子菜单 + /// + /// 所有菜单 + /// + /// + private List GetChildList(List list, SysMenu sysMenu) + { + return list.Where(p => p.parentId == sysMenu.MenuId).ToList(); + } + + /// + /// 获取路由侧边栏,动态生成 + /// + /// + /// + public List BuildMenus(List menus) + { + List routers = new List(); + + foreach (var menu in menus) + { + RouterVo router = new() + { + Hidden = "1".Equals(menu.visible), + Name = GetRouteName(menu), + Path = GetRoutePath(menu), + Component = GetComponent(menu), + Meta = new Meta(menu.MenuName, menu.icon, "1".Equals(menu.isCache), menu.MenuNameKey, menu.path) + }; + + List cMenus = menu.children; + //是目录并且有子菜单 + if (cMenus != null && cMenus.Count > 0 && (UserConstants.TYPE_DIR.Equals(menu.menuType))) + { + router.AlwaysShow = true; + router.Redirect = "noRedirect"; + router.Children = BuildMenus(cMenus); + } + else if (IsMeunFrame(menu)) + { + router.Meta = null; + List childrenList = new(); + RouterVo children = new() + { + Path = menu.path, + Component = menu.component, + Name = string.IsNullOrEmpty(menu.path) ? "" : menu.path.ToLower(), + Meta = new Meta(menu.MenuName, menu.icon, "1".Equals(menu.isCache), menu.MenuNameKey, menu.path) + }; + childrenList.Add(children); + router.Children = childrenList; + } + else if (menu.parentId == 0 && IsInnerLink(menu)) + { + router.Meta = new Meta(menu.MenuName, menu.icon); + router.Path = "/"; + List childrenList = new(); + RouterVo children = new(); + string routerPath = InnerLinkReplaceEach(menu.path); + children.Path = routerPath; + children.Component = UserConstants.INNER_ARWNK; + children.Name = routerPath.ToLower(); + children.Meta = new Meta(menu.MenuName, menu.icon, menu.path); + childrenList.Add(children); + router.Children = childrenList; + } + routers.Add(router); + } + + return routers; + } + + /// + /// 构建前端所需要下拉树结构 + /// + /// 菜单列表 + /// 下拉树结构列表 + public List BuildMenuTree(List menus) + { + List returnList = new List(); + List tempList = menus.Select(f => f.MenuId).ToList(); + + foreach (var menu in menus) + { + // 如果是顶级节点, 遍历该父节点的所有子节点 + if (!tempList.Contains(menu.parentId)) + { + RecursionFn(menus, menu); + returnList.Add(menu); + } + } + if (!returnList.Any()) + { + returnList = menus; + } + return returnList; + } + + /// + /// 构建前端所需要下拉树结构 + /// + /// + /// + public List BuildMenuTreeSelect(List menus) + { + List menuTrees = BuildMenuTree(menus); + List treeMenuVos = new List(); + foreach (var item in menuTrees) + { + treeMenuVos.Add(new TreeSelectVo(item)); + } + return treeMenuVos; + } + + /// + /// 获取路由名称 + /// + /// 菜单信息 + /// 路由名称 + public string GetRouteName(SysMenu menu) + { + string routerName = menu.path.ToLower(); + // 非外链并且是一级目录(类型为目录) + if (IsMeunFrame(menu)) + { + routerName = string.Empty; + } + return routerName; + } + + /// + /// 获取路由路径 + /// + /// 菜单信息 + /// 路由地址 + public string GetRoutePath(SysMenu menu) + { + string routerPath = menu.path; + // 内链打开外网方式 + if (menu.parentId != 0 && IsInnerLink(menu)) + { + routerPath = InnerLinkReplaceEach(routerPath); + } + // 非外链并且是一级目录(类型为目录) + if (0 == menu.parentId && UserConstants.TYPE_DIR.Equals(menu.menuType) + && UserConstants.NO_FRAME.Equals(menu.isFrame)) + { + routerPath = "/" + menu.path; + } + else if (IsMeunFrame(menu))// 非外链并且是一级目录(类型为菜单) + { + routerPath = "/"; + } + return routerPath; + } + + /// + /// 获取组件名称 + /// + /// + /// + public string GetComponent(SysMenu menu) + { + string component = UserConstants.LAYOUT; + if (!string.IsNullOrEmpty(menu.component) && !IsMeunFrame(menu)) + { + component = menu.component; + } + else if (menu.component.IsEmpty() && menu.parentId != 0 && IsInnerLink(menu)) + { + component = UserConstants.INNER_ARWNK; + } + else if (string.IsNullOrEmpty(menu.component) && IsParentView(menu)) + { + component = UserConstants.PARENT_VIEW; + } + return component; + } + + /// + /// 是否为菜单内部跳转 + /// + /// 菜单信息 + /// + public bool IsMeunFrame(SysMenu menu) + { + return menu.parentId == 0 && UserConstants.TYPE_MENU.Equals(menu.menuType) + && menu.isFrame.Equals(UserConstants.NO_FRAME); + } + + /// + /// 是否为内链组件 + /// + /// 菜单信息 + /// 结果 + public bool IsInnerLink(SysMenu menu) + { + return menu.isFrame.Equals(UserConstants.NO_FRAME) && Tools.IsUrl(menu.path); + } + + /// + /// + /// 是否为parent_view组件 + /// + /// 菜单信息 + /// + public bool IsParentView(SysMenu menu) + { + return menu.parentId != 0 && UserConstants.TYPE_DIR.Equals(menu.menuType); + } + + /// + /// 内链域名特殊字符替换 + /// + /// + /// < returns > + public string InnerLinkReplaceEach(string path) + { + return path.IsNotEmpty() ? path.Replace(UserConstants.HTTP, "").Replace(UserConstants.HTTPS, "") : path; + } + #endregion + + } +} diff --git a/ARW.Service/System/SysNoticeService.cs b/ARW.Service/System/SysNoticeService.cs new file mode 100644 index 0000000..e2d86a1 --- /dev/null +++ b/ARW.Service/System/SysNoticeService.cs @@ -0,0 +1,46 @@ +using Infrastructure; +using Infrastructure.Attribute; +using SqlSugar; +using System.Collections.Generic; +using ARW.Model.Models; +using ARW.Model.System; +using ARW.Repository; +using ARW.Repository.System; +using ARW.Service.System.IService; + +namespace ARW.Service.System +{ + /// + /// 通知公告表Service业务层处理 + /// + /// @author zr + /// @date 2021-12-15 + /// + [AppService(ServiceType = typeof(ISysNoticeService), ServiceLifetime = LifeTime.Transient)] + public class SysNoticeService : BaseService, ISysNoticeService + { + private readonly SysNoticeRepository _SysNoticerepository; + public SysNoticeService(SysNoticeRepository repository) + { + _SysNoticerepository = repository; + } + + #region 业务逻辑代码 + + /// + /// 查询系统通知 + /// + /// + public List GetSysNotices() + { + //开始拼装查询条件 + var predicate = Expressionable.Create(); + + //搜索条件查询语法参考Sqlsugar + predicate = predicate.And(m => m.Status == "0"); + return _SysNoticerepository.GetList(predicate.ToExpression()); + } + + #endregion + } +} \ No newline at end of file diff --git a/ARW.Service/System/SysOperLogService.cs b/ARW.Service/System/SysOperLogService.cs new file mode 100644 index 0000000..e3ff3b9 --- /dev/null +++ b/ARW.Service/System/SysOperLogService.cs @@ -0,0 +1,86 @@ +using Infrastructure; +using Infrastructure.Attribute; +using ARW.Model; +using ARW.Model.System; +using ARW.Model.System.Dto; +using ARW.Repository.System; +using ARW.Service.System.IService; + +namespace ARW.Service.System +{ + /// + /// 操作日志 + /// + [AppService(ServiceType = typeof(ISysOperLogService), ServiceLifetime = LifeTime.Transient)] + public class SysOperLogService : BaseService, ISysOperLogService + { + public SysOperLogRepository sysOperLogRepository; + + public SysOperLogService(SysOperLogRepository sysOperLog) + { + sysOperLogRepository = sysOperLog; + } + + /// + /// 新增操作日志操作 + /// + /// 日志对象 + public void InsertOperlog(SysOperLog operLog) + { + if (operLog.operParam.Length >= 1000) + { + operLog.operParam = operLog.operParam.Substring(0, 1000); + } + sysOperLogRepository.AddSysOperLog(operLog); + } + + /// + /// 查询系统操作日志集合 + /// + /// 操作日志对象 + /// + /// 操作日志集合 + public PagedInfo SelectOperLogList(SysOperLogDto operLog, PagerInfo pager) + { + operLog.BeginTime = DateTimeHelper.GetBeginTime(operLog.BeginTime, -1); + operLog.EndTime = DateTimeHelper.GetBeginTime(operLog.EndTime, 1); + + bool isDemoMode = AppSettings.GetAppConfig("DemoMode", false); + if (isDemoMode) + { + return new PagedInfo(); + } + var list = sysOperLogRepository.GetSysOperLog(operLog, pager); + + return list; + } + + /// + /// 清空操作日志 + /// + public void CleanOperLog() + { + sysOperLogRepository.ClearOperLog(); + } + + /// + /// 批量删除系统操作日志 + /// + /// 需要删除的操作日志ID + /// 结果 + public int DeleteOperLogByIds(long[] operIds) + { + return sysOperLogRepository.DeleteOperLogByIds(operIds); + } + + /// + /// 查询操作日志详细 + /// + /// 操作ID + /// 操作日志对象 + public SysOperLog SelectOperLogById(long operId) + { + return sysOperLogRepository.SelectOperLogById(operId); + } + } +} diff --git a/ARW.Service/System/SysPermissionService.cs b/ARW.Service/System/SysPermissionService.cs new file mode 100644 index 0000000..125a86b --- /dev/null +++ b/ARW.Service/System/SysPermissionService.cs @@ -0,0 +1,68 @@ +using Infrastructure; +using Infrastructure.Attribute; +using System; +using System.Collections.Generic; +using System.Text; +using ARW.Model.System; +using ARW.Service.System.IService; + +namespace ARW.Service.System +{ + /// + /// 角色权限 + /// + [AppService(ServiceType = typeof(ISysPermissionService), ServiceLifetime = LifeTime.Transient)] + public class SysPermissionService : ISysPermissionService + { + private readonly ISysRoleService SysRoleService; + private readonly ISysMenuService SysMenuService; + + public SysPermissionService( + ISysRoleService sysRoleService, + ISysMenuService sysMenuService) + { + SysRoleService = sysRoleService; + SysMenuService = sysMenuService; + } + + /// + /// 获取角色数据权限 + /// + /// 用户信息 + /// 角色权限信息 + public List GetRolePermission(SysUser user) + { + List roles = new List(); + // 管理员拥有所有权限 + if (user.IsAdmin()) + { + roles.Add("admin"); + } + else + { + roles.AddRange(SysRoleService.SelectUserRoleKeys(user.UserId)); + } + return roles; + } + + /// + /// 获取菜单数据权限 + /// + /// 用户信息 + /// 菜单权限信息 + public List GetMenuPermission(SysUser user) + { + List perms = new(); + // 管理员拥有所有权限 + if (user.IsAdmin() || GetRolePermission(user).Exists(f => f.Equals(GlobalConstant.AdminRole))) + { + perms.Add(GlobalConstant.AdminPerm); + } + else + { + perms.AddRange(SysMenuService.SelectMenuPermsByUserId(user.UserId)); + } + return perms; + } + } +} diff --git a/ARW.Service/System/SysPostService.cs b/ARW.Service/System/SysPostService.cs new file mode 100644 index 0000000..12b05ac --- /dev/null +++ b/ARW.Service/System/SysPostService.cs @@ -0,0 +1,59 @@ +using Infrastructure.Attribute; +using System; +using System.Collections.Generic; +using System.Text; +using ARW.Model.System; +using ARW.Repository; +using ARW.Repository.System; +using ARW.Service.System.IService; + +namespace ARW.Service.System +{ + /// + /// 岗位管理 + /// + [AppService(ServiceType = typeof(ISysPostService), ServiceLifetime = LifeTime.Transient)] + public class SysPostService : BaseService, ISysPostService + { + public SysPostRepository PostRepository; + public SysPostService(SysPostRepository postRepository) + { + PostRepository = postRepository; + } + + /// + /// 校验岗位编码是否唯一 + /// + /// + /// + public string CheckPostCodeUnique(SysPost post) + { + SysPost info = PostRepository.GetFirst(it => it.PostCode.Equals(post.PostCode)); + if (info != null && info.PostId != post.PostId) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /// + /// 校验岗位名称是否唯一 + /// + /// + /// + public string CheckPostNameUnique(SysPost post) + { + SysPost info = PostRepository.GetFirst(it => it.PostName.Equals(post.PostName)); + if (info != null && info.PostId != post.PostId) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + public List GetAll() + { + return PostRepository.GetAll(); + } + } +} diff --git a/ARW.Service/System/SysRoleService.cs b/ARW.Service/System/SysRoleService.cs new file mode 100644 index 0000000..52d0edb --- /dev/null +++ b/ARW.Service/System/SysRoleService.cs @@ -0,0 +1,315 @@ +using Infrastructure; +using Infrastructure.Attribute; +using Infrastructure.Model; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ARW.Model; +using ARW.Model.System; +using ARW.Repository.System; +using ARW.Service.System.IService; + +namespace ARW.Service +{ + /// + /// 角色 + /// + [AppService(ServiceType = typeof(ISysRoleService), ServiceLifetime = LifeTime.Transient)] + public class SysRoleService : BaseService, ISysRoleService + { + private SysRoleRepository SysRoleRepository; + private ISysUserRoleService SysUserRoleService; + private ISysDeptService DeptService; + + public SysRoleService( + SysRoleRepository sysRoleRepository, + ISysUserRoleService sysUserRoleService, + ISysDeptService deptService) + { + SysRoleRepository = sysRoleRepository; + SysUserRoleService = sysUserRoleService; + DeptService = deptService; + } + + /// + /// 根据条件分页查询角色数据 + /// + /// 角色信息 + /// 分页信息 + /// 角色数据集合信息 + public PagedInfo SelectRoleList(SysRole role, PagerInfo pager) + { + return SysRoleRepository.SelectRoleList(role, pager); + } + + /// + /// 查询所有角色 + /// + /// + /// + public List SelectRoleAll() + { + return SysRoleRepository.SelectRoleList(); + } + + /// + /// 根据用户查询 + /// + /// + /// + public List SelectRolePermissionByUserId(long userId) + { + return SysRoleRepository.SelectRolePermissionByUserId(userId); + } + + /// + /// 通过角色ID查询角色 + /// + /// 角色ID + /// 角色对象信息 + public SysRole SelectRoleById(long roleId) + { + return SysRoleRepository.SelectRoleById(roleId); + } + + /// + /// 批量删除角色信息 + /// + /// 需要删除的角色ID + /// + public int DeleteRoleByRoleId(long[] roleIds) + { + foreach (var item in roleIds) + { + CheckRoleAllowed(new SysRole(item)); + SysRole role = SelectRoleById(item); + if (SysUserRoleService.CountUserRoleByRoleId(item) > 0) + { + throw new CustomException($"{role.RoleName}已分配,不能删除"); + } + } + return SysRoleRepository.DeleteRoleByRoleIds(roleIds); + } + + /// + /// 更改角色权限状态 + /// + /// + /// + public int UpdateRoleStatus(SysRole roleDto) + { + return SysRoleRepository.UpdateRoleStatus(roleDto); + } + + /// + /// 校验角色权限是否唯一 + /// + /// 角色信息 + /// + public string CheckRoleKeyUnique(SysRole sysRole) + { + long roleId = 0 == sysRole.RoleId ? -1L : sysRole.RoleId; + SysRole info = SysRoleRepository.CheckRoleKeyUnique(sysRole.RoleKey); + if (info != null && info.RoleId != roleId) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /// + /// 校验角色是否允许操作 + /// + /// + public void CheckRoleAllowed(SysRole role) + { + if (IsRoleAdmin(role.RoleId)) + { + throw new CustomException("不允许操作超级管理员角色"); + } + } + + /// + /// 新增保存角色信息 + /// + /// 角色信息 + /// + public long InsertRole(SysRole sysRole) + { + return SysRoleRepository.InsertRole(sysRole); + //return InsertRoleMenu(sysRole); + } + + /// + /// 通过角色ID删除角色和菜单关联 + /// + /// 角色ID + /// + public int DeleteRoleMenuByRoleId(long roleId) + { + return SysRoleRepository.DeleteRoleMenuByRoleId(roleId); + } + + /// + /// 修改数据权限信息 + /// + /// + /// + public bool AuthDataScope(SysRole sysRoleDto) + { + return UseTran2(() => + { + //删除角色菜单 + DeleteRoleMenuByRoleId(sysRoleDto.RoleId); + InsertRoleMenu(sysRoleDto); + }); + } + #region Service + + + /// + /// 批量新增角色菜单信息 + /// + /// + /// + public int InsertRoleMenu(SysRole sysRoleDto) + { + int rows = 1; + // 新增用户与角色管理 + List sysRoleMenus = new List(); + foreach (var item in sysRoleDto.MenuIds) + { + SysRoleMenu rm = new SysRoleMenu + { + Menu_id = item, + Role_id = sysRoleDto.RoleId, + Create_by = sysRoleDto.Create_by, + Create_time = DateTime.Now + }; + sysRoleMenus.Add(rm); + } + //添加角色菜单 + if (sysRoleMenus.Count > 0) + { + rows = SysRoleRepository.AddRoleMenu(sysRoleMenus); + } + + return rows; + } + + /// + /// 判断是否是管理员 + /// + /// + /// + public bool IsAdmin(long userid) + { + List roles = SelectUserRoleKeys(userid); + + return ((IList)roles).Contains("admin"); + } + + /// + /// 判断是否是管理员 + /// + /// + /// + public bool IsRoleAdmin(long roleid) + { + var roleInfo = GetFirst(x => x.RoleId == roleid); + + return roleInfo.RoleKey == "admin"; + } + + /// + /// 获取角色菜单id集合 + /// + /// + /// + public List SelectUserRoleMenus(long roleId) + { + var list = SysRoleRepository.SelectRoleMenuByRoleId(roleId); + + return list.Select(x => x.Menu_id).Distinct().ToList(); + } + + /// + /// 根据用户所有角色获取菜单 + /// + /// + /// + public List SelectRoleMenuByRoleIds(long[] roleIds) + { + return SysRoleRepository.SelectRoleMenuByRoleIds(roleIds) + .Select(x => x.Menu_id) + .Distinct().ToList(); + } + + /// + /// 获取用户角色列表 + /// + /// + /// + public List SelectUserRoleListByUserId(long userId) + { + return SysRoleRepository.SelectUserRoleListByUserId(userId); + } + + /// + /// 获取用户权限集合 + /// + /// + /// + public List SelectUserRoles(long userId) + { + var list = SelectUserRoleListByUserId(userId).Where(f => f.Status == "0"); + + return list.Select(x => x.RoleId).ToList(); + } + + /// + /// 获取用户权限字符串集合 + /// + /// + /// + public List SelectUserRoleKeys(long userId) + { + var list = SelectUserRoleListByUserId(userId); + return list.Select(x => x.RoleKey).ToList(); + } + + /// + /// 获取用户所有角色名 + /// + /// + /// + public List SelectUserRoleNames(long userId) + { + var list = SelectUserRoleListByUserId(userId); + return list.Select(x => x.RoleName).ToList(); + } + #endregion + + /// + /// 修改保存角色信息 + /// + /// 角色信息 + /// + public int UpdateRole(SysRole sysRole) + { + var result = UseTran(() => + { + //修改角色信息 + SysRoleRepository.UpdateSysRole(sysRole); + //删除角色与部门管理 + DeptService.DeleteRoleDeptByRoleId(sysRole.RoleId); + //插入角色部门数据 + DeptService.InsertRoleDepts(sysRole); + }); + + return result.IsSuccess ? 1 : 0; + } + } +} diff --git a/ARW.Service/System/SysTasksLogService.cs b/ARW.Service/System/SysTasksLogService.cs new file mode 100644 index 0000000..7aeffbf --- /dev/null +++ b/ARW.Service/System/SysTasksLogService.cs @@ -0,0 +1,42 @@ +using Infrastructure.Attribute; +using System; +using System.Linq.Expressions; +using System.Threading.Tasks; +using ARW.Model; +using ARW.Model.System; +using ARW.Repository; +using ARW.Service.System.IService; + +namespace ARW.Service.System +{ + /// + /// 任务日志 + /// + [AppService(ServiceLifetime = LifeTime.Scoped, ServiceType = typeof(ISysTasksLogService))] + public class SysTasksLogService : BaseService, ISysTasksLogService + { + private ISysTasksQzService _tasksQzService; + public SysTasksLogService(ISysTasksQzService tasksQzService) + { + _tasksQzService = tasksQzService; + } + + public async Task AddTaskLog(string jobId, SysTasksLog logModel) + { + //获取任务信息 + var model = await _tasksQzService.GetSingleAsync(f => f.ID.ToString() == jobId); + + if (model != null) + { + logModel.JobId = jobId; + logModel.JobName = model.Name; + logModel.JobGroup = model.JobGroup; + logModel.CreateTime = DateTime.Now; + } + + await InsertAsync(logModel); + return logModel; + } + + } +} diff --git a/ARW.Service/System/SysTasksQzService.cs b/ARW.Service/System/SysTasksQzService.cs new file mode 100644 index 0000000..430fa01 --- /dev/null +++ b/ARW.Service/System/SysTasksQzService.cs @@ -0,0 +1,18 @@ +using Infrastructure.Attribute; +using ARW.Model.System; +using ARW.Repository.System; +using ARW.Service.System.IService; + +namespace ARW.Service.System +{ + /// + /// 定时任务 + /// + [AppService(ServiceType = typeof(ISysTasksQzService), ServiceLifetime = LifeTime.Scoped)] + public class SysTasksQzService : BaseService, ISysTasksQzService + { + public SysTasksQzService(SysTasksQzRepository repository) + { + } + } +} diff --git a/ARW.Service/System/SysUserPostService.cs b/ARW.Service/System/SysUserPostService.cs new file mode 100644 index 0000000..9179409 --- /dev/null +++ b/ARW.Service/System/SysUserPostService.cs @@ -0,0 +1,67 @@ +using Infrastructure.Attribute; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ARW.Model.System; +using ARW.Repository.System; +using ARW.Service.System.IService; + +namespace ARW.Service.System +{ + /// + /// 用户岗位 + /// + [AppService(ServiceType = typeof(ISysUserPostService), ServiceLifetime = LifeTime.Transient)] + public class SysUserPostService : ISysUserPostService + { + private SysUserPostRepository UserPostRepository; + public SysUserPostService(SysUserPostRepository userPostRepository) + { + UserPostRepository = userPostRepository; + } + + /// + /// 新增用户岗位信息 + /// + /// + public void InsertUserPost(SysUser user) + { + // 新增用户与岗位管理 + List list = new List(); + foreach (var item in user.PostIds) + { + list.Add(new SysUserPost() { PostId = item, UserId = user.UserId }); + } + UserPostRepository.Insert(list); + } + + + /// + /// 查询用户岗位集合 + /// + /// + /// + public List GetUserPostsByUserId(long userId) + { + var list = UserPostRepository.GetList(f => f.UserId == userId); + return list.Select(x => x.PostId).ToList(); + } + + /// + /// 获取用户岗位 + /// + /// + /// + public string GetPostsStrByUserId(long userId) + { + var list = UserPostRepository.SelectPostsByUserId(userId); + return string.Join(',', list.Select(x => x.PostName)); + } + + public bool Delete(long userId) + { + return UserPostRepository.Delete(x => x.UserId == userId); + } + } +} diff --git a/ARW.Service/System/SysUserRoleService.cs b/ARW.Service/System/SysUserRoleService.cs new file mode 100644 index 0000000..5465dbc --- /dev/null +++ b/ARW.Service/System/SysUserRoleService.cs @@ -0,0 +1,131 @@ +using Infrastructure.Attribute; +using System; +using System.Collections.Generic; +using System.Text; +using ARW.Model; +using ARW.Model.System.Dto; +using ARW.Model.System; +using ARW.Repository.System; +using ARW.Service.System.IService; + +namespace ARW.Service.System +{ + /// + /// 用户角色 + /// + [AppService(ServiceType = typeof(ISysUserRoleService), ServiceLifetime = LifeTime.Transient)] + public class SysUserRoleService : ISysUserRoleService + { + public SysUserRoleRepository SysUserRoleRepository; + + public SysUserRoleService(SysUserRoleRepository sysUserRoleRepository) + { + SysUserRoleRepository = sysUserRoleRepository; + } + + + /// + /// 通过角色ID查询角色使用数量 + /// + /// + /// + public int CountUserRoleByRoleId(long roleId) + { + return SysUserRoleRepository.CountUserRoleByRoleId(roleId); + } + + /// + /// 删除用户角色 + /// + /// + /// + public int DeleteUserRoleByUserId(int userId) + { + return SysUserRoleRepository.DeleteUserRoleByUserId(userId); + } + + /// + /// 批量删除角色对应用户 + /// + /// + /// + /// + public int DeleteRoleUserByUserIds(long roleId, List userIds) + { + return SysUserRoleRepository.DeleteRoleUserByUserIds(roleId, userIds); + } + + /// + /// 添加用户角色 + /// + /// + /// + public int AddUserRole(List sysUsers) + { + return SysUserRoleRepository.AddUserRole(sysUsers); + } + + /// + /// 获取用户数据根据角色id + /// + /// + /// + public List GetSysUsersByRoleId(long roleId) + { + return SysUserRoleRepository.GetSysUsersByRoleId(roleId); + } + + /// + /// 获取用户数据根据角色id + /// + /// + /// + public PagedInfo GetSysUsersByRoleId(RoleUserQueryDto roleUserQueryDto) + { + return SysUserRoleRepository.GetSysUsersByRoleId(roleUserQueryDto); + } + + /// + /// 获取尚未指派的用户数据根据角色id + /// + /// + /// + public PagedInfo GetExcludedSysUsersByRoleId(RoleUserQueryDto roleUserQueryDto) + { + return SysUserRoleRepository.GetExcludedSysUsersByRoleId(roleUserQueryDto); + } + + /// + /// 新增用户角色信息 + /// + /// + /// + public int InsertUserRole(SysUser user) + { + List userRoles = new List(); + foreach (var item in user.RoleIds) + { + userRoles.Add(new SysUserRole() { RoleId = item, UserId = user.UserId }); + } + + return userRoles.Count > 0 ? AddUserRole(userRoles) : 0; + } + + /// + /// 新增加角色用户 + /// + /// 角色id + /// 用户ids + /// + public int InsertRoleUser(RoleUsersCreateDto roleUsersCreateDto) + { + List userRoles = new List(); + foreach (var item in roleUsersCreateDto.UserIds) + { + userRoles.Add(new SysUserRole() { RoleId = roleUsersCreateDto.RoleId, UserId = item }); + } + + return userRoles.Count > 0 ? AddUserRole(userRoles) : 0; + } + } +} diff --git a/ARW.Service/System/SysUserService.cs b/ARW.Service/System/SysUserService.cs new file mode 100644 index 0000000..1af4786 --- /dev/null +++ b/ARW.Service/System/SysUserService.cs @@ -0,0 +1,236 @@ +using Infrastructure; +using Infrastructure.Attribute; +using Microsoft.AspNetCore.Http; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ARW.Common; +using ARW.Model; +using ARW.Model.System; +using ARW.Model.System.Dto; +using ARW.Repository.System; +using ARW.Service.System.IService; + +namespace ARW.Service +{ + /// + /// 系统用户 + /// + [AppService(ServiceType = typeof(ISysUserService), ServiceLifetime = LifeTime.Transient)] + public class SysUserService : BaseService, ISysUserService + { + private readonly SysUserRepository UserRepository; + private readonly ISysRoleService RoleService; + private readonly ISysUserRoleService UserRoleService; + private readonly ISysUserPostService UserPostService; + + public SysUserService( + SysUserRepository userRepository, + ISysRoleService sysRoleService, + ISysUserRoleService userRoleService, + ISysUserPostService userPostService) + { + UserRepository = userRepository; + RoleService = sysRoleService; + UserRoleService = userRoleService; + UserPostService = userPostService; + } + + /// + /// 根据条件分页查询用户列表 + /// + /// + public PagedInfo SelectUserList(SysUser user, PagerInfo pager) + { + var list = UserRepository.SelectUserList(user, pager); + + return list; + } + + /// + /// 通过用户ID查询用户 + /// + /// + /// + public SysUser SelectUserById(long userId) + { + var user = UserRepository.SelectUserById(userId); + if (user != null && user.UserId > 0) + { + user.Roles = RoleService.SelectUserRoleListByUserId(userId); + user.RoleIds = user.Roles.Select(x => x.RoleId).ToArray(); + } + return user; + } + + /// + /// 通过用户邮箱查询用户 + /// + /// + /// + public SysUser SelectUserByEmail(string email) + { + var user = UserRepository.Queryable().Where(s => s.Email == email).First(); + return user; + } + + /// + /// 校验用户名称是否唯一 + /// + /// + /// + public string CheckUserNameUnique(string userName) + { + int count = UserRepository.CheckUserNameUnique(userName); + if (count > 0) + { + return UserConstants.NOT_UNIQUE; + } + return UserConstants.UNIQUE; + } + + /// + /// 新增保存用户信息 + /// + /// + /// + public long InsertUser(SysUser sysUser) + { + long userId = UserRepository.AddUser(sysUser); + sysUser.UserId = userId; + //新增用户角色信息 + UserRoleService.InsertUserRole(sysUser); + //新增用户岗位信息 + UserPostService.InsertUserPost(sysUser); + return userId; + } + + /// + /// 修改用户信息 + /// + /// + /// + public int UpdateUser(SysUser user) + { + var roleIds = RoleService.SelectUserRoles(user.UserId); + var diffArr = roleIds.Where(c => !((IList)user.RoleIds).Contains(c)).ToArray(); + var diffArr2 = user.RoleIds.Where(c => !((IList)roleIds).Contains(c)).ToArray(); + + if (diffArr.Length > 0 || diffArr2.Length > 0) + { + //删除用户与角色关联 + UserRoleService.DeleteUserRoleByUserId((int)user.UserId); + //新增用户与角色关联 + UserRoleService.InsertUserRole(user); + } + // 删除用户与岗位关联 + UserPostService.Delete(user.UserId); + // 新增用户与岗位管理 + UserPostService.InsertUserPost(user); + return UserRepository.UpdateUser(user); + } + + public int ChangeUser(SysUser user) + { + return UserRepository.UpdateUser(user); + } + + /// + /// 重置密码 + /// + /// + /// + /// + public int ResetPwd(long userid, string password) + { + return UserRepository.ResetPwd(userid, password); + } + + public int ChangeUserStatus(SysUser user) + { + return UserRepository.ChangeUserStatus(user); + } + + /// + /// 删除用户 + /// + /// + /// + public int DeleteUser(long userid) + { + CheckUserAllowed(new SysUser() { UserId = userid}); + //删除用户与角色关联 + UserRoleService.DeleteUserRoleByUserId((int)userid); + // 删除用户与岗位关联 + UserPostService.Delete(userid); + return UserRepository.DeleteUser(userid); + } + + /// + /// 修改用户头像 + /// + /// + /// + public int UpdatePhoto(SysUser user) + { + return UserRepository.UpdatePhoto(user); + } + + /// + /// 注册用户 + /// + /// + /// + public SysUser Register(RegisterDto dto) + { + //密码md5 + string password = NETCore.Encrypt.EncryptProvider.Md5(dto.Password); + if (!Tools.PasswordStrength(dto.Password)) + { + throw new CustomException("密码强度不符合要求"); + } + SysUser user = new() + { + Create_time = DateTime.Now, + UserName = dto.Username, + NickName = dto.Username, + Password = password, + Status = "0", + DeptId = 0, + Remark = "用户注册" + }; + + user.UserId = UserRepository.AddUser(user); + return user; + } + + /// + /// 校验角色是否允许操作 + /// + /// + public void CheckUserAllowed(SysUser user) + { + if (user.IsAdmin()) + { + throw new CustomException("不允许操作超级管理员角色"); + } + } + + /// + /// 校验用户是否有数据权限 + /// + /// + /// + public void CheckUserDataScope(long userid, long loginUserId) + { + if (!SysUser.IsAdmin(loginUserId)) + { + SysUser user = new SysUser() { UserId = userid}; + + //TODO 判断用户是否有数据权限 + } + } + } +} diff --git a/ARW.Tasks/ARW.Tasks.csproj b/ARW.Tasks/ARW.Tasks.csproj new file mode 100644 index 0000000..1e8ffaa --- /dev/null +++ b/ARW.Tasks/ARW.Tasks.csproj @@ -0,0 +1,22 @@ + + + + net6.0 + ARW.Tasks + ARW.Tasks + + + + + + + + + + + + + + + + diff --git a/ARW.Tasks/ITaskSchedulerServer.cs b/ARW.Tasks/ITaskSchedulerServer.cs new file mode 100644 index 0000000..15640f7 --- /dev/null +++ b/ARW.Tasks/ITaskSchedulerServer.cs @@ -0,0 +1,28 @@ +using Infrastructure.Model; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using ARW.Model.System; + +namespace ARW.Tasks +{ + public interface ITaskSchedulerServer + { + Task StartTaskScheduleAsync(); + + Task StopTaskScheduleAsync(); + + Task AddTaskScheduleAsync(SysTasksQz tasksQz); + + Task PauseTaskScheduleAsync(SysTasksQz tasksQz); + + Task ResumeTaskScheduleAsync(SysTasksQz tasksQz); + + Task DeleteTaskScheduleAsync(SysTasksQz tasksQz); + + Task RunTaskScheduleAsync(SysTasksQz tasksQz); + + Task UpdateTaskScheduleAsync(SysTasksQz tasksQz); + } +} diff --git a/ARW.Tasks/JobFactory.cs b/ARW.Tasks/JobFactory.cs new file mode 100644 index 0000000..8321fe7 --- /dev/null +++ b/ARW.Tasks/JobFactory.cs @@ -0,0 +1,55 @@ +using ARW.Model.System; +using ARW.Service.System.IService; +using Infrastructure; +using Microsoft.Extensions.DependencyInjection; +using Quartz; +using Quartz.Spi; +using System; +using System.Threading.Tasks; + +namespace ARW.Tasks +{ + public class JobFactory : IJobFactory + { + private readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + + /// + /// 注入反射获取依赖对象 + /// + private readonly IServiceProvider _serviceProvider; + public JobFactory(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + /// + /// 实现接口Job + /// + /// + /// + /// + public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler) + { + try + { + var serviceScope = _serviceProvider.CreateScope(); + var job = serviceScope.ServiceProvider.GetService(bundle.JobDetail.JobType) as IJob; + return job; + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + logger.Error(ex, ex.Message); + throw; + } + } + + public void ReturnJob(IJob job) + { + if (job is IDisposable disposable) + { + disposable.Dispose(); + } + } + + } +} diff --git a/ARW.Tasks/TaskScheduler/Business/SubscribeTask_Job.cs b/ARW.Tasks/TaskScheduler/Business/SubscribeTask_Job.cs new file mode 100644 index 0000000..ec3bd98 --- /dev/null +++ b/ARW.Tasks/TaskScheduler/Business/SubscribeTask_Job.cs @@ -0,0 +1,146 @@ +using ARW.Common; +using ARW.Model.Models.Business.SubscribeTasks; +using ARW.Model.System; +using ARW.Service.Business.IBusinessService.SubscribeTasks; +using ARW.Service.System.IService; +using Infrastructure; +using Infrastructure.Attribute; +using Infrastructure.WeChat.SubScribe; +using Quartz; +using Senparc.CO2NET.Extensions; +using Senparc.Weixin.Entities.TemplateMessage; +using Senparc.Weixin.WxOpen.AdvancedAPIs.WxApp.WxAppJson; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using SystemTime = System.SystemTime; + +namespace ARW.Tasks.TaskScheduler.Business +{ + /// + /// 订阅推送任务 + /// + [AppService(ServiceType = typeof(SubscribeTask_Job), ServiceLifetime = LifeTime.Scoped)] + public class SubscribeTask_Job : JobBase, IJob + { + private readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + private readonly ISysTasksLogService SysTasksLogService; + private readonly ISysTasksQzService SysTasksQzService; + + private readonly ISubscribeTaskService _SubscribeTaskService; + + + public SubscribeTask_Job(ISysTasksLogService sysTasksLogService, ISysTasksQzService sysTasksQzService, ISubscribeTaskService subscribeTaskService) + { + SysTasksLogService = sysTasksLogService; + SysTasksQzService = sysTasksQzService; + _SubscribeTaskService = subscribeTaskService; + } + + public async Task Execute(IJobExecutionContext context) + { + var message = await Run(); + var logModel = await ExecuteJob(context, async () => await Run(), message); + await RecordTaskLog(context, logModel); + } + + + public async Task Run() + { + await Task.Delay(1); + //TODO 业务逻辑 + + var waitPushList = _SubscribeTaskService.GetSubscribeTaskList(); + if (waitPushList.Count > 0) + { + var pagePath = "pages/myMessage/myMessage"; + var templateMessageData = new TemplateMessageData(); + templateMessageData["thing1"] = new TemplateMessageDataValue("测试门店"); + templateMessageData["thing2"] = new TemplateMessageDataValue("佛山市顺德区xxx健身"); + templateMessageData["time3"] = new TemplateMessageDataValue(SystemTime.Now.ToString("yyyy年MM月dd日 HH:mm")); + templateMessageData["short_thing4"] = new TemplateMessageDataValue("1小时"); + templateMessageData["thing5"] = new TemplateMessageDataValue("还有1个小时开始健身,请熟知!"); + + var taskList = new List(); + foreach (var item in waitPushList) + { + try + { + if (item.EndTime < DateTime.Now) + { + logger.Info("执行到了这里" + item.OpenId); + logger.Info("一共有" + waitPushList.Count + "个"); + var res = await Subscribe.SubscribeMessage(item.TemplateId, item.OpenId, templateMessageData); + logger.Info("推送结果:" + res); + + if (res == "消息已发送,请注意查收") + { + + // 修改推送状态 + await _SubscribeTaskService.UpdateAsync(f => new SubscribeTask + { + SubscribeTaskStatus = 1 + }, s => s.SubscribeTaskGuid == item.SubscribeTaskGuid); + taskList.Add(item.OpenId + "用户的订阅已推送"); + } + } + } + catch (Exception ex) + { + return ex.ToString(); + } + } + return taskList.ToJson().ToString(); + } + else + { + logger.Info("空的"); + return "没有需要执行的任务"; + } + //return "执行成功!"; + + #region 公众号模板消息信息 -- DPBMARK MP + + //可选参数(需要和公众号模板消息匹配): + //var templateData = new + //{ + // first = new Senparc.Weixin.MP.AdvancedAPIs.TemplateMessage.TemplateDataItem("预约健身开始提醒"), + // keyword1 = new Senparc.Weixin.MP.AdvancedAPIs.TemplateMessage.TemplateDataItem("测试门店"), + // keyword2 = new Senparc.Weixin.MP.AdvancedAPIs.TemplateMessage.TemplateDataItem("佛山市顺德区xxx健身"), + // keyword3 = new Senparc.Weixin.MP.AdvancedAPIs.TemplateMessage.TemplateDataItem(SystemTime.Now.ToString("yyyy年MM月dd日 HH:mm")), + // keyword4 = new Senparc.Weixin.MP.AdvancedAPIs.TemplateMessage.TemplateDataItem("1小时"), + // keyword5 = new Senparc.Weixin.MP.AdvancedAPIs.TemplateMessage.TemplateDataItem("还有1个小时开始健身,请熟知!"), + // remark = new Senparc.Weixin.MP.AdvancedAPIs.TemplateMessage.TemplateDataItem("您的 OpenId:" + openId), + //}; + #endregion DPBMARK_END + //System.Console.WriteLine("job test"); + } + + + /// + /// 记录到日志 + /// + /// + /// + public async Task RecordTaskLog(IJobExecutionContext context, SysTasksLog logModel) + { + + //可以直接获取 JobDetail 的值 + IJobDetail job = context.JobDetail; + + logModel.InvokeTarget = job.JobType.FullName; + logModel = await SysTasksLogService.AddTaskLog(job.Key.Name, logModel); + //成功后执行次数+1 + if (logModel.Status == "0") + { + await SysTasksQzService.UpdateAsync(f => new SysTasksQz() + { + RunTimes = f.RunTimes + 1, + LastRunTime = DateTime.Now + }, f => f.ID.ToString() == job.Key.Name); + } + logger.Info($"执行任务【{job.Key.Name}|{logModel.JobName}】结果={logModel.JobMessage}"); + } + } +} diff --git a/ARW.Tasks/TaskScheduler/JobBase.cs b/ARW.Tasks/TaskScheduler/JobBase.cs new file mode 100644 index 0000000..e0eaa87 --- /dev/null +++ b/ARW.Tasks/TaskScheduler/JobBase.cs @@ -0,0 +1,68 @@ +using Infrastructure; +using NLog; +using Quartz; +using System; +using System.Diagnostics; +using System.Threading.Tasks; +using ARW.Model.System; +using ARW.Service.System.IService; +using Microsoft.Extensions.DependencyInjection; +using Google.Protobuf.Reflection; +using Microsoft.AspNetCore.Builder; + +namespace ARW.Tasks +{ + public class JobBase + { + /// + /// 日志接口 + /// + private static readonly Logger logger = LogManager.GetCurrentClassLogger(); + + + /// + /// 执行指定任务 + /// + /// 作业上下文 + /// 业务逻辑方法 + public async Task ExecuteJob(IJobExecutionContext context, Func job,string msg) + { + double elapsed = 0; + int status = 0; + string logMsg; + try + { + //var s = context.Trigger.Key.Name; + //记录Job时间 + Stopwatch stopwatch = new Stopwatch(); + stopwatch.Start(); + //执行任务 + await job(); + stopwatch.Stop(); + elapsed = stopwatch.Elapsed.TotalMilliseconds; + logMsg = msg; + } + catch (Exception ex) + { + JobExecutionException e2 = new(ex) + { + //true 是立即重新执行任务 + RefireImmediately = true + }; + status = 1; + logMsg = $"Fail,Exception:{ex.Message}"; + } + + var logModel = new SysTasksLog() + { + Elapsed = elapsed, + Status = status.ToString(), + JobMessage = logMsg + }; + + //await RecordTaskLog(context, logModel); + return logModel; + } + + } +} diff --git a/ARW.Tasks/TaskScheduler/Job_HttpRequest.cs b/ARW.Tasks/TaskScheduler/Job_HttpRequest.cs new file mode 100644 index 0000000..9ddacea --- /dev/null +++ b/ARW.Tasks/TaskScheduler/Job_HttpRequest.cs @@ -0,0 +1,44 @@ +using Infrastructure; +using Infrastructure.Attribute; +using Quartz; +using Quartz.Impl; +using Quartz.Impl.Triggers; +using System; +using System.Threading.Tasks; +using ARW.Service.System.IService; + +namespace ARW.Tasks.TaskScheduler +{ + /// + /// 定时任务http请求 + /// + [AppService(ServiceType = typeof(Job_HttpRequest), ServiceLifetime = LifeTime.Scoped)] + internal class Job_HttpRequest : JobBase, IJob + { + private readonly ISysTasksQzService tasksQzService; + private readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + + public Job_HttpRequest(ISysTasksQzService tasksQzService) + { + this.tasksQzService = tasksQzService; + } + public async Task Execute(IJobExecutionContext context) + { + await ExecuteJob(context, async () => await Run(context),"Success!"); + } + public async Task Run(IJobExecutionContext context) + { + AbstractTrigger trigger = (context as JobExecutionContextImpl).Trigger as AbstractTrigger; + var info = await tasksQzService.GetByIdAsync(trigger.Name); + if (info != null) + { + var result = await HttpHelper.HttpGetAsync("http://" + info.ApiUrl); + logger.Info($"任务【{info.Name}】网络请求执行结果=" + result); + } + else + { + throw new CustomException("任务网络请求执行失败,任务不存在"); + } + } + } +} diff --git a/ARW.Tasks/TaskScheduler/Job_SyncTest.cs b/ARW.Tasks/TaskScheduler/Job_SyncTest.cs new file mode 100644 index 0000000..c67beef --- /dev/null +++ b/ARW.Tasks/TaskScheduler/Job_SyncTest.cs @@ -0,0 +1,75 @@ +using ARW.Common; +using ARW.Model.System; +using ARW.Service.System.IService; +using Infrastructure; +using Infrastructure.Attribute; +using Quartz; +using System; +using System.Threading.Tasks; + +namespace ARW.Tasks.TaskScheduler +{ + /// + /// 定时任务测试 + /// 使用如下注册后TaskExtensions里面不用再注册了 + /// + [AppService(ServiceType = typeof(Job_SyncTest), ServiceLifetime = LifeTime.Scoped)] + public class Job_SyncTest : JobBase, IJob + { + private readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + private readonly ISysTasksLogService SysTasksLogService; + private readonly ISysTasksQzService SysTasksQzService; + + + public Job_SyncTest(ISysTasksLogService sysTasksLogService, ISysTasksQzService sysTasksQzService) + { + SysTasksLogService = sysTasksLogService; + SysTasksQzService = sysTasksQzService; + } + + public async Task Execute(IJobExecutionContext context) + { + var logModel = await ExecuteJob(context, async () => await Run(),"发送成功!"); + await RecordTaskLog(context, logModel); + } + + + public async Task Run() + { + await Task.Delay(1); + //TODO 业务逻辑 + + MailHelper mailHelper = new MailHelper(); + string[] strings = {"2679599887@qq.com", "2423579486@qq.com" }; + mailHelper.SendMail(strings, "炒币强","喜欢吗?"); + + //System.Console.WriteLine("job test"); + } + + + /// + /// 记录到日志 + /// + /// + /// + public async Task RecordTaskLog(IJobExecutionContext context, SysTasksLog logModel) + { + + //可以直接获取 JobDetail 的值 + IJobDetail job = context.JobDetail; + + logModel.InvokeTarget = job.JobType.FullName; + logModel = await SysTasksLogService.AddTaskLog(job.Key.Name, logModel); + //成功后执行次数+1 + if (logModel.Status == "0") + { + await SysTasksQzService.UpdateAsync(f => new SysTasksQz() + { + RunTimes = f.RunTimes + 1, + LastRunTime = DateTime.Now + }, f => f.ID.ToString() == job.Key.Name); + } + logger.Info($"执行任务【{job.Key.Name}|{logModel.JobName}】结果={logModel.JobMessage}"); + } + } +} diff --git a/ARW.Tasks/TaskSchedulerServer.cs b/ARW.Tasks/TaskSchedulerServer.cs new file mode 100644 index 0000000..26a2823 --- /dev/null +++ b/ARW.Tasks/TaskSchedulerServer.cs @@ -0,0 +1,366 @@ +using Infrastructure.Model; +using NLog; +using Quartz; +using Quartz.Impl; +using Quartz.Impl.Matchers; +using Quartz.Impl.Triggers; +using Quartz.Spi; +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using ARW.Model.System; + +namespace ARW.Tasks +{ + /// + /// 计划任务中心 + /// + //[AppService] + public class TaskSchedulerServer : ITaskSchedulerServer + { + private Task _scheduler; + private readonly IJobFactory _jobFactory; + /// + /// 日志接口 + /// + private static Logger logger = LogManager.GetCurrentClassLogger(); + + public TaskSchedulerServer(IJobFactory jobFactory) + { + _scheduler = GetTaskSchedulerAsync(); + _jobFactory = jobFactory; + } + + /// + /// 开启计划任务 + /// 参考文章:https://www.quartz-scheduler.net/documentation/quartz-3.x/configuration/reference.html#datasources-ado-net-jobstores + /// + /// + private Task GetTaskSchedulerAsync() + { + if (_scheduler != null) + { + return _scheduler; + } + + NameValueCollection collection = new NameValueCollection + { + { "quartz.serializer.type","binary" }, + //quartz参数 + //{ "quartz.scheduler.instanceId", "AUTO" }, + //{ "quartz.serializer.type","json" }, + ////下面为指定quartz持久化数据库的配置 + //{ "quartz.jobStore.type","Quartz.Impl.AdoJobStore.JobStoreTX, Quartz" }, + //{ "quartz.jobStore.tablePrefix","QRTZ_"}, + //{ "quartz.jobStore.driverDelegateType", "Quartz.Impl.AdoJobStore.MySQLDelegate, Quartz"}, + //{ "quartz.jobStore.useProperties", "true"}, + //{ "quartz.jobStore.dataSource", "myDS" }, + //{ "quartz.dataSource.myDS.connectionString", @"server=xxx.xxx.xxx.xxx;port=3306;database=Admin;uid=zrry;pwd=********;Charset=utf8;"}, + //{ "quartz.dataSource.myDS.provider", "MySql" }, + }; + + StdSchedulerFactory factory = new StdSchedulerFactory(collection); + + return _scheduler = factory.GetScheduler(); + } + + public async Task StartTaskScheduleAsync() + { + try + { + _scheduler.Result.JobFactory = _jobFactory; + if (_scheduler.Result.IsStarted) + { + return ApiResult.Error(500, $"计划任务已经开启"); + } + + //等待任务运行完成 + await _scheduler.Result.Start(); + return ApiResult.Success("计划任务开启成功"); + } + catch (Exception) + { + throw; + } + } + + /// + /// 停止计划任务 + /// + /// + public async Task StopTaskScheduleAsync() + { + try + { + if (_scheduler.Result.IsShutdown) + { + return ApiResult.Error(500, $"计划任务已经停止"); + } + + await _scheduler.Result.Shutdown(); + return ApiResult.Success("计划任务已经停止"); + } + catch (Exception) + { + throw; + } + } + + /// + /// 添加一个计划任务 + /// + /// + /// + public async Task AddTaskScheduleAsync(SysTasksQz tasksQz) + { + try + { + JobKey jobKey = new JobKey(tasksQz.ID.ToString(), tasksQz.JobGroup); + if (await _scheduler.Result.CheckExists(jobKey)) + { + return ApiResult.Error(500, $"该计划任务已经在执行:【{tasksQz.Name}】,请勿重复添加!"); + } + if (tasksQz?.EndTime <= DateTime.Now) + { + return ApiResult.Error(500, $"结束时间小于当前时间计划将不会被执行"); + } + #region 设置开始时间和结束时间 + + tasksQz.BeginTime = tasksQz.BeginTime == null ? DateTime.Now : tasksQz.BeginTime; + tasksQz.EndTime = tasksQz.EndTime == null ? DateTime.MaxValue.AddDays(-1) : tasksQz.EndTime; + + DateTimeOffset starRunTime = DateBuilder.NextGivenSecondDate(tasksQz.BeginTime, 1);//设置开始时间 + DateTimeOffset endRunTime = DateBuilder.NextGivenSecondDate(tasksQz.EndTime, 1);//设置暂停时间 + + #endregion + + #region 通过反射获取程序集类型和类 + + Assembly assembly = Assembly.Load(new AssemblyName(tasksQz.AssemblyName)); + Type jobType = assembly.GetType(tasksQz.AssemblyName + "." + tasksQz.ClassName); + + #endregion + //2、开启调度器。判断任务调度是否开启 + if (!_scheduler.Result.IsStarted) + { + await StartTaskScheduleAsync(); + } + + //3、创建任务。传入反射出来的执行程序集 + IJobDetail job = new JobDetailImpl(tasksQz.ID.ToString(), tasksQz.JobGroup, jobType); + job.JobDataMap.Add("JobParam", tasksQz.JobParams); + ITrigger trigger; + + //4、创建一个触发器 + if (tasksQz.Cron != null && CronExpression.IsValidExpression(tasksQz.Cron)) + { + trigger = CreateCronTrigger(tasksQz); + //解决Quartz启动后第一次会立即执行问题解决办法 + ((CronTriggerImpl)trigger).MisfireInstruction = MisfireInstruction.CronTrigger.DoNothing; + } + else + { + trigger = CreateSimpleTrigger(tasksQz); + ((SimpleTriggerImpl)trigger).MisfireInstruction = MisfireInstruction.CronTrigger.DoNothing; + } + + // 5、将触发器和任务器绑定到调度器中 + await _scheduler.Result.ScheduleJob(job, trigger); + //任务没有启动、暂停任务 + //if (!tasksQz.IsStart) + //{ + // _scheduler.Result.PauseJob(jobKey).Wait(); + //} + //按新的trigger重新设置job执行 + await _scheduler.Result.ResumeTrigger(trigger.Key); + return ApiResult.Success($"启动计划任务:【{tasksQz.Name}】成功!"); + } + catch (Exception ex) + { + logger.Error(ex, $"启动计划任务失败,分组:{tasksQz.JobGroup},作业:【{tasksQz.Name}】,error:{ex.Message}"); + return ApiResult.Error(500, $"启动计划任务:【{tasksQz.Name}】失败!"); + } + } + + /// + /// 暂停指定的计划任务 + /// + /// + /// + public async Task PauseTaskScheduleAsync(SysTasksQz tasksQz) + { + try + { + JobKey jobKey = new JobKey(tasksQz.ID.ToString(), tasksQz.JobGroup); + if (await _scheduler.Result.CheckExists(jobKey)) + { + // 防止创建时存在数据问题 先移除,然后在执行创建操作 + await _scheduler.Result.PauseJob(jobKey); + } + return ApiResult.Success($"暂停计划任务:【{tasksQz.Name}】成功"); + } + catch (Exception ex) + { + logger.Error(ex); + return new ApiResult(500, $"暂停计划任务:【{tasksQz.Name}】失败,{ex.Message}"); + } + } + + /// + /// 恢复指定计划任务 + /// + /// + /// + public async Task ResumeTaskScheduleAsync(SysTasksQz tasksQz) + { + try + { + JobKey jobKey = new JobKey(tasksQz.ID.ToString(), tasksQz.JobGroup); + if (!await _scheduler.Result.CheckExists(jobKey)) + { + return ApiResult.Error(500, $"未找到计划任务:【{tasksQz.Name}】"); + } + await _scheduler.Result.ResumeJob(jobKey); + return ApiResult.Success($"恢复计划任务:【{tasksQz.Name}】成功"); + } + catch (Exception) + { + throw; + } + } + + /// + /// 删除指定计划任务 + /// + /// + /// + public async Task DeleteTaskScheduleAsync(SysTasksQz tasksQz) + { + try + { + JobKey jobKey = new JobKey(tasksQz.ID.ToString(), tasksQz.JobGroup); + + //await _scheduler.Result.ScheduleJob() + + await _scheduler.Result.DeleteJob(jobKey); + return ApiResult.Success($"删除计划任务:【{tasksQz.Name}】成功"); + } + catch (Exception ex) + { + logger.Error(ex); + return ApiResult.Error($"删除计划任务:【{tasksQz.Name}】失败, error={ex.Message}"); + } + } + + /// + /// 立即运行 + /// + /// + /// + public async Task RunTaskScheduleAsync(SysTasksQz tasksQz) + { + try + { + JobKey jobKey = new JobKey(tasksQz.ID.ToString(), tasksQz.JobGroup); + List jobKeys = _scheduler.Result.GetJobKeys(GroupMatcher.GroupEquals(tasksQz.JobGroup)).Result.ToList(); + if (jobKeys == null || jobKeys.Count == 0) + { + await AddTaskScheduleAsync(tasksQz); + } + + var triggers = await _scheduler.Result.GetTriggersOfJob(jobKey); + if (triggers.Count <= 0) + { + return new ApiResult(110, $"未找到触发器[{jobKey.Name}]"); + } + await _scheduler.Result.TriggerJob(jobKey); + + return ApiResult.Success($"运行计划任务:【{tasksQz.Name}】成功"); + } + catch (Exception ex) + { + return new ApiResult(500, $"执行计划任务:【{tasksQz.Name}】失败,{ex.Message}"); + } + } + + /// + /// 更新计划任务 + /// + /// + /// + public async Task UpdateTaskScheduleAsync(SysTasksQz tasksQz) + { + try + { + JobKey jobKey = new JobKey(tasksQz.ID.ToString(), tasksQz.JobGroup); + if (await _scheduler.Result.CheckExists(jobKey)) + { + //防止创建时存在数据问题 先移除,然后在执行创建操作 + await _scheduler.Result.DeleteJob(jobKey); + } + //await AddTaskScheduleAsync(tasksQz); + return ApiResult.Success("修改计划成功"); + } + catch (Exception ex) + { + logger.Error(ex); + return ApiResult.Error($"修改计划失败,error={ex.Message}"); + } + } + + #region 创建触发器帮助方法 + + /// + /// 创建SimpleTrigger触发器(简单触发器) + /// + /// + /// + private ITrigger CreateSimpleTrigger(SysTasksQz tasksQz) + { + if (tasksQz.RunTimes > 0) + { + ITrigger trigger = TriggerBuilder.Create() + .WithIdentity(tasksQz.ID.ToString(), tasksQz.JobGroup) + .StartAt(tasksQz.BeginTime.Value) + .EndAt(tasksQz.EndTime.Value) + .WithSimpleSchedule(x => x.WithIntervalInSeconds(tasksQz.IntervalSecond) + .WithRepeatCount(tasksQz.RunTimes)).ForJob(tasksQz.ID.ToString(), tasksQz.JobGroup).Build(); + return trigger; + } + else + { + ITrigger trigger = TriggerBuilder.Create() + .WithIdentity(tasksQz.ID.ToString(), tasksQz.JobGroup) + .StartAt(tasksQz.BeginTime.Value) + .EndAt(tasksQz.EndTime.Value) + .WithSimpleSchedule(x => x.WithIntervalInSeconds(tasksQz.IntervalSecond) + .RepeatForever()).ForJob(tasksQz.ID.ToString(), tasksQz.JobGroup).Build(); + return trigger; + } + // 触发作业立即运行,然后每10秒重复一次,无限循环 + } + + /// + /// 创建类型Cron的触发器 + /// + /// + /// + private ITrigger CreateCronTrigger(SysTasksQz tasksQz) + { + // 作业触发器 + return TriggerBuilder.Create() + .WithIdentity(tasksQz.ID.ToString(), tasksQz.JobGroup) + .StartAt(tasksQz.BeginTime.Value)//开始时间 + .EndAt(tasksQz.EndTime.Value)//结束数据 + .WithCronSchedule(tasksQz.Cron)//指定cron表达式 + .ForJob(tasksQz.ID.ToString(), tasksQz.JobGroup)//作业名称 + .Build(); + } + + #endregion + + } +} diff --git a/ARW.WebApi/.config/dotnet-tools.json b/ARW.WebApi/.config/dotnet-tools.json new file mode 100644 index 0000000..82e7e22 --- /dev/null +++ b/ARW.WebApi/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-ef": { + "version": "6.0.2", + "commands": [ + "dotnet-ef" + ] + } + } +} \ No newline at end of file diff --git a/ARW.WebApi/ARW.WebApi.csproj b/ARW.WebApi/ARW.WebApi.csproj new file mode 100644 index 0000000..f4a20eb --- /dev/null +++ b/ARW.WebApi/ARW.WebApi.csproj @@ -0,0 +1,77 @@ + + + net6.0 + enable + enable + True + + ARW.WebApi + ARW.WebApi + + + False + + + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Always + + + + + diff --git a/ARW.WebApi/ARW.WebApi.xml b/ARW.WebApi/ARW.WebApi.xml new file mode 100644 index 0000000..eb04174 --- /dev/null +++ b/ARW.WebApi/ARW.WebApi.xml @@ -0,0 +1,1455 @@ + + + + ARW.WebApi + + + + + 基础控制器 + + + + + 时间格式化 2020-01-01 09:21:03 + + + + + 时间格式化 01-01 09:21:03 + + + + + 返回成功封装 + + + + + + + + json输出带时间格式的 + + + + + + + + + + + + + + + + + + + + + + + + 响应返回结果 + + 受影响行数 + + + + + 响应返回结果,带消息 + + + + + + + + 全局Code使用 + + + + + + + + + + + + + + + + 导出Excel + + + + + + + + + 下载导入模板 + + + + + 下载文件名 + + + + + 班级控制器 + + + + + 获取班级列表 + + 查询参数 + + + + + 添加班级 + + + + + + 更新班级 + + + + + + 删除文章 + + + + + + 产品管理Controller + + + + + 依赖注入 + + 产品类型服务 + + + + 查询产品类型列表树 + + + + + + + 添加产品类型 + + + + + + 更新产品类型 + + + + + + 删除产品类型 + + + + + + 学生控制器 + + + + + 依赖注入 + + 学生服务 + 班级服务 + + + + 获取学生列表 + + 查询参数 + + + + + 添加学生 + + 参数 + 名字 + + + + + + 更新学生 + + + + + + 删除文章 + + + + + + 获取班级列表(下拉框) + + + + + + 导出学生 + + 使用IFromFile必须使用name属性否则获取不到文件 + + + + + 学生导入模板下载 + + + + + + 导出学生 + + + + + + 公共模块 + + + + + hello + + + + + + 发送邮件 + + 请求参数接收实体 + + + + + 存储文件 + + + 存储目录 + 自定义文件名 + 上传类型1、保存到本地 2、保存到阿里云 + + + + + 存储文件到阿里云(已弃用) + + + 自定义文件名 + 上传文件夹路径 + + + + + 代码生成 + + + + + 获取所有数据库的信息 + + + + + + 获取所有表根据数据库名 + + 数据库名 + 表名 + 分页信息 + + + + + 查询生成表数据 + + 表名 + 分页信息 + + + + + 修改代码生成业务查询 + + genTable表id + + + + + 根据表id查询表列 + + genTable表id + + + + + 删除代码生成 + + + + + + + 导入表结构(保存) + + + + + + + + 修改保存代码生成业务 + + 请求参数实体 + + + + + 预览代码 + + + + + + + + 生成代码(下载方式) + + 数据传输对象 + + + + + 同步数据库 + + + + + + + + 多语言配置Controller + + + + + 多语言配置接口 + + + + + 查询多语言配置列表 + + + + + + + 查询多语言配置列表 + + + + + + 查询多语言配置详情 + + + + + + + 查询多语言配置详情 + + + + + + + 更新多语言配置 + + + + + + 删除多语言配置 + + + + + + 导出多语言配置 + + + + + + 系统监控 + + + + + 获取缓存监控数据 + + + + + + 获取服务器信息 + + + + + + 系统访问记录 + + + + + 查询登录日志 + + + + + + + + 清空登录日志 + + + + + + + + + + + + 登录日志导出 + + + + + + 操作日志记录 + + + + + 查询操作日志 + + + + + + + 删除操作日志 + + + + + + + 清空操作日志 + + + + + + 导出操作日志 + + + + + + 参数配置Controller + + + + + 参数配置接口 + + + + + 查询参数配置列表 + + + + + + 查询参数配置详情 + + + + + + + 根据参数键名查询参数值 + + + + + + + 添加参数配置 + + + + + + 更新参数配置 + + + + + + 删除参数配置 + + + + + + 部门 + + + + + 获取部门列表 + + + + + + 查询部门列表(排除节点) + + + + + + + 获取部门下拉树列表 + + + + + + + 获取角色部门信息 + 加载对应角色部门列表树 + + + + + + + 根据部门编号获取详细信息 + + + + + + 新增部门 + + + + + + + 修改部门 + + + + + + + 删除部门 + + + + + + 数据字典信息 + + + + + 搜索 + + + + + + + + 根据字典类型查询字典数据信息 + + + + + + + 根据字典类型查询字典数据信息 + + + + + + + 查询字典数据详细 + + + + + + + 添加 + + + + + + + 修改 + + + + + + + 删除字典类型 + + + + + + + 数据字典信息 + + + + + 查询 + + + + + + + + 查询字典类型详细 + + + + + + + 添加字典类型 + + + + + + + 修改字典类型 + + + + + + + 删除字典类型 + + + + + + 字典导出 + + + + + + 登录 + + + + + 登录 + + 登录对象 + + + + + 注销 + + + + + + 获取用户信息 + + + + + + 获取路由信息 + + + + + + 生成图片验证码 + + + + + + 记录用户登陆信息 + + + + + + + 注册 + + + + + + + 系统菜单 + + + + + 获取菜单列表 + + + + + + 根据菜单编号获取详细信息 + + + + + + + 根据菜单编号获取菜单列表,菜单管理首次进入 + + + + + + + 获取角色菜单信息 + 加载对应角色菜单列表树 + + + + + + + 修改菜单 + + + + + + + 添加菜单 + + + + + + + 菜单删除 + + + + + + + 保存排序 + + + + + + + + 系统通知 + + + + + 通知公告表接口 + + + + + 查询通知公告表列表 + + + + + + 查询通知公告表列表 + + + + + + 查询通知公告表详情 + + + + + + + 添加通知公告表 + + + + + + 更新通知公告表 + + + + + + 发送通知公告表 + + + + + + 删除通知公告表 + + + + + + 通知公告表导出 + + + + + + 岗位管理 + + + + + 岗位列表查询 + + + + + + 岗位查询 + + + + + + + 岗位管理 + + + + + + + 岗位管理 + + + + + + + 岗位删除 + + + + + + + 获取岗位选择框列表 + + + + + 岗位导出 + + + + + + 个人中心 + + + + + 个人中心用户信息获取 + + + + + + 修改用户 + + + + + + 修改密码 + + + + + + 修改头像 + + + + + + + 角色信息 + + + + + 获取系统角色管理 + + + + + + 根据角色编号获取详细信息 + + + + + + + 添加角色 + + + + + + + 修改角色 √ + + + + + + + 根据角色分配菜单 + + + + + + + 角色删除 + + + + + + + 修改角色状态 + + 角色对象 + + + + + 角色导出 + + + + + + 用户管理 + + + + + 用户管理 -> 获取用户 + /system/user/list + + + + + + 用户管理 -> 编辑、添加用户获取用户,信息查询 + + + + + + + 添加用户 + + + + + + + 修改用户 + + + + + + + 改变用户状态 + + + + + + + 删除用户 + + + + + + + 重置密码 + + + + + + 导入 + + 使用IFromFile必须使用name属性否则获取不到文件 + + + + + 用户导入模板下载 + + + + + + 用户导出 + + + + + + + 用户角色管理 + + + + + 根据角色编号获取已分配的用户 + + + + + + + 添加角色用户 + + + + + + 删除角色用户 + + + + + + + 获取未分配用户角色 + + + + + + + 任务日志 + + + + + 查询日志 + + + + + + + + 删除定时任务调用日志 + + + + + + + 清空日志 + + + + + + 定时任务日志导出 + + + + + + 文件存储Controller + + + + + 文件存储接口 + + + + + 查询文件存储列表 + + + + + + + 查询文件存储详情 + + + + + + + 删除文件存储 + + + + + + 文件存储导出 + + + + + + 计划任务 + + + + + 查询计划任务列表 + + + + + + 查询单个计划任务 + + 编码 + + + + + 添加任务 + + + + + + 更新任务 + + + + + + 删除任务 + + + + + + 启动任务 + + + + + + 停止任务 + + + + + + 定时任务立即执行一次 + + + + + + + 定时任务导出 + + + + + + 数据过滤 + + 多库id + + + + HttpContext扩展类 + + + + + 是否是ajax请求 + + + + + + + 获取客户端IP + + + + + + + ClaimsIdentity + + + + + + + 获取请求令牌 + + + + + + + 设置请求参数 + + + + + + + + + + + + + 定时任务扩展方法 + + + + + 程序启动后添加任务计划 + + + + + + + API授权判断 + + + + + 权限字符串,例如 system:user:view + + + + + 执行Action前校验是否有权限访问 + + + + + + + + Action请求前 + + + + + + + + OnActionExecuted是在Action中的代码执行之后运行的方法。 + + + + + + 授权校验访问 + 如果跳过授权登录在Action 或controller加上 AllowAnonymousAttribute + + + + + 只判断token是否正确,不判断权限 + 如果需要判断权限的在Action上加上ApiActionPermission属性标识权限类别,ActionPermissionFilter作权限处理 + + + + + + 2020-11-20 + + + + + 获取用户身份信息 + + + + + + + 生成token + + + + + + + + 验证Token + + + + + + 从令牌中获取数据声明 + + 令牌 + + + + + jwt token校验 + + + + + + + 组装Claims + + + + + + + + + + + + + + + + + + 客户端连接的时候调用 + + + + + + 连接终止时调用。 + + + + + + 注册信息 + + + + + + + + + 客户端连接Id + + + + + 用户id + + + + + 全局异常处理中间件 + + + + + 全局异常捕获 + 暂时没用了,改为中间件 2021-2-26 + + + + diff --git a/ARW.WebApi/Controllers/Api/CommonController.cs b/ARW.WebApi/Controllers/Api/CommonController.cs new file mode 100644 index 0000000..b00c7e9 --- /dev/null +++ b/ARW.WebApi/Controllers/Api/CommonController.cs @@ -0,0 +1,194 @@ +using Infrastructure; +using Infrastructure.Attribute; +using Infrastructure.Enums; +using Infrastructure.Extensions; +using Infrastructure.Model; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; +using Newtonsoft.Json; +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using ARW.Admin.WebApi.Extensions; +using ARW.Admin.WebApi.Filters; +using ARW.Common; +using ARW.Model.System; +using ARW.Service.System.IService; + +namespace ARW.Admin.WebApi.Controllers.Api +{ + /// + /// 公共模块 + /// + [Route("api/[controller]/[action]")] + public class CommonController : BaseController + { + private OptionsSetting OptionsSetting; + private NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + + private IWebHostEnvironment WebHostEnvironment; + private ISysFileService SysFileService; + public CommonController(IOptions options, IWebHostEnvironment webHostEnvironment, ISysFileService fileService) + { + WebHostEnvironment = webHostEnvironment; + SysFileService = fileService; + OptionsSetting = options.Value; + } + + /// + /// hello + /// + /// + [Route("/api")] + [HttpGet] + public IActionResult Index() + { + return Content("前端api"); + } + + /// + /// 发送邮件 + /// + /// 请求参数接收实体 + /// + [ActionPermissionFilter(Permission = "tool:email:send")] + [Log(Title = "发送邮件", IsSaveRequestData = false)] + [HttpPost] + public IActionResult SendEmail([FromBody] SendEmailDto sendEmailVo) + { + if (sendEmailVo == null || string.IsNullOrEmpty(sendEmailVo.Subject) || string.IsNullOrEmpty(sendEmailVo.ToUser)) + { + return ToResponse(ApiResult.Error($"请求参数不完整")); + } + if (string.IsNullOrEmpty(OptionsSetting.MailOptions.From) || string.IsNullOrEmpty(OptionsSetting.MailOptions.Password)) + { + return ToResponse(ApiResult.Error($"请配置邮箱信息")); + } + + MailHelper mailHelper = new(); + + string[] toUsers = sendEmailVo.ToUser.Split(",", StringSplitOptions.RemoveEmptyEntries); + if (sendEmailVo.SendMe) + { + toUsers.Append(mailHelper.FromEmail); + } + mailHelper.SendMail(toUsers, sendEmailVo.Subject, sendEmailVo.Content, sendEmailVo.FileUrl, sendEmailVo.HtmlContent); + + logger.Info($"发送邮件{JsonConvert.SerializeObject(sendEmailVo)}"); + + return SUCCESS(true); + } + + #region 上传 + + /// + /// 存储文件 + /// + /// + /// 存储目录 + /// 自定义文件名 + /// 上传类型1、保存到本地 2、保存到阿里云 + /// + [HttpPost] + //[Verify] + [ActionPermissionFilter(Permission = "common")] + public async Task UploadFile([FromForm(Name = "file")] IFormFile formFile, string? fileName = "", string? fileDir = "", StoreType storeType = StoreType.LOCAL) + { + if (formFile == null) throw new CustomException(ResultCode.PARAM_ERROR, "上传文件不能为空"); + SysFile file = new(); + string fileExt = Path.GetExtension(formFile.FileName);//文件后缀 + 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)) + { + return ToResponse(ResultCode.CUSTOM_ERROR, "上传失败,未经允许上传类型"); + } + switch (storeType) + { + case StoreType.LOCAL: + string savePath = Path.Combine(WebHostEnvironment.WebRootPath); + if (fileDir.IsEmpty()) + { + fileDir = AppSettings.App(new string[] { "Upload", "localSavePath" }); + } + file = await SysFileService.SaveFileToLocal(savePath, fileName, fileDir, HttpContext.GetName(), formFile); + break; + case StoreType.REMOTE: + break; + case StoreType.AARWYUN: + if ((fileSize / 1024) > MaxContentLength) + { + return ToResponse(ResultCode.CUSTOM_ERROR, "上传文件过大,不能超过 " + MaxContentLength + " MB"); + } + file = new(formFile.FileName, fileName, fileExt, fileSize + "kb", fileDir, HttpContext.GetName()) + { + StoreType = (int)StoreType.AARWYUN, + FileType = formFile.ContentType + }; + file = await SysFileService.SaveFileToAliyun(file, formFile); + + if (file.Id <= 0) { return ToResponse(ApiResult.Error("阿里云连接失败")); } + break; + case StoreType.TENCENT: + break; + case StoreType.QINIU: + break; + default: + break; + } + return SUCCESS(new + { + url = file.AccessUrl, + fileName = file.FileName, + fileId = file.Id.ToString() + }); + } + + /// + /// 存储文件到阿里云(已弃用) + /// + /// + /// 自定义文件名 + /// 上传文件夹路径 + /// + [HttpPost] + [Verify] + [ActionPermissionFilter(Permission = "common")] + public async Task UploadFileAliyun([FromForm(Name = "file")] IFormFile formFile, string fileName = "", string fileDir = "") + { + if (formFile == null) throw new CustomException(ResultCode.PARAM_ERROR, "上传文件不能为空"); + string fileExt = Path.GetExtension(formFile.FileName);//文件后缀 + 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)) + { + return ToResponse(ResultCode.CUSTOM_ERROR, "上传失败,未经允许上传类型"); + } + if ((fileSize / 1024) > MaxContentLength) + { + return ToResponse(ResultCode.CUSTOM_ERROR, "上传文件过大,不能超过 " + MaxContentLength + " MB"); + } + SysFile file = new(formFile.FileName, fileName, fileExt, fileSize + "kb", fileDir, HttpContext.GetName()) + { + StoreType = (int)StoreType.AARWYUN, + FileType = formFile.ContentType + }; + file = await SysFileService.SaveFileToAliyun(file, formFile); + + if (file.Id <= 0) { return ToResponse(ApiResult.Error("阿里云连接失败")); } + + return SUCCESS(new + { + url = file.AccessUrl, + fileName = file.FileName, + fileId = file.Id.ToString() + }); + } + #endregion + } +} diff --git a/ARW.WebApi/Controllers/Api/My/MyController.cs b/ARW.WebApi/Controllers/Api/My/MyController.cs new file mode 100644 index 0000000..bc7938e --- /dev/null +++ b/ARW.WebApi/Controllers/Api/My/MyController.cs @@ -0,0 +1,92 @@ +using ARW.Admin.WebApi.Controllers; +using ARW.Admin.WebApi.Extensions; +using ARW.Admin.WebApi.Filters; +using ARW.Common; +using ARW.Model.Dto.Business.Customers; +using ARW.Model.Models.Business.Customers; +using ARW.Service.Business.IBusinessService.Customers; +using Infrastructure; +using Infrastructure.Attribute; +using Infrastructure.Enums; +using Infrastructure.Model; +using Mapster; +using Microsoft.AspNetCore.Mvc; + +namespace ARW.WebApi.Controllers.Api.My +{ + /// + /// 我的控制器 + /// + [Verify] + [Route("api/[controller]")] + public class MyController : BaseController + { + + private readonly ICustomerService _CustomerService; + + public MyController(ICustomerService customerService) + { + _CustomerService = customerService; + } + + + /// + /// 获取用户信息(通过Guid) + /// + /// 查询参数 + /// + [HttpGet("getCustomer")] + public IActionResult GetCustomer([FromQuery] CustomerDto parm) + { + var res = _CustomerService.GetFirst(s => s.CustomerXcxOpenid == parm.CustomerXcxOpenid); + if (res == null) + throw new CustomException("用户不存在"); + + return SUCCESS(res); + } + + /// + /// 添加或修改小程序客户 + /// + /// + /// + [HttpPost("addOrUpdateCustomer")] + [ActionPermissionFilter(Permission = "business:customer:addOrUpdate")] + [Log(Title = "添加或修改小程序客户", BusinessType = BusinessType.ADDORUPDATE)] + public IActionResult AddOrUpdateCustomer([FromBody] CustomerDto parm) + { + if (parm == null) { throw new CustomException("请求参数错误"); } + + var updateModal = parm.Adapt().ToUpdate(HttpContext); + var addModal = parm.Adapt().ToCreate(HttpContext); + + if (parm.CustomerId != 0) + { + var response = _CustomerService.UpdateAsync(updateModal); + return SUCCESS("修改成功!"); + } + else + { + var response = _CustomerService.InsertReturnSnowflakeIdAsync(addModal); + return SUCCESS("添加成功!"); + } + } + + /// + /// 删除小程序客户 + /// + /// + [HttpDelete("{ids}")] + [ActionPermissionFilter(Permission = "business:customer:delete")] + [Log(Title = "小程序客户删除", BusinessType = BusinessType.DELETE)] + public IActionResult Delete(string ids) + { + long[] idsArr = Tools.SpitLongArrary(ids); + if (idsArr.Length <= 0) { return ToResponse(ApiResult.Error($"删除失败Id 不能为空")); } + var response = _CustomerService.Delete(idsArr); + return ToResponse(response, "删除成功!"); + } + + } + +} diff --git a/ARW.WebApi/Controllers/Api/Wechat/WeChatLoginController.cs b/ARW.WebApi/Controllers/Api/Wechat/WeChatLoginController.cs new file mode 100644 index 0000000..3af4861 --- /dev/null +++ b/ARW.WebApi/Controllers/Api/Wechat/WeChatLoginController.cs @@ -0,0 +1,94 @@ +using ARW.Admin.WebApi.Controllers; +using ARW.Admin.WebApi.Extensions; +using ARW.Admin.WebApi.Framework; +using ARW.Model.Dto.Business.Customers; +using ARW.Model.Models.Business.Customers; +using ARW.Model.System; +using ARW.Service.Business.IBusinessService.Customers; +using Infrastructure.WeChat.Login; +using Infrastructure; +using Mapster; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; +using System.Net; +using Senparc.Weixin.WxOpen.AdvancedAPIs.WxApp.Business.JsonResult; +using Senparc.Weixin.WxOpen; +using Senparc.Weixin; +using Senparc.Weixin.CommonAPIs; + +namespace ARW.WebApi.Controllers.Api.Wechat +{ + /// + /// 小程序登录控制器 + /// + //[Verify] + [Route("api/[controller]")] + public class WeChatLoginController : BaseController + { + + private readonly WeChatLogin _weChat; + private readonly ICustomerService _customerService; + private readonly OptionsSetting _jwtSettings; + + + static string session_key = ""; + static string openId = ""; + public WeChatLoginController(WeChatLogin weChat, ICustomerService customerService, IOptions jwtSettings) + { + _weChat = weChat; + _customerService = customerService; + _jwtSettings = jwtSettings.Value; + } + + /// + /// 注册小程序客户 + /// + /// + /// + [HttpPost("Login")] + public IActionResult AddCustomer([FromBody] CustomerDto parm) + { + + if (parm == null) { throw new CustomException("请求参数错误"); } + + var addModal = parm.Adapt().ToCreate(HttpContext); + + var user = _customerService.GetFirst(s => s.CustomerXcxOpenid == parm.CustomerXcxOpenid); + + if (user == null) + { + + var response = _customerService.InsertReturnSnowflakeId(addModal); + if (response == 0) + throw new CustomException("添加失败!"); + + var newUser = _customerService.GetFirst(s => s.CustomerGuid == response); + if (newUser != null) + { + LoginUser loginUser = new LoginUser + { + UserId = newUser.CustomerGuid, + UserName = newUser.CustomerXcxName, + IsApi = true, + }; + var jwt = JwtUtil.GenerateJwtToken(JwtUtil.AddClaims(loginUser), _jwtSettings.JwtSettings); + return SUCCESS(jwt); + } + } + else + { + LoginUser loginUser = new LoginUser + { + UserId = user.CustomerGuid, + UserName = user.CustomerXcxName, + IsApi = true, + }; + var jwt = JwtUtil.GenerateJwtToken(JwtUtil.AddClaims(loginUser), _jwtSettings.JwtSettings); + return SUCCESS(jwt); + } + + return SUCCESS("666"); + } + + } +} diff --git a/ARW.WebApi/Controllers/Api/Wechat/WxPay/WxPayController.cs b/ARW.WebApi/Controllers/Api/Wechat/WxPay/WxPayController.cs new file mode 100644 index 0000000..b42b6df --- /dev/null +++ b/ARW.WebApi/Controllers/Api/Wechat/WxPay/WxPayController.cs @@ -0,0 +1,296 @@ +using ARW.Admin.WebApi.Controllers; +using ARW.Model.Models.Business.Payments; +using ARW.Service.Business.IBusinessService.Customers; +using ARW.Service.Business.IBusinessService.Payments; +using Infrastructure.WeChat.TenPay; +using Infrastructure; +using Microsoft.AspNetCore.Mvc; +using Senparc.CO2NET.HttpUtility; +using Senparc.Weixin.TenPayV3.Apis; +using static Infrastructure.WeChat.TenPay.Pay; +using ARW.Admin.WebApi.Framework; + +namespace ARW.WebApi.Controllers.Api.Wechat.WxPay +{ + /// + /// 微信支付控制器 + /// + //[Verify] + [Route("api/[controller]")] + public class WxPayController : BaseController + { + + private readonly ICustomerService _CustomerService; + private readonly IPaymentService _PaymentService; + private readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + private readonly SenparcHttpClient _httpClient; + + public WxPayController(ICustomerService customerService, SenparcHttpClient httpClient, IPaymentService paymentService) + { + _CustomerService = customerService; + _httpClient = httpClient; + _PaymentService = paymentService; + } + + #region 微信支付 + /// + /// 微信支付 + /// + /// + /// + [HttpPost("wxPay")] + public async Task WxPay([FromBody] PayDto parm) + { + if (parm == null) { throw new CustomException("请求参数错误"); } + + Pay pay = new Pay(_httpClient); + + // 获取金额 + var price = 1;//单位:分 + + + var orderNo = Common.Common.CreateNoQuery(); + var payEntity = await pay.PrePay(parm.ProductGuid, parm.openId, orderNo, parm.type, price); + + if (payEntity == null) + { + throw new CustomException("下单失败!"); + } + else + { + var user = JwtUtil.GetLoginUser(App.HttpContext); + var userId = 1600478763014033408; + + Payment payment = new Payment + { + PaymentBusinessGuid = parm.ProductGuid, + PaymentNumber = orderNo, + PaymentBuytype = parm.type, + CustomerGuid = userId, + PaymentStatus = 1 + }; + + var response = _PaymentService.InsertReturnSnowflakeId(payment); + if (response == 0) + throw new CustomException("数据加入失败"); + + var res = _PaymentService.GetFirst(s => s.PaymentGuid == response); + + PayParams pay1 = new PayParams + { + jsApiUiPackage = payEntity, + outTradeNo = orderNo, + CreateTime = res.Create_time, + OverTime = res.Create_time.AddMinutes(1) + }; + + return new JsonResult(pay1); + + } + + + } + + /// + /// 微信支付回调 + /// + /// + [HttpPost("Notify")] + public async Task Notify() + { + try + { + logger.Info("进入微信支付回调!", "2134234234"); + Pay pay = new Pay(_httpClient); + var res = await pay.PayNotifyUrl(); + + if (res.trade_state == "SUCCESS") + { + logger.Info("微信支付回调之业务:", res.trade_state); + // 业务 + var respones = _PaymentService.UpdateAsync(f => new Payment + { + PaymentWeixinNumber = res.transaction_id, + PaymentBeforeMoney = res.amount.total, + PaymentMoney = res.amount.payer_total, + PaymentStatus = 2, + Update_time = DateTime.Now, + }, f => f.PaymentNumber == res.out_trade_no); + + } + + return SUCCESS("66666"); + } + catch (Exception e) + { + logger.Error("微信支付回调错误信息:", e); + throw; + } + } + #endregion + + + #region 订单查询 + /// + /// 微信支付订单查询 + /// + /// + /// + [HttpPost("orderQuery")] + public async Task OrderQuery([FromBody] OrderQueryDto parm) + { + Pay pay = new Pay(_httpClient); + var res = await pay.OrderQuery(parm.outTradeNo, parm.transactionId); + if (res.VerifySignSuccess == null) + throw new CustomException("订单查询失败!"); + + return SUCCESS(res); + } + #endregion + + + #region 关闭订单 + /// + /// 关闭订单接口 + /// + /// + /// + [HttpPost("closeOrder")] + public async Task CloseOrder([FromBody] OrderQueryDto parm) + { + Pay pay = new Pay(_httpClient); + var res = await pay.CloseOrder(parm.outTradeNo); + if (res == null) + throw new CustomException("订单关闭失败!"); + else + { + var respones = _PaymentService.UpdateAsync(f => new Payment + { + PaymentStatus = 3, + Update_time = DateTime.Now + }, f => f.PaymentNumber == parm.outTradeNo); + } + + return SUCCESS(res); + } + #endregion + + + #region 退款 + /// + /// 退款接口 + /// + /// + /// + [HttpPost("refund")] + public async Task Refund([FromBody] OrderQueryDto parm) + { + Pay pay = new Pay(_httpClient); + var payment = _PaymentService.GetFirstAsync(s => s.PaymentNumber == parm.outTradeNo).Result; + var transactionId = payment.PaymentWeixinNumber; + string paymentRefundNumber = ""; + if (!string.IsNullOrEmpty(payment.PaymentRefundNumber)) + { + paymentRefundNumber = payment.PaymentRefundNumber; + } + + var totalFee = payment.PaymentMoney; + var res = await pay.Refund(transactionId, totalFee, paymentRefundNumber); + if (res.ResultCode.Success == false) + throw new CustomException("订单退款失败!"); + else + { + var respones = _PaymentService.UpdateAsync(f => new Payment + { + PaymentRefundNumber = res.out_refund_no, + }, f => f.PaymentNumber == res.out_trade_no); + } + + return SUCCESS(res); + } + + + /// + /// 退款回调 + /// + /// + [HttpPost("refundNotifyUrl")] + public async Task RefundNotifyUrl() + { + try + { + logger.Info("进入退款回调!", "2134234234"); + Pay pay = new Pay(_httpClient); + var res = await pay.RefundNotifyUrl(); + + if (res.refund_status == "SUCCESS") + { + logger.Info("退款回调之业务:", res.refund_status); + // 业务 + + var respones = _PaymentService.UpdateAsync(f => new Payment + { + PaymentRefundNumber = res.out_refund_no, + PaymentStatus = 4, + Update_time = DateTime.Now + }, f => f.PaymentNumber == res.out_trade_no); + + } + + return SUCCESS("66666"); + } + catch (Exception e) + { + logger.Error("退款回调错误信息:", e); + throw; + } + } + #endregion + + + #region 账单 + /// + /// 申请交易账单 + /// + /// + [HttpGet("tradeBill")] + public async Task TradeBill(string date) + { + var filePath = $"wwwroot/wxpay/{date}-TradeBill.csv"; + Console.WriteLine("FilePath:" + filePath); + using (var fs = new FileStream(filePath, FileMode.OpenOrCreate)) + { + BasePayApis basePayApis = new BasePayApis(); + + var result = basePayApis.TradeBillQueryAsync(date, fileStream: fs).GetAwaiter().GetResult(); + + fs.Flush(); + } + return SUCCESS("已经下载倒指定目录,文件名:" + filePath); + } + + + /// + /// 申请资金账单接口 + /// + /// + [HttpGet("fundflowBill")] + public async Task FundflowBill(string date) + { + var filePath = $"wwwroot/wxpay/{date}-FundflowBill.csv"; + Console.WriteLine("FilePath:" + filePath); + using (var fs = new FileStream(filePath, FileMode.OpenOrCreate)) + { + BasePayApis basePayApis = new BasePayApis(); + + var result = await basePayApis.FundflowBillQueryAsync(date, fs); + + fs.Flush(); + } + return SUCCESS("已经下载倒指定目录,文件名:" + filePath); + } + #endregion + + } + +} diff --git a/ARW.WebApi/Controllers/Api/Wechat/WxSubscribe/WxSubscribeController.cs b/ARW.WebApi/Controllers/Api/Wechat/WxSubscribe/WxSubscribeController.cs new file mode 100644 index 0000000..54f1226 --- /dev/null +++ b/ARW.WebApi/Controllers/Api/Wechat/WxSubscribe/WxSubscribeController.cs @@ -0,0 +1,64 @@ +using ARW.Admin.WebApi.Filters; +using Infrastructure.WeChat.TenPay; +using Infrastructure; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using static Infrastructure.WeChat.TenPay.Pay; +using System.Net.Http; +using ARW.Admin.WebApi.Controllers; +using Infrastructure.WeChat.SubScribe; +using Senparc.Weixin.Entities.TemplateMessage; +using ARW.Model.Models.Business.SubscribeTasks; +using ARW.Admin.WebApi.Framework; +using ARW.Service.Business.IBusinessService.SubscribeTasks; +using Mapster; +using ARW.Admin.WebApi.Extensions; + +namespace ARW.WebApi.Controllers.Api.Wechat.WxSubscribe +{ + + [Route("api/[controller]")] + //[Verify] + public class WxSubscribeController : BaseController + { + + private readonly ISubscribeTaskService _SubscribeTaskService; + + /// + /// 依赖注入 + /// + /// 订阅推送任务订阅推送任务服务 + public WxSubscribeController(ISubscribeTaskService SubscribeTaskService) + { + _SubscribeTaskService = SubscribeTaskService; + } + + + /// + /// 添加微信推送任务 + /// + /// + /// + [HttpPost("pushWxSubscribe")] + public async Task PushWxSubscribe([FromBody] SubscribeTask parm) + { + if (parm == null) { throw new CustomException("请求参数错误"); } + + //var templateId = parm.TemplateId; + //var user = JwtUtil.GetLoginUser(App.HttpContext); + //parm.CustomerGuid = user.UserId; + parm.CustomerGuid = 1600478763014033408; + parm.SubscribeTaskStatus = 0; + + var addModal = parm.Adapt().ToCreate(HttpContext); + + var response = _SubscribeTaskService.InsertReturnSnowflakeIdAsync(addModal); + return SUCCESS("添加成功!"); + + } + + + } + + +} diff --git a/ARW.WebApi/Controllers/BaseController.cs b/ARW.WebApi/Controllers/BaseController.cs new file mode 100644 index 0000000..5d84329 --- /dev/null +++ b/ARW.WebApi/Controllers/BaseController.cs @@ -0,0 +1,453 @@ +using Infrastructure; +using Infrastructure.Model; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; +using MySqlX.XDevAPI.Relational; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using OfficeOpenXml; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; + +namespace ARW.Admin.WebApi.Controllers +{ + /// + /// 基础控制器 + /// + public class BaseController : ControllerBase + { + /// + /// 时间格式化 2020-01-01 09:21:03 + /// + public static string TIME_FORMAT_FULL = "yyyy-MM-dd HH:mm:ss"; + + /// + /// 时间格式化 01-01 09:21:03 + /// + public static string TIME_FORMAT_FULL_2 = "MM-dd HH:mm:ss"; + + /// + /// 返回成功封装 + /// + /// + /// + /// + protected IActionResult SUCCESS(object data, string timeFormatStr = "yyyy-MM-dd HH:mm:ss") + { + string jsonStr = GetJsonStr(GetApiResult(data != null ? ResultCode.SUCCESS : ResultCode.FAIL, data), timeFormatStr); + return Content(jsonStr, "application/json"); + } + + protected IActionResult SUCCESSApi(object data) + { + string jsonStr = GetJsonStr(GetApiResult(data != null ? ResultCode.SUCCESS : ResultCode.FAIL, data), "yyyy-MM-dd HH:mm:ss"); + return Content(jsonStr, "application/json"); + } + + protected IActionResult SUCCESSApi(object data, string msg) + { + string jsonStr = GetJsonStr(GetApiResult(data != null ? ResultCode.SUCCESS : ResultCode.FAIL, msg, data), "yyyy-MM-dd HH:mm:ss"); + return Content(jsonStr, "application/json"); + } + + protected IActionResult SUCCESSApi(string msg) + { + string jsonStr = GetJsonStr(GetApiResult(ResultCode.SUCCESS, msg), "yyyy-MM-dd HH:mm:ss"); + return Content(jsonStr, "application/json"); + } + + /// + /// json输出带时间格式的 + /// + /// + /// + /// + protected IActionResult ToResponse(ApiResult apiResult, string timeFormatStr = "yyyy-MM-dd HH:mm:ss") + { + string jsonStr = GetJsonStr(apiResult, timeFormatStr); + + return Content(jsonStr, "application/json"); + } + + /// + /// + /// + /// + /// + /// + protected IActionResult ToResponse(long rows, string timeFormatStr = "yyyy-MM-dd HH:mm:ss") + { + string jsonStr = GetJsonStr(ToJson(rows), timeFormatStr); + + return Content(jsonStr, "application/json"); + } + + /// + /// + /// + /// + /// + /// + protected IActionResult ToResponse(ResultCode resultCode, string msg = "") + { + return ToResponse(GetApiResult(resultCode, msg)); + } + + #region 方法 + + /// + /// 响应返回结果 + /// + /// 受影响行数 + /// + protected ApiResult ToJson(long rows) + { + return rows > 0 ? GetApiResult(ResultCode.SUCCESS) : GetApiResult(ResultCode.FAIL); + } + /// + /// 响应返回结果,带消息 + /// + /// + /// + /// + protected ApiResult ToJson(long rows, object data) + { + return rows > 0 ? GetApiResult(ResultCode.SUCCESS, data) : GetApiResult(ResultCode.FAIL); + } + /// + /// 全局Code使用 + /// + /// + /// + /// + protected ApiResult GetApiResult(ResultCode resultCode, object? data = null) + { + var apiResult = new ApiResult((int)resultCode, resultCode.ToString()) + { + Data = data + }; + + return apiResult; + } + + protected ApiResult GetApiResult(ResultCode resultCode, string msg, object? data = null) + { + var apiResult = new ApiResult((int)resultCode, msg, resultCode.ToString()) + { + Data = data + }; + + return apiResult; + } + + /// + /// + /// + /// + /// + /// + protected ApiResult GetApiResult(ResultCode resultCode, string msg) + { + return new ApiResult((int)resultCode, msg); + } + private static string GetJsonStr(ApiResult apiResult, string timeFormatStr) + { + if (string.IsNullOrEmpty(timeFormatStr)) + { + timeFormatStr = TIME_FORMAT_FULL; + } + var serializerSettings = new JsonSerializerSettings + { + // 设置为驼峰命名 + ContractResolver = new CamelCasePropertyNamesContractResolver(), + DateFormatString = timeFormatStr + }; + + return JsonConvert.SerializeObject(apiResult, Formatting.Indented, serializerSettings); + } + #endregion + + /// + /// 导出Excel + /// + /// + /// + /// + /// + protected string ExportExcel(List list, string sheetName, string fileName) + { + IWebHostEnvironment webHostEnvironment = (IWebHostEnvironment)App.ServiceProvider.GetService(typeof(IWebHostEnvironment)); + string sFileName = $"{fileName}{DateTime.Now:MMddHHmmss}.xlsx"; + string newFileName = Path.Combine(webHostEnvironment.WebRootPath, "export", sFileName); + //调试模式需要加上 + ExcelPackage.LicenseContext = LicenseContext.NonCommercial; + Directory.CreateDirectory(Path.GetDirectoryName(newFileName)); + using (ExcelPackage package = new(new FileInfo(newFileName))) + { + // 添加worksheet + ExcelWorksheet worksheet = package.Workbook.Worksheets.Add(sheetName); + //单元格自动适应大小 + worksheet.Cells.Style.ShrinkToFit = true; + //单元格自动换行 + //worksheet.Cells.Style.WrapText = true; + //全部字段导出 + worksheet.Cells.LoadFromCollection(list, true, OfficeOpenXml.Table.TableStyles.Light13); + + #region 样式设置 + + //获得有数据的区域 + //var lastAddress = worksheet.Dimension.Address; + ////获得有数据的区域最上且最左的单元格 + //var startCell = worksheet.Dimension.Start.Address; + ////获得有数据的区域最下且最右的单元格 + //var endCell = worksheet.Dimension.End.Address; + + //获取最后的行数 + var endCellRow = worksheet.Dimension.End.Row; + //获取最后的列数 + var endCellColumn = worksheet.Dimension.End.Column; + + //获得第一行有数据的最后一个单元格 + string rowCell = "null"; + var lastRowCell = worksheet.Cells.LastOrDefault(c => c.Start.Row == 1); + if (lastRowCell != null) rowCell = lastRowCell.Address; + + var firstTitle = "A1" + ":" + rowCell; + + //字体大小 + worksheet.Cells[firstTitle].Style.Font.Size = 13; + //字体粗细 + worksheet.Cells[firstTitle].Style.Font.Bold = true; + //字体颜色 + //worksheet.Cells[row, col].Style.Font.Color.SetColor(Color.Red); + + //左右居中 + worksheet.Cells[firstTitle].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center; + //上下居中 + worksheet.Cells[firstTitle].Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.Center; + + //for (int i = 1; i <= endCellRow; i++) + //{ + worksheet.Row(1).Height = 30; //行高 + //} + for (int i = 1; i <= endCellColumn; i++) + { + worksheet.Column(i).Width = 25;//列寬 + } + #endregion + + package.Save(); + } + + return sFileName; + } + + + /// + /// 下载导入模板 + /// + /// + /// + /// + /// 下载文件名 + /// + protected string DownloadImportTemplate(List list, Stream stream, string fileName, List values) + { + IWebHostEnvironment webHostEnvironment = (IWebHostEnvironment)App.ServiceProvider.GetService(typeof(IWebHostEnvironment)); + string sFileName = $"{fileName}模板.xlsx"; + string newFileName = Path.Combine(webHostEnvironment.WebRootPath, "importTemplate", sFileName); + //调试模式需要加上 + ExcelPackage.LicenseContext = LicenseContext.NonCommercial; + if (!Directory.Exists(newFileName)) + { + Directory.CreateDirectory(Path.GetDirectoryName(newFileName)); + } + using (ExcelPackage package = new(new FileInfo(newFileName))) + { + // 添加worksheet + ExcelWorksheet worksheet = package.Workbook.Worksheets.Add(fileName); + + //单元格自动适应大小 + worksheet.Cells.Style.ShrinkToFit = true; + //单元格自动换行 + //worksheet.Cells.Style.WrapText = true; + + //全部字段导出 + worksheet.Cells.LoadFromCollection(list, true, OfficeOpenXml.Table.TableStyles.Light13); + + + #region 样式设置 + + //获得有数据的区域 + //var lastAddress = worksheet.Dimension.Address; + ////获得有数据的区域最上且最左的单元格 + //var startCell = worksheet.Dimension.Start.Address; + ////获得有数据的区域最下且最右的单元格 + //var endCell = worksheet.Dimension.End.Address; + + //获取最后的行数 + var endCellRow = worksheet.Dimension.End.Row; + //获取最后的列数 + var endCellColumn = worksheet.Dimension.End.Column; + + //获得第一行有数据的最后一个单元格 + string rowCell = "null"; + var lastRowCell = worksheet.Cells.LastOrDefault(c => c.Start.Row == 1); + if (lastRowCell != null) rowCell = lastRowCell.Address; + + var firstTitle = "A1" + ":" + rowCell; + + //字体大小 + worksheet.Cells[firstTitle].Style.Font.Size = 13; + //字体粗细 + worksheet.Cells[firstTitle].Style.Font.Bold = true; + //字体颜色 + //worksheet.Cells[row, col].Style.Font.Color.SetColor(Color.Red); + + //左右居中 + worksheet.Cells[firstTitle].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center; + //上下居中 + worksheet.Cells[firstTitle].Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.Center; + + //for (int i = 1; i <= endCellRow; i++) + //{ + worksheet.Row(1).Height = 30; //行高 + //} + for (int i = 1; i <= endCellColumn; i++) + { + worksheet.Column(i).Width = 25;//列寬 + } + #endregion + + + //示例内容 + //var cloum_i = 2; + //var cloum_i2 = 0; + //foreach (var item in values) + //{ + // cloum_i++; + // foreach (var item2 in item) + // { + // cloum_i2++; + // worksheet.Cells[cloum_i, cloum_i2 + 1].Value = item2[cloum_i2]; + // } + + //} + + for (int i = 0; i < values.Count; i++) + { + worksheet.Cells[2, i + 1].Value = values[i]; + } + + package.SaveAs(stream); + } + + return sFileName; + } + + + /// + /// 下载导入模板 + /// + /// + /// + /// + /// 下载文件名 + /// + /// + protected string DownloadImportTemplate(List list, Stream stream, string fileName, List> values) + { + IWebHostEnvironment webHostEnvironment = (IWebHostEnvironment)App.ServiceProvider.GetService(typeof(IWebHostEnvironment)); + string sFileName = $"{fileName}模板.xlsx"; + string newFileName = Path.Combine(webHostEnvironment.WebRootPath, "importTemplate", sFileName); + //调试模式需要加上 + ExcelPackage.LicenseContext = LicenseContext.NonCommercial; + if (!Directory.Exists(newFileName)) + { + Directory.CreateDirectory(Path.GetDirectoryName(newFileName)); + } + using (ExcelPackage package = new(new FileInfo(newFileName))) + { + // 添加worksheet + ExcelWorksheet worksheet = package.Workbook.Worksheets.Add(fileName); + + //单元格自动适应大小 + worksheet.Cells.Style.ShrinkToFit = true; + //单元格自动换行 + //worksheet.Cells.Style.WrapText = true; + + //全部字段导出 + worksheet.Cells.LoadFromCollection(list, true, OfficeOpenXml.Table.TableStyles.Light13); + + + #region 样式设置 + + //获得有数据的区域 + //var lastAddress = worksheet.Dimension.Address; + ////获得有数据的区域最上且最左的单元格 + //var startCell = worksheet.Dimension.Start.Address; + ////获得有数据的区域最下且最右的单元格 + //var endCell = worksheet.Dimension.End.Address; + + //获取最后的行数 + var endCellRow = worksheet.Dimension.End.Row; + //获取最后的列数 + var endCellColumn = worksheet.Dimension.End.Column; + + //获得第一行有数据的最后一个单元格 + string rowCell = "null"; + var lastRowCell = worksheet.Cells.LastOrDefault(c => c.Start.Row == 1); + if (lastRowCell != null) rowCell = lastRowCell.Address; + + var firstTitle = "A1" + ":" + rowCell; + + //字体大小 + worksheet.Cells[firstTitle].Style.Font.Size = 13; + //字体粗细 + worksheet.Cells[firstTitle].Style.Font.Bold = true; + //字体颜色 + //worksheet.Cells[row, col].Style.Font.Color.SetColor(Color.Red); + + //左右居中 + worksheet.Cells[firstTitle].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center; + //上下居中 + worksheet.Cells[firstTitle].Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.Center; + + //for (int i = 1; i <= endCellRow; i++) + //{ + worksheet.Row(1).Height = 30; //行高 + //} + for (int i = 1; i <= endCellColumn; i++) + { + worksheet.Column(i).Width = 25;//列寬 + } + #endregion + + + //示例内容 + var cloum_i = 1; + foreach (var item in values) + { + cloum_i++; + var cloum_i2 = 0; + foreach (var item2 in item) + { + worksheet.Cells[cloum_i, cloum_i2 + 1].Value = item2; + cloum_i2++; + } + } + + //for (int i = 0; i < values.Count; i++) + //{ + // worksheet.Cells[2, i+1].Value = values[i]; + //} + + package.SaveAs(stream); + } + + return sFileName; + } + } +} diff --git a/ARW.WebApi/Controllers/Business/Customers/CustomerController.cs b/ARW.WebApi/Controllers/Business/Customers/CustomerController.cs new file mode 100644 index 0000000..0cfbd7c --- /dev/null +++ b/ARW.WebApi/Controllers/Business/Customers/CustomerController.cs @@ -0,0 +1,109 @@ +using Infrastructure; +using Infrastructure.Attribute; +using Infrastructure.Enums; +using Infrastructure.Model; +using Mapster; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using ARW.Admin.WebApi.Extensions; +using ARW.Admin.WebApi.Filters; +using ARW.Common; +using ARW.Model.Dto.Business.Customers; +using ARW.Service.Business.IBusinessService.Customers; +using ARW.Admin.WebApi.Controllers; +using ARW.Model.Models.Business.Customers; + +namespace ARW.WebApi.Controllers.Business.Customers +{ + /// + /// 小程序客户控制器 + /// + [Verify] + [Route("business/[controller]")] + public class CustomerController : BaseController + { + private readonly ICustomerService _CustomerService; + + /// + /// 依赖注入 + /// + /// 小程序客户小程序客户服务 + public CustomerController(ICustomerService CustomerService) + { + _CustomerService = CustomerService; + } + + /// + /// 获取小程序客户列表 + /// + /// 查询参数 + /// + [HttpGet("getCustomerList")] + [ActionPermissionFilter(Permission = "business:customer:list")] + public IActionResult GetCustomerList([FromQuery] CustomerQueryDto parm) + { + var res = _CustomerService.GetCustomerList(parm); + return SUCCESS(res.Result); + } + + /// + /// 添加或修改小程序客户 + /// + /// + /// + [HttpPost("addOrUpdateCustomer")] + [ActionPermissionFilter(Permission = "business:customer:addOrUpdate")] + [Log(Title = "添加或修改小程序客户", BusinessType = BusinessType.ADDORUPDATE)] + public IActionResult AddOrUpdateCustomer([FromBody] CustomerDto parm) + { + if (parm == null) { throw new CustomException("请求参数错误"); } + + var updateModal = parm.Adapt().ToUpdate(HttpContext); + var addModal = parm.Adapt().ToCreate(HttpContext); + + if (parm.CustomerId != 0) + { + var response = _CustomerService.UpdateAsync(updateModal); + return SUCCESS("修改成功!"); + } + else + { + var response = _CustomerService.InsertReturnSnowflakeIdAsync(addModal); + return SUCCESS("添加成功!"); + } + } + + /// + /// 删除小程序客户 + /// + /// + [HttpDelete("{ids}")] + [ActionPermissionFilter(Permission = "business:customer:delete")] + [Log(Title = "小程序客户删除", BusinessType = BusinessType.DELETE)] + public IActionResult Delete(string ids) + { + long[] idsArr = Tools.SpitLongArrary(ids); + if (idsArr.Length <= 0) { return ToResponse(ApiResult.Error($"删除失败Id 不能为空")); } + var response = _CustomerService.Delete(idsArr); + return ToResponse(response, "删除成功!"); + } + + + /// + /// 导出小程序客户 + /// + /// + [Log(Title = "小程序客户导出", BusinessType = BusinessType.EXPORT, IsSaveResponseData = false)] + [HttpGet("export")] + [ActionPermissionFilter(Permission = "business:customer:export")] + public IActionResult ExportExcel([FromQuery] CustomerQueryDto parm) + { + parm.PageSize = 10000; + var list = _CustomerService.GetCustomerList(parm).Result.Result; + + string sFileName = ExportExcel(list, "Customer", "学生列表"); + return SUCCESS(new { path = "/export/" + sFileName, fileName = sFileName }); + } + + } +} diff --git a/ARW.WebApi/Controllers/Business/Payments/PaymentController.cs b/ARW.WebApi/Controllers/Business/Payments/PaymentController.cs new file mode 100644 index 0000000..04db7c2 --- /dev/null +++ b/ARW.WebApi/Controllers/Business/Payments/PaymentController.cs @@ -0,0 +1,109 @@ +using Infrastructure; +using Infrastructure.Attribute; +using Infrastructure.Enums; +using Infrastructure.Model; +using Mapster; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using ARW.Admin.WebApi.Extensions; +using ARW.Admin.WebApi.Filters; +using ARW.Common; +using ARW.Model.Dto.Business.Payments; +using ARW.Service.Business.IBusinessService.Payments; +using ARW.Admin.WebApi.Controllers; +using ARW.Model.Models.Business.Payments; + +namespace ARW.WebApi.Controllers.Business.Payments +{ + /// + /// 支付订单控制器 + /// + [Verify] + [Route("business/[controller]")] + public class PaymentController : BaseController + { + private readonly IPaymentService _PaymentService; + + /// + /// 依赖注入 + /// + /// 支付订单支付订单服务 + public PaymentController(IPaymentService PaymentService) + { + _PaymentService = PaymentService; + } + + /// + /// 获取支付订单列表 + /// + /// 查询参数 + /// + [HttpGet("getPaymentList")] + [ActionPermissionFilter(Permission = "business:payment:list")] + public IActionResult GetPaymentList([FromQuery] PaymentQueryDto parm) + { + var res = _PaymentService.GetPaymentList(parm); + return SUCCESS(res.Result); + } + + /// + /// 添加或修改支付订单 + /// + /// + /// + [HttpPost("addOrUpdatePayment")] + [ActionPermissionFilter(Permission = "business:payment:addOrUpdate")] + [Log(Title = "添加或修改支付订单", BusinessType = BusinessType.ADDORUPDATE)] + public IActionResult AddOrUpdatePayment([FromBody] PaymentDto parm) + { + if (parm == null) { throw new CustomException("请求参数错误"); } + + var updateModal = parm.Adapt().ToUpdate(HttpContext); + var addModal = parm.Adapt().ToCreate(HttpContext); + + if (parm.PaymentId != 0) + { + var response = _PaymentService.UpdateAsync(updateModal); + return SUCCESS("修改成功!"); + } + else + { + var response = _PaymentService.InsertReturnSnowflakeIdAsync(addModal); + return SUCCESS("添加成功!"); + } + } + + /// + /// 删除支付订单 + /// + /// + [HttpDelete("{ids}")] + [ActionPermissionFilter(Permission = "business:payment:delete")] + [Log(Title = "支付订单删除", BusinessType = BusinessType.DELETE)] + public IActionResult Delete(string ids) + { + long[] idsArr = Tools.SpitLongArrary(ids); + if (idsArr.Length <= 0) { return ToResponse(ApiResult.Error($"删除失败Id 不能为空")); } + var response = _PaymentService.Delete(idsArr); + return ToResponse(response, "删除成功!"); + } + + + /// + /// 导出支付订单 + /// + /// + [Log(Title = "支付订单导出", BusinessType = BusinessType.EXPORT, IsSaveResponseData = false)] + [HttpGet("export")] + [ActionPermissionFilter(Permission = "business:payment:export")] + public IActionResult ExportExcel([FromQuery] PaymentQueryDto parm) + { + parm.PageSize = 10000; + var list = _PaymentService.GetPaymentList(parm).Result.Result; + + string sFileName = ExportExcel(list, "Payment", "支付订单列表"); + return SUCCESS(new { path = "/export/" + sFileName, fileName = sFileName }); + } + + } +} diff --git a/ARW.WebApi/Controllers/Business/SubscribeTasks/SubscribeTaskController.cs b/ARW.WebApi/Controllers/Business/SubscribeTasks/SubscribeTaskController.cs new file mode 100644 index 0000000..7d6bf56 --- /dev/null +++ b/ARW.WebApi/Controllers/Business/SubscribeTasks/SubscribeTaskController.cs @@ -0,0 +1,94 @@ +using Infrastructure; +using Infrastructure.Attribute; +using Infrastructure.Enums; +using Infrastructure.Model; +using Mapster; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using ARW.Admin.WebApi.Extensions; +using ARW.Admin.WebApi.Filters; +using ARW.Common; +using ARW.Model.Dto.Business.SubscribeTasks; +using ARW.Service.Business.IBusinessService.SubscribeTasks; +using ARW.Admin.WebApi.Controllers; +using ARW.Model.Models.Business.SubscribeTasks; + +namespace ARW.WebApi.Controllers.Business.SubscribeTasks +{ + /// + /// 订阅推送任务控制器 + /// + [Verify] + [Route("business/[controller]")] + public class SubscribeTaskController : BaseController + { + private readonly ISubscribeTaskService _SubscribeTaskService; + + /// + /// 依赖注入 + /// + /// 订阅推送任务订阅推送任务服务 + public SubscribeTaskController(ISubscribeTaskService SubscribeTaskService) + { + _SubscribeTaskService = SubscribeTaskService; + } + + /// + /// 获取订阅推送任务列表 + /// + /// 查询参数 + /// + [HttpGet("getSubscribeTaskList")] + [ActionPermissionFilter(Permission = "business:subscribetask:list")] + public IActionResult GetSubscribeTaskList([FromQuery] SubscribeTaskQueryDto parm) + { + var res = _SubscribeTaskService.GetSubscribeTaskList(); + return SUCCESS(res); + } + + /// + /// 添加或修改订阅推送任务 + /// + /// + /// + [HttpPost("addOrUpdateSubscribeTask")] + [ActionPermissionFilter(Permission = "business:subscribetask:addOrUpdate")] + [Log(Title = "添加或修改订阅推送任务", BusinessType = BusinessType.ADDORUPDATE)] + public IActionResult AddOrUpdateSubscribeTask([FromBody] SubscribeTaskDto parm) + { + if (parm == null) { throw new CustomException("请求参数错误"); } + + var updateModal = parm.Adapt().ToUpdate(HttpContext); + var addModal = parm.Adapt().ToCreate(HttpContext); + + if (parm.SubscribeTaskId != 0) + { + var response = _SubscribeTaskService.UpdateAsync(updateModal); + return SUCCESS("修改成功!"); + } + else + { + var response = _SubscribeTaskService.InsertReturnSnowflakeIdAsync(addModal); + return SUCCESS("添加成功!"); + } + } + + /// + /// 删除订阅推送任务 + /// + /// + [HttpDelete("{ids}")] + [ActionPermissionFilter(Permission = "business:subscribetask:delete")] + [Log(Title = "订阅推送任务删除", BusinessType = BusinessType.DELETE)] + public IActionResult Delete(string ids) + { + long[] idsArr = Tools.SpitLongArrary(ids); + if (idsArr.Length <= 0) { return ToResponse(ApiResult.Error($"删除失败Id 不能为空")); } + var response = _SubscribeTaskService.Delete(idsArr); + return ToResponse(response, "删除成功!"); + } + + + + } +} diff --git a/ARW.WebApi/Controllers/CommonController.cs b/ARW.WebApi/Controllers/CommonController.cs new file mode 100644 index 0000000..de958a9 --- /dev/null +++ b/ARW.WebApi/Controllers/CommonController.cs @@ -0,0 +1,194 @@ +using Infrastructure; +using Infrastructure.Attribute; +using Infrastructure.Enums; +using Infrastructure.Extensions; +using Infrastructure.Model; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; +using Newtonsoft.Json; +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using ARW.Admin.WebApi.Extensions; +using ARW.Admin.WebApi.Filters; +using ARW.Common; +using ARW.Model.System; +using ARW.Service.System.IService; + +namespace ARW.Admin.WebApi.Controllers +{ + /// + /// 公共模块 + /// + [Route("[controller]/[action]")] + public class CommonController : BaseController + { + private OptionsSetting OptionsSetting; + private NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + + private IWebHostEnvironment WebHostEnvironment; + private ISysFileService SysFileService; + public CommonController(IOptions options, IWebHostEnvironment webHostEnvironment, ISysFileService fileService) + { + WebHostEnvironment = webHostEnvironment; + SysFileService = fileService; + OptionsSetting = options.Value; + } + + /// + /// hello + /// + /// + [Route("/")] + [HttpGet] + public IActionResult Index() + { + return Content("Hello看到这里页面说明你已经成功启动了本项目,加油吧 少年。"); + } + + /// + /// 发送邮件 + /// + /// 请求参数接收实体 + /// + [ActionPermissionFilter(Permission = "tool:email:send")] + [Log(Title = "发送邮件", IsSaveRequestData = false)] + [HttpPost] + public IActionResult SendEmail([FromBody] SendEmailDto sendEmailVo) + { + if (sendEmailVo == null || string.IsNullOrEmpty(sendEmailVo.Subject) || string.IsNullOrEmpty(sendEmailVo.ToUser)) + { + return ToResponse(ApiResult.Error($"请求参数不完整")); + } + if (string.IsNullOrEmpty(OptionsSetting.MailOptions.From) || string.IsNullOrEmpty(OptionsSetting.MailOptions.Password)) + { + return ToResponse(ApiResult.Error($"请配置邮箱信息")); + } + + MailHelper mailHelper = new(); + + string[] toUsers = sendEmailVo.ToUser.Split(",", StringSplitOptions.RemoveEmptyEntries); + if (sendEmailVo.SendMe) + { + toUsers.Append(mailHelper.FromEmail); + } + mailHelper.SendMail(toUsers, sendEmailVo.Subject, sendEmailVo.Content, sendEmailVo.FileUrl, sendEmailVo.HtmlContent); + + logger.Info($"发送邮件{JsonConvert.SerializeObject(sendEmailVo)}"); + + return SUCCESS(true); + } + + #region 上传 + + /// + /// 存储文件 + /// + /// + /// 存储目录 + /// 自定义文件名 + /// 上传类型1、保存到本地 2、保存到阿里云 + /// + [HttpPost()] + [Verify] + [ActionPermissionFilter(Permission = "common")] + public async Task UploadFile([FromForm(Name = "file")] IFormFile formFile, string? fileName = "", string? fileDir = "", StoreType storeType = StoreType.LOCAL) + { + if (formFile == null) throw new CustomException(ResultCode.PARAM_ERROR, "上传文件不能为空"); + SysFile file = new(); + string fileExt = Path.GetExtension(formFile.FileName);//文件后缀 + 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)) + { + return ToResponse(ResultCode.CUSTOM_ERROR, "上传失败,未经允许上传类型"); + } + switch (storeType) + { + case StoreType.LOCAL: + string savePath = Path.Combine(WebHostEnvironment.WebRootPath); + if (fileDir.IsEmpty()) + { + fileDir = AppSettings.App(new string[] { "Upload", "localSavePath" }); + } + file = await SysFileService.SaveFileToLocal(savePath, fileName, "Uploads/" + fileDir, HttpContext.GetName(), formFile); + break; + case StoreType.REMOTE: + break; + case StoreType.AARWYUN: + if ((fileSize / 1024) > MaxContentLength) + { + return ToResponse(ResultCode.CUSTOM_ERROR, "上传文件过大,不能超过 " + MaxContentLength + " MB"); + } + file = new(formFile.FileName, fileName, fileExt, fileSize + "kb", "Uploads/" + fileDir, HttpContext.GetName()) + { + StoreType = (int)StoreType.AARWYUN, + FileType = formFile.ContentType + }; + file = await SysFileService.SaveFileToAliyun(file, formFile); + + if (file.Id <= 0) { return ToResponse(ApiResult.Error("阿里云连接失败")); } + break; + case StoreType.TENCENT: + break; + case StoreType.QINIU: + break; + default: + break; + } + return SUCCESS(new + { + url = file.AccessUrl, + fileName = file.FileName, + fileId = file.Id.ToString() + }); + } + + /// + /// 存储文件到阿里云(已弃用) + /// + /// + /// 自定义文件名 + /// 上传文件夹路径 + /// + [HttpPost] + [Verify] + [ActionPermissionFilter(Permission = "common")] + public async Task UploadFileAliyun([FromForm(Name = "file")] IFormFile formFile, string fileName = "", string fileDir = "") + { + if (formFile == null) throw new CustomException(ResultCode.PARAM_ERROR, "上传文件不能为空"); + string fileExt = Path.GetExtension(formFile.FileName);//文件后缀 + 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)) + { + return ToResponse(ResultCode.CUSTOM_ERROR, "上传失败,未经允许上传类型"); + } + if ((fileSize / 1024) > MaxContentLength) + { + return ToResponse(ResultCode.CUSTOM_ERROR, "上传文件过大,不能超过 " + MaxContentLength + " MB"); + } + SysFile file = new(formFile.FileName, fileName, fileExt, fileSize + "kb", fileDir, HttpContext.GetName()) + { + StoreType = (int)StoreType.AARWYUN, + FileType = formFile.ContentType + }; + file = await SysFileService.SaveFileToAliyun(file, formFile); + + if (file.Id <= 0) { return ToResponse(ApiResult.Error("阿里云连接失败")); } + + return SUCCESS(new + { + url = file.AccessUrl, + fileName = file.FileName, + fileId = file.Id.ToString() + }); + } + #endregion + } +} diff --git a/ARW.WebApi/Controllers/System/CodeGeneratorController.cs b/ARW.WebApi/Controllers/System/CodeGeneratorController.cs new file mode 100644 index 0000000..b49a2f5 --- /dev/null +++ b/ARW.WebApi/Controllers/System/CodeGeneratorController.cs @@ -0,0 +1,363 @@ +using Infrastructure; +using Infrastructure.Attribute; +using Infrastructure.Enums; +using Infrastructure.Extensions; +using Mapster; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.IO; +using ARW.Admin.WebApi.Extensions; +using ARW.Admin.WebApi.Filters; +using ARW.CodeGenerator; +using ARW.CodeGenerator.Model; +using ARW.CodeGenerator.Service; +using ARW.Common; +using ARW.Model; +using ARW.Model.System.Dto; +using ARW.Model.System.Generate; +using ARW.Service.System.IService; + +namespace ARW.Admin.WebApi.Controllers +{ + /// + /// 代码生成 + /// + [Verify] + [Route("tool/gen")] + public class CodeGeneratorController : BaseController + { + private readonly CodeGeneraterService _CodeGeneraterService = new CodeGeneraterService(); + private readonly IGenTableService GenTableService; + private readonly IGenTableColumnService GenTableColumnService; + + private readonly IWebHostEnvironment WebHostEnvironment; + public CodeGeneratorController( + IGenTableService genTableService, + IGenTableColumnService genTableColumnService, + IWebHostEnvironment webHostEnvironment) + { + GenTableService = genTableService; + GenTableColumnService = genTableColumnService; + WebHostEnvironment = webHostEnvironment; + } + + /// + /// 获取所有数据库的信息 + /// + /// + [HttpGet("getDbList")] + [ActionPermissionFilter(Permission = "tool:gen:list")] + public IActionResult GetListDataBase() + { + var dbList = _CodeGeneraterService.GetAllDataBases(); + var defaultDb = dbList.Count > 0 ? dbList[0] : null; + return SUCCESS(new { dbList, defaultDb }); + } + + /// + ///获取所有表根据数据库名 + /// + /// 数据库名 + /// 表名 + /// 分页信息 + /// + [HttpGet("getTableList")] + [ActionPermissionFilter(Permission = "tool:gen:list")] + public IActionResult FindListTable(string dbName, string? tableName, PagerInfo pager) + { + List list = _CodeGeneraterService.GetAllTables(dbName, tableName, pager); + var page = new PagedInfo + { + TotalPage = pager.TotalPage, + TotalNum = pager.TotalNum, + PageSize = pager.PageSize, + PageIndex = pager.PageNum, + Result = list + }; + return SUCCESS(page); + } + + /// + /// 查询生成表数据 + /// + /// 表名 + /// 分页信息 + /// + [HttpGet("list")] + [ActionPermissionFilter(Permission = "tool:gen:list")] + public IActionResult GetGenTable(string? tableName, PagerInfo pagerInfo) + { + //查询原表数据,部分字段映射到代码生成表字段 + var rows = GenTableService.GetGenTables(new GenTable() { TableName = tableName }, pagerInfo); + + return SUCCESS(rows); + } + + /// + /// 修改代码生成业务查询 + /// + /// genTable表id + /// + [HttpGet("{tableId}")] + [ActionPermissionFilter(Permission = "tool:gen:query")] + public IActionResult GetColumnList(long tableId) + { + var tableInfo = GenTableService.GetGenTableInfo(tableId); + var tables = GenTableService.GetGenTableAll(); + if (tableInfo != null) + { + tableInfo.Columns = GenTableColumnService.GenTableColumns(tableId); + } + return SUCCESS(new { info = tableInfo, tables }); + } + + /// + /// 根据表id查询表列 + /// + /// genTable表id + /// + [HttpGet("column/{tableId}")] + [ActionPermissionFilter(Permission = "tool:gen:query")] + public IActionResult GetTableColumnList(long tableId) + { + var tableColumns = GenTableColumnService.GenTableColumns(tableId); + + return SUCCESS(new { columns = tableColumns }); + } + /// + /// 删除代码生成 + /// + /// + /// + [Log(Title = "代码生成", BusinessType = BusinessType.DELETE)] + [HttpDelete("{tableIds}")] + [ActionPermissionFilter(Permission = "tool:gen:remove")] + public IActionResult Remove(string tableIds) + { + long[] tableId = Tools.SpitLongArrary(tableIds); + + int result = GenTableService.DeleteGenTableByIds(tableId); + return SUCCESS(result); + } + + /// + /// 导入表结构(保存) + /// + /// + /// + /// + [HttpPost("importTable")] + [Log(Title = "代码生成", BusinessType = BusinessType.IMPORT)] + [ActionPermissionFilter(Permission = "tool:gen:import")] + public IActionResult ImportTableSave(string tables, string dbName) + { + if (string.IsNullOrEmpty(tables)) + { + throw new CustomException("表不能为空"); + } + string[] tableNames = tables.Split(',', StringSplitOptions.RemoveEmptyEntries); + int result = 0; + foreach (var tableName in tableNames) + { + var tabInfo = _CodeGeneraterService.GetTableInfo(dbName, tableName); + if (tabInfo != null) + { + GenTable genTable = CodeGeneratorTool.InitTable(dbName, HttpContext.GetName(), tableName, tabInfo?.Description); + genTable.TableId = GenTableService.ImportGenTable(genTable); + + if (genTable.TableId > 0) + { + //保存列信息 + List dbColumnInfos = _CodeGeneraterService.GetColumnInfo(dbName, tableName); + List genTableColumns = CodeGeneratorTool.InitGenTableColumn(genTable, dbColumnInfos); + + GenTableColumnService.DeleteGenTableColumnByTableName(tableName); + GenTableColumnService.InsertGenTableColumn(genTableColumns); + genTable.Columns = genTableColumns; + result++; + } + } + } + + return ToResponse(result); + } + + /// + /// 修改保存代码生成业务 + /// + /// 请求参数实体 + /// + [HttpPut] + [Log(Title = "代码生成", BusinessType = BusinessType.GENCODE, IsSaveRequestData = false)] + [ActionPermissionFilter(Permission = "tool:gen:edit")] + public IActionResult EditSave([FromBody] GenTableDto genTableDto) + { + if (genTableDto == null) throw new CustomException("请求参数错误"); + if (genTableDto.BusinessName.Equals(genTableDto.ModuleName, StringComparison.OrdinalIgnoreCase)) + { + return ToResponse(ResultCode.CUSTOM_ERROR, "模块名不能和业务名一样"); + } + var genTable = genTableDto.Adapt().ToUpdate(HttpContext); + + //将前端额外参数转成字符串存入Options中 + genTable.Options = genTableDto.Params.Adapt(); + DbResult result = GenTableService.UseTran(() => + { + int rows = GenTableService.UpdateGenTable(genTable); + if (rows > 0) + { + GenTableColumnService.UpdateGenTableColumn(genTable.Columns); + } + }); + + return SUCCESS(result.IsSuccess); + } + + /// + /// 预览代码 + /// + /// + /// + /// + [HttpPost("preview/{tableId}")] + [ActionPermissionFilter(Permission = "tool:gen:preview")] + public IActionResult Preview(long tableId = 0, int VueVersion = 0) + { + GenerateDto dto = new(); + dto.TableId = tableId; + dto.VueVersion = VueVersion; + if (dto == null || dto.TableId <= 0) + { + throw new CustomException(ResultCode.CUSTOM_ERROR, "请求参数为空"); + } + var genTableInfo = GenTableService.GetGenTableInfo(dto.TableId); + genTableInfo.Columns = GenTableColumnService.GenTableColumns(dto.TableId); + + dto.DbType = AppSettings.GetAppConfig("gen:dbType", 0); + dto.GenTable = genTableInfo; + dto.IsPreview = true; + //生成代码 + CodeGeneratorTool.Generate(dto); + + return SUCCESS(dto.GenCodes); + } + + /// + /// 生成代码(下载方式) + /// + /// 数据传输对象 + /// + [HttpPost("genCode")] + [Log(Title = "代码生成", BusinessType = BusinessType.GENCODE)] + [ActionPermissionFilter(Permission = "tool:gen:code")] + public IActionResult CodeGenerate([FromBody] GenerateDto dto) + { + if (dto?.TableId <= 0) + { + throw new CustomException(ResultCode.CUSTOM_ERROR, "请求参数为空"); + } + var genTableInfo = GenTableService.GetGenTableInfo(dto.TableId); + genTableInfo.Columns = GenTableColumnService.GenTableColumns(dto.TableId); + + dto.DbType = AppSettings.GetAppConfig("gen:dbType", 0); + dto.GenTable = genTableInfo; + //自定义路径 + if (genTableInfo.GenType == "1") + { + string tempPath = WebHostEnvironment.ContentRootPath; + var parentPath = Directory.GetParent(tempPath)?.Parent?.FullName; + dto.GenType = "1"; + //代码生成文件夹路径 + dto.GenCodePath = genTableInfo.GenPath.IsEmpty() ? parentPath : genTableInfo.GenPath; + } + else + { + dto.GenType = "0"; + dto.ZipPath = Path.Combine(WebHostEnvironment.WebRootPath, "Generatecode"); + dto.GenCodePath = Path.Combine(dto.ZipPath, DateTime.Now.ToString("yyyyMMdd")); + } + //生成压缩包 + string zipReturnFileName = $"ARWAdmin.NET-{genTableInfo.TableComment}-{DateTime.Now:MMddHHmmss}.zip"; + + //生成代码到指定文件夹 + CodeGeneratorTool.Generate(dto); + //下载文件 + FileHelper.ZipGenCode(dto.ZipPath, dto.GenCodePath, zipReturnFileName); + + return SUCCESS(new { path = "/Generatecode/" + zipReturnFileName, fileName = dto.ZipFileName }); + } + + + /// + /// 生成Api代码(下载方式) + /// + /// 数据传输对象 + /// + [HttpPost("genCodeApi")] + [Log(Title = "Api代码生成", BusinessType = BusinessType.GENCODE)] + [ActionPermissionFilter(Permission = "tool:gen:codeApi")] + public IActionResult CodeGenerateApi([FromBody] GenerateDto dto) + { + if (dto?.TableId <= 0) + { + throw new CustomException(ResultCode.CUSTOM_ERROR, "请求参数为空"); + } + var genTableInfo = GenTableService.GetGenTableInfo(dto.TableId); + genTableInfo.Columns = GenTableColumnService.GenTableColumns(dto.TableId); + + dto.DbType = AppSettings.GetAppConfig("gen:dbType", 0); + dto.GenTable = genTableInfo; + //自定义路径 + if (genTableInfo.GenType == "1") + { + string tempPath = WebHostEnvironment.ContentRootPath; + var parentPath = Directory.GetParent(tempPath)?.Parent?.FullName; + dto.GenType = "1"; + //代码生成文件夹路径 + dto.GenCodePath = genTableInfo.GenPath.IsEmpty() ? parentPath : genTableInfo.GenPath; + } + else + { + dto.GenType = "0"; + dto.ZipPath = Path.Combine(WebHostEnvironment.WebRootPath, "Generatecode"); + dto.GenCodePath = Path.Combine(dto.ZipPath, DateTime.Now.ToString("yyyyMMdd")); + } + //生成压缩包 + string zipReturnFileName = $"ARWAdmin.NET-{genTableInfo.TableComment}-{DateTime.Now:MMddHHmmss}.zip"; + + //生成代码到指定文件夹 + CodeGeneratorTool.GenerateApi(dto); + //下载文件 + FileHelper.ZipGenCode(dto.ZipPath, dto.GenCodePath, zipReturnFileName); + + return SUCCESS(new { path = "/Generatecode/" + zipReturnFileName, fileName = dto.ZipFileName }); + } + + + /// + /// 同步数据库 + /// + /// + /// + /// + [ActionPermissionFilter(Permission = "tool:gen:edit")] + [Log(Title = "代码生成", BusinessType = BusinessType.UPDATE)] + [HttpGet("synchDb/{tableId}")] + public IActionResult SynchDb(string tableName, long tableId = 0) + { + if (string.IsNullOrEmpty(tableName) || tableId <= 0) throw new CustomException("参数错误"); + GenTable table = GenTableService.GetGenTableInfo(tableId); + if (table == null) { throw new CustomException("原表不存在"); } + + List dbColumnInfos = _CodeGeneraterService.GetColumnInfo(table.DbName, tableName); + List dbTableColumns = CodeGeneratorTool.InitGenTableColumn(table, dbColumnInfos); + + GenTableService.SynchDb(tableId, table, dbTableColumns); + return SUCCESS(true); + } + } +} diff --git a/ARW.WebApi/Controllers/System/CommonLangController.cs b/ARW.WebApi/Controllers/System/CommonLangController.cs new file mode 100644 index 0000000..8ec33ea --- /dev/null +++ b/ARW.WebApi/Controllers/System/CommonLangController.cs @@ -0,0 +1,157 @@ +using Infrastructure; +using Infrastructure.Attribute; +using Infrastructure.Enums; +using Infrastructure.Extensions; +using Infrastructure.Model; +using Mapster; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using ARW.Admin.WebApi.Filters; +using ARW.Common; +using ARW.Model; +using ARW.Model.Dto; +using ARW.Model.Models; +using ARW.Service.System.IService; + +namespace ARW.Admin.WebApi.Controllers +{ + /// + /// 多语言配置Controller + /// + [Verify] + [Route("system/CommonLang")] + public class CommonLangController : BaseController + { + /// + /// 多语言配置接口 + /// + private readonly ICommonLangService _CommonLangService; + + public CommonLangController(ICommonLangService CommonLangService) + { + _CommonLangService = CommonLangService; + } + + /// + /// 查询多语言配置列表 + /// + /// + /// + [HttpGet("list")] + [ActionPermissionFilter(Permission = "system:lang:list")] + public IActionResult QueryCommonLang([FromQuery] CommonLangQueryDto parm) + { + if (parm.ShowMode == 2) + { + PagedInfo pagedInfo = new() + { + Result = _CommonLangService.GetListToPivot(parm) + }; + + return SUCCESS(pagedInfo); + } + + return SUCCESS(_CommonLangService.GetList(parm)); + } + + /// + /// 查询多语言配置列表 + /// + /// + [HttpGet("list/{lang}")] + [AllowAnonymous] + public IActionResult QueryCommonLangs(string lang) + { + var msgList = _CommonLangService.GetLangList(new CommonLangQueryDto() { LangCode = lang }); + + return SUCCESS(_CommonLangService.SetLang(msgList)); + } + + /// + /// 查询多语言配置详情 + /// + /// + /// + [HttpGet("{Id}")] + [ActionPermissionFilter(Permission = "system:lang:query")] + public IActionResult GetCommonLang(long Id) + { + var response = _CommonLangService.GetFirst(x => x.Id == Id); + + var list = _CommonLangService.GetList(x => x.LangKey == response.LangKey); + var vo = list.Adapt>(); + var modal = new CommonLangDto() { LangKey = response.LangKey, LangList = vo }; + return SUCCESS(modal); + } + + /// + /// 查询多语言配置详情 + /// + /// + /// + [HttpGet("key/{langKey}")] + [ActionPermissionFilter(Permission = "system:lang:query")] + public IActionResult GetCommonLangByKey(string langKey) + { + var list = _CommonLangService.GetList(x => x.LangKey == langKey); + var vo = list.Adapt>(); + var modal = new CommonLangDto() { LangKey = langKey, LangList = vo }; + + return SUCCESS(modal); + } + + /// + /// 更新多语言配置 + /// + /// + [HttpPut] + [ActionPermissionFilter(Permission = "system:lang:edit")] + [Log(Title = "多语言配置", BusinessType = BusinessType.UPDATE)] + public IActionResult UpdateCommonLang([FromBody] CommonLangDto parm) + { + if (parm == null || parm.LangKey.IsEmpty()) + { + throw new CustomException("请求实体不能为空"); + } + + _CommonLangService.StorageCommonLang(parm); + + return ToResponse(1); + } + + /// + /// 删除多语言配置 + /// + /// + [HttpDelete("{ids}")] + [ActionPermissionFilter(Permission = "system:lang:delete")] + [Log(Title = "多语言配置", BusinessType = BusinessType.DELETE)] + public IActionResult DeleteCommonLang(string ids) + { + long[] idsArr = Tools.SpitLongArrary(ids); + if (idsArr.Length <= 0) { return ToResponse(ApiResult.Error($"删除失败Id 不能为空")); } + + var response = _CommonLangService.Delete(idsArr); + + return ToResponse(response); + } + + /// + /// 导出多语言配置 + /// + /// + [Log(Title = "多语言配置", BusinessType = BusinessType.EXPORT, IsSaveResponseData = false)] + [HttpGet("export")] + [ActionPermissionFilter(Permission = "system:lang:export")] + public IActionResult Export([FromQuery] CommonLangQueryDto parm) + { + parm.PageSize = 10000; + var list = _CommonLangService.GetList(parm).Result; + + string sFileName = ExportExcel(list, "CommonLang", "多语言配置"); + return SUCCESS(new { path = "/export/" + sFileName, fileName = sFileName }); + } + + } +} \ No newline at end of file diff --git a/ARW.WebApi/Controllers/System/SysConfigController.cs b/ARW.WebApi/Controllers/System/SysConfigController.cs new file mode 100644 index 0000000..0dd9c1b --- /dev/null +++ b/ARW.WebApi/Controllers/System/SysConfigController.cs @@ -0,0 +1,159 @@ +using Infrastructure; +using Infrastructure.Attribute; +using Infrastructure.Enums; +using Infrastructure.Extensions; +using Infrastructure.Model; +using Mapster; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using ARW.Admin.WebApi.Extensions; +using ARW.Admin.WebApi.Filters; +using ARW.Common; +using ARW.Model.Dto; +using ARW.Model.System; +using ARW.Model.System.Dto; +using ARW.Service.System; + +namespace ARW.Admin.WebApi.Controllers +{ + /// + /// 参数配置Controller + /// + [Verify] + [Route("system/config")] + public class SysConfigController : BaseController + { + /// + /// 参数配置接口 + /// + private readonly ISysConfigService _SysConfigService; + + public SysConfigController(ISysConfigService SysConfigService) + { + _SysConfigService = SysConfigService; + } + + /// + /// 查询参数配置列表 + /// + /// + [HttpGet("list")] + [ActionPermissionFilter(Permission = "system:config:list")] + public IActionResult QuerySysConfig([FromQuery] SysConfigQueryDto parm) + { + var predicate = Expressionable.Create(); + + predicate = predicate.AndIF(!parm.ConfigType.IsEmpty(),m => m.ConfigType == parm.ConfigType); + predicate = predicate.AndIF(!parm.ConfigName.IsEmpty(),m => m.ConfigName.Contains(parm.ConfigType)); + predicate = predicate.AndIF(!parm.ConfigKey.IsEmpty(),m => m.ConfigKey.Contains(parm.ConfigKey)); + predicate = predicate.AndIF(!parm.BeginTime.IsEmpty(),m => m.Create_time >= parm.BeginTime ); + predicate = predicate.AndIF(!parm.BeginTime.IsEmpty(),m => m.Create_time <= parm.EndTime); + + var response = _SysConfigService.GetPages(predicate.ToExpression(), parm); + + return SUCCESS(response); + } + + /// + /// 查询参数配置详情 + /// + /// + /// + [HttpGet("{ConfigId}")] + [ActionPermissionFilter(Permission = "system:config:query")] + public IActionResult GetSysConfig(int ConfigId) + { + var response = _SysConfigService.GetId(ConfigId); + + return SUCCESS(response); + } + + /// + /// 根据参数键名查询参数值 + /// + /// + /// + [HttpGet("configKey/{configKey}")] + [AllowAnonymous] + public IActionResult GetConfigKey(string configKey) + { + var response = _SysConfigService.Queryable().First(f=> f.ConfigKey == configKey); + + return SUCCESS(response?.ConfigValue); + } + + /// + /// 添加参数配置 + /// + /// + [HttpPost] + [ActionPermissionFilter(Permission = "system:config:add")] + [Log(Title = "参数配置添加", BusinessType = BusinessType.INSERT)] + public IActionResult AddSysConfig([FromBody] SysConfigDto parm) + { + if (parm == null) + { + throw new CustomException("请求参数错误"); + } + var model = parm.Adapt().ToCreate(HttpContext); + + return SUCCESS(_SysConfigService.Insert(model, it => new + { + it.ConfigName, + it.ConfigKey, + it.ConfigValue, + it.ConfigType, + it.Create_by, + it.Create_time, + it.Remark, + })); + } + + /// + /// 更新参数配置 + /// + /// + [HttpPut] + [ActionPermissionFilter(Permission = "system:config:update")] + [Log(Title = "参数配置修改", BusinessType = BusinessType.UPDATE)] + public IActionResult UpdateSysConfig([FromBody] SysConfigDto parm) + { + if (parm == null) + { + throw new CustomException("请求实体不能为空"); + } + var model = parm.Adapt().ToUpdate(HttpContext); + + var response = _SysConfigService.Update(w => w.ConfigId == model.ConfigId, it => new SysConfig() + { + ConfigName = model.ConfigName, + ConfigKey = model.ConfigKey, + ConfigValue = model.ConfigValue, + ConfigType = model.ConfigType, + Update_by = model.Update_by, + Update_time = model.Update_time, + Remark = model.Remark + }); + + return SUCCESS(response); + } + + /// + /// 删除参数配置 + /// + /// + [HttpDelete("{ids}")] + [ActionPermissionFilter(Permission = "system:config:remove")] + [Log(Title = "参数配置删除", BusinessType = BusinessType.DELETE)] + public IActionResult DeleteSysConfig(string ids) + { + int[] idsArr = Tools.SpitIntArrary(ids); + if (idsArr.Length <= 0) { return ToResponse(ApiResult.Error($"删除失败Id 不能为空")); } + + var response = _SysConfigService.Delete(idsArr); + + return SUCCESS(response); + } + } +} \ No newline at end of file diff --git a/ARW.WebApi/Controllers/System/SysDeptController.cs b/ARW.WebApi/Controllers/System/SysDeptController.cs new file mode 100644 index 0000000..9f48fd0 --- /dev/null +++ b/ARW.WebApi/Controllers/System/SysDeptController.cs @@ -0,0 +1,166 @@ +using Infrastructure; +using Infrastructure.Attribute; +using Infrastructure.Enums; +using Microsoft.AspNetCore.Mvc; +using System.Collections; +using ARW.Admin.WebApi.Filters; +using ARW.Common; +using ARW.Model.System; +using ARW.Service.System.IService; + +namespace ARW.Admin.WebApi.Controllers.System +{ + /// + /// 部门 + /// + [Verify] + [Route("system/dept")] + public class SysDeptController : BaseController + { + public ISysDeptService DeptService; + public ISysUserService UserService; + public SysDeptController(ISysDeptService deptService + , ISysUserService userService) + { + DeptService = deptService; + UserService = userService; + } + + /// + /// 获取部门列表 + /// + /// + [ActionPermissionFilter(Permission = "system:dept:list")] + [HttpGet("list")] + public IActionResult List([FromQuery] SysDept dept) + { + return SUCCESS(DeptService.GetSysDepts(dept), TIME_FORMAT_FULL); + } + + /// + /// 查询部门列表(排除节点) + /// + /// + /// + [HttpGet("list/exclude/{deptId}")] + public IActionResult ExcludeChild(long deptId) + { + var depts = DeptService.GetSysDepts(new SysDept()); + + for (int i = 0; i < depts.Count; i++) + { + SysDept d = depts[i]; + long[] deptIds = Tools.SpitLongArrary(d.Ancestors); + if (d.DeptId == deptId || ((IList)deptIds).Contains(deptId)) + { + depts.Remove(d); + } + } + return SUCCESS(depts); + } + + /// + /// 获取部门下拉树列表 + /// + /// + /// + [HttpGet("treeselect")] + public IActionResult TreeSelect(SysDept dept) + { + var depts = DeptService.GetSysDepts(dept); + + return SUCCESS(DeptService.BuildDeptTreeSelect(depts), TIME_FORMAT_FULL); + } + + /// + /// 获取角色部门信息 + /// 加载对应角色部门列表树 + /// + /// + /// + [HttpGet("roleDeptTreeselect/{roleId}")] + public IActionResult RoleMenuTreeselect(int roleId) + { + var depts = DeptService.GetSysDepts(new SysDept()); + var checkedKeys = DeptService.SelectRoleDepts(roleId); + return SUCCESS(new + { + checkedKeys, + depts = DeptService.BuildDeptTreeSelect(depts), + }); + } + + /// + /// 根据部门编号获取详细信息 + /// + /// + [HttpGet("{deptId}")] + [ActionPermissionFilter(Permission = "system:dept:query")] + public IActionResult GetInfo(long deptId) + { + var info = DeptService.GetFirst(f => f.DeptId == deptId); + return SUCCESS(info); + } + + /// + /// 新增部门 + /// + /// + /// + [HttpPost] + [Log(Title = "部门管理", BusinessType = BusinessType.INSERT)] + [ActionPermissionFilter(Permission = "system:dept:add")] + public IActionResult Add([FromBody] SysDept dept) + { + if (UserConstants.NOT_UNIQUE.Equals(DeptService.CheckDeptNameUnique(dept))) + { + return ToResponse(GetApiResult(ResultCode.CUSTOM_ERROR, $"新增部门{dept.DeptName}失败,部门名称已存在")); + } + dept.Create_by = User.Identity.Name; + return ToResponse(ToJson(DeptService.InsertDept(dept))); + } + + /// + /// 修改部门 + /// + /// + /// + [HttpPut] + [Log(Title = "部门管理", BusinessType = BusinessType.UPDATE)] + [ActionPermissionFilter(Permission = "system:dept:update")] + public IActionResult Update([FromBody] SysDept dept) + { + if (UserConstants.NOT_UNIQUE.Equals(DeptService.CheckDeptNameUnique(dept))) + { + return ToResponse(GetApiResult(ResultCode.CUSTOM_ERROR, $"修改部门{dept.DeptName}失败,部门名称已存在")); + } + else if (dept.ParentId.Equals(dept.DeptId)) + { + return ToResponse(GetApiResult(ResultCode.CUSTOM_ERROR, $"修改部门{dept.DeptName}失败,上级部门不能是自己")); + } + dept.Update_by = User.Identity.Name; + return ToResponse(ToJson(DeptService.UpdateDept(dept))); + } + + /// + /// 删除部门 + /// + /// + [HttpDelete("{deptId}")] + [ActionPermissionFilter(Permission = "system:dept:remove")] + [Log(Title = "部门管理", BusinessType = BusinessType.DELETE)] + public IActionResult Remove(long deptId) + { + if (DeptService.Queryable().Count(it => it.ParentId == deptId && it.DelFlag == "0") > 0) + { + return ToResponse(GetApiResult(ResultCode.CUSTOM_ERROR, $"存在下级部门,不允许删除")); + } + if (UserService.Queryable().Count(it => it.DeptId == deptId && it.DelFlag == "0") > 0) + { + return ToResponse(GetApiResult(ResultCode.CUSTOM_ERROR, $"部门存在用户,不允许删除")); + } + + return SUCCESS(DeptService.Delete(deptId)); + } + } +} diff --git a/ARW.WebApi/Controllers/System/SysDictDataController.cs b/ARW.WebApi/Controllers/System/SysDictDataController.cs new file mode 100644 index 0000000..b48d5e5 --- /dev/null +++ b/ARW.WebApi/Controllers/System/SysDictDataController.cs @@ -0,0 +1,137 @@ +using Infrastructure.Attribute; +using Infrastructure.Enums; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using ARW.Admin.WebApi.Extensions; +using ARW.Admin.WebApi.Filters; +using ARW.Model; +using ARW.Model.System; +using ARW.Model.System.Dto; +using ARW.Service.System.IService; + +namespace ARW.Admin.WebApi.Controllers.System +{ + /// + /// 数据字典信息 + /// + [Verify] + [Route("system/dict/data")] + public class SysDictDataController : BaseController + { + private readonly ISysDictDataService SysDictDataService; + private readonly ISysDictService SysDictService; + + public SysDictDataController(ISysDictService sysDictService, ISysDictDataService sysDictDataService) + { + SysDictService = sysDictService; + SysDictDataService = sysDictDataService; + } + + /// + /// 搜索 + /// + /// + /// + /// + [ActionPermissionFilter(Permission = "system:dict:list")] + [HttpGet("list")] + public IActionResult List([FromQuery] SysDictData dictData, [FromQuery] PagerInfo pagerInfo) + { + var list = SysDictDataService.SelectDictDataList(dictData, pagerInfo); + return SUCCESS(list); + } + + /// + /// 根据字典类型查询字典数据信息 + /// + /// + /// + [AllowAnonymous] + [HttpGet("type/{dictType}")] + public IActionResult DictType(string dictType) + { + return SUCCESS(SysDictDataService.SelectDictDataByType(dictType)); + } + + /// + /// 根据字典类型查询字典数据信息 + /// + /// + /// + [AllowAnonymous] + [HttpPost("types")] + public IActionResult DictTypes([FromBody] List dto) + { + var list = SysDictDataService.SelectDictDataByTypes(dto.Select(f => f.DictType).ToArray()); + List dataVos = new(); + + foreach (var dic in dto) + { + SysdictDataDto vo = new() + { + DictType = dic.DictType, + ColumnName = dic.ColumnName, + List = list.FindAll(f => f.DictType == dic.DictType) + }; + dataVos.Add(vo); + } + return SUCCESS(dataVos); + } + + /// + /// 查询字典数据详细 + /// + /// + /// + [AllowAnonymous] + [HttpGet("info/{dictCode}")] + public IActionResult GetInfo(long dictCode) + { + return SUCCESS(SysDictDataService.SelectDictDataById(dictCode)); + } + + /// + /// 添加 + /// + /// + /// + [ActionPermissionFilter(Permission = "system:dict:add")] + [Log(Title = "字典数据", BusinessType = BusinessType.INSERT)] + [HttpPost()] + public IActionResult Add([FromBody] SysDictData dict) + { + dict.Create_by = HttpContext.GetName(); + dict.Create_time = DateTime.Now; + return SUCCESS(SysDictDataService.InsertDictData(dict)); + } + + /// + /// 修改 + /// + /// + /// + [ActionPermissionFilter(Permission = "system:dict:edit")] + [Log(Title = "字典数据", BusinessType = BusinessType.UPDATE)] + [HttpPut()] + public IActionResult Edit([FromBody] SysDictData dict) + { + dict.Update_by = HttpContext.GetName(); + return SUCCESS(SysDictDataService.UpdateDictData(dict)); + } + + /// + /// 删除字典类型 + /// + /// + /// + [ActionPermissionFilter(Permission = "system:dict:remove")] + [Log(Title = "字典类型", BusinessType = BusinessType.DELETE)] + [HttpDelete("{dictCode}")] + public IActionResult Remove(string dictCode) + { + long[] dictCodes = Common.Tools.SpitLongArrary(dictCode); + + return SUCCESS(SysDictDataService.DeleteDictDataByIds(dictCodes)); + } + } +} diff --git a/ARW.WebApi/Controllers/System/SysDictTypeController.cs b/ARW.WebApi/Controllers/System/SysDictTypeController.cs new file mode 100644 index 0000000..e1fa894 --- /dev/null +++ b/ARW.WebApi/Controllers/System/SysDictTypeController.cs @@ -0,0 +1,123 @@ +using Infrastructure.Attribute; +using Infrastructure.Enums; +using Infrastructure.Model; +using Microsoft.AspNetCore.Mvc; +using ARW.Admin.WebApi.Extensions; +using ARW.Admin.WebApi.Filters; +using ARW.Common; +using ARW.Model; +using ARW.Model.System; +using ARW.Service.System.IService; + +namespace ARW.Admin.WebApi.Controllers.System +{ + /// + /// 数据字典信息 + /// + [Verify] + [Route("system/dict/type")] + public class SysDictTypeController : BaseController + { + private readonly ISysDictService SysDictService; + + public SysDictTypeController(ISysDictService sysDictService) + { + SysDictService = sysDictService; + } + + /// + /// 查询 + /// + /// + /// + /// + [ActionPermissionFilter(Permission = "system:dict:list")] + [HttpGet("list")] + public IActionResult List([FromQuery] SysDictType dict, [FromQuery] PagerInfo pagerInfo) + { + var list = SysDictService.SelectDictTypeList(dict, pagerInfo); + + return SUCCESS(list, TIME_FORMAT_FULL); + } + + /// + /// 查询字典类型详细 + /// + /// + /// + [HttpGet("{dictId}")] + [ActionPermissionFilter(Permission = "system:dict:query")] + public IActionResult GetInfo(long dictId = 0) + { + return SUCCESS(SysDictService.GetInfo(dictId)); + } + + /// + /// 添加字典类型 + /// + /// + /// + [ActionPermissionFilter(Permission = "system:dict:add")] + [Log(Title = "字典操作", BusinessType = BusinessType.INSERT)] + [HttpPost("edit")] + public IActionResult Add([FromBody] SysDictType dict) + { + if (UserConstants.NOT_UNIQUE.Equals(SysDictService.CheckDictTypeUnique(dict))) + { + return ToResponse(ApiResult.Error($"新增字典'{dict.DictName}'失败,字典类型已存在")); + } + dict.Create_by = HttpContext.GetName(); + dict.Create_time = DateTime.Now; + return SUCCESS(SysDictService.InsertDictType(dict)); + } + + /// + /// 修改字典类型 + /// + /// + /// + [ActionPermissionFilter(Permission = "system:dict:edit")] + [Log(Title = "字典操作", BusinessType = BusinessType.UPDATE)] + [Route("edit")] + [HttpPut] + public IActionResult Edit([FromBody] SysDictType dict) + { + if (UserConstants.NOT_UNIQUE.Equals(SysDictService.CheckDictTypeUnique(dict))) + { + return ToResponse(ApiResult.Error($"修改字典'{dict.DictName}'失败,字典类型已存在")); + } + //设置添加人 + dict.Update_by = HttpContext.GetName(); + return SUCCESS(SysDictService.UpdateDictType(dict)); + } + + /// + /// 删除字典类型 + /// + /// + [ActionPermissionFilter(Permission = "system:dict:remove")] + [Log(Title = "删除字典类型", BusinessType = BusinessType.DELETE)] + [HttpDelete("{ids}")] + public IActionResult Remove(string ids) + { + long[] idss = Tools.SpitLongArrary(ids); + + return SUCCESS(SysDictService.DeleteDictTypeByIds(idss)); + } + + /// + /// 字典导出 + /// + /// + [Log(BusinessType = BusinessType.EXPORT, IsSaveResponseData = false, Title = "字典导出")] + [HttpGet("export")] + [ActionPermissionFilter(Permission = "system:dict:export")] + public IActionResult Export() + { + var list = SysDictService.GetAll(); + + string sFileName = ExportExcel(list, "sysdictType", "字典"); + return SUCCESS(new { path = "/export/" + sFileName, fileName = sFileName }); + } + } +} diff --git a/ARW.WebApi/Controllers/System/SysFileController.cs b/ARW.WebApi/Controllers/System/SysFileController.cs new file mode 100644 index 0000000..82da0cb --- /dev/null +++ b/ARW.WebApi/Controllers/System/SysFileController.cs @@ -0,0 +1,101 @@ +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using Infrastructure.Attribute; +using Infrastructure.Enums; +using Infrastructure.Model; +using ARW.Admin.WebApi.Filters; +using ARW.Common; +using ARW.Model.System; +using ARW.Service.System.IService; +using ARW.Model.System.Dto; + +namespace ARW.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); + predicate = predicate.AndIF(parm.FileId != null, m => m.Id == parm.FileId); + predicate = predicate.And(m => m.IsDelete == false); + + //搜索条件查询语法参考Sqlsugar + var response = _SysFileService.GetPages(predicate.ToExpression(), parm, x => x.Id, OrderByType.Desc); + return SUCCESS(response); + } + + /// + /// 查询文件存储详情 + /// + /// + /// + [HttpGet("{Id}")] + [ActionPermissionFilter(Permission = "tool:file:query")] + public IActionResult GetSysFile(long Id) + { + var response = _SysFileService.GetFirst(x => x.Id == Id); + + return SUCCESS(response); + } + + /// + /// 删除文件存储 + /// + /// + [HttpDelete("{ids}")] + [ActionPermissionFilter(Permission = "tool:file:delete")] + [Log(Title = "文件存储", BusinessType = BusinessType.DELETE)] + public IActionResult DeleteSysFile(string ids) + { + long[] idsArr = Tools.SpitLongArrary(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/ARW.WebApi/Controllers/System/SysLoginController.cs b/ARW.WebApi/Controllers/System/SysLoginController.cs new file mode 100644 index 0000000..a940e4c --- /dev/null +++ b/ARW.WebApi/Controllers/System/SysLoginController.cs @@ -0,0 +1,294 @@ +using Hei.Captcha; +using Infrastructure; +using Infrastructure.Attribute; +using Infrastructure.Model; +using IPTools.Core; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using UAParser; +using ARW.Admin.WebApi.Extensions; +using ARW.Admin.WebApi.Filters; +using ARW.Admin.WebApi.Framework; +using ARW.Common; +using ARW.Model.System; +using ARW.Model.System.Dto; +using ARW.Service.System; +using ARW.Service.System.IService; + +namespace ARW.Admin.WebApi.Controllers.System +{ + /// + /// 登录 + /// + public class SysLoginController : BaseController + { + static readonly NLog.Logger logger = NLog.LogManager.GetLogger("LoginController"); + private readonly IHttpContextAccessor httpContextAccessor; + private readonly ISysUserService sysUserService; + private readonly ISysMenuService sysMenuService; + private readonly ISysLoginService sysLoginService; + private readonly ISysPermissionService permissionService; + private readonly SecurityCodeHelper SecurityCodeHelper; + private readonly ISysConfigService sysConfigService; + private readonly ISysRoleService roleService; + private readonly OptionsSetting jwtSettings; + + public SysLoginController( + IHttpContextAccessor contextAccessor, + ISysMenuService sysMenuService, + ISysUserService sysUserService, + ISysLoginService sysLoginService, + ISysPermissionService permissionService, + ISysConfigService configService, + ISysRoleService sysRoleService, + SecurityCodeHelper captcha, + IOptions jwtSettings) + { + httpContextAccessor = contextAccessor; + SecurityCodeHelper = captcha; + this.sysMenuService = sysMenuService; + this.sysUserService = sysUserService; + this.sysLoginService = sysLoginService; + this.permissionService = permissionService; + this.sysConfigService = configService; + roleService = sysRoleService; + this.jwtSettings = jwtSettings.Value; + } + + + /// + /// 登录 + /// + /// 登录对象 + /// + [Route("login")] + [HttpPost] + //[Log(Title = "登录")] + public IActionResult Login([FromBody] LoginBodyDto loginBody) + { + if (loginBody == null) { throw new CustomException("请求参数错误"); } + loginBody.LoginIP = HttpContextExtension.GetClientUserIp(HttpContext); + SysConfig sysConfig = sysConfigService.GetSysConfigByKey("sys.account.captchaOnOff"); + if (sysConfig?.ConfigValue != "off" && CacheHelper.Get(loginBody.Uuid) is string str && !str.ToLower().Equals(loginBody.Code.ToLower())) + { + return ToResponse(ResultCode.CAPTCHA_ERROR, "验证码错误"); + } + + var user = sysLoginService.Login(loginBody, RecordLogInfo(httpContextAccessor.HttpContext)); + + List roles = roleService.SelectUserRoleListByUserId(user.UserId); + //权限集合 eg *:*:*,system:user:list + List permissions = permissionService.GetMenuPermission(user); + + LoginUser loginUser = new(user, roles, permissions); + CacheService.SetUserPerms(GlobalConstant.UserPermKEY + user.UserId, permissions); + return SUCCESS(JwtUtil.GenerateJwtToken(JwtUtil.AddClaims(loginUser), jwtSettings.JwtSettings)); + } + + /// + /// 注销 + /// + /// + [Log(Title = "注销")] + [HttpPost("logout")] + public IActionResult LogOut() + { + //Task.Run(async () => + //{ + // //注销登录的用户,相当于ASP.NET中的FormsAuthentication.SignOut + // await HttpContext.SignOutAsync(); + //}).Wait(); + var userid = HttpContext.GetUId(); + var name = HttpContext.GetName(); + + CacheService.RemoveUserPerms(GlobalConstant.UserPermKEY + userid); + return SUCCESS(new { name, id = userid }); + } + + /// + /// 获取用户信息 + /// + /// + [Verify] + [HttpGet("getInfo")] + public IActionResult GetUserInfo() + { + long userid = HttpContext.GetUId(); + var user = sysUserService.SelectUserById(userid); + + //前端校验按钮权限使用 + //角色集合 eg: admin,yunying,common + List roles = permissionService.GetRolePermission(user); + //权限集合 eg *:*:*,system:user:list + List permissions = permissionService.GetMenuPermission(user); + user.WelcomeContent = GlobalConstant.WelcomeMessages[new Random().Next(0, GlobalConstant.WelcomeMessages.Length)]; + return SUCCESS(new { user, roles, permissions }); + } + + /// + /// 获取路由信息 + /// + /// + [Verify] + [HttpGet("getRouters")] + public IActionResult GetRouters() + { + long uid = HttpContext.GetUId(); + var menus = sysMenuService.SelectMenuTreeByUserId(uid); + + return ToResponse(ToJson(1, sysMenuService.BuildMenus(menus))); + } + + /// + /// 发送邮箱验证码 + /// + /// + /// + [HttpPost("postEmailCode")] + public IActionResult PostEmailCode([FromBody] PostEmailDto dto) + { + var user = sysUserService.SelectUserByEmail(dto.Email); + if (user == null) + { + throw new CustomException("用户不存在"); + } + if (string.IsNullOrEmpty(dto.Email)) { + throw new CustomException("邮箱不能为空!"); + } + MailHelper mailHelper = new(); + var code = Tools.GetNumCode(4); + mailHelper.SendMail(dto.Email, "Aerwen邮箱验证码", "您的验证码为:" + code +",5分钟内有效!", "", ""); + CacheHelper.SetCache(user.UserId.ToString()+"emailCode", code , 5); + + var emailCode = CacheHelper.GetCache(user.UserId.ToString() + "emailCode"); + Console.WriteLine(user.UserId.ToString()+":"+emailCode); + + return SUCCESS("发送成功!"); + } + + /// + /// 通过邮箱修改密码 + /// + /// + /// + [HttpPost("changePwByEmail")] + public IActionResult ChangePwByEmail([FromBody] ChangePwByEmailDto dto) + { + var user = sysUserService.SelectUserByEmail(dto.Email); + var emailCode = (string)CacheHelper.GetCache(user.UserId.ToString() + "emailCode"); + + if (emailCode == null) + { + throw new CustomException("验证码已过期,请重新获取!"); + } + + if (dto.code == emailCode) + { + sysUserService.ResetPwd(user.UserId,dto.Password); + return SUCCESS("密码重置成功"); + } + else + { + throw new CustomException("验证码错误,请重试!"); + } + + + } + + + /// + /// 生成图片验证码 + /// + /// + [HttpGet("captchaImage")] + public ApiResult CaptchaImage() + { + string uuid = Guid.NewGuid().ToString().Replace("-", ""); + + SysConfig sysConfig = sysConfigService.GetSysConfigByKey("sys.account.captchaOnOff"); + var captchaOff = sysConfig?.ConfigValue ?? "0"; + + var code = SecurityCodeHelper.GetRandomEnDigitalText(4); + byte[] imgByte; + if (captchaOff == "1") + { + imgByte = SecurityCodeHelper.GetGifEnDigitalCodeByte(code);//动态gif数字字母 + } + else if (captchaOff == "2") + { + imgByte = SecurityCodeHelper.GetGifBubbleCodeByte(code);//动态gif泡泡 + } + else if (captchaOff == "3") + { + imgByte = SecurityCodeHelper.GetBubbleCodeByte(code);//泡泡 + } + else + { + imgByte = SecurityCodeHelper.GetEnDigitalCodeByte(code);//英文字母加数字 + } + string base64Str = Convert.ToBase64String(imgByte); + CacheHelper.SetCache(uuid, code); + var obj = new { uuid, img = base64Str };// File(stream, "image/png") + + return ToJson(1, obj); + } + + /// + /// 记录用户登陆信息 + /// + /// + /// + public SysLogininfor RecordLogInfo(HttpContext context) + { + var ipAddr = context.GetClientUserIp(); + var ip_info = IpTool.Search(ipAddr); + ClientInfo clientInfo = context.GetClientInfo(); + SysLogininfor sysLogininfor = new() + { + browser = clientInfo.Device.Family, + os = clientInfo.OS.ToString(), + ipaddr = ipAddr, + userName = context.GetName(), + loginLocation = ip_info.Province + "-" + ip_info.City + }; + + return sysLogininfor; + } + + /// + /// 注册 + /// + /// + /// + [HttpPost("/register")] + [AllowAnonymous] + [Log(Title = "注册", BusinessType = Infrastructure.Enums.BusinessType.INSERT)] + public IActionResult Register([FromBody] RegisterDto dto) + { + SysConfig config = sysConfigService.GetSysConfigByKey("sys.account.register"); + if (config?.ConfigValue != "true") + { + return ToResponse(ResultCode.CUSTOM_ERROR, "当前系统没有开启注册功能!"); + } + SysConfig sysConfig = sysConfigService.GetSysConfigByKey("sys.account.captchaOnOff"); + if (sysConfig?.ConfigValue != "off" && CacheHelper.Get(dto.Uuid) is string str && !str.ToLower().Equals(dto.Code.ToLower())) + { + return ToResponse(ResultCode.CAPTCHA_ERROR, "验证码错误"); + } + if (UserConstants.NOT_UNIQUE.Equals(sysUserService.CheckUserNameUnique(dto.Username))) + { + return ToResponse(ResultCode.CUSTOM_ERROR, $"保存用户{dto.Username}失败,注册账号已存在"); + } + SysUser user = sysUserService.Register(dto); + if (user.UserId > 0) + { + return SUCCESS(user); + } + return ToResponse(ResultCode.CUSTOM_ERROR, "注册失败,请联系管理员"); + } + } +} diff --git a/ARW.WebApi/Controllers/System/SysMenuController.cs b/ARW.WebApi/Controllers/System/SysMenuController.cs new file mode 100644 index 0000000..c669ef5 --- /dev/null +++ b/ARW.WebApi/Controllers/System/SysMenuController.cs @@ -0,0 +1,205 @@ +using Infrastructure; +using Infrastructure.Attribute; +using Infrastructure.Enums; +using Infrastructure.Model; +using Mapster; +using Microsoft.AspNetCore.Mvc; +using ARW.Admin.WebApi.Extensions; +using ARW.Admin.WebApi.Filters; +using ARW.Model.System; +using ARW.Model.System.Dto; +using ARW.Service.System.IService; + +namespace ARW.Admin.WebApi.Controllers.System +{ + /// + /// 系统菜单 + /// + [Verify] + [Route("/system/menu")] + public class SysMenuController : BaseController + { + private readonly ISysRoleService sysRoleService; + private readonly ISysMenuService sysMenuService; + + public SysMenuController( + ISysRoleService sysRoleService, + ISysMenuService sysMenuService) + { + this.sysRoleService = sysRoleService; + this.sysMenuService = sysMenuService; + } + + /// + /// 获取菜单列表 + /// + /// + [ActionPermissionFilter(Permission = "system:menu:list")] + [HttpGet("list")] + public IActionResult TreeMenuList([FromQuery] MenuQueryDto menu) + { + long userId = HttpContext.GetUId(); + return SUCCESS(sysMenuService.SelectTreeMenuList(menu, userId), "yyyy-MM-dd HH:mm:ss"); + } + + /// + /// 根据菜单编号获取详细信息 + /// + /// + /// + [HttpGet("{menuId}")] + [ActionPermissionFilter(Permission = "system:menu:query")] + public IActionResult GetMenuInfo(int menuId = 0) + { + return SUCCESS(sysMenuService.GetMenuByMenuId(menuId), "yyyy-MM-dd HH:mm:ss"); + } + + /// + /// 根据菜单编号获取菜单列表,菜单管理首次进入 + /// + /// + /// + [HttpGet("list/{menuId}")] + [ActionPermissionFilter(Permission = "system:menu:query")] + public IActionResult GetMenuList(int menuId = 0) + { + return SUCCESS(sysMenuService.GetMenusByMenuId(menuId), "yyyy-MM-dd HH:mm:ss"); + } + + /// + /// 获取角色菜单信息 + /// 加载对应角色菜单列表树 + /// + /// + /// + [HttpGet("roleMenuTreeselect/{roleId}")] + public IActionResult RoleMenuTreeselect(int roleId) + { + long userId = HttpContext.GetUId(); + var menus = sysMenuService.SelectMenuList(new MenuQueryDto(), userId); + var checkedKeys = sysRoleService.SelectUserRoleMenus(roleId); + return SUCCESS(new + { + checkedKeys, + menus = sysMenuService.BuildMenuTreeSelect(menus), + }); + } + + /// + /// 修改菜单 + /// + /// + /// + [HttpPost("edit")] + [Log(Title = "菜单管理", BusinessType = BusinessType.UPDATE)] + [ActionPermissionFilter(Permission = "system:menu:edit")] + public IActionResult MenuEdit([FromBody] MenuDto menuDto) + { + if (menuDto == null) { return ToResponse(ApiResult.Error(101, "请求参数错误")); } + //if (UserConstants.NOT_UNIQUE.Equals(sysMenuService.CheckMenuNameUnique(MenuDto))) + //{ + // return ToResponse(ApiResult.Error($"修改菜单'{MenuDto.menuName}'失败,菜单名称已存在")); + //} + var config = new TypeAdapterConfig(); + //映射规则 + config.ForType() + .NameMatchingStrategy(NameMatchingStrategy.IgnoreCase);//忽略字段名称的大小写;//忽略除以上配置的所有字段 + + var modal = menuDto.Adapt(config).ToUpdate(HttpContext); + if (UserConstants.YES_FRAME.Equals(modal.isFrame) && !modal.path.StartsWith("http")) + { + return ToResponse(ApiResult.Error($"修改菜单'{modal.MenuName}'失败,地址必须以http(s)://开头")); + } + if (modal.MenuId.Equals(modal.parentId)) + { + return ToResponse(ApiResult.Error($"修改菜单'{modal.MenuName}'失败,上级菜单不能选择自己")); + } + modal.Update_by = HttpContext.GetName(); + int result = sysMenuService.EditMenu(modal); + + return ToResponse(result); + } + + /// + /// 添加菜单 + /// + /// + /// + [HttpPut("add")] + [Log(Title = "菜单管理", BusinessType = BusinessType.INSERT)] + [ActionPermissionFilter(Permission = "system:menu:add")] + public IActionResult MenuAdd([FromBody] MenuDto menuDto) + { + var config = new TypeAdapterConfig(); + //映射规则 + config.ForType() + .NameMatchingStrategy(NameMatchingStrategy.IgnoreCase); + var menu = menuDto.Adapt(config).ToCreate(HttpContext); + + if (menu == null) { return ToResponse(ApiResult.Error(101, "请求参数错误")); } + if (UserConstants.NOT_UNIQUE.Equals(sysMenuService.CheckMenuNameUnique(menu))) + { + return ToResponse(ApiResult.Error($"新增菜单'{menu.MenuName}'失败,菜单名称已存在")); + } + if (UserConstants.YES_FRAME.Equals(menu.isFrame) && !menu.path.StartsWith("http")) + { + return ToResponse(ApiResult.Error($"新增菜单'{menu.MenuName}'失败,地址必须以http(s)://开头")); + } + + menu.Create_by = HttpContext.GetName(); + int result = sysMenuService.AddMenu(menu); + + return ToResponse(result); + } + + /// + /// 菜单删除 + /// + /// + /// + [HttpDelete("{menuId}")] + [Log(Title = "菜单管理", BusinessType = BusinessType.DELETE)] + [ActionPermissionFilter(Permission = "system:menu:remove")] + public IActionResult Remove(int menuId = 0) + { + if (sysMenuService.HasChildByMenuId(menuId)) + { + var childMenus = sysMenuService.SelectChildByMenuId(menuId); + foreach (var item in childMenus) + { + sysMenuService.DeleteMenuById((int)item.MenuId); + } + //return ToResponse(ResultCode.CUSTOM_ERROR, "存在子菜单,不允许删除"); + } + //if (sysMenuService.CheckMenuExistRole(menuId)) + //{ + // return ToResponse(ResultCode.CUSTOM_ERROR, "菜单已分配,不允许删除"); + //} + int result = sysMenuService.DeleteMenuById(menuId); + + return ToResponse(result); + } + + /// + /// 保存排序 + /// + /// + /// + /// + [ActionPermissionFilter(Permission = "system:menu:update")] + [HttpGet("ChangeSort")] + [Log(Title = "保存排序", BusinessType = BusinessType.UPDATE)] + public IActionResult ChangeSort(int id = 0, int value = 0) + { + MenuDto MenuDto = new() + { + MenuId = id, + orderNum = value + }; + if (MenuDto == null) { return ToResponse(ApiResult.Error(101, "请求参数错误")); } + + int result = sysMenuService.ChangeSortMenu(MenuDto); + return ToResponse(result); + } + } +} diff --git a/ARW.WebApi/Controllers/System/SysNoticeController.cs b/ARW.WebApi/Controllers/System/SysNoticeController.cs new file mode 100644 index 0000000..0a793d5 --- /dev/null +++ b/ARW.WebApi/Controllers/System/SysNoticeController.cs @@ -0,0 +1,200 @@ +using Infrastructure; +using Infrastructure.Attribute; +using Infrastructure.Constant; +using Infrastructure.Enums; +using Infrastructure.Model; +using Mapster; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.SignalR; +using SqlSugar; +using ARW.Admin.WebApi.Extensions; +using ARW.Admin.WebApi.Filters; +using ARW.Admin.WebApi.Hubs; +using ARW.Common; +using ARW.Model.System; +using ARW.Model.System.Dto; +using ARW.Service.System.IService; + +namespace ARW.Admin.WebApi.Controllers.System +{ + /// + /// 系统通知 + /// + [Verify] + [Route("system/notice")] + public class SysNoticeController : BaseController + { + /// + /// 通知公告表接口 + /// + private readonly ISysNoticeService _SysNoticeService; + private readonly IHubContext _hubContext; + + public SysNoticeController(ISysNoticeService SysNoticeService, IHubContext hubContext) + { + _SysNoticeService = SysNoticeService; + _hubContext = hubContext; + } + + /// + /// 查询通知公告表列表 + /// + /// + [HttpGet("queryNotice")] + public IActionResult QueryNotice([FromQuery] SysNoticeQueryDto parm) + { + var predicate = Expressionable.Create(); + + predicate = predicate.And(m => m.Status == "0"); + var response = _SysNoticeService.GetPages(predicate.ToExpression(), parm); + return SUCCESS(response); + } + + /// + /// 查询通知公告表列表 + /// + /// + [HttpGet("list")] + [ActionPermissionFilter(Permission = "system:notice:list")] + public IActionResult QuerySysNotice([FromQuery] SysNoticeQueryDto parm) + { + var predicate = Expressionable.Create(); + + predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.NoticeTitle), m => m.NoticeTitle.Contains(parm.NoticeTitle)); + predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.NoticeType), m => m.NoticeType == parm.NoticeType); + predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.CreateBy), m => m.Create_by.Contains(parm.CreateBy) || m.Update_by.Contains(parm.CreateBy)); + predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.Status), m => m.Status == parm.Status); + var response = _SysNoticeService.GetPages(predicate.ToExpression(), parm); + return SUCCESS(response); + } + + /// + /// 查询通知公告表详情 + /// + /// + /// + [HttpGet("{NoticeId}")] + [ActionPermissionFilter(Permission = "system:notice:query")] + public IActionResult GetSysNotice(int NoticeId) + { + var response = _SysNoticeService.GetFirst(x => x.NoticeId == NoticeId); + + return SUCCESS(response); + } + + /// + /// 添加通知公告表 + /// + /// + [HttpPost] + [ActionPermissionFilter(Permission = "system:notice:add")] + [Log(Title = "通知公告表", BusinessType = BusinessType.INSERT)] + public IActionResult AddSysNotice([FromBody] SysNoticeDto parm) + { + if (parm == null) + { + throw new CustomException("请求参数错误"); + } + //从 Dto 映射到 实体 + var modal = parm.Adapt().ToCreate(HttpContext); + modal.Create_by = HttpContext.GetName(); + modal.Create_time = DateTime.Now; + + int result = _SysNoticeService.Insert(modal, it => new + { + it.NoticeTitle, + it.NoticeType, + it.NoticeContent, + it.Status, + it.Remark, + it.Create_by, + it.Create_time + }); + + return SUCCESS(result); + } + + /// + /// 更新通知公告表 + /// + /// + [HttpPut] + [ActionPermissionFilter(Permission = "system:notice:update")] + [Log(Title = "通知公告表", BusinessType = BusinessType.UPDATE)] + public IActionResult UpdateSysNotice([FromBody] SysNoticeDto parm) + { + if (parm == null) + { + throw new CustomException("请求实体不能为空"); + } + //从 Dto 映射到 实体 + var model = parm.Adapt().ToUpdate(HttpContext); + + var response = _SysNoticeService.Update(w => w.NoticeId == model.NoticeId, it => new SysNotice() + { + //Update 字段映射 + NoticeTitle = model.NoticeTitle, + NoticeType = model.NoticeType, + NoticeContent = model.NoticeContent, + Status = model.Status, + Remark = model.Remark, + Update_by = HttpContext.GetName(), + Update_time = DateTime.Now + }); + + return SUCCESS(response); + } + /// + /// 发送通知公告表 + /// + /// + [HttpPut("send/{NoticeId}")] + [ActionPermissionFilter(Permission = "system:notice:update")] + [Log(Title = "通知公告表", BusinessType = BusinessType.OTHER)] + public IActionResult SendNotice(int NoticeId = 0) + { + if (NoticeId <= 0) + { + throw new CustomException("请求实体不能为空"); + } + var response = _SysNoticeService.GetFirst(x => x.NoticeId == NoticeId); + if (response != null && response.Status == "0") + { + _hubContext.Clients.All.SendAsync(HubsConstant.ReceiveNotice, response.NoticeTitle, response.NoticeContent); + } + return SUCCESS(response); + } + + /// + /// 删除通知公告表 + /// + /// + [HttpDelete("{ids}")] + [ActionPermissionFilter(Permission = "system:notice:delete")] + [Log(Title = "通知公告表", BusinessType = BusinessType.DELETE)] + public IActionResult DeleteSysNotice(string ids) + { + int[] idsArr = Tools.SpitIntArrary(ids); + if (idsArr.Length <= 0) { return ToResponse(ApiResult.Error($"删除失败Id 不能为空")); } + + var response = _SysNoticeService.Delete(idsArr); + + return SUCCESS(response); + } + + /// + /// 通知公告表导出 + /// + /// + [Log(BusinessType = BusinessType.EXPORT, IsSaveResponseData = false, Title = "通知公告表")] + [HttpGet("export")] + [ActionPermissionFilter(Permission = "system:notice:export")] + public IActionResult Export() + { + var list = _SysNoticeService.GetAll(); + + string sFileName = ExportExcel(list, "SysNotice", "通知公告表"); + return SUCCESS(new { path = "/export/" + sFileName, fileName = sFileName }); + } + } +} \ No newline at end of file diff --git a/ARW.WebApi/Controllers/System/SysPostController.cs b/ARW.WebApi/Controllers/System/SysPostController.cs new file mode 100644 index 0000000..c40c94c --- /dev/null +++ b/ARW.WebApi/Controllers/System/SysPostController.cs @@ -0,0 +1,141 @@ +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using System.Collections.Generic; +using ARW.Admin.WebApi.Filters; +using ARW.Model; +using ARW.Model.System; +using Infrastructure.Extensions; +using Infrastructure.Attribute; +using Infrastructure.Enums; +using Infrastructure; +using ARW.Service.System.IService; +using ARW.Common; +using ARW.Admin.WebApi.Extensions; + +namespace ARW.Admin.WebApi.Controllers.System +{ + /// + /// 岗位管理 + /// + [Verify] + [Route("system/post")] + public class SysPostController : BaseController + { + private readonly ISysPostService PostService; + public SysPostController(ISysPostService postService) + { + PostService = postService; + } + + /// + /// 岗位列表查询 + /// + /// + [HttpGet("list")] + [ActionPermissionFilter(Permission = "system:post:list")] + public IActionResult List([FromQuery] SysPost post, [FromQuery] PagerInfo pagerInfo) + { + var predicate = Expressionable.Create(); + predicate = predicate.AndIF(post.Status.IfNotEmpty(), it => it.Status == post.Status); + var list = PostService.GetPages(predicate.ToExpression(), pagerInfo, s => new { s.PostSort }); + + return SUCCESS(list); + } + + /// + /// 岗位查询 + /// + /// + /// + [HttpGet("{postId}")] + [ActionPermissionFilter(Permission = "system:post:query")] + public IActionResult Query(long postId = 0) + { + return SUCCESS(PostService.GetId(postId)); + } + + /// + /// 岗位管理 + /// + /// + /// + [HttpPost] + [ActionPermissionFilter(Permission = "system:post:add")] + [Log(Title = "岗位添加", BusinessType = BusinessType.INSERT)] + public IActionResult Add([FromBody] SysPost post) + { + if (UserConstants.NOT_UNIQUE.Equals(PostService.CheckPostNameUnique(post))) + { + throw new CustomException($"修改岗位{post.PostName}失败,岗位名已存在"); + } + if (UserConstants.NOT_UNIQUE.Equals(PostService.CheckPostCodeUnique(post))) + { + throw new CustomException($"修改岗位{post.PostName}失败,岗位编码已存在"); + } + + post.Create_by = HttpContext.GetName(); + return ToResponse(ToJson(PostService.Add(post))); + } + + /// + /// 岗位管理 + /// + /// + /// + [HttpPut] + [ActionPermissionFilter(Permission = "system:post:edit")] + [Log(Title = "岗位编辑", BusinessType = BusinessType.UPDATE)] + public IActionResult Update([FromBody] SysPost post) + { + if (UserConstants.NOT_UNIQUE.Equals(PostService.CheckPostNameUnique(post))) + { + throw new CustomException($"修改岗位{post.PostName}失败,岗位名已存在"); + } + if (UserConstants.NOT_UNIQUE.Equals(PostService.CheckPostCodeUnique(post))) + { + throw new CustomException($"修改岗位{post.PostName}失败,岗位编码已存在"); + } + post.Update_by = HttpContext.GetName(); + return ToResponse(PostService.Update(post)); + } + + /// + /// 岗位删除 + /// + /// + /// + [HttpDelete("{id}")] + [ActionPermissionFilter(Permission = "system:post:remove")] + [Log(Title = "岗位删除", BusinessType = BusinessType.DELETE)] + public IActionResult Delete(string id) + { + int[] ids = Tools.SpitIntArrary(id); + return ToResponse(ToJson(PostService.Delete(ids))); + } + + /// + /// 获取岗位选择框列表 + /// + [HttpGet("optionselect")] + public IActionResult Optionselect() + { + List posts = PostService.GetAll(); + return SUCCESS(posts); + } + + /// + /// 岗位导出 + /// + /// + [Log(BusinessType = BusinessType.EXPORT, IsSaveResponseData = false, Title= "岗位导出")] + [HttpGet("export")] + [ActionPermissionFilter(Permission = "system:post:export")] + public IActionResult Export() + { + var list = PostService.GetAll(); + + string sFileName = ExportExcel(list, "syspost", "岗位"); + return SUCCESS(new { path = "/export/" + sFileName, fileName = sFileName }); + } + } +} diff --git a/ARW.WebApi/Controllers/System/SysProfileController.cs b/ARW.WebApi/Controllers/System/SysProfileController.cs new file mode 100644 index 0000000..9b81689 --- /dev/null +++ b/ARW.WebApi/Controllers/System/SysProfileController.cs @@ -0,0 +1,139 @@ +using Infrastructure; +using Infrastructure.Attribute; +using Infrastructure.Enums; +using Infrastructure.Model; +using Mapster; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; +using System; +using System.Threading.Tasks; +using ARW.Admin.WebApi.Extensions; +using ARW.Admin.WebApi.Filters; +using ARW.Model.System; +using ARW.Model.System.Dto; +using ARW.Service.System.IService; + +namespace ARW.Admin.WebApi.Controllers.System +{ + /// + /// 个人中心 + /// + [Verify] + [Route("system/user/profile")] + public class SysProfileController : BaseController + { + private readonly ISysUserService UserService; + private readonly ISysRoleService RoleService; + private readonly ISysUserPostService UserPostService; + private readonly ISysDeptService DeptService; + private readonly ISysFileService FileService; + private IWebHostEnvironment hostEnvironment; + + public SysProfileController( + ISysUserService userService, + ISysRoleService roleService, + ISysUserPostService postService, + ISysDeptService deptService, + ISysFileService sysFileService, + IWebHostEnvironment hostEnvironment) + { + UserService = userService; + RoleService = roleService; + UserPostService = postService; + DeptService = deptService; + FileService = sysFileService; + this.hostEnvironment = hostEnvironment; + } + + /// + /// 个人中心用户信息获取 + /// + /// + [HttpGet] + public IActionResult Profile() + { + long userId = HttpContext.GetUId(); + var user = UserService.SelectUserById(userId); + + var roles = RoleService.SelectUserRoleNames(userId); + var postGroup = UserPostService.GetPostsStrByUserId(userId); + var deptInfo = DeptService.GetFirst(f => f.DeptId == user.DeptId); + user.DeptName = deptInfo?.DeptName ?? "-"; + + return SUCCESS(new { user, roles, postGroup }, TIME_FORMAT_FULL); + } + + /// + /// 修改用户 + /// + /// + [HttpPut] + [ActionPermissionFilter(Permission = "common")] + [Log(Title = "修改信息", BusinessType = BusinessType.UPDATE)] + public IActionResult UpdateProfile([FromBody] SysUserDto userDto) + { + if (userDto == null) + { + throw new CustomException(ResultCode.PARAM_ERROR, "请求参数错误"); + } + var user = userDto.Adapt().ToUpdate(HttpContext); + + int result = UserService.ChangeUser(user); + return ToResponse(result); + } + + /// + /// 修改密码 + /// + /// + [HttpPut("updatePwd")] + [ActionPermissionFilter(Permission = "common")] + [Log(Title = "修改密码", BusinessType = BusinessType.UPDATE)] + public IActionResult UpdatePwd(string oldPassword, string newPassword) + { + LoginUser loginUser = Framework.JwtUtil.GetLoginUser(HttpContext); + + SysUser user = UserService.SelectUserById(loginUser.UserId); + string oldMd5 = NETCore.Encrypt.EncryptProvider.Md5(oldPassword); + string newMd5 = NETCore.Encrypt.EncryptProvider.Md5(newPassword); + + if (!user.Password.Equals(oldMd5, StringComparison.OrdinalIgnoreCase)) + { + return ToResponse(ApiResult.Error("修改密码失败,旧密码错误")); + } + if (user.Password.Equals(newMd5, StringComparison.OrdinalIgnoreCase)) + { + return ToResponse(ApiResult.Error("新密码不能和旧密码相同")); + } + if (UserService.ResetPwd(loginUser.UserId, newMd5.ToLower()) > 0) + { + //TODO 更新缓存 + + return SUCCESS(1); + } + + return ToResponse(ApiResult.Error("修改密码异常,请联系管理员")); + } + + /// + /// 修改头像 + /// + /// + /// + [HttpPost("Avatar")] + [ActionPermissionFilter(Permission = "common")] + [Log(Title = "修改头像", BusinessType = BusinessType.UPDATE, IsSaveRequestData = false)] + public async Task Avatar([FromForm(Name = "picture")] IFormFile formFile) + { + LoginUser loginUser = Framework.JwtUtil.GetLoginUser(HttpContext); + if (formFile == null) throw new CustomException("请选择文件"); + + SysFile file = await FileService.SaveFileToLocal(hostEnvironment.WebRootPath, "", "avatar", HttpContext.GetName(), formFile); + + UserService.UpdatePhoto(new SysUser() { Avatar = file.AccessUrl, UserId = loginUser.UserId }); + return SUCCESS(new { imgUrl = file.AccessUrl }); + } + } +} diff --git a/ARW.WebApi/Controllers/System/SysRoleController.cs b/ARW.WebApi/Controllers/System/SysRoleController.cs new file mode 100644 index 0000000..7f8e908 --- /dev/null +++ b/ARW.WebApi/Controllers/System/SysRoleController.cs @@ -0,0 +1,180 @@ +using Infrastructure; +using Infrastructure.Attribute; +using Infrastructure.Enums; +using Infrastructure.Model; +using Microsoft.AspNetCore.Mvc; +using ARW.Common; +using ARW.Admin.WebApi.Filters; +using ARW.Model; +using ARW.Model.System; +using ARW.Service.System.IService; +using ARW.Admin.WebApi.Extensions; + +namespace ARW.Admin.WebApi.Controllers.System +{ + /// + /// 角色信息 + /// + [Verify] + [Route("system/role")] + public class SysRoleController : BaseController + { + private readonly ISysRoleService sysRoleService; + + public SysRoleController( + ISysRoleService sysRoleService) + { + this.sysRoleService = sysRoleService; + } + + /// + /// 获取系统角色管理 + /// + /// + [ActionPermissionFilter(Permission = "system:role:list")] + [HttpGet("list")] + public IActionResult List([FromQuery] SysRole role, [FromQuery] PagerInfo pager) + { + var list = sysRoleService.SelectRoleList(role, pager); + + return SUCCESS(list, TIME_FORMAT_FULL); + } + + /// + /// 根据角色编号获取详细信息 + /// + /// + /// + [HttpGet("{roleId}")] + public IActionResult GetInfo(long roleId = 0) + { + var info = sysRoleService.SelectRoleById(roleId); + + return SUCCESS(info, TIME_FORMAT_FULL); + } + + /// + /// 添加角色 + /// + /// + /// + [HttpPost] + [ActionPermissionFilter(Permission = "system:role:add")] + [Log(Title = "角色管理", BusinessType = BusinessType.INSERT)] + [Route("edit")] + public IActionResult RoleAdd([FromBody] SysRole sysRoleDto) + { + if (sysRoleDto == null) return ToResponse(ApiResult.Error(101, "请求参数错误")); + + if (UserConstants.NOT_UNIQUE.Equals(sysRoleService.CheckRoleKeyUnique(sysRoleDto))) + { + return ToResponse(ApiResult.Error((int)ResultCode.CUSTOM_ERROR, $"新增角色'{sysRoleDto.RoleName}'失败,角色权限已存在")); + } + + sysRoleDto.Create_by = HttpContext.GetName(); + long roleId = sysRoleService.InsertRole(sysRoleDto); + + return ToResponse(ToJson(roleId)); + } + + /// + /// 修改角色 √ + /// + /// + /// + [HttpPut] + [ActionPermissionFilter(Permission = "system:role:edit")] + [Log(Title = "角色管理", BusinessType = BusinessType.UPDATE)] + [Route("edit")] + public IActionResult RoleEdit([FromBody] SysRole sysRoleDto) + { + if (sysRoleDto == null || sysRoleDto.RoleId <= 0 || string.IsNullOrEmpty(sysRoleDto.RoleKey)) + { + return ToResponse(ApiResult.Error(101, "请求参数错误")); + } + sysRoleService.CheckRoleAllowed(sysRoleDto); + var info = sysRoleService.SelectRoleById(sysRoleDto.RoleId); + if (info != null && info.RoleKey != sysRoleDto.RoleKey) + { + if (UserConstants.NOT_UNIQUE.Equals(sysRoleService.CheckRoleKeyUnique(sysRoleDto))) + { + return ToResponse(ApiResult.Error($"编辑角色'{sysRoleDto.RoleName}'失败,角色权限已存在")); + } + } + sysRoleDto.Update_by = HttpContext.GetName(); + int upResult = sysRoleService.UpdateRole(sysRoleDto); + if (upResult > 0) + { + return SUCCESS(upResult); + } + return ToResponse(ApiResult.Error($"修改角色'{sysRoleDto.RoleName}'失败,请联系管理员")); + } + + /// + /// 根据角色分配菜单 + /// + /// + /// + [HttpPut("dataScope")] + [ActionPermissionFilter(Permission = "system:role:authorize")] + [Log(Title = "角色管理", BusinessType = BusinessType.UPDATE)] + public IActionResult DataScope([FromBody] SysRole sysRoleDto) + { + if (sysRoleDto == null || sysRoleDto.RoleId <= 0) return ToResponse(ApiResult.Error(101, "请求参数错误")); + + sysRoleDto.Create_by = HttpContext.GetName(); + sysRoleService.CheckRoleAllowed(sysRoleDto); + + bool result = sysRoleService.AuthDataScope(sysRoleDto); + + return SUCCESS(result); + } + + /// + /// 角色删除 + /// + /// + /// + [HttpDelete("{roleId}")] + [Log(Title = "角色管理", BusinessType = BusinessType.DELETE)] + [ActionPermissionFilter(Permission = "system:role:remove")] + public IActionResult Remove(string roleId) + { + long[] roleIds = Tools.SpitLongArrary(roleId); + int result = sysRoleService.DeleteRoleByRoleId(roleIds); + + return ToResponse(ToJson(result)); + } + + /// + /// 修改角色状态 + /// + /// 角色对象 + /// + [HttpPut("changeStatus")] + [Log(Title = "修改角色状态", BusinessType = BusinessType.UPDATE)] + [ActionPermissionFilter(Permission = "system:role:edit")] + public IActionResult ChangeStatus([FromBody] SysRole roleDto) + { + sysRoleService.CheckRoleAllowed(roleDto); + int result = sysRoleService.UpdateRoleStatus(roleDto); + + return ToResponse(ToJson(result)); + } + + /// + /// 角色导出 + /// + /// + [Log(BusinessType = BusinessType.EXPORT, IsSaveResponseData = false, Title = "角色导出")] + [HttpGet("export")] + //[ActionPermissionFilter(Permission = "system:role:export")] + public IActionResult Export() + { + var list = sysRoleService.SelectRoleAll(); + + string sFileName = ExportExcel(list, "sysrole", "角色"); + return SUCCESS(new { path = "/export/" + sFileName, fileName = sFileName }); + } + } +} diff --git a/ARW.WebApi/Controllers/System/SysUserController.cs b/ARW.WebApi/Controllers/System/SysUserController.cs new file mode 100644 index 0000000..33eb157 --- /dev/null +++ b/ARW.WebApi/Controllers/System/SysUserController.cs @@ -0,0 +1,222 @@ +using Infrastructure.Attribute; +using Infrastructure.Enums; +using Infrastructure.Model; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.IO; +using ARW.Admin.WebApi.Extensions; +using ARW.Admin.WebApi.Filters; +using ARW.Common; +using ARW.Model; +using ARW.Model.System; +using ARW.Service.System.IService; + +namespace ARW.Admin.WebApi.Controllers.System +{ + /// + /// 用户管理 + /// + [Verify] + [Route("system/user")] + public class SysUserController : BaseController + { + private readonly ISysUserService UserService; + private readonly ISysRoleService RoleService; + private readonly ISysPostService PostService; + private readonly ISysUserPostService UserPostService; + + public SysUserController( + ISysUserService userService, + ISysRoleService roleService, + ISysPostService postService, + ISysUserPostService userPostService) + { + UserService = userService; + RoleService = roleService; + PostService = postService; + UserPostService = userPostService; + } + + /// + /// 用户管理 -> 获取用户 + /// /system/user/list + /// + /// + [ActionPermissionFilter(Permission = "system:user:list")] + [HttpGet("list")] + public IActionResult List([FromQuery] SysUser user, PagerInfo pager) + { + var list = UserService.SelectUserList(user, pager); + + return SUCCESS(list, TIME_FORMAT_FULL); + } + + /// + /// 用户管理 -> 编辑、添加用户获取用户,信息查询 + /// + /// + /// + [HttpGet("")] + [HttpGet("{userId:int=0}")] + public IActionResult GetInfo(int userId) + { + Dictionary dic = new(); + var roles = RoleService.SelectRoleAll(); + dic.Add("roles", roles); + //dic.Add("roles", SysUser.IsAdmin(userId) ? roles : roles.FindAll(f => !f.IsAdmin())); + dic.Add("posts", PostService.GetAll()); + + //编辑 + if (userId > 0) + { + SysUser sysUser = UserService.SelectUserById(userId); + dic.Add("user", sysUser); + dic.Add("postIds", UserPostService.GetUserPostsByUserId(userId)); + dic.Add("roleIds", sysUser.RoleIds); + } + + return ToResponse(ApiResult.Success(dic)); + } + + /// + /// 添加用户 + /// + /// + /// + [HttpPost("add")] + [Log(Title = "用户管理", BusinessType = BusinessType.INSERT)] + [ActionPermissionFilter(Permission = "system:user:add")] + public IActionResult AddUser([FromBody] SysUser user) + { + if (user == null) { return ToResponse(ApiResult.Error(101, "请求参数错误")); } + if (UserConstants.NOT_UNIQUE.Equals(UserService.CheckUserNameUnique(user.UserName))) + { + return ToResponse(ApiResult.Error($"新增用户 '{user.UserName}'失败,登录账号已存在")); + } + + user.Create_by = HttpContext.GetName(); + user.Password = NETCore.Encrypt.EncryptProvider.Md5(user.Password); + + return ToResponse(UserService.InsertUser(user)); + } + + /// + /// 修改用户 + /// + /// + /// + [HttpPut("edit")] + [Log(Title = "用户管理", BusinessType = BusinessType.UPDATE)] + [ActionPermissionFilter(Permission = "system:user:edit")] + public IActionResult UpdateUser([FromBody] SysUser user) + { + if (user == null || user.UserId <= 0) { return ToResponse(ApiResult.Error(101, "请求参数错误")); } + + user.Update_by = HttpContext.GetName(); + int upResult = UserService.UpdateUser(user); + + return ToResponse(upResult); + } + + /// + /// 改变用户状态 + /// + /// + /// + [HttpPut("changeStatus")] + [Log(Title = "修改用户状态", BusinessType = BusinessType.UPDATE)] + [ActionPermissionFilter(Permission = "system:user:update")] + public IActionResult ChangeStatus([FromBody] SysUser user) + { + if (user == null) { return ToResponse(ApiResult.Error(101, "请求参数错误")); } + + int result = UserService.ChangeUserStatus(user); + return ToResponse(ToJson(result)); + } + + /// + /// 删除用户 + /// + /// + /// + [HttpDelete("{userId}")] + [Log(Title = "用户管理", BusinessType = BusinessType.DELETE)] + [ActionPermissionFilter(Permission = "system:user:remove")] + public IActionResult Remove(int userid = 0) + { + if (userid <= 0) { return ToResponse(ApiResult.Error(101, "请求参数错误")); } + if (userid == 1) return ToResponse(Infrastructure.ResultCode.FAIL, "不能删除管理员账号"); + int result = UserService.DeleteUser(userid); + + return ToResponse(ToJson(result)); + } + + /// + /// 重置密码 + /// + /// + [HttpPut("resetPwd")] + [Log(Title = "重置密码", BusinessType = BusinessType.UPDATE)] + [ActionPermissionFilter(Permission = "system:user:update")] + public IActionResult ResetPwd([FromBody] SysUser sysUser) + { + //密码md5 + sysUser.Password = NETCore.Encrypt.EncryptProvider.Md5(sysUser.Password); + + int result = UserService.ResetPwd(sysUser.UserId, sysUser.Password); + return ToResponse(ToJson(result)); + } + + /// + /// 导入 + /// + /// 使用IFromFile必须使用name属性否则获取不到文件 + /// + [HttpPost("importData")] + [Log(Title = "用户导入", BusinessType = BusinessType.IMPORT, IsSaveRequestData = false, IsSaveResponseData = false)] + //[ActionPermissionFilter(Permission = "system:user:import")] + public IActionResult ImportData([FromForm(Name = "file")] IFormFile formFile) + { + IEnumerable users = ExcelHelper.ImportData(formFile.OpenReadStream()); + + //TODO 业务逻辑,自行插入数据到db + return SUCCESS(users); + } + + /// + /// 用户导入模板下载 + /// + /// + [HttpGet("importTemplate")] + [Log(Title = "用户模板", BusinessType = BusinessType.EXPORT, IsSaveRequestData = false, IsSaveResponseData = false)] + [AllowAnonymous] + public IActionResult ImportTemplateExcel() + { + List user = new List(); + var values = new List(); + MemoryStream stream = new MemoryStream(); + + string sFileName = DownloadImportTemplate(user, stream, "用户列表", values); + return File(stream.ToArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", $"{sFileName}"); + } + + /// + /// 用户导出 + /// + /// + /// + [HttpGet("export")] + [Log(Title = "用户导出", BusinessType = BusinessType.EXPORT)] + [ActionPermissionFilter(Permission = "system:user:export")] + public IActionResult UserExport([FromQuery] SysUser user) + { + var list = UserService.SelectUserList(user, new PagerInfo(1, 10000)); + + //调试模式需要加上 + string sFileName = ExportExcel(list.Result, "user", "用户列表"); + return SUCCESS(new { path = "/export/" + sFileName, fileName = sFileName }); + } + } +} diff --git a/ARW.WebApi/Controllers/System/SysUserRoleController.cs b/ARW.WebApi/Controllers/System/SysUserRoleController.cs new file mode 100644 index 0000000..d1d2fd1 --- /dev/null +++ b/ARW.WebApi/Controllers/System/SysUserRoleController.cs @@ -0,0 +1,88 @@ +using Infrastructure; +using Infrastructure.Attribute; +using Microsoft.AspNetCore.Mvc; +using ARW.Admin.WebApi.Filters; +using ARW.Model.System.Dto; +using ARW.Service.System.IService; + +namespace ARW.Admin.WebApi.Controllers.System +{ + /// + /// 用户角色管理 + /// + [Verify] + [Route("system/userRole")] + public class SysUserRoleController : BaseController + { + private readonly ISysUserRoleService SysUserRoleService; + private readonly ISysUserService UserService; + + public SysUserRoleController( + ISysUserRoleService sysUserRoleService, + ISysUserService userService) + { + SysUserRoleService = sysUserRoleService; + UserService = userService; + } + + /// + /// 根据角色编号获取已分配的用户 + /// + /// + /// + [HttpGet("list")] + [ActionPermissionFilter(Permission = "system:roleusers:list")] + public IActionResult GetList([FromQuery] RoleUserQueryDto roleUserQueryDto) + { + var list = SysUserRoleService.GetSysUsersByRoleId(roleUserQueryDto); + + return SUCCESS(list, TIME_FORMAT_FULL); + } + + /// + /// 添加角色用户 + /// + /// + [HttpPost("create")] + [ActionPermissionFilter(Permission = "system:roleusers:add")] + [Log(Title = "添加角色用户", BusinessType = Infrastructure.Enums.BusinessType.INSERT)] + public IActionResult Create([FromBody] RoleUsersCreateDto roleUsersCreateDto) + { + var response = SysUserRoleService.InsertRoleUser(roleUsersCreateDto); + + return SUCCESS(response); + } + + /// + /// 删除角色用户 + /// + /// + /// + [HttpPost("delete")] + [ActionPermissionFilter(Permission = "system:roleusers:remove")] + [Log(Title = "删除角色用户", BusinessType = Infrastructure.Enums.BusinessType.DELETE)] + public IActionResult Delete([FromBody] RoleUsersCreateDto roleUsersCreateDto) + { + return SUCCESS(SysUserRoleService.DeleteRoleUserByUserIds(roleUsersCreateDto.RoleId, roleUsersCreateDto.UserIds)); + } + + /// + /// 获取未分配用户角色 + /// + /// + /// + [HttpGet("GetExcludeUsers")] + public IActionResult GetExcludeUsers([FromQuery] RoleUserQueryDto roleUserQueryDto) + { + if (roleUserQueryDto.RoleId <= 0) + { + throw new CustomException(ResultCode.PARAM_ERROR, "roleId不能为空"); + } + + // 获取未添加用户 + var list = SysUserRoleService.GetExcludedSysUsersByRoleId(roleUserQueryDto); + + return SUCCESS(list, TIME_FORMAT_FULL); + } + } +} diff --git a/ARW.WebApi/Controllers/System/TasksController.cs b/ARW.WebApi/Controllers/System/TasksController.cs new file mode 100644 index 0000000..58b9993 --- /dev/null +++ b/ARW.WebApi/Controllers/System/TasksController.cs @@ -0,0 +1,309 @@ +using Infrastructure; +using Infrastructure.Attribute; +using Infrastructure.Enums; +using Mapster; +using Microsoft.AspNetCore.Mvc; +using Quartz; +using SqlSugar; +using System; +using System.Threading.Tasks; +using ARW.Admin.WebApi.Extensions; +using ARW.Admin.WebApi.Filters; +using ARW.Model; +using ARW.Model.System.Dto; +using ARW.Model.System; +using ARW.Service.System.IService; +using ARW.Tasks; +using Snowflake.Core; +using Infrastructure.Extensions; + +namespace ARW.Admin.WebApi.Controllers +{ + /// + /// 计划任务 + /// + [Verify] + [Route("system/Tasks")] + public class TasksController : BaseController + { + private ISysTasksQzService _tasksQzService; + private ITaskSchedulerServer _schedulerServer; + + public TasksController( + ISysTasksQzService sysTasksQzService, + ITaskSchedulerServer taskScheduler) + { + _tasksQzService = sysTasksQzService; + _schedulerServer = taskScheduler; + } + + /// + /// 查询计划任务列表 + /// + /// + [HttpGet("list")] + [ActionPermissionFilter(Permission = "monitor:job:list")] + public IActionResult Query([FromQuery] TasksQueryDto parm, [FromQuery] PagerInfo pager) + { + //开始拼装查询条件 + var predicate = Expressionable.Create(); + + predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.QueryText), + m => m.Name.Contains(parm.QueryText) || + m.JobGroup.Contains(parm.QueryText) || + m.AssemblyName.Contains(parm.QueryText)); + + var response = _tasksQzService.GetPages(predicate.ToExpression(), pager, f => f.IsStart, OrderByType.Desc); + + return SUCCESS(response, TIME_FORMAT_FULL); + } + + /// + /// 查询单个计划任务 + /// + /// 编码 + /// + [HttpGet("get")] + public IActionResult Get(string id) + { + if (!string.IsNullOrEmpty(id)) + { + return SUCCESS(_tasksQzService.GetId(id)); + } + return SUCCESS(null); + } + + /// + /// 添加任务 + /// + /// + [HttpPost("create")] + [ActionPermissionFilter(Permission = "monitor:job:add")] + [Log(Title = "添加任务", BusinessType = BusinessType.INSERT)] + public IActionResult Create([FromBody] TasksCreateDto parm) + { + //判断是否已经存在 + if (_tasksQzService.Any(m => m.Name == parm.Name)) + { + throw new CustomException($"添加 {parm.Name} 失败,该用任务存在,不能重复!"); + } + if (!string.IsNullOrEmpty(parm.Cron) && !CronExpression.IsValidExpression(parm.Cron)) + { + throw new CustomException($"cron表达式不正确"); + } + if (string.IsNullOrEmpty(parm.ApiUrl) && parm.TaskType == 2) + { + throw new CustomException($"地址不能为空"); + } + if (parm.TaskType == 1 && (parm.AssemblyName.IsEmpty() || parm.ClassName.IsEmpty())) + { + throw new CustomException($"程序集或者类名不能为空"); + } + //从 Dto 映射到 实体 + var tasksQz = parm.Adapt().ToCreate(); + var worker = new IdWorker(1, 1); + + tasksQz.ID = (int)worker.NextId(); + tasksQz.IsStart = false; + tasksQz.Create_by = HttpContext.GetName(); + tasksQz.TaskType = parm.TaskType; + tasksQz.ApiUrl = parm.ApiUrl; + if (parm.ApiUrl.IfNotEmpty() && parm.TaskType == 2) + { + tasksQz.AssemblyName = "ARW.Tasks"; + tasksQz.ClassName = "TaskScheduler.Job_HttpRequest"; + } + return SUCCESS(_tasksQzService.Add(tasksQz)); + } + + /// + /// 更新任务 + /// + /// + [HttpPost("update")] + [ActionPermissionFilter(Permission = "monitor:job:edit")] + [Log(Title = "修改任务", BusinessType = BusinessType.UPDATE)] + public async Task Update([FromBody] TasksUpdateDto parm) + { + //判断是否已经存在 + if (_tasksQzService.Any(m => m.Name == parm.Name && m.ID.ToString().ToString() != parm.ID.ToString())) + { + throw new CustomException($"更新 {parm.Name} 失败,该用任务存在,不能重复!"); + } + if (string.IsNullOrEmpty(parm.Cron) && parm.TriggerType == 1) + { + throw new CustomException($"触发器 Corn 模式下,运行时间表达式必须填写"); + } + if (!string.IsNullOrEmpty(parm.Cron) && !CronExpression.IsValidExpression(parm.Cron)) + { + throw new CustomException($"cron表达式不正确"); + } + var tasksQz = _tasksQzService.GetFirst(m => m.ID.ToString().ToString() == parm.ID.ToString()); + if (string.IsNullOrEmpty(parm.ApiUrl) && parm.TaskType == 2) + { + throw new CustomException($"api地址不能为空"); + } + if (parm.ApiUrl.IfNotEmpty() && parm.TaskType == 2) + { + parm.AssemblyName = "ARW.Tasks"; + parm.ClassName = "TaskScheduler.Job_HttpRequest"; + } + if (tasksQz.IsStart) + { + throw new CustomException($"该任务正在运行中,请先停止在更新"); + } + + var response = _tasksQzService.Update(m => m.ID.ToString().ToString() == parm.ID.ToString(), m => new SysTasksQz + { + Name = parm.Name, + JobGroup = parm.JobGroup, + Cron = parm.Cron, + AssemblyName = parm.AssemblyName, + ClassName = parm.ClassName, + Remark = parm.Remark, + TriggerType = parm.TriggerType, + IntervalSecond = parm.IntervalSecond, + JobParams = parm.JobParams, + Update_by = HttpContextExtension.GetName(HttpContext), + Update_time = DateTime.Now, + BeginTime = parm.BeginTime, + EndTime = parm.EndTime, + TaskType = parm.TaskType, + ApiUrl = parm.ApiUrl, + }); + if (response > 0) + { + //先暂停原先的任务 + var respon = await _schedulerServer.UpdateTaskScheduleAsync(tasksQz); + } + + return SUCCESS(response); + } + + /// + /// 删除任务 + /// + /// + [HttpDelete("delete")] + [ActionPermissionFilter(Permission = "monitor:job:delete")] + [Log(Title = "删除任务", BusinessType = BusinessType.DELETE)] + public async Task Delete(string id) + { + if (string.IsNullOrEmpty(id)) + { + throw new CustomException("删除任务 Id 不能为空"); + } + + if (!_tasksQzService.Any(m => m.ID.ToString().ToString() == id)) + { + throw new CustomException("任务不存在"); + } + + var tasksQz = _tasksQzService.GetFirst(m => m.ID.ToString().ToString() == id); + var taskResult = await _schedulerServer.DeleteTaskScheduleAsync(tasksQz); + + if (taskResult.Code == 200) + { + _tasksQzService.Delete(id); + } + return ToResponse(taskResult); + } + + /// + /// 启动任务 + /// + /// + [HttpGet("start")] + [ActionPermissionFilter(Permission = "monitor:job:start")] + [Log(Title = "启动任务", BusinessType = BusinessType.OTHER)] + public async Task Start(string id) + { + if (string.IsNullOrEmpty(id)) + { + throw new CustomException("启动任务 Id 不能为空"); + } + + if (!_tasksQzService.Any(m => m.ID.ToString().ToString() == id)) + { + throw new CustomException("任务不存在"); + } + + var tasksQz = _tasksQzService.GetFirst(m => m.ID.ToString().ToString() == id); + var taskResult = await _schedulerServer.AddTaskScheduleAsync(tasksQz); + + if (taskResult.Code == 200) + { + tasksQz.IsStart = true; + _tasksQzService.Update(tasksQz); + } + + return ToResponse(taskResult); + } + + /// + /// 停止任务 + /// + /// + [HttpGet("stop")] + [ActionPermissionFilter(Permission = "monitor:job:stop")] + [Log(Title = "停止任务", BusinessType = BusinessType.OTHER)] + public async Task Stop(string id) + { + if (string.IsNullOrEmpty(id)) + { + throw new CustomException("停止任务 Id 不能为空"); + } + + if (!_tasksQzService.Any(m => m.ID.ToString() == id)) + { + throw new CustomException("任务不存在"); + } + + var tasksQz = _tasksQzService.GetFirst(m => m.ID.ToString() == id); + var taskResult = await _schedulerServer.DeleteTaskScheduleAsync(tasksQz);//await _schedulerServer.PauseTaskScheduleAsync(tasksQz); + + if (taskResult.Code == 200) + { + tasksQz.IsStart = false; + _tasksQzService.Update(tasksQz); + } + + return ToResponse(taskResult); + } + + /// + /// 定时任务立即执行一次 + /// + /// + /// + [HttpGet("run")] + [ActionPermissionFilter(Permission = "monitor:job:run")] + [Log(Title = "执行任务", BusinessType = BusinessType.OTHER)] + public async Task Run(string id) + { + if (!_tasksQzService.Any(m => m.ID.ToString() == id)) + { + throw new CustomException("任务不存在"); + } + var tasksQz = _tasksQzService.GetFirst(m => m.ID.ToString() == id); + var taskResult = await _schedulerServer.RunTaskScheduleAsync(tasksQz); + + return ToResponse(taskResult); + } + + /// + /// 定时任务导出 + /// + /// + [Log(BusinessType = BusinessType.EXPORT, IsSaveResponseData = false, Title = "定时任务导出")] + [HttpGet("export")] + [ActionPermissionFilter(Permission = "monitor:job:export")] + public IActionResult Export() + { + var list = _tasksQzService.GetAll(); + + string sFileName = ExportExcel(list, "monitorjob", "定时任务"); + return SUCCESS(new { path = "/export/" + sFileName, fileName = sFileName }); + } + } +} diff --git a/ARW.WebApi/Controllers/System/TasksLogController.cs b/ARW.WebApi/Controllers/System/TasksLogController.cs new file mode 100644 index 0000000..fe8ea3e --- /dev/null +++ b/ARW.WebApi/Controllers/System/TasksLogController.cs @@ -0,0 +1,98 @@ +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using ARW.Model; +using ARW.Model.System.Dto; +using ARW.Model.System; +using Infrastructure.Extensions; +using Infrastructure.Attribute; +using ARW.Admin.WebApi.Filters; +using ARW.Common; +using Infrastructure.Enums; +using ARW.Service.System.IService; +using Infrastructure; + +namespace ARW.Admin.WebApi.Controllers.System +{ + /// + /// 任务日志 + /// + [Verify] + [Route("/monitor/jobLog")] + public class TasksLogController : BaseController + { + private readonly ISysTasksLogService tasksLogService; + + public TasksLogController(ISysTasksLogService tasksLogService) + { + this.tasksLogService = tasksLogService; + } + + /// + /// 查询日志 + /// + /// + /// + /// + [HttpGet("list")] + public IActionResult GetList([FromQuery] PagerInfo pager, [FromQuery] TasksLogQueryDto queryDto) + { + queryDto.BeginTime = DateTimeHelper.GetBeginTime(queryDto.BeginTime, -7); + queryDto.EndTime = DateTimeHelper.GetBeginTime(queryDto.EndTime, 7); + + var predicate = Expressionable.Create().And(it => it.CreateTime >= queryDto.BeginTime && it.CreateTime <= queryDto.EndTime); + predicate = predicate.AndIF(queryDto.JobName.IfNotEmpty(), m => m.JobName.Contains(queryDto.JobName)); + predicate = predicate.AndIF(queryDto.JobGroup.IfNotEmpty(), m => m.JobGroup == queryDto.JobGroup); + predicate = predicate.AndIF(queryDto.Status.IfNotEmpty(), m => m.Status == queryDto.Status); + predicate = predicate.AndIF(queryDto.JobId.IfNotEmpty(), m => m.JobId == queryDto.JobId); + + var response = tasksLogService.GetPages(predicate.ToExpression(), pager, m => m.CreateTime, OrderByType.Desc); + + return SUCCESS(response, TIME_FORMAT_FULL); + } + + /// + /// 删除定时任务调用日志 + /// + /// + /// + [HttpDelete("{jobIds}")] + [ActionPermissionFilter(Permission = "PRIV_JOBLOG_DELETE")] + [Log(Title = "删除任务日志", BusinessType = BusinessType.DELETE)] + public IActionResult Delete(string jobIds) + { + long[] jobIdArr = Tools.SpitLongArrary(jobIds); + + int result = tasksLogService.Delete(jobIdArr); + + return ToResponse(ToJson(result, result)); + } + + /// + /// 清空日志 + /// + /// + [HttpDelete("clean")] + [ActionPermissionFilter(Permission = "PRIV_JOBLOG_REMOVE")] + [Log(Title = "清空任务日志", BusinessType = BusinessType.CLEAN)] + public IActionResult Clean() + { + tasksLogService.DeleteTable(); + return SUCCESS(1); + } + + /// + /// 定时任务日志导出 + /// + /// + [Log(BusinessType = BusinessType.EXPORT, IsSaveResponseData = false, Title = "定时任务日志导出")] + [HttpGet("export")] + [ActionPermissionFilter(Permission = "PRIV_JOBLOG_EXPORT")] + public IActionResult Export() + { + var list = tasksLogService.GetAll(); + + string sFileName = ExportExcel(list, "jobLog", "定时任务日志"); + return SUCCESS(new { path = "/export/" + sFileName, fileName = sFileName }); + } + } +} diff --git a/ARW.WebApi/Controllers/System/monitor/MonitorController.cs b/ARW.WebApi/Controllers/System/monitor/MonitorController.cs new file mode 100644 index 0000000..0b6003c --- /dev/null +++ b/ARW.WebApi/Controllers/System/monitor/MonitorController.cs @@ -0,0 +1,80 @@ +using Infrastructure; +using Infrastructure.Extensions; +using Infrastructure.Model; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace ARW.Admin.WebApi.Controllers.monitor +{ + /// + /// 系统监控 + /// + public class MonitorController : BaseController + { + private OptionsSetting Options; + private IWebHostEnvironment HostEnvironment; + private NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + public MonitorController(IOptions options, IWebHostEnvironment hostEnvironment) + { + this.HostEnvironment = hostEnvironment; + this.Options = options.Value; + } + + /// + /// 获取缓存监控数据 + /// + /// + [HttpGet("monitor/cache")] + public ApiResult GetCache() + { + return ToJson(1); + } + + /// + /// 获取服务器信息 + /// + /// + [HttpGet("monitor/server")] + //[AllowAnonymous] + public IActionResult Server() + { + //核心数 + int cpuNum = Environment.ProcessorCount; + string computerName = Environment.MachineName; + string osName = RuntimeInformation.OSDescription; + string osArch = RuntimeInformation.OSArchitecture.ToString(); + string version = RuntimeInformation.FrameworkDescription; + string appRAM = ((double)Process.GetCurrentProcess().WorkingSet64 / 1048576).ToString("N2") + " MB"; + string startTime = Process.GetCurrentProcess().StartTime.ToString("yyyy-MM-dd HH:mm:ss"); + string sysRunTime = ComputerHelper.GetRunTime(); + string serverIP = Request.HttpContext.Connection.LocalIpAddress.MapToIPv4().ToString() + ":" + Request.HttpContext.Connection.LocalPort;//获取服务器IP + + var programStartTime = Process.GetCurrentProcess().StartTime; + string programRunTime = DateTimeHelper.FormatTime((DateTime.Now - programStartTime).TotalMilliseconds.ToString().Split('.')[0].ParseToLong()); + var data = new + { + cpu = ComputerHelper.GetComputerInfo(), + disk = ComputerHelper.GetDiskInfos(), + sys = new { cpuNum, computerName, osName, osArch, serverIP, runTime = sysRunTime }, + app = new + { + name = HostEnvironment.EnvironmentName, + rootPath = HostEnvironment.ContentRootPath, + webRootPath = HostEnvironment.WebRootPath, + version, + appRAM, + startTime, + runTime = programRunTime, + host = serverIP + }, + }; + + return SUCCESS(data); + } + } +} diff --git a/ARW.WebApi/Controllers/System/monitor/SysLogininforController.cs b/ARW.WebApi/Controllers/System/monitor/SysLogininforController.cs new file mode 100644 index 0000000..e54979f --- /dev/null +++ b/ARW.WebApi/Controllers/System/monitor/SysLogininforController.cs @@ -0,0 +1,99 @@ +using Infrastructure; +using Infrastructure.Attribute; +using Infrastructure.Enums; +using Infrastructure.Model; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using ARW.Admin.WebApi.Extensions; +using ARW.Admin.WebApi.Filters; +using ARW.Common; +using ARW.Model; +using ARW.Model.System; +using ARW.Service.System.IService; + +namespace ARW.Admin.WebApi.Controllers.monitor +{ + /// + /// 系统访问记录 + /// + [Verify] + [Route("/monitor/logininfor")] + public class SysLogininforController : BaseController + { + private ISysLoginService sysLoginService; + + public SysLogininforController(ISysLoginService sysLoginService) + { + this.sysLoginService = sysLoginService; + } + + /// + /// 查询登录日志 + /// + /// + /// + /// + [HttpGet("list")] + public IActionResult LoignLogList([FromQuery] SysLogininfor sysLogininfoDto, [FromQuery] PagerInfo pagerInfo) + { + var list = sysLoginService.GetLoginLog(sysLogininfoDto, pagerInfo); + + return SUCCESS(list, TIME_FORMAT_FULL_2); + } + + /// + /// 清空登录日志 + /// + /// + [Log(Title = "清空登录日志", BusinessType= BusinessType.CLEAN)] + [ActionPermissionFilter(Permission = "monitor:logininfor:remove")] + [HttpDelete("clean")] + public IActionResult CleanLoginInfo() + { + if (!HttpContextExtension.IsAdmin(HttpContext)) + { + return ToResponse(ApiResult.Error("操作失败")); + } + sysLoginService.TruncateLogininfo(); + return SUCCESS(1); + } + + /// + /// + /// + /// + [Log(Title = "删除登录日志", BusinessType = BusinessType.DELETE)] + [HttpDelete("{infoIds}")] + [ActionPermissionFilter(Permission = "monitor:logininfor:remove")] + public IActionResult Remove(string infoIds) + { + if (!HttpContextExtension.IsAdmin(HttpContext)) + { + return ToResponse(ApiResult.Error("操作失败")); + } + long[] infoIdss = Tools.SpitLongArrary(infoIds); + return SUCCESS(sysLoginService.DeleteLogininforByIds(infoIdss)); + } + + /// + /// 登录日志导出 + /// + /// + [Log(BusinessType = BusinessType.EXPORT, IsSaveResponseData = false, Title = "登录日志导出")] + [HttpGet("export")] + [ActionPermissionFilter(Permission = "monitor:logininfor:export")] + public IActionResult Export([FromQuery] SysLogininfor logininfoDto) + { + logininfoDto.BeginTime = DateTimeHelper.GetBeginTime(logininfoDto.BeginTime, -1); + logininfoDto.EndTime = DateTimeHelper.GetBeginTime(logininfoDto.EndTime, 1); + var exp = Expressionable.Create() + .And(it => it.loginTime >= logininfoDto.BeginTime && it.loginTime <= logininfoDto.EndTime); + + var list = sysLoginService.Queryable().Where(exp.ToExpression()) + .ToList(); + + string sFileName = ExportExcel(list, "loginlog", "登录日志"); + return SUCCESS(new { path = "/export/" + sFileName, fileName = sFileName }); + } + } +} diff --git a/ARW.WebApi/Controllers/System/monitor/SysOperlogController.cs b/ARW.WebApi/Controllers/System/monitor/SysOperlogController.cs new file mode 100644 index 0000000..ace5cc5 --- /dev/null +++ b/ARW.WebApi/Controllers/System/monitor/SysOperlogController.cs @@ -0,0 +1,98 @@ +using Infrastructure.Attribute; +using Infrastructure.Enums; +using Infrastructure.Model; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; +using ARW.Admin.WebApi.Extensions; +using ARW.Admin.WebApi.Filters; +using ARW.Common; +using ARW.Model; +using ARW.Model.System.Dto; +using ARW.Service.System.IService; + +namespace ARW.Admin.WebApi.Controllers.monitor +{ + /// + /// 操作日志记录 + /// + [Verify] + [Route("/monitor/operlog")] + public class SysOperlogController : BaseController + { + private ISysOperLogService sysOperLogService; + private IWebHostEnvironment WebHostEnvironment; + + public SysOperlogController(ISysOperLogService sysOperLogService, IWebHostEnvironment hostEnvironment) + { + this.sysOperLogService = sysOperLogService; + WebHostEnvironment = hostEnvironment; + } + + /// + /// 查询操作日志 + /// + /// + /// + [HttpGet("list")] + public IActionResult OperList([FromQuery] SysOperLogDto sysOperLog) + { + PagerInfo pagerInfo = new(sysOperLog.pageNum, sysOperLog.PageSize); + + sysOperLog.operName = !HttpContextExtension.IsAdmin(HttpContext) ? HttpContextExtension.GetName(HttpContext) : sysOperLog.operName; + var list = sysOperLogService.SelectOperLogList(sysOperLog, pagerInfo); + + return SUCCESS(list, "MM/dd HH:mm"); + } + + /// + /// 删除操作日志 + /// + /// + /// + [Log(Title = "操作日志", BusinessType = BusinessType.DELETE)] + [ActionPermissionFilter(Permission = "monitor:operlog:delete")] + [HttpDelete("{operIds}")] + public IActionResult Remove(string operIds) + { + if (!HttpContextExtension.IsAdmin(HttpContext)) + { + return ToResponse(ApiResult.Error("操作失败")); + } + long[] operIdss = Tools.SpitLongArrary(operIds); + return SUCCESS(sysOperLogService.DeleteOperLogByIds(operIdss)); + } + + /// + /// 清空操作日志 + /// + /// + [Log(Title = "清空操作日志", BusinessType = BusinessType.CLEAN)] + [ActionPermissionFilter(Permission = "monitor:operlog:delete")] + [HttpDelete("clean")] + public ApiResult ClearOperLog() + { + if (!HttpContextExtension.IsAdmin(HttpContext)) + { + return ApiResult.Error("操作失败"); + } + sysOperLogService.CleanOperLog(); + + return ToJson(1); + } + + /// + /// 导出操作日志 + /// + /// + [Log(Title = "操作日志", BusinessType = BusinessType.EXPORT)] + [ActionPermissionFilter(Permission = "monitor:operlog:export")] + [HttpGet("export")] + public IActionResult Export([FromQuery] SysOperLogDto sysOperLog) + { + var list = sysOperLogService.SelectOperLogList(sysOperLog, new PagerInfo(1, 10000)); + string sFileName = ExportExcel(list.Result, "operlog", "操作日志"); + return SUCCESS(new { path = "/export/" + sFileName, fileName = sFileName }); + } + + } +} diff --git a/ARW.WebApi/Controllers/System/monitor/SysUserOnlineController.cs b/ARW.WebApi/Controllers/System/monitor/SysUserOnlineController.cs new file mode 100644 index 0000000..3167c5a --- /dev/null +++ b/ARW.WebApi/Controllers/System/monitor/SysUserOnlineController.cs @@ -0,0 +1,16 @@ +using Microsoft.AspNetCore.Mvc; +using ARW.Admin.WebApi.Filters; + +namespace ARW.Admin.WebApi.Controllers.monitor +{ + [Verify] + [Route("monitor/online")] + public class SysUserOnlineController : BaseController + { + [HttpGet("list")] + public IActionResult Index() + { + return SUCCESS(null); + } + } +} diff --git a/ARW.WebApi/Dockerfile b/ARW.WebApi/Dockerfile new file mode 100644 index 0000000..5edc338 --- /dev/null +++ b/ARW.WebApi/Dockerfile @@ -0,0 +1,21 @@ +FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base +#创建 /app文件夹 +WORKDIR /app +#创建挂载目录,用于将程序部署在服务器本地 +#VOLUME /app +#设置docker容器对外暴露端口 +EXPOSE 8888 +VOLUME /app/logs +#COPY bin/Release/net5.0/publish/ app/ +COPY . app/ + +#设置容器内的时区,如果不设置,默认时区是标准时间比北京时间晚8个小时 +RUN echo "Asia/shanghai" > /etc/timezone +RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime + +# 复制发布文件到工作目录 +#COPY . app/ +WORKDIR /app + +#等价于 dotnet ARW.Admin.WebApi.dll,如果不指定启动端口默认在docker里面启动端口是80端口 +ENTRYPOINT ["dotnet", "ARW.Admin.WebApi.dll", "--server.urls","http://*:8888"] \ No newline at end of file diff --git a/ARW.WebApi/Extensions/DbExtension.cs b/ARW.WebApi/Extensions/DbExtension.cs new file mode 100644 index 0000000..1583093 --- /dev/null +++ b/ARW.WebApi/Extensions/DbExtension.cs @@ -0,0 +1,185 @@ +using Infrastructure; +using Infrastructure.Helper; +using SqlSugar; +using SqlSugar.IOC; +using System.Linq; +using System.Reflection; +using ARW.Admin.WebApi.Framework; +using ARW.Model.System; +using ARW.Model.Models.Business; +using Infrastructure.Extensions; +using System.Linq.Dynamic.Core; +using System.Linq.Expressions; + +namespace ARW.Admin.WebApi.Extensions +{ + public static class DbExtension + { + private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + //全部数据权限 + public static string DATA_SCOPE_ALL = "1"; + //自定数据权限 + public static string DATA_SCOPE_CUSTOM = "2"; + //部门数据权限 + public static string DATA_SCOPE_DEPT = "3"; + //部门及以下数据权限 + public static string DATA_SCOPE_DEPT_AND_CHILD = "4"; + //仅本人数据权限 + public static string DATA_SCOPE_SELF = "5"; + + + + + public static void AddDb(IConfiguration Configuration) + { + string connStr = Configuration.GetConnectionString("conn_db"); + int dbType = Convert.ToInt32(Configuration.GetConnectionString("conn_db_type")); + + SugarIocServices.AddSqlSugar(new List() { + new IocConfig() { + ConfigId = "0",//默认db + ConnectionString = connStr, + DbType = (IocDbType)dbType, + IsAutoCloseConnection = true + }, + new IocConfig() { + ConfigId = "1", + ConnectionString = "替换成你的字符串", + DbType = IocDbType.MySql, + IsAutoCloseConnection = true + } + //...增加其他数据库 + }); + SugarIocServices.ConfigurationSugar(db => + { + //db0数据过滤 + FilterData(0); + + #region db0 + db.GetConnectionScope(0).Aop.OnLogExecuting = (sql, pars) => + { + var param = db.GetConnectionScope(0).Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value)); + + logger.Info($"【sql语句】{sql},{param}\n"); + }; + + db.GetConnectionScope(0).Aop.OnError = (e) => + { + logger.Error(e, $"执行SQL出错:{e.Message}"); + }; + //SQL执行完 + db.GetConnectionScope(0).Aop.OnLogExecuted = (sql, pars) => + { + //执行完了可以输出SQL执行时间 (OnLogExecutedDelegate) + }; + #endregion + + #region db1 + //Db1 + db.GetConnection(1).Aop.OnLogExecuting = (sql, pars) => + { + var param = db.GetConnection(1).Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value)); + + logger.Info($"【sql语句】{sql}, {param}"); + }; + //Db1错误日志 + db.GetConnection(1).Aop.OnError = (e) => + { + logger.Error($"执行Sql语句失败:{e.Sql},原因:{e.Message}"); + }; + #endregion + }); + + } + + public static void InitDb(this IServiceProvider service) + { + var db = DbScoped.SugarScope; + new MySql.Data.MySqlClient.MySqlConnection("server=47.242.159.172;Database=demo;Uid=demo;Pwd=demo;SslMode=none;CharSet=utf8mb4;AllowLoadLocalInfile=true;AllowUserVariables=true;").Open(); + //db.DbMaintenance.CreateDatabase(); + //db.CodeFirst. + + var baseType = typeof(SysBase); + //var entityes = AssemblyUtils.GetAllTypes().Where(p => !p.IsAbstract && p != baseType && /*!p.IsAssignableTo(baseType)&&*/ p.GetCustomAttribute()!=null).ToArray(); + + Type[] types = Assembly + .LoadFrom("bin/Debug/net6.0/ARW.Model.dll")//如果 .dll报错,可以换成 xxx.exe 有些生成的是exe + .GetTypes().Where(it => it.FullName.Contains("Business.") && it.GetCustomAttribute() != null && it != typeof(BusinessBase))//命名空间过滤,当然你也可以写其他条件过滤 + .ToArray(); + + db.CodeFirst.SetStringDefaultLength(512).InitTables(types); + } + + /// + /// 数据过滤 + /// + /// 多库id + private static void FilterData(int configId) + { + + var db = DbScoped.SugarScope.GetConnectionScope(configId); + + // 软删除过滤 + Type[] types = Assembly + .LoadFrom("bin/Debug/net6.0/ARW.Model.dll")//如果 .dll报错,可以换成 xxx.exe 有些生成的是exe + .GetTypes().Where(it => it.FullName.Contains("Business.") && it.GetCustomAttribute() != null && it != typeof(BusinessBase))//命名空间过滤,当然你也可以写其他条件过滤 + .ToArray(); + foreach (var entityType in types) + { + //构建动态Lambda + var lambda = DynamicExpressionParser.ParseLambda + (new[] { Expression.Parameter(entityType, "it") }, + typeof(bool), $"{nameof(BusinessBase.IsDelete)} == @0", + false); + db.QueryFilter.Add(new TableFilterItem(entityType, lambda)); //将Lambda传入过滤器 + } + + var u = App.User; + if (u == null) return; + //获取当前用户的信息 + var user = JwtUtil.GetLoginUser(App.HttpContext); + if (user == null) return; + + if (user.IsApi) return; + //管理员不过滤 + if (user.RoleIds.Any(f => f.Equals("admin"))) return; + foreach (var role in user.Roles.OrderBy(f => f.DataScope)) + { + string dataScope = role.DataScope; + if (DATA_SCOPE_ALL.Equals(dataScope))//所有权限 + { + break; + } + else if (DATA_SCOPE_CUSTOM.Equals(dataScope))//自定数据权限 + { + //" OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias, role.getRoleId())); + var filter1 = new TableFilterItem(it => SqlFunc.Subqueryable().Where(f => f.DeptId == it.DeptId && f.RoleId == role.RoleId).Any()); + db.QueryFilter.Add(filter1); + } + else if (DATA_SCOPE_DEPT.Equals(dataScope))//本部门数据 + { + var filter1 = new TableFilterItem(it => it.DeptId == user.DeptId); + db.QueryFilter.Add(filter1); + } + else if (DATA_SCOPE_DEPT_AND_CHILD.Equals(dataScope))//本部门及以下数据 + { + //SQl OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) ) + var allChildDepts = db.Queryable().ToChildList(it => it.ParentId, user.DeptId); + + var filter1 = new TableFilterItem(it => allChildDepts.Select(f => f.DeptId).ToList().Contains(it.DeptId)); + db.QueryFilter.Add(filter1); + + var filter2 = new TableFilterItem(it => allChildDepts.Select(f => f.DeptId).ToList().Contains(it.DeptId)); + db.QueryFilter.Add(filter2); + } + else if (DATA_SCOPE_SELF.Equals(dataScope))//仅本人数据 + { + var filter1 = new TableFilterItem(it => it.UserId == user.UserId, true); + db.QueryFilter.Add(filter1); + } + } + + + } + } +} diff --git a/ARW.WebApi/Extensions/EntityExtension.cs b/ARW.WebApi/Extensions/EntityExtension.cs new file mode 100644 index 0000000..aedbbb2 --- /dev/null +++ b/ARW.WebApi/Extensions/EntityExtension.cs @@ -0,0 +1,62 @@ +//using Microsoft.AspNetCore.Http; +//using Snowflake.Core; +using System; + +namespace ARW.Admin.WebApi.Extensions +{ + public static class EntityExtension + { + public static TSource ToCreate(this TSource source, HttpContext? context = null) + { + var types = source?.GetType(); + + if (types.GetProperty("CreateTime") != null) + { + types.GetProperty("CreateTime").SetValue(source, DateTime.Now, null); + } + if (types.GetProperty("AddTime") != null) + { + types.GetProperty("AddTime").SetValue(source, DateTime.Now, null); + } + if (types.GetProperty("UpdateTime") != null) + { + types.GetProperty("UpdateTime").SetValue(source, DateTime.Now, null); + } + if (types.GetProperty("Create_by") != null && context != null) + { + types.GetProperty("Create_by").SetValue(source, context.GetName(), null); + } + if (types.GetProperty("UserId") != null && context != null) + { + types.GetProperty("UserId").SetValue(source, context.GetUId(), null); + } + return source; + } + + public static TSource ToUpdate(this TSource source, HttpContext context = null) + { + var types = source.GetType(); + + if (types.GetProperty("UpdateTime") != null) + { + types.GetProperty("UpdateTime").SetValue(source, DateTime.Now, null); + } + if (types.GetProperty("Update_time") != null) + { + types.GetProperty("Update_time").SetValue(source, DateTime.Now, null); + } + + if (types.GetProperty("UpdateBy") != null) + { + types.GetProperty("UpdateBy").SetValue(source,context.GetName(), null); + } + if (types.GetProperty("Update_by") != null) + { + types.GetProperty("Update_by").SetValue(source, context.GetName(), null); + } + + return source; + } + + } +} diff --git a/ARW.WebApi/Extensions/Filters/ActionPermissionFilter.cs b/ARW.WebApi/Extensions/Filters/ActionPermissionFilter.cs new file mode 100644 index 0000000..9b5296d --- /dev/null +++ b/ARW.WebApi/Extensions/Filters/ActionPermissionFilter.cs @@ -0,0 +1,92 @@ +using Infrastructure; +using Infrastructure.Model; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using ARW.Model.System; + +namespace ARW.Admin.WebApi.Filters +{ + /// + /// API授权判断 + /// + public class ActionPermissionFilter : ActionFilterAttribute//, IAsyncActionFilter + { + private NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + + /// + /// 权限字符串,例如 system:user:view + /// + public string Permission { get; set; } + private bool HasPermi { get; set; } + private bool HasRole { get; set; } + public ActionPermissionFilter() { } + public ActionPermissionFilter(string permission) + { + Permission = permission; + HasPermi = !string.IsNullOrEmpty(Permission); + } + + /// + /// 执行Action前校验是否有权限访问 + /// + /// + /// + /// + public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + LoginUser info = Framework.JwtUtil.GetLoginUser(context.HttpContext); + + if (info != null && info?.UserId > 0) + { + List perms = info.Permissions; + List rolePerms = info.RoleIds; + + if (info.IsApi) + { + HasPermi = true; + + } + else + { + if (perms.Exists(f => f.Equals(GlobalConstant.AdminPerm))) + { + HasPermi = true; + } + else if (rolePerms.Exists(f => f.Equals(GlobalConstant.AdminRole))) + { + HasPermi = true; + } + else if (!string.IsNullOrEmpty(Permission)) + { + HasPermi = perms.Exists(f => f.ToLower() == Permission.ToLower()); + } + } + + bool isDemoMode = AppSettings.GetAppConfig("DemoMode", false); + var url = context.HttpContext.Request.Path; + //演示公开环境屏蔽权限 + string[] denyPerms = new string[] { "update", "add", "remove", "add", "edit", "delete", "import", "run", "start", "stop", "clear", "send", "export", "upload", "common" }; + if (isDemoMode && denyPerms.Any(f => Permission.ToLower().Contains(f))) + { + context.Result = new JsonResult(new { code = ResultCode.FORBIDDEN, msg = "演示模式 , 不允许操作" }); + } + if (!HasPermi && !Permission.Equals("common")) + { + logger.Info($"用户{info.UserName}没有权限访问{url},当前权限[{Permission}]"); + JsonResult result = new(new ApiResult() + { + Code = (int)ResultCode.FORBIDDEN, + Msg = $"你当前没有权限[{Permission}]访问,请联系管理员", + Data = url + }) + { + ContentType = "application/json", + }; + context.Result = result; + } + } + + return base.OnActionExecutionAsync(context, next); + } + } +} diff --git a/ARW.WebApi/Extensions/Filters/GlobalActionMonitor.cs b/ARW.WebApi/Extensions/Filters/GlobalActionMonitor.cs new file mode 100644 index 0000000..f659753 --- /dev/null +++ b/ARW.WebApi/Extensions/Filters/GlobalActionMonitor.cs @@ -0,0 +1,142 @@ +using Infrastructure; +using Infrastructure.Attribute; +using Infrastructure.Model; +using IPTools.Core; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Filters; +using NLog; +using ARW.Admin.WebApi.Extensions; +using ARW.Model.System; +using ARW.Service.System.IService; + +namespace ARW.Admin.WebApi.Filters +{ + public class GlobalActionMonitor : ActionFilterAttribute + { + static readonly Logger logger = LogManager.GetCurrentClassLogger(); + private ISysOperLogService OperLogService; + public GlobalActionMonitor(ISysOperLogService operLogService) + { + OperLogService = operLogService; + } + + /// + /// Action请求前 + /// + /// + /// + /// + public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + ApiResult response = new(); + response.Code = (int)ResultCode.PARAM_ERROR; + + var values = context.ModelState.Values; + foreach (var item in values) + { + foreach (var err in item.Errors) + { + if (err.ErrorMessage.Contains("JSON")) + { + return next(); + } + if (!string.IsNullOrEmpty(response.Msg)) + { + response.Msg += " | "; + } + + response.Msg += err.ErrorMessage; + } + } + if (!string.IsNullOrEmpty(response.Msg)) + { + logger.Info($"请求参数错误,{response.Msg}"); + context.Result = new JsonResult(response); + } + return base.OnActionExecutionAsync(context, next); + } + + /// + /// OnActionExecuted是在Action中的代码执行之后运行的方法。 + /// + /// + public override void OnResultExecuted(ResultExecutedContext context) + { + if (context.ActionDescriptor is not ControllerActionDescriptor controllerActionDescriptor) return; + + //获得注解信息 + LogAttribute logAttribute = GetLogAttribute(controllerActionDescriptor); + if (logAttribute == null) return; + + try + { + string method = context.HttpContext.Request.Method.ToUpper(); + // 获取当前的用户 + string userName = context.HttpContext.GetName(); + string jsonResult = string.Empty; + if (context.Result is ContentResult result && result.ContentType == "application/json") + { + jsonResult = result.Content.Replace("\r\n", "").Trim(); + } + if (context.Result is JsonResult result2) + { + jsonResult = result2.Value?.ToString(); + } + //获取当前执行方法的类名 + //string className = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name; + //获取当前成员的名称 + //string methodName = System.Reflection.MethodBase.GetCurrentMethod().Name; + string controller = context.RouteData.Values["Controller"].ToString(); + string action = context.RouteData.Values["Action"].ToString(); + + string ip = HttpContextExtension.GetClientUserIp(context.HttpContext); + var ip_info = IpTool.Search(ip); + + SysOperLog sysOperLog = new() + { + status = 0, + operName = userName, + operIp = ip, + operUrl = HttpContextExtension.GetRequestUrl(context.HttpContext), + requestMethod = method, + jsonResult = jsonResult, + operLocation = ip_info.Province + " " + ip_info.City, + method = controller + "." + action + "()", + //Elapsed = _stopwatch.ElapsedMilliseconds, + operTime = DateTime.Now + }; + HttpContextExtension.GetRequestValue(context.HttpContext, sysOperLog); + + if (logAttribute != null) + { + sysOperLog.title = logAttribute?.Title; + sysOperLog.businessType = (int)logAttribute?.BusinessType; + sysOperLog.operParam = logAttribute.IsSaveRequestData ? sysOperLog.operParam : ""; + sysOperLog.jsonResult = logAttribute.IsSaveResponseData ? sysOperLog.jsonResult : ""; + } + + LogEventInfo ei = new(NLog.LogLevel.Info, "GlobalActionMonitor", ""); + + ei.Properties["jsonResult"] = !HttpMethods.IsGet(method) ? jsonResult : ""; + ei.Properties["requestParam"] = sysOperLog.operParam; + ei.Properties["user"] = userName; + logger.Log(ei); + + OperLogService.InsertOperlog(sysOperLog); + } + catch (Exception ex) + { + logger.Error(ex, $"记录操作日志出错了#{ex.Message}"); + } + } + + private LogAttribute? GetLogAttribute(ControllerActionDescriptor controllerActionDescriptor) + { + var attribute = controllerActionDescriptor.MethodInfo.GetCustomAttributes(inherit: true) + .FirstOrDefault(a => a.GetType().Equals(typeof(LogAttribute))); + + return attribute as LogAttribute; + } + } +} diff --git a/ARW.WebApi/Extensions/Filters/GlobalExceptionFilter.cs b/ARW.WebApi/Extensions/Filters/GlobalExceptionFilter.cs new file mode 100644 index 0000000..4e65dd0 --- /dev/null +++ b/ARW.WebApi/Extensions/Filters/GlobalExceptionFilter.cs @@ -0,0 +1,67 @@ +using System; +using System.Diagnostics; +using Infrastructure; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; + +namespace ARWAdmin.Filters +{ + /// + /// 全局异常捕获 + /// 暂时没用了,改为中间件 2021-2-26 + /// + public class GlobalExceptionFilter : IExceptionFilter + { + readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + + private IWebHostEnvironment _hostingEnvironment; + + public GlobalExceptionFilter(IWebHostEnvironment environment) + { + _hostingEnvironment = environment; + } + + public void OnException(ExceptionContext context) + { + Exception ex = context.Exception; + + int code = (int)ResultCode.GLOBAL_ERROR; + string msg; + //自定义异常 + if (ex is CustomException customException) + { + code = customException.Code; + msg = customException.Message; + + logger.Info($"自定义异常code={code},msg={msg}"); + } + else + //参数异常 + if (ex is ArgumentException) + { + code = (int)ResultCode.PARAM_ERROR; + msg = ex.Message; + } + else + { + msg = "服务器好像出了点问题......"; + Console.WriteLine(ex.StackTrace); + // 获取异常堆栈 + var traceFrame = new StackTrace(ex, true).GetFrame(0); + // 获取出错的文件名 + var exceptionFileName = traceFrame.GetFileName(); + // 获取出错的行号 + var exceptionFileLineNumber = traceFrame.GetFileLineNumber(); + var errorMsg = $"{ex.Message}##{traceFrame}##{exceptionFileName}##行号:{exceptionFileLineNumber}"; + + logger.Error(ex, $"系统出错了error={ex.Message}#{errorMsg}"); + //context.Response.StatusCode = 500; + } + + context.Result = new JsonResult(new { code, msg }); + context.ExceptionHandled = true; + } + + } +} \ No newline at end of file diff --git a/ARW.WebApi/Extensions/Filters/VerifyAttribute.cs b/ARW.WebApi/Extensions/Filters/VerifyAttribute.cs new file mode 100644 index 0000000..dc5a6a2 --- /dev/null +++ b/ARW.WebApi/Extensions/Filters/VerifyAttribute.cs @@ -0,0 +1,56 @@ +using Infrastructure; +using Infrastructure.Model; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Filters; +using NLog; +using System; +using System.Linq; +using ARW.Admin.WebApi.Extensions; +using ARW.Admin.WebApi.Framework; +using ARW.Model.System; + +namespace ARW.Admin.WebApi.Filters +{ + /// + /// 授权校验访问 + /// 如果跳过授权登录在Action 或controller加上 AllowAnonymousAttribute + /// + public class VerifyAttribute : Attribute, IAuthorizationFilter + { + static readonly Logger logger = LogManager.GetCurrentClassLogger(); + + /// + /// 只判断token是否正确,不判断权限 + /// 如果需要判断权限的在Action上加上ApiActionPermission属性标识权限类别,ActionPermissionFilter作权限处理 + /// + /// + public void OnAuthorization(AuthorizationFilterContext context) + { + var noNeedCheck = false; + if (context.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor) + { + noNeedCheck = controllerActionDescriptor.MethodInfo.GetCustomAttributes(inherit: true) + .Any(a => a.GetType().Equals(typeof(AllowAnonymousAttribute))); + } + + if (noNeedCheck) return; + + string ip = HttpContextExtension.GetClientUserIp(context.HttpContext); + string url = context.HttpContext.Request.Path; + var isAuthed = context.HttpContext.User.Identity.IsAuthenticated; + + //使用jwt token校验2020-11-21 + LoginUser info = JwtUtil.GetLoginUser(context.HttpContext); + + if (info == null || !isAuthed) + { + string msg = $"请求访问[{url}]失败,无法访问系统资源"; + logger.Info($"{msg}"); + + context.Result = new JsonResult(new ApiResult((int)ResultCode.DENY, msg)); + } + } + } +} diff --git a/ARW.WebApi/Extensions/HttpContextExtension.cs b/ARW.WebApi/Extensions/HttpContextExtension.cs new file mode 100644 index 0000000..3641814 --- /dev/null +++ b/ARW.WebApi/Extensions/HttpContextExtension.cs @@ -0,0 +1,156 @@ +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Claims; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using UAParser; +using ARW.Model.System; + +namespace ARW.Admin.WebApi.Extensions +{ + /// + /// HttpContext扩展类 + /// + public static class HttpContextExtension + { + /// + /// 是否是ajax请求 + /// + /// + /// + public static bool IsAjaxRequest(this HttpRequest request) + { + if (request == null) + { + throw new ArgumentNullException(nameof(request)); + } + + //return request.Headers.ContainsKey("X-Requested-With") && + // request.Headers["X-Requested-With"].Equals("XMLHttpRequest"); + + return request.Headers["X-Requested-With"] == "XMLHttpRequest" || (request.Headers != null && request.Headers["X-Requested-With"] == "XMLHttpRequest"); + } + + /// + /// 获取客户端IP + /// + /// + /// + public static string GetClientUserIp(this HttpContext context) + { + if (context == null) return ""; + var result = context.Request.Headers["X-Forwarded-For"].FirstOrDefault(); + if (string.IsNullOrEmpty(result)) + { + result = context.Connection.RemoteIpAddress?.ToString(); + } + if (string.IsNullOrEmpty(result) || result.Contains("::1")) + result = "127.0.0.1"; + + result = result.Replace("::ffff:", "127.0.0.1"); + result = IsIP(result) ? result : "127.0.0.1"; + return result; + } + + public static bool IsIP(string ip) + { + return Regex.IsMatch(ip, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$"); + } + + public static long GetUId(this HttpContext context) + { + var uid = context.User.FindFirstValue(ClaimTypes.PrimarySid); + + return !string.IsNullOrEmpty(uid) ? long.Parse(uid) : 0; + } + public static string? GetName(this HttpContext context) + { + var uid = context.User?.Identity?.Name; + + return uid; + } + + public static bool IsAdmin(this HttpContext context) + { + long id = GetUId(context); + return id == 1; + } + + /// + /// ClaimsIdentity + /// + /// + /// + public static IEnumerable? GetClaims(this HttpContext context) + { + return context.User?.Identities; + } + //public static int GetRole(this HttpContext context) + //{ + // var roleid = context.User.FindFirstValue(ClaimTypes.Role) ?? "0"; + + // return int.Parse(roleid); + //} + + public static string GetUserAgent(this HttpContext context) + { + return context.Request.Headers["User-Agent"]; + } + + /// + /// 获取请求令牌 + /// + /// + /// + public static string GetToken(this HttpContext context) + { + return context.Request.Headers["Authorization"]; + } + + public static ClientInfo GetClientInfo(this HttpContext context) + { + var str = GetUserAgent(context); + var uaParser = Parser.GetDefault(); + ClientInfo c = uaParser.Parse(str); + + return c; + } + + public static string? GetRequestUrl(this HttpContext context) + { + return context != null ? context.Request.Path.Value : ""; + } + + /// + /// 设置请求参数 + /// + /// + /// + public static void GetRequestValue(this HttpContext context, SysOperLog operLog) + { + string reqMethod = operLog.requestMethod; + string param; + + if (HttpMethods.IsPost(reqMethod) || HttpMethods.IsPut(reqMethod)) + { + context.Request.Body.Seek(0, SeekOrigin.Begin); + using var reader = new StreamReader(context.Request.Body, Encoding.UTF8); + //需要使用异步方式才能获取 + param = reader.ReadToEndAsync().Result; + } + else + { + param = context.Request.QueryString.Value.ToString(); + } + operLog.operParam = param; + } + + } + +} diff --git a/ARW.WebApi/Extensions/IPRateExtension.cs b/ARW.WebApi/Extensions/IPRateExtension.cs new file mode 100644 index 0000000..c055f24 --- /dev/null +++ b/ARW.WebApi/Extensions/IPRateExtension.cs @@ -0,0 +1,27 @@ +using AspNetCoreRateLimit; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using System; + +namespace ARW.Admin.WebApi.Extensions +{ + public static class IPRateExtension + { + public static void AddIPRate(this IServiceCollection services, IConfiguration configuration) + { + if (services == null) throw new ArgumentNullException(nameof(services)); + + //从appsettings.json中加载常规配置,IpRateLimiting与配置文件中节点对应 + services.Configure(configuration.GetSection("IpRateLimiting")); + + //从appsettings.json中加载Ip规则 + services.Configure(configuration.GetSection("IpRateLimitPolicies")); + //注入计数器和规则存储 + services.AddSingleton(); + services.AddSingleton(); + //配置(解析器、计数器密钥生成器) + services.AddSingleton(); + services.AddSingleton(); + } + } +} diff --git a/ARW.WebApi/Extensions/SwaggerExtension.cs b/ARW.WebApi/Extensions/SwaggerExtension.cs new file mode 100644 index 0000000..942da1f --- /dev/null +++ b/ARW.WebApi/Extensions/SwaggerExtension.cs @@ -0,0 +1,100 @@ +using Infrastructure; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.Filters; +using Swashbuckle.AspNetCore.SwaggerUI; + +namespace ARW.Admin.WebApi.Extensions +{ + public static class SwaggerExtension + { + /// + /// + /// + /// + public static void UseSwagger(this IApplicationBuilder app) + { + app.UseSwagger(c => + { + c.RouteTemplate = "swagger/{documentName}/swagger.json"; + c.PreSerializeFilters.Add((swaggerDoc, httpReq) => + { + var url = $"{httpReq.Scheme}://{httpReq.Host.Value}"; + var referer = httpReq.Headers["Referer"].ToString(); + if (referer.Contains(GlobalConstant.DevApiProxy)) + url = referer.Substring(0, + referer.IndexOf(GlobalConstant.DevApiProxy, StringComparison.InvariantCulture) + GlobalConstant.DevApiProxy.Length - 1); + swaggerDoc.Servers = + new List + { + new OpenApiServer + { + Url = url + } + }; + }); + }); + app.UseSwaggerUI(c => + { + c.SwaggerEndpoint("v1/swagger.json", "ARWAdmin v1"); + c.DocExpansion(DocExpansion.None); + } + ); + } + + public static void AddSwaggerConfig(this IServiceCollection services) + { + if (services == null) throw new ArgumentNullException(nameof(services)); + //IWebHostEnvironment hostEnvironment = App.GetRequiredService(); + + services.AddSwaggerGen(c => + { + c.SwaggerDoc("v1", new OpenApiInfo + { + Title = "ARW 接口文档", + Version = "v1", + Description = "", + }); + try + { + //添加文档注释 + c.IncludeXmlComments("ARW.WebApi.xml", true); + } + catch (Exception ex) + { + Console.WriteLine("swagger 文档加载失败" + ex.Message); + } + + //参考文章:http://www.zyiz.net/tech/detail-134965.html + //需要安装包Swashbuckle.AspNetCore.Filters + // 开启权限小锁 需要在对应的Action上添加[Authorize]才能看到 + c.OperationFilter(); + c.OperationFilter(); + + //在header 中添加token,传递到后台 + c.OperationFilter(); + + c.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme, + new OpenApiSecurityScheme + { + In = ParameterLocation.Header, + Description = "请输入Login接口返回的Token,前置Bearer。示例:Bearer {Token}", + Name = "Authorization",//jwt默认的参数名称, + Type = SecuritySchemeType.ApiKey, //指定ApiKey + BearerFormat = "JWT",//标识承载令牌的格式 该信息主要是出于文档目的 + Scheme = JwtBearerDefaults.AuthenticationScheme//授权中要使用的HTTP授权方案的名称 + }); + c.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } + }, + new List() + } + }); + }); + } + } +} diff --git a/ARW.WebApi/Extensions/TasksExtension.cs b/ARW.WebApi/Extensions/TasksExtension.cs new file mode 100644 index 0000000..ca0078e --- /dev/null +++ b/ARW.WebApi/Extensions/TasksExtension.cs @@ -0,0 +1,57 @@ +using Infrastructure; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Quartz.Spi; +using System; +using System.Threading.Tasks; +using ARW.Service.System.IService; +using ARW.Tasks; + +namespace ARW.Admin.WebApi.Extensions +{ + /// + /// 定时任务扩展方法 + /// + public static class TasksExtension + { + public static void AddTaskSchedulers(this IServiceCollection services) + { + if (services == null) throw new ArgumentNullException(nameof(services)); + + //添加Quartz服务 + services.AddSingleton(); + //添加我们的服务 + //services.AddTransient(); + + services.AddTransient(); + } + + /// + /// 程序启动后添加任务计划 + /// + /// + /// + public static IApplicationBuilder UseAddTaskSchedulers(this IApplicationBuilder app) + { + //var _tasksQzService = (ISysTasksQzService)App.GetRequiredService(typeof(ISysTasksQzService)); + + ITaskSchedulerServer _schedulerServer = app.ApplicationServices.GetRequiredService(); + + //var tasks = _tasksQzService.GetList(m => m.IsStart); + var tasks = SqlSugar.IOC.DbScoped.SugarScope.Queryable().Where(m => m.IsStart).ToList(); + + //程序启动后注册所有定时任务 + foreach (var task in tasks) + { + var result = _schedulerServer.AddTaskScheduleAsync(task); + if (result.Result.Code == 200) + { + Console.WriteLine($"注册任务[{task.Name}]ID:{task.ID}成功"); + } + } + + return app; + } + + } +} diff --git a/ARW.WebApi/Framework/CookieUtil.cs b/ARW.WebApi/Framework/CookieUtil.cs new file mode 100644 index 0000000..2c42662 --- /dev/null +++ b/ARW.WebApi/Framework/CookieUtil.cs @@ -0,0 +1,34 @@ +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Threading.Tasks; + +namespace ARW.Admin.WebApi.Framework +{ + public class CookieUtil + { + public static void WhiteCookie(HttpContext context, List claims) + { + //2.创建声明主题 指定认证方式 这里使用cookie + var claimsIdentity = new ClaimsIdentity(claims, "Login"); + + Task.Run(async () => + { + await context.SignInAsync( + JwtBearerDefaults.AuthenticationScheme,//这里要注意的是HttpContext.SignInAsync(AuthenticationType,…) 所设置的Scheme一定要与前面的配置一样,这样对应的登录授权才会生效。 + new ClaimsPrincipal(claimsIdentity), + new AuthenticationProperties() + { + IsPersistent = true, + AllowRefresh = true, + ExpiresUtc = DateTimeOffset.Now.AddDays(1),//有效时间 + }); + }).Wait(); + } + } +} diff --git a/ARW.WebApi/Framework/JsonConverterUtil.cs b/ARW.WebApi/Framework/JsonConverterUtil.cs new file mode 100644 index 0000000..b199178 --- /dev/null +++ b/ARW.WebApi/Framework/JsonConverterUtil.cs @@ -0,0 +1,37 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace ARW.Admin.WebApi.Framework +{ + public class JsonConverterUtil + { + public class DateTimeNullConverter : JsonConverter + { + public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + => string.IsNullOrEmpty(reader.GetString()) ? default(DateTime?) : ParseDateTime(reader.GetString()); + + public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options) + => writer.WriteStringValue(value?.ToString("yyyy-MM-dd HH:mm:ss")); + } + + public class DateTimeConverter : JsonConverter + { + public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + var dateTime = ParseDateTime(reader.GetString()); + return dateTime == null ? DateTime.MinValue : dateTime.Value; + } + + public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) + => writer.WriteStringValue(value.ToString("yyyy-MM-dd HH:mm:ss")); + } + + public static DateTime? ParseDateTime(string dateStr) + { + if (System.Text.RegularExpressions.Regex.IsMatch(dateStr, @"^\d{4}[/-]") && DateTime.TryParse(dateStr, null,System.Globalization.DateTimeStyles.AssumeLocal, out var dateVal)) + return dateVal; + return null; + } + } +} diff --git a/ARW.WebApi/Framework/JwtUtil.cs b/ARW.WebApi/Framework/JwtUtil.cs new file mode 100644 index 0000000..37d38a0 --- /dev/null +++ b/ARW.WebApi/Framework/JwtUtil.cs @@ -0,0 +1,180 @@ +using Infrastructure; +using Infrastructure.Extensions; +using Microsoft.IdentityModel.Tokens; +using Newtonsoft.Json; +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Text; +using ARW.Admin.WebApi.Extensions; +using ARW.Model.System; +using ARW.Service.System; +using ARW.Model.Models.Business.Customers; + +namespace ARW.Admin.WebApi.Framework +{ + /// + /// 2020-11-20 + /// + public class JwtUtil + { + /// + /// 获取用户身份信息 + /// + /// + /// + public static LoginUser GetLoginUser(HttpContext httpContext) + { + string token = httpContext.GetToken(); + + if (!string.IsNullOrEmpty(token)) + { + var res = ValidateJwtToken(ParseToken(token)); + return res; + } + return null; + } + + /// + /// 生成token + /// + /// + /// + /// + public static string GenerateJwtToken(List claims, JwtSettings jwtSettings) + { + var authTime = DateTime.Now; + var expiresAt = authTime.AddMinutes(jwtSettings.Expire); + var tokenHandler = new JwtSecurityTokenHandler(); + var key = Encoding.ASCII.GetBytes(jwtSettings.SecretKey); + claims.Add(new Claim("Audience", jwtSettings.Audience)); + claims.Add(new Claim("Issuer", jwtSettings.Issuer)); + + var tokenDescriptor = new SecurityTokenDescriptor + { + Subject = new ClaimsIdentity(claims), + Issuer = jwtSettings.Issuer, + Audience = jwtSettings.Audience, + IssuedAt = authTime,//token生成时间 + Expires = expiresAt, + //NotBefore = authTime, + TokenType = "Bearer", + //对称秘钥,签名证书 + SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) + }; + var token = tokenHandler.CreateToken(tokenDescriptor); + return tokenHandler.WriteToken(token); + } + /// + /// 验证Token + /// + /// + public static TokenValidationParameters ValidParameters() + { + JwtSettings jwtSettings = new(); + AppSettings.Bind("JwtSettings", jwtSettings); + + if (jwtSettings == null || jwtSettings.SecretKey.IsEmpty()) + { + throw new Exception("JwtSettings获取失败"); + } + var key = Encoding.ASCII.GetBytes(jwtSettings.SecretKey); + + var tokenDescriptor = new TokenValidationParameters + { + ValidateIssuerSigningKey = true, + ValidateIssuer = true, + ValidateAudience = true, + ValidIssuer = jwtSettings.Issuer, + ValidAudience = jwtSettings.Audience, + IssuerSigningKey = new SymmetricSecurityKey(key), + ValidateLifetime = true,//是否验证Token有效期,使用当前时间与Token的Claims中的NotBefore和Expires对比 + ClockSkew = TimeSpan.FromSeconds(30) + //RequireExpirationTime = true,//过期时间 + }; + return tokenDescriptor; + } + /// + /// 从令牌中获取数据声明 + /// + /// 令牌 + /// + public static IEnumerable? ParseToken(string token) + { + var tokenHandler = new JwtSecurityTokenHandler(); + var validateParameter = ValidParameters(); + token = token.Replace("Bearer ", ""); + try + { + tokenHandler.ValidateToken(token, validateParameter, out SecurityToken validatedToken); + + var jwtToken = tokenHandler.ReadJwtToken(token); + var res = jwtToken.Claims; + return res; + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + // return null if validation fails + return null; + } + } + + /// + /// jwt token校验 + /// + /// + /// + public static LoginUser? ValidateJwtToken(IEnumerable jwtToken) + { + try + { + var userData = jwtToken.FirstOrDefault(x => x.Type == ClaimTypes.UserData).Value; + var loginUser = JsonConvert.DeserializeObject(userData); + + if (loginUser != null) + { + if (loginUser.IsApi) + { + return loginUser; + } + } + + var permissions = CacheService.GetUserPerms(GlobalConstant.UserPermKEY + loginUser?.UserId); + if (loginUser?.UserName == "admin") + { + permissions = new List() { GlobalConstant.AdminPerm }; + } + if (permissions == null) return null; + loginUser.Permissions = permissions; + return loginUser; + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + return null; + } + } + + /// + ///组装Claims + /// + /// + /// + public static List AddClaims(LoginUser user) + { + if (user?.Permissions.Count > 50) + { + user.Permissions = new List(); + } + var claims = new List() + { + new Claim(ClaimTypes.PrimarySid, user.UserId.ToString()), + new Claim(ClaimTypes.Name, user.UserName), + new Claim(ClaimTypes.UserData, JsonConvert.SerializeObject(user)) + }; + + return claims; + } + + } +} diff --git a/ARW.WebApi/Hubs/ChatHub.cs b/ARW.WebApi/Hubs/ChatHub.cs new file mode 100644 index 0000000..f19fd57 --- /dev/null +++ b/ARW.WebApi/Hubs/ChatHub.cs @@ -0,0 +1,175 @@ +//using Infrastructure; +//using Infrastructure.Constant; +//using Infrastructure.Model; +//using IPTools.Core; +//using Microsoft.AspNetCore.SignalR; +//using Microsoft.AspNetCore.Mvc; +//using Microsoft.AspNetCore.Http; +//using ARW.Admin.WebApi.Extensions; +//using ARW.Admin.WebApi.Framework; +//using ARW.Model; +//using ARW.Model.System; +//using ARW.Service.System.IService; +//using JinianNet.JNTemplate; +//using Microsoft.AspNetCore.Http; +//using RestSharp; +//using System.Net; +//using Infrastructure.Extensions; + +//namespace ARW.Admin.WebApi.Hubs +//{ +// /// +// /// 聊天室SignalR +// /// +// public class ChatHub : Hub +// { +// private static readonly List clientusers = new(); +// //private readonly IChatLoginService _ChatLoginService; +// //private readonly IGroupUserService _GroupUserService; + +// //public ChatHub(IChatLoginService chatLoginService, IGroupUserService groupUserService) +// //{ +// // this._ChatLoginService = chatLoginService; +// // _GroupUserService = groupUserService; +// //} + +// private readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + +// //private ApiResult SendNotice() +// //{ +// // var result = SysNoticeService.GetSysNotices(); + +// // return new ApiResult(200, "success", result); +// //} + +// #region 客户端连接 + +// /// +// /// 客户端连接的时候调用 +// /// +// /// +// public override Task OnConnectedAsync() +// { +// var httpContext = Context.GetHttpContext(); +// var username = httpContext.Request.Cookies["username"]; +// if (username == null) +// { +// throw new Exception("系统异常连接失败"); +// } +// //var userInfo = _ChatLoginService.FindUserByName(username); + +// //_ChatLoginService.Update(s => s.ChatUserName == username, +// // f => new ChatUser +// // { +// // Status = 1 +// // }); + +// var user = clientusers.Any(u => u.ConnectionId == Context.ConnectionId); +// ////判断用户是否存在,否则添加集合 +// if (user == false) +// { +// OnlineUsersForChat users = new(Context.ConnectionId, userInfo.ChatUserName, userInfo.ChatUserGuId) +// { +// }; + +// clientusers.Add(users); +// } + +// foreach (var item in clientusers) +// { +// Console.WriteLine(item); +// } + +// //Clients.All.SendAsync(HubsConstant.OnlineNum, clientUsers.Count); +// Clients.All.SendAsync("onlineChatUser", clientusers); +// return base.OnConnectedAsync(); +// } + +// /// +// /// 连接终止时调用。 +// /// +// /// +// public override Task OnDisconnectedAsync(Exception? exception) +// { +// var httpContext = Context.GetHttpContext(); +// var username = httpContext.Request.Cookies["username"]; + +// if (username == null) +// { +// throw new Exception("系统异常连接失败"); +// } + +// // 修改用户登录状态 +// //_ChatLoginService.Update(s => s.ChatUserName == username, +// // f => new ChatUser +// // { +// // Status = 0 +// // }); + +// var user = clientusers.Where(p => p.ConnectionId == Context.ConnectionId).FirstOrDefault(); +// ////判断用户是否存在,否则添加集合 +// if (user != null) +// { +// clientusers.Remove(user); +// } +// return base.OnDisconnectedAsync(exception); +// } + +// #endregion + +// /// +// /// 好友发送信息 +// /// +// /// +// /// +// /// +// public async Task SendFriendsChat(string selfConnectionId, string connectId, string sender, string receiver, string message) +// { +// if (string.IsNullOrEmpty(connectId)) +// { +// throw new CustomException("好友不在线,请留言!"); +// } + +// // 服务端主动调用客户端的方法 +// // 向指定用户(connectId)发送指定消息 +// // 监听接受方法("ReceiveMessage")来获取消息 -> ( new { sender, receiver, message } ) +// await Clients.Client(connectId).SendAsync("ReceiveMessage", new { sender, receiver, message }); +// await Clients.Client(selfConnectionId).SendAsync("ReceiveMessage", new { sender, receiver, message }); +// } + + +// /// +// /// 进入指定组 +// /// +// /// +// /// 组的名称 +// [HubMethodName(nameof(EnterRoom))] +// public void EnterRoom(string connectId, string roomName) +// { +// Groups.AddToGroupAsync(connectId, roomName); +// } + +// /// +// /// 群聊天(发送信息) +// /// +// /// +// public async Task SendGroupChat(string roomName, string groupGuId, string selfConnectionId, string senderId, string receiver, string message) +// { +// var guid = senderId.ParseToLong(); +// var groupguid = groupGuId.ParseToLong(); +// //var sender = _ChatLoginService.FindUserByGuid(guid).Result; + +// await Clients.Group(roomName) +// .SendAsync("groupMessages", new { roomName, sender, receiver, message }); + +// //_GroupUserService.Update(s => s.GroupGuId == groupguid, +// //f => new GroupUser +// //{ +// // IsRead = false +// //}); + +// //await Clients.Client(selfConnectionId).SendAsync("groupMessages", new { sender, receiver, message }); +// } + +// } +//} diff --git a/ARW.WebApi/Hubs/MessageHub.cs b/ARW.WebApi/Hubs/MessageHub.cs new file mode 100644 index 0000000..9160fc4 --- /dev/null +++ b/ARW.WebApi/Hubs/MessageHub.cs @@ -0,0 +1,125 @@ +using Infrastructure; +using Infrastructure.Constant; +using Infrastructure.Model; +using IPTools.Core; +using Microsoft.AspNetCore.SignalR; +using ARW.Admin.WebApi.Extensions; +using ARW.Admin.WebApi.Framework; +using ARW.Model; +using ARW.Model.System; +using ARW.Service.System.IService; + +namespace ARW.Admin.WebApi.Hubs +{ + /// + /// + /// + public class MessageHub : Hub + { + //创建用户集合,用于存储所有链接的用户数据 + private static readonly List clientUsers = new(); + private readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + private readonly ISysNoticeService SysNoticeService; + + /// + /// + /// + /// + public MessageHub(ISysNoticeService noticeService) + { + SysNoticeService = noticeService; + } + + private ApiResult SendNotice() + { + var result = SysNoticeService.GetSysNotices(); + + return new ApiResult(200, "success", result); + } + + #region 客户端连接 + + /// + /// 客户端连接的时候调用 + /// + /// + public override Task OnConnectedAsync() + { + var name = Context.User.Identity.Name; + var ip = HttpContextExtension.GetClientUserIp(App.HttpContext); + var ip_info = IpTool.Search(ip); + + LoginUser loginUser = JwtUtil.GetLoginUser(App.HttpContext); + var user = clientUsers.Any(u => u.ConnnectionId == Context.ConnectionId); + //判断用户是否存在,否则添加集合 + if (!user && Context.User.Identity.IsAuthenticated) + { + OnlineUsers users = new(Context.ConnectionId, name, loginUser?.UserId, ip) + { + Location = ip_info.City + }; + clientUsers.Add(users); + Console.WriteLine($"{DateTime.Now}:{name},{Context.ConnectionId}连接服务端success,当前已连接{clientUsers.Count}个"); + //Clients.All.SendAsync("welcome", $"欢迎您:{name},当前时间:{DateTime.Now}"); + Clients.All.SendAsync(HubsConstant.MoreNotice, SendNotice()); + } + + Clients.All.SendAsync(HubsConstant.OnlineNum, clientUsers.Count); + Clients.All.SendAsync(HubsConstant.OnlineUser, clientUsers); + return base.OnConnectedAsync(); + } + + /// + /// 连接终止时调用。 + /// + /// + public override Task OnDisconnectedAsync(Exception? exception) + { + var user = clientUsers.Where(p => p.ConnnectionId == Context.ConnectionId).FirstOrDefault(); + //判断用户是否存在,否则添加集合 + if (user != null) + { + clientUsers.Remove(user); + Clients.All.SendAsync(HubsConstant.OnlineNum, clientUsers.Count); + Clients.All.SendAsync(HubsConstant.OnlineUser, clientUsers); + Console.WriteLine($"用户{user?.Name}离开了,当前已连接{clientUsers.Count}个"); + } + return base.OnDisconnectedAsync(exception); + } + + #endregion + + /// + /// 注册信息 + /// + /// + /// + /// + /// + [HubMethodName("SendMessage")] + public async Task SendMessage(string connectId, string userName, string message) + { + Console.WriteLine($"{connectId},message={message}"); + bool isDemoMode = AppSettings.GetAppConfig("DemoMode", true); + if (isDemoMode) + { + await Clients.Caller.SendAsync("receiveChat", new { userName, message = "当前环境为演示环境,消息不会发送给对方" }); + return; + } + await Clients.Client(connectId).SendAsync("receiveChat", new { userName, message }); + } + + + /// + /// 发送消息 + /// + /// + /// + /// + public async Task SendChat(string user, string message) + { + // 服务端主动调用客户端的方法 + await Clients.All.SendAsync("ReceiveMessage", new { user,message }); + } + } +} diff --git a/ARW.WebApi/Hubs/OnlineUsers.cs b/ARW.WebApi/Hubs/OnlineUsers.cs new file mode 100644 index 0000000..61858e0 --- /dev/null +++ b/ARW.WebApi/Hubs/OnlineUsers.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ARW.Admin.WebApi.Hubs +{ + public class OnlineUsers + { + /// + /// 客户端连接Id + /// + public string ConnnectionId { get; set; } + /// + /// 用户id + /// + public long? Userid { get; set; } + public string Name { get; set; } + public DateTime LoginTime { get; set; } + public string UserIP { get; set; } + public string Location { get; set; } + + public OnlineUsers(string clientid, string name, long? userid, string userip) + { + ConnnectionId = clientid; + Name = name; + LoginTime = DateTime.Now; + Userid = userid; + UserIP = userip; + } + } +} diff --git a/ARW.WebApi/Hubs/OnlineUsersForChat.cs b/ARW.WebApi/Hubs/OnlineUsersForChat.cs new file mode 100644 index 0000000..9294eb8 --- /dev/null +++ b/ARW.WebApi/Hubs/OnlineUsersForChat.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ARW.Admin.WebApi.Hubs +{ + /// + /// 在线用户(聊天室) + /// + public class OnlineUsersForChat + { + /// + /// 客户端连接Id + /// + public string ConnectionId { get; set; } + /// + /// 用户id + /// + public long? UserGuid { get; set; } + public string Name { get; set; } + public DateTime LoginTime { get; set; } + + public OnlineUsersForChat(string clientid, string name, long? userguid) + { + ConnectionId = clientid; + Name = name; + LoginTime = DateTime.Now; + UserGuid = userguid; + } + } +} diff --git a/ARW.WebApi/Middleware/GlobalExceptionMiddleware.cs b/ARW.WebApi/Middleware/GlobalExceptionMiddleware.cs new file mode 100644 index 0000000..f64e6b0 --- /dev/null +++ b/ARW.WebApi/Middleware/GlobalExceptionMiddleware.cs @@ -0,0 +1,136 @@ +using Infrastructure; +using Infrastructure.Attribute; +using Infrastructure.Model; +using IPTools.Core; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; +using NLog; +using System; +using System.Text.Encodings.Web; +using System.Text.Json; +using System.Threading.Tasks; +using ARW.Admin.WebApi.Extensions; +using ARW.Model.System; +using ARW.Service.System.IService; + +namespace ARW.Admin.WebApi.Middleware +{ + /// + /// 全局异常处理中间件 + /// + // 调用 app.UseMiddleware() + public class GlobalExceptionMiddleware + { + private readonly RequestDelegate next; + private readonly ISysOperLogService SysOperLogService; + + static readonly Logger Logger = LogManager.GetCurrentClassLogger();//声明NLog变量 + + public GlobalExceptionMiddleware(RequestDelegate next, ISysOperLogService sysOperLog) + { + this.next = next; + this.SysOperLogService = sysOperLog; + } + + public async Task Invoke(HttpContext context) + { + try + { + await next(context); + } + catch (Exception ex) + { + await HandleExceptionAsync(context, ex); + } + } + + private async Task HandleExceptionAsync(HttpContext context, Exception ex) + { + NLog.LogLevel logLevel = NLog.LogLevel.Info; + int code = (int)ResultCode.GLOBAL_ERROR; + string msg; + string error = string.Empty; + //自定义异常 + if (ex is CustomException customException) + { + code = customException.Code; + msg = customException.Message; + error = customException.LogMsg; + } + else if (ex is ArgumentException)//参数异常 + { + code = (int)ResultCode.PARAM_ERROR; + msg = ex.Message; + } + else + { + msg = "服务器好像出了点问题......"; + error = $"{ex.Message}"; + logLevel = NLog.LogLevel.Error; + context.Response.StatusCode = 500; + } + var options = new JsonSerializerOptions + { + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + WriteIndented = true + }; + + ApiResult apiResult = new(code, msg); + string responseResult = JsonSerializer.Serialize(apiResult, options).ToLower(); + string ip = HttpContextExtension.GetClientUserIp(context); + var ip_info = IpTool.Search(ip); + + SysOperLog sysOperLog = new() + { + status = 1, + operIp = ip, + operUrl = HttpContextExtension.GetRequestUrl(context), + requestMethod = context.Request.Method, + jsonResult = responseResult, + errorMsg = string.IsNullOrEmpty(error) ? msg : error, + operName = HttpContextExtension.GetName(context) , + operLocation = ip_info.Province + " " + ip_info.City, + operTime = DateTime.Now + }; + HttpContextExtension.GetRequestValue(context, sysOperLog); + var endpoint = GetEndpoint(context); + if (endpoint != null) + { + var logAttribute = endpoint.Metadata.GetMetadata(); + if (logAttribute != null) + { + sysOperLog.businessType = (int)logAttribute?.BusinessType; + sysOperLog.title = logAttribute?.Title; + sysOperLog.operParam = logAttribute.IsSaveRequestData ? sysOperLog.operParam : ""; + sysOperLog.jsonResult = logAttribute.IsSaveResponseData ? sysOperLog.jsonResult : ""; + } + } + LogEventInfo ei = new(logLevel, "GlobalExceptionMiddleware", error) + { + Exception = ex, + Message = error + }; + ei.Properties["status"] = 1;//走正常返回都是通过走GlobalExceptionFilter不通过 + ei.Properties["jsonResult"] = responseResult; + ei.Properties["requestParam"] = sysOperLog.operParam; + ei.Properties["user"] = HttpContextExtension.GetName(context); + + Logger.Log(ei); + context.Response.ContentType = "text/json;charset=utf-8"; + await context.Response.WriteAsync(responseResult, System.Text.Encoding.UTF8); + + SysOperLogService.InsertOperlog(sysOperLog); + } + + public static Endpoint GetEndpoint(HttpContext context) + { + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + return context.Features.Get()?.Endpoint; + } + } +} diff --git a/ARW.WebApi/NLog.config b/ARW.WebApi/NLog.config new file mode 100644 index 0000000..2258b34 --- /dev/null +++ b/ARW.WebApi/NLog.config @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ARW.WebApi/Program.cs b/ARW.WebApi/Program.cs new file mode 100644 index 0000000..f12bafc --- /dev/null +++ b/ARW.WebApi/Program.cs @@ -0,0 +1,180 @@ +using Infrastructure; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.DataProtection; +using ARW.Admin.WebApi.Framework; +using Hei.Captcha; +using Infrastructure.Extensions; +using ARW.Admin.WebApi.Extensions; +using ARW.Admin.WebApi.Filters; +using ARW.Admin.WebApi.Middleware; +using ARW.Admin.WebApi.Hubs; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using Infrastructure.WeChat.Login; +using Senparc.Weixin.RegisterServices; +using Senparc.CO2NET.RegisterServices; +using Microsoft.Extensions.Options; +using Senparc.CO2NET; +using Senparc.Weixin.Entities; +using Senparc.Weixin; +using ARW.Model.System.Generate; +using Senparc.Weixin.WxOpen.Containers; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. + +builder.Services.AddControllers().AddNewtonsoftJson(opt => +{ + //忽略循环引用 + opt.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; + + //不改变字段大小 + opt.SerializerSettings.ContractResolver = new DefaultContractResolver(); +}); +// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); +//注入HttpContextAccessor +builder.Services.AddSingleton(); + +// 微信服务配置 +builder.Services.AddMemoryCache(); +builder.Services.AddSenparcGlobalServices(builder.Configuration)//Senparc.CO2NET 全局注册 + .AddSenparcWeixinServices(builder.Configuration); +var senparcSetting = builder.Services.BuildServiceProvider().GetRequiredService>(); +IRegisterService register = RegisterService.Start(senparcSetting.Value).UseSenparcGlobal();// 启动 CO2NET 全局注册,必须! +var senparcWeixinSetting = builder.Services.BuildServiceProvider().GetRequiredService>(); +register.UseSenparcWeixin(senparcWeixinSetting.Value, senparcSetting.Value);//微信全局注册,必须! + +// 小程序 +await AccessTokenContainer.RegisterAsync("wx34436769371ceb7c", "8ded49f94c8e607de7cc4244639d4666"); +// 公众号 +await AccessTokenContainer.RegisterAsync("wx99caf571c9fb1cc5", "61100d9c4fff5acf97517f0c8799e2e2"); + +// 添加WeChat单例服务 +builder.Services.AddSingleton(new WeChatLogin("wxf3f7f286bfbb7dfa", "c2a02e478d9f0683d8dafec646c3d2ca")); + +//配置跨域 +builder.Services.AddCors(c => +{ + c.AddPolicy("Policy", policy => + { + policy.WithOrigins(builder.Configuration["corsUrls"].Split(',', StringSplitOptions.RemoveEmptyEntries)) + .AllowAnyHeader()//允许任意头 + .AllowCredentials()//允许cookie + .AllowAnyMethod();//允许任意方法 + }); +}); + +//注入SignalR实时通讯,默认用json传输 +builder.Services.AddSignalR(); +//消除Error unprotecting the session cookie警告 +builder.Services.AddDataProtection() + .PersistKeysToFileSystem(new DirectoryInfo(Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + "DataProtection")); +//普通验证码 +builder.Services.AddHeiCaptcha(); +//builder.Services.AddSession(); +builder.Services.AddHttpContextAccessor(); +//绑定整个对象到Model上 +builder.Services.Configure(builder.Configuration); + +//jwt 认证 +builder.Services.AddAuthentication(options => +{ + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; +}).AddCookie() +.AddJwtBearer(o => +{ + o.TokenValidationParameters = JwtUtil.ValidParameters(); +}); + +//InternalApp.InternalServices = builder.Services; +builder.Services.AddAppService(); +builder.Services.AddSingleton(new AppSettings(builder.Configuration)); +//开启计划任务 +builder.Services.AddTaskSchedulers(); +//初始化db +DbExtension.AddDb(builder.Configuration); + +//注册REDIS 服务 +Task.Run(() => +{ + //RedisServer.Initalize(); +}); +builder.Services.AddMvc(options => +{ + options.Filters.Add(typeof(GlobalActionMonitor));//全局注册 +}) +.AddJsonOptions(options => +{ + options.JsonSerializerOptions.Converters.Add(new JsonConverterUtil.DateTimeConverter()); + options.JsonSerializerOptions.Converters.Add(new JsonConverterUtil.DateTimeNullConverter()); +}); + +builder.Services.AddSwaggerConfig(); + +var app = builder.Build(); +if (builder.Configuration["InitDb"].ParseToBool() == true) +{ + InternalApp.ServiceProvider = app.Services; + app.Services.InitDb(); +} + +app.UseSwagger(); + +//使可以多次多去body内容 +app.Use((context, next) => +{ + context.Request.EnableBuffering(); + if (context.Request.Query.TryGetValue("access_token", out var token)) + { + context.Request.Headers.Add("Authorization", $"Bearer {token}"); + } + return next(); +}); + +//app.UseSenparcWeixin(app.Environment, null, null, register => { }, +// (register, weixinSetting) => +//{ +// //注册公众号信息(可以执行多次,注册多个公众号) +// register.RegisterMpAccount(weixinSetting, "【盛派网络小助手】公众号"); +//}); + +//开启访问静态文件/wwwroot目录文件,要放在UseRouting前面 +app.UseStaticFiles(); +//开启路由访问 +app.UseRouting(); +app.UseCors("Policy");//要放在app.UseEndpoints前。 +//app.UseHttpsRedirection(); + +app.UseAuthentication(); +app.UseAuthorization(); + +//开启缓存 +app.UseResponseCaching(); +//恢复/启动任务 +app.UseAddTaskSchedulers(); +//使用全局异常中间件 +app.UseMiddleware(); + +app.UseEndpoints(endpoints => +{ + //设置socket连接 + endpoints.MapHub("/msgHub"); + + endpoints.MapControllerRoute( + name: "default", + pattern: "{controller=Home}/{action=Index}/{id?}"); +}); +app.MapControllers(); + +//app.UseSenparcWeixin(app.Environment, null, null, register => { }, +// (register, weixinSetting) => +// { +// //注册公众号信息(可以执行多次,注册多个公众号) +// register.RegisterMpAccount(weixinSetting, "【盛派网络小助手】公众号"); +// }); + +app.Run(); \ No newline at end of file diff --git a/ARW.WebApi/Properties/PublishProfiles/FolderProfile.pubxml b/ARW.WebApi/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 0000000..5dc798d --- /dev/null +++ b/ARW.WebApi/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,20 @@ + + + + + true + false + true + Release + Any CPU + FileSystem + bin\Release\net6.0\publish\ + FileSystem + + net6.0 + e5497bb4-b0c1-4794-9fae-163f626ec399 + false + + \ No newline at end of file diff --git a/ARW.WebApi/Properties/PublishProfiles/FolderProfile1.pubxml b/ARW.WebApi/Properties/PublishProfiles/FolderProfile1.pubxml new file mode 100644 index 0000000..d0d2ce9 --- /dev/null +++ b/ARW.WebApi/Properties/PublishProfiles/FolderProfile1.pubxml @@ -0,0 +1,16 @@ + + + + + False + False + True + Release + Any CPU + FileSystem + bin\Release\net6.0\publish\ + FileSystem + + \ No newline at end of file diff --git a/ARW.WebApi/Properties/PublishProfiles/FolderProfile2.pubxml b/ARW.WebApi/Properties/PublishProfiles/FolderProfile2.pubxml new file mode 100644 index 0000000..d0d2ce9 --- /dev/null +++ b/ARW.WebApi/Properties/PublishProfiles/FolderProfile2.pubxml @@ -0,0 +1,16 @@ + + + + + False + False + True + Release + Any CPU + FileSystem + bin\Release\net6.0\publish\ + FileSystem + + \ No newline at end of file diff --git a/ARW.WebApi/appsettings.json b/ARW.WebApi/appsettings.json new file mode 100644 index 0000000..efedd49 --- /dev/null +++ b/ARW.WebApi/appsettings.json @@ -0,0 +1,157 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "ConnectionStrings": { + "conn_db": "server=47.242.159.172;Database=net_template;Uid=net_template;Pwd=pZLC23cAmRCKmCKf;SslMode=none;CharSet=utf8mb4;AllowLoadLocalInfile=true;AllowUserVariables=true;", + //"conn_db": "server=127.0.0.1;Database= net_template;Uid=root;Pwd=root;SslMode=none;CharSet=utf8mb4;AllowLoadLocalInfile=true;AllowUserVariables=true;", + "conn_db_type": "8" //数据库类型 MySql = 0, SqlServer = 1 + }, + "urls": "http://localhost:8888", //项目启动url,如果改动端口前端对应devServer也需要进行修改 + "corsUrls": "http://localhost:8887", //跨域地址(前端启动项目,前后端分离单独部署需要设置),多个用","隔开 + "JwtSettings": { + "Issuer": "ARWAdmin.NET", + "Audience": "ARWAdmin.NET", + "SecretKey": "SecretKey-ARWADMIN.NET-20210101", + "Expire": 1440 //jwt登录过期时间(分) + }, + "InitDb": false, //是否初始化db + "DemoMode": false, //是否演示模式 + "Upload": { + "UploadUrl": "http://localhost:8888", //本地存储资源访问路径 + "localSavePath": "uploads" //本地上传默认文件存储目录 wwwroot/uploads + }, + //阿里云存储配置 + "AARWYUN_OSS": { + "REGIONID": "oss-cn-shenzhen.aliyuncs.com", + "KEY": "LTAI5tLGSBenBxmdvZB4TpVg", + "SECRET": "OR1kPyaOAP7q4zEtsmEqepZcyWG1yh", + "bucketName": "aerwen", + "domainUrl": "http://119.23.54.43/oss" //访问资源域名 + }, + //阿里云短信配置 + "AARWYUN_MSG": { + "signName": "阿里云短信测试", + "accessKeyId": "LTAI5tLGSBenBxmdvZB4TpVg", + "accessSecret": "OR1kPyaOAP7q4zEtsmEqepZcyWG1yh", + "templateCode": "SMS_154950909" + }, + "gen": { + "conn": "server=47.242.159.172;Database=net_template;Uid=net_template;Pwd=pZLC23cAmRCKmCKf;SslMode=none;CharSet=utf8mb4;AllowLoadLocalInfile=true;AllowUserVariables=true;", + //"conn": "server=127.0.0.1;Database= net_template;Uid=root;Pwd=root;SslMode=none;CharSet=utf8mb4;AllowLoadLocalInfile=true;AllowUserVariables=true;", + "dbType": 8, //MySql = 0, SqlServer = 1 + "autoPre": true, //自动去除表前缀 + "author": "admin", + "tablePrefix": "tb_", //"表前缀(生成类名不会包含表前缀,多个用逗号分隔)", + "vuePath": "D:\\.Net\\Aerwen\\wpf\\\tnet_template_new_back" //前端代码存储路径eg:D:\Work\ARWAdmin-Vue3 + }, + //邮箱配置信息 + "MailOptions": { + //发送人邮箱 + "From": "2679599887@qq.com", //eg:xxxx@qq.com + //发送人邮箱密码 + "Password": "njxixccztolbeaaf", + //协议 + "Smtp": "smtp.qq.com", + "Port": 465, + "Signature": "" + }, + //redis服务配置 + "RedisServer": { + "Cache": "127.0.0.1:6379,defaultDatabase=0,poolsize=50,ssl=false,writeBuffer=10240,prefix=cache:", + "Session": "127.0.0.1:6379,defaultDatabase=0,poolsize=50,ssl=false,writeBuffer=10240,prefix=session:" + }, + //接口请求限制 + "IpRateLimiting": { + "EnableEndpointRateLimiting": true, + "StackBlockedRequests": false, + "RealIpHeader": "X-Real-IP", + "ClientIdHeader": "X-ClientId", + "HttpStatusCode": 429, + "EndpointWhitelist": [ "post:/system/dict/data/types", "*:/msghub/negotiate", "*:/LogOut" ], + "QuotaExceededResponse": { + "Content": "{{\"code\":429,\"msg\":\"访问过于频繁,请稍后重试\"}}", + "ContentType": "application/json", + "StatusCode": 429 + }, + //通用规则,api规则,结尾一定要带* + "GeneralRules": [ + { + "Endpoint": "*:/captchaImage", + //时间段,格式:{数字}{单位};可使用单位:s, m, h, d + "Period": "3s", + "Limit": 5 + }, + { + "Endpoint": "post:*", + //时间段,格式:{数字}{单位};可使用单位:s, m, h, d + "Period": "3s", + "Limit": 1 + }, + { + "Endpoint": "put:*", + //时间段,格式:{数字}{单位};可使用单位:s, m, h, d + "Period": "3s", + "Limit": 1 + } + ], + "IpRateLimitPolicies": { + //ip规则 + "IpRules": [ + ] + } + }, + "CrawlerConfigs": { + "crawler": [ + { + "name": "yellow", + "hosts": [ + + ] + }, + { + "name": "buxiuse", + "hosts": [ + "https://www.buxiuse.com/?page=1" + ] + } + ] + }, + //Senparc.Weixin SDK 设置 + "SenparcWeixinSetting": { + //以下为 Senparc.Weixin 的 SenparcWeixinSetting 微信配置 + //注意:所有的字符串值都可能被用于字典索引,因此请勿留空字符串(但可以根据需要,删除对应的整条设置)! + + //微信全局 + "IsDebug": true, + + //以下不使用的参数可以删除,key 修改后将会失效 + + //公众号 + "Token": "63_I_BSEoa_qwlHgGSVxLmyNylHJ11ejzc9_WiWPRt64sDetCJe9CLU9YwVbL-VoAjqCH0Pg5QElGL4p_B2z63SKG9jj-dRPp-BD1gpiaAe6uxrwocfFeX4JXepvgcRAGhACAHQW", + "EncodingAESKey": "", //公众号解密秘钥 + "WeixinAppId": "wx99caf571c9fb1cc5", //公众号AppId + "WeixinAppSecret": "61100d9c4fff5acf97517f0c8799e2e2", //公众号秘钥 + + //微信支付V3 + "TenPayV3_AppId": "wx34436769371ceb7c", // 小程序AppId + "TenPayV3_AppSecret": "8ded49f94c8e607de7cc4244639d4666", // 小程序AppSecret + "TenPayV3_SubAppId": "", //子小程序AppId,没有可留空 + "TenPayV3_SubAppSecret": "", //子小程序AppSecret,没有可留空 + "TenPayV3_MchId": "1626418383", //商户号 + "TenPayV3_SubMchId": "", //子商户,没有可留空 + "TenPayV3_Key": "", // (旧) Key + "TenPayV3_CertPath": "C:\\Users\\PC\\Desktop\\ARW2.0\\ARW-net\\ARW.WebApi\\WeChat\\certificate", //支付证书物理路径,如:D:\\cert\\apiclient_cert.p12 + "TenPayV3_CertSecret": "1626418383", //支付证书密码(原始密码和 MchId 相同) + "TenPayV3_TenpayNotify": "http://aerwen.net/prod-api/api/WxPay/Notify", // 回调方法 + "TenPayV3_WxOpenNotify": "http://aerwen.net/prod-api/api/WxPay/Notify", // 小程序回调方法 + "TenPayV3_PrivateKey": "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDfVjagN3LpB6EdUx1YQvKlIsVhJyLkpezWRd8Sq7G65i0Z9YnhzJ4LA5YCgfdzwywrFjy/Dps60YYbS8vfVvuyrobP5Y143ID9i2nB8oZOBZERJKHwc3sdYKL3upOQUx+2k+Sd15iWlUCGSdsU8KE/k6aprvAkKjhdGRdQwgEd8KycOTjGIPYM1MoHcAI7JTjelEoggcCCxKHRHX3ASGw2WZbj0xAEAWmxBGQ9+KPrFtg4rqFB69sk/V9cb5lF/hy5sJf44FYS/UowH9xIrf0niC5j5ROSAbPI4nCa/N6LpNFQzLHQ0aOJWdStjZwdU3iqo5WMtXruPwv+dr6Fe8DBAgMBAAECggEARUwr8PSjjBjY7g9vCIblYUXztpx9IDM31JijidiKcjKfhfGBEfX6h/JZ5ndLP7ksiEYDHUk78zk2Alw3axpDSQMMQ4+3oOvSfll2vD4zXBwwEgCq2sAKUGg+yN00klCog29KPYu7BeZTuhdKiinL7r0ytm3Yh3AuQvzZFi7MR+xkK6wwcGlMdnK3WkwOsAb4g77xg0Iek4TC150RK5jLbAOW/9/jaz/QSjJZzgbqpUNMJaeXjT0rUx8cGOSXpRxziSJNFGcX5BwozcdIhp3PHx/VugfliPcfr7HP6FVMLX3jhNAKE32UQyaq/2bCSy9mnbaRubho6jDur5vp+vBVAQKBgQD5wfjFUavsEBsbt0DjXw6D2Qjj67U9ccgqQjzUPFbeYb+awmXOPCqb5as1dkaZ71f+whv7nWKL+P6f3TIsM1Pz8nL/lm0LxjLO50n/JxjIR6GGQ/vCGtJb84c+gavJ49y3SjsMAVWTvTHZYUj/mYYZ7Urnuz0nb1hJqlahWb1VEQKBgQDk6zE0QzL/fbYYc7fQQ8O2ddvnSuwwNZDjasXpuWXAYNTqGNrhIdLBiEpj9uIO3Z7UhCjoh+mFWhDcbUQ+G0l6rQHE3Z7IMFBOHZDCGoQgWuwsMuz8tGXIa5nrdZ4ep2DB4VxsGGFJqRiopj7f5IDRbNlifmr2CfzxVGHcDJTwsQKBgCdvhURCvQ6tDFq3+LruC3CuGEVEtn1ZNe3WP5yTWnQKoyJgh4qk3WV4QixS3Jr5u78yDxEPrLvFOQ8s8fsgr6TZJ2dL7TPqu6MHyhtLpRIanVqB6YKgkY6LSVOJTgK2w+b9BY3DuCt3uCNGxSv2pcH6QdWNLv7HCf23s64OaWLBAoGAF/OHtWkmh9bWW56X5+F/M7MHLB8JsU2ZeEHurTKps8Qt4sRw+kc4rukcp3LoWhfUC3Y8dX/q7fnrc7S3BCyEtqItYjSx7U4oyNONFtIBawU4WrOFWjdhwuOHOjyXK6vlksOKkQDIBRX9L4Adaf2VgNP7trN1a4LGBVYH2ycx2jECgYBM/Ge2QKkRXaVkfmbnJ6ZPg0KIAZJ7tL7GxAICVeqZ4OeqyQP9cFvaJjdvGnE2B0xo2ApZhLgzno+pZRd4tnV3IHXBeHyMhAGZ5I4r4shwzF4U84FZk7bg/CeyNyyv7Ljflw7erlDMDCr/xvloerwzwggxHc35JUCiT5FI02jWhQ==", //(新)证书私钥 + "TenPayV3_SerialNumber": "1BD546C97BFA3BF71672C6915AC4E9E1EAE9C90E", //(新)证书序列号 + "TenPayV3_ApiV3Key": "CHOFVQJOXBJEWZJEJKUWTHUBOSVQBRIW" //(新)APIv3 密钥 + } + +} diff --git a/ARW.WebApi/ip2region.db b/ARW.WebApi/ip2region.db new file mode 100644 index 0000000..0fc60e6 Binary files /dev/null and b/ARW.WebApi/ip2region.db differ diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/Add.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/Add.txt new file mode 100644 index 0000000..06b9695 --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/Add.txt @@ -0,0 +1,266 @@ + + + + \ No newline at end of file diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/CurdForm.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/CurdForm.txt new file mode 100644 index 0000000..bfc1360 --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/CurdForm.txt @@ -0,0 +1,108 @@ +$foreach(column in genTable.Columns) +$set(labelName = "") +$set(labelDisabled = "") +$set(columnName = column.CsharpFieldFl) +$set(value = "item.dictValue") +$if(column.ColumnComment != "") +$set(labelName = column.ColumnComment) +$else +$set(labelName = column.CsharpFieldFl) +$end +$if(column.IsPk == true) +$set(labelDisabled = ":disabled=true") +$end +$if(column.CsharpType == "int" || column.CsharpType == "long") + $set(value = "parseInt(item.dictValue)") +$end + +$if(tool.CheckInputDtoNoField(column.CsharpField)) +$elseif(column.IsInsert == false && column.IsEdit == false) + + {{form.${columnName}}} + +$elseif(tool.CheckTree(genTable ,column.CsharpField)) + + + + + +$elseif(column.IsPK || column.IsIncrement) + + +$if(column.IsIncrement == false) + +$else + +$end + + +$else +$if(column.HtmlType == "inputNumber") + + + + + +$elseif(column.HtmlType == "datetime") + + + + + +$elseif(column.HtmlType == "imageUpload") + + + + + +$elseif(column.HtmlType == "fileUpload") + + + + + +$elseif(column.HtmlType == "radio") + + + + {{item.dictLabel}} + + + +$elseif(column.HtmlType == "textarea") + + + + + +$elseif(column.HtmlType == "editor") + + + + + +$elseif(column.HtmlType == "select") + + + + + + + +$elseif(column.HtmlType == "checkbox") + + + + {{item.dictLabel}} + + + +$else + + + + + +$end +$end +$end \ No newline at end of file diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/Detail.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/Detail.txt new file mode 100644 index 0000000..76023da --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/Detail.txt @@ -0,0 +1,223 @@ + + + diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/Edit.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/Edit.txt new file mode 100644 index 0000000..7be3345 --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/Edit.txt @@ -0,0 +1,278 @@ + + + diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/MySqlTemplate.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/MySqlTemplate.txt new file mode 100644 index 0000000..7bc0746 --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/MySqlTemplate.txt @@ -0,0 +1,31 @@ + +-- 菜单 +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time) +VALUES ('${genTable.functionName}', ${parentId}, 999, '${genTable.BusinessName}', 'business/${options.SubNamespace}/index', 0, 0, 'C', '0', '0', '$if(genTable.TplCategory == "tree")${replaceDto.PermissionPrefix}:treelist$else${replaceDto.PermissionPrefix}:list$end', '', 'system', sysdate()); + +-- 按钮父菜单id +SET @menuId := LAST_INSERT_ID(); + +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time) +VALUES ('新增或删除', @menuId, 1, '#', NULL, 0, 0, 'F', '0', '0', '${replaceDto.PermissionPrefix}:addOrUpdate', '', 'system', sysdate()); + +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time) +VALUES ('删除', @menuId, 2, '#', NULL, 0, 0, 'F', '0', '0', '${replaceDto.PermissionPrefix}:delete', '', 'system', sysdate()); + +$if(replaceDto.ShowBtnImport) +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time) +VALUES ('导入', @menuId, 3, '#', NULL, 0, 0, 'F', '0', '0', '${replaceDto.PermissionPrefix}:import', '', 'system', sysdate()); +$end + +$if(replaceDto.ShowBtnExport) +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time) +VALUES ('导出', @menuId, 5, '#', NULL, 0, 0, 'F', '0', '0', '${replaceDto.PermissionPrefix}:export', '', 'system', sysdate()); +$end + +$if(replaceDto.ShowBtnAudit) +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time) +VALUES ('审核', @menuId, 6, '#', NULL, 0, 0, 'F', '0', '0', '${replaceDto.PermissionPrefix}:export', '', 'system', sysdate()); +$end + +SELECT * FROM sys_menu WHERE parentId = @menuId; +SELECT * FROM sys_menu WHERE menuId = @menuId; \ No newline at end of file diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/QueryForm.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/QueryForm.txt new file mode 100644 index 0000000..396efa9 --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/QueryForm.txt @@ -0,0 +1,33 @@ +$foreach(column in genTable.Columns) +$set(labelName = "") +$set(columnName = "") +$set(numLabel = "") +$if(column.IsQuery == true) + $set(columnName = column.CsharpFieldFl) + $if(column.ColumnComment != "") + $set(labelName = column.ColumnComment) + $else + $set(labelName = column.CsharpFieldFl) + $end + $if(column.CsharpType == "int" || column.CsharpType == "long") + $set(numLabel = ".number") + $end + +$if(column.HtmlType == "datetime") + + + +$elseif(column.HtmlType == "select" || column.HtmlType == "radio") + + + + + +$else + + + +$end +$end +$end \ No newline at end of file diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/SqlTemplate.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/SqlTemplate.txt new file mode 100644 index 0000000..011cbf1 --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/SqlTemplate.txt @@ -0,0 +1,39 @@ +use LiAdmin; + +-- ${genTable.functionName}菜单 +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time) +VALUES ('${genTable.functionName}', ${parentId}, 999, '${genTable.BusinessName}', '${tool.FirstLowerCase(genTable.ModuleName)}/${genTable.BusinessName}', 0, 0, 'C', '0', '0', '${replaceDto.PermissionPrefix}:list', 'icon1', 'system', GETDATE()); + +-- 按钮父菜单id +declare @menuId int = @@identity + + +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by,create_time) +VALUES ('查询', @menuId, 1, '#', NULL, 0, 0, 'F', '0', '0', '${replaceDto.PermissionPrefix}:query', '', 'system', GETDATE()); + +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by,create_time) +VALUES ('新增', @menuId, 2, '#', NULL, 0, 0, 'F', '0', '0', '${replaceDto.PermissionPrefix}:add', '', 'system', GETDATE()); + +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by,create_time) +VALUES ('删除', @menuId, 3, '#', NULL, 0, 0, 'F', '0', '0', '${replaceDto.PermissionPrefix}:delete', '', 'system', GETDATE()); + +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by,create_time) +VALUES ('修改', @menuId, 4, '#', NULL, 0, 0, 'F', '0', '0', '${replaceDto.PermissionPrefix}:edit', '', 'system', GETDATE()); + +$if(replaceDto.ShowBtnExport) +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by,create_time) +VALUES ('导出', @menuId, 5, '#', NULL, 0, 0, 'F', '0', '0', '${replaceDto.PermissionPrefix}:export', '', 'system', GETDATE()); +$end + +$if(replaceDto.ShowBtnImport) +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by,create_time) +VALUES ('导入', @menuId, 6, '#', NULL, 0, 0, 'F', '0', '0', '${replaceDto.PermissionPrefix}:import', '', 'system', GETDATE()); +$end + +$if(replaceDto.ShowBtnAudit) +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by,create_time) +VALUES ('审核', @menuId, 7, '#', NULL, 0, 0, 'F', '0', '0', '${replaceDto.PermissionPrefix}:audit', '', 'system', GETDATE()); +$end + +SELECT * FROM sys_menu WHERE parentId = @menuId; +SELECT * FROM sys_menu WHERE menuId = @menuId; \ No newline at end of file diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/TableList.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/TableList.txt new file mode 100644 index 0000000..eb32a34 --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/TableList.txt @@ -0,0 +1,45 @@ +$foreach(column in genTable.Columns) +$set(labelName = "") +$set(checkboxHtml = "") +$set(showToolTipHtml = "") +$set(columnName = column.CsharpFieldFl) +$if(column.CsharpType == "string" || column.HtmlType == "datetime") +$set(showToolTipHtml = " :show-overflow-tooltip=\"true\"") +$end +$if(column.ColumnComment != "") +$set(labelName = column.ColumnComment) +$else +$set(labelName = column.CsharpFieldFl) +$end +$if(column.IsList == true) +$if(column.HtmlType == "customInput" && column.IsPk == false) + + + +$elseif(column.HtmlType == "imageUpload") + + + +$elseif(column.HtmlType == "checkbox" || column.HtmlType == "select" || column.HtmlType == "radio") + + + +$else + +$end +$end +$end \ No newline at end of file diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/TplControllers.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/TplControllers.txt new file mode 100644 index 0000000..0fc1d48 --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/TplControllers.txt @@ -0,0 +1,261 @@ +using Infrastructure; +using Infrastructure.Attribute; +using Infrastructure.Enums; +using Infrastructure.Model; +using Mapster; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using ARW.Admin.WebApi.Extensions; +using ARW.Admin.WebApi.Filters; +using ARW.Common; +using ARW.Model.Dto.Business.${genTable.moduleName}; +using ARW.Service.Business.IBusinessService.${genTable.moduleName}; +using ARW.Admin.WebApi.Controllers; +using ARW.Model.Models.Business.${genTable.moduleName}; +using ARW.Model.Vo.Business.${genTable.moduleName}; +using Microsoft.AspNetCore.Authorization; +using ARW.Admin.WebApi.Framework; + + +namespace ${options.ApiControllerNamespace}.Controllers.Business.${genTable.moduleName} +{ + /// + /// ${genTable.FunctionName}控制器 + /// + [Verify] + [Route("business/[controller]")] + public class ${replaceDto.ModelTypeName}Controller : BaseController + { + private readonly I${replaceDto.ModelTypeName}Service _${replaceDto.ModelTypeName}Service; + + /// + /// 依赖注入 + /// + /// ${genTable.FunctionName}服务 + public ${replaceDto.ModelTypeName}Controller(I${replaceDto.ModelTypeName}Service ${replaceDto.ModelTypeName}Service) + { + _${replaceDto.ModelTypeName}Service = ${replaceDto.ModelTypeName}Service; + } + + +$if(genTable.TplCategory == "tree") + /// + /// 获取${genTable.FunctionName}树形列表 + /// + /// 查询参数 + /// + [HttpGet("get${replaceDto.ModelTypeName}TreeList")] + [ActionPermissionFilter(Permission = "${replaceDto.PermissionPrefix}:treelist")] + public async Task Get${replaceDto.ModelTypeName}List([FromQuery] ${replaceDto.ModelTypeName}QueryDto parm) + { + var res = await _${replaceDto.ModelTypeName}Service.Get${replaceDto.ModelTypeName}TreeList(parm); + res ??= new List<${replaceDto.ModelTypeName}Vo>(); + + return SUCCESS(res); + } +$else + /// + /// 获取${genTable.FunctionName}列表 + /// + /// 查询参数 + /// + [HttpGet("get${replaceDto.ModelTypeName}List")] + [ActionPermissionFilter(Permission = "${replaceDto.PermissionPrefix}:list")] + public async Task Get${replaceDto.ModelTypeName}List([FromQuery] ${replaceDto.ModelTypeName}QueryDto parm) + { + var res = await _${replaceDto.ModelTypeName}Service.Get${replaceDto.ModelTypeName}List(parm); + return SUCCESS(res); + } +$end + + /// + /// 添加或修改${genTable.FunctionName} + /// + /// + /// + [HttpPost("addOrUpdate${replaceDto.ModelTypeName}")] + [ActionPermissionFilter(Permission = "${replaceDto.PermissionPrefix}:addOrUpdate")] + [Log(Title = "添加或修改${genTable.FunctionName}", BusinessType = BusinessType.ADDORUPDATE)] + public async Task AddOrUpdate${replaceDto.ModelTypeName}([FromBody] ${replaceDto.ModelTypeName}Dto parm) + { + if (parm == null) { throw new CustomException("请求参数错误"); } + + var modal = new ${replaceDto.ModelTypeName}(); + if (parm.${replaceDto.ModelTypeName}Id != 0) modal = parm.Adapt<${replaceDto.ModelTypeName}>().ToUpdate(HttpContext); + else modal = parm.Adapt<${replaceDto.ModelTypeName}>().ToCreate(HttpContext); + + var res = await _${replaceDto.ModelTypeName}Service.AddOrUpdate${replaceDto.ModelTypeName}(modal); + return SUCCESS(res); + } + +$if(replaceDto.ShowBtnDelete) + /// + /// 删除${genTable.FunctionName} + /// + /// + [HttpDelete("{ids}")] + [ActionPermissionFilter(Permission = "${replaceDto.PermissionPrefix}:delete")] + [Log(Title = "${genTable.FunctionName}删除", BusinessType = BusinessType.DELETE)] + public IActionResult Delete(string ids) + { + long[] idsArr = Tools.SpitLongArrary(ids); + if (idsArr.Length <= 0) { return ToResponse(ApiResult.Error($"删除失败Id 不能为空")); } + var response = _${replaceDto.ModelTypeName}Service.Delete(idsArr); + return SUCCESS("删除成功!"); + } +$end + +$if(replaceDto.ShowBtnImport) + /// + /// 导入${genTable.FunctionName} + /// + /// 使用IFromFile必须使用name属性否则获取不到文件 + /// 是否需要更新 + /// + [HttpPost("importData")] + [Log(Title = "${genTable.FunctionName}导入", BusinessType = BusinessType.IMPORT, IsSaveRequestData = false, IsSaveResponseData = false)] + [ActionPermissionFilter(Permission = "business:${replaceDto.PermissionPrefix}:import")] + public async Task ImportExcel([FromForm(Name = "file")] IFormFile formFile,bool updateSupport) + { + var isUpdateSupport = updateSupport; + IEnumerable<${replaceDto.ModelTypeName}Vo> parm = ExcelHelper<${replaceDto.ModelTypeName}Vo>.ImportData(formFile.OpenReadStream()); + + var i = 0; + var msgList = new List(); + foreach (${replaceDto.ModelTypeName}Vo item in parm) + { + i++; + var ${replaceDto.ModelTypeName} = await _${replaceDto.ModelTypeName}Service.HandleImportData(item); + var modal = ${replaceDto.ModelTypeName}.Adapt<${replaceDto.ModelTypeName}>().ToCreate(HttpContext); + var user = JwtUtil.GetLoginUser(App.HttpContext).UserName; + var msg = await _${replaceDto.ModelTypeName}Service.ImportExcel(modal,i,isUpdateSupport,user); + msgList.Add(msg); + } + + return SUCCESS(msgList.ToArray()); + } + + + /// + /// ${genTable.FunctionName}导入模板下载 + /// + /// + [HttpGet("importTemplate")] + [Log(Title = "${genTable.FunctionName}模板", BusinessType = BusinessType.EXPORT, IsSaveRequestData = false, IsSaveResponseData = false)] + [AllowAnonymous] + public IActionResult ImportTemplateExcel() + { + List<${replaceDto.ModelTypeName}Vo> ${replaceDto.ModelTypeName} = new List<${replaceDto.ModelTypeName}Vo>(); + MemoryStream stream = new MemoryStream(); + + // 示例数据 +$if(genTable.TplCategory != "tree") + var values = new List() { "111", "222", "333" }; + string sFileName = DownloadImportTemplate(${replaceDto.ModelTypeName}, stream, "${genTable.FunctionName}导入模板", values); +$else + var allValues = new List>(); + var values = new List() { "111", "222", "333" }; + var values2 = new List() { "444", "555", "666" }; + allValues.Add(values); + allValues.Add(values2); + string sFileName = DownloadImportTemplate(${replaceDto.ModelTypeName}, stream, "${genTable.FunctionName}导入模板", allValues); +$end + + return File(stream.ToArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", $"{sFileName}"); + } +$end + +$if(replaceDto.ShowBtnExport) + /// + /// 导出${genTable.FunctionName} + /// + /// + [Log(Title = "${genTable.FunctionName}导出", BusinessType = BusinessType.EXPORT, IsSaveResponseData = false)] + [HttpGet("export${replaceDto.ModelTypeName}")] + [ActionPermissionFilter(Permission = "${replaceDto.PermissionPrefix}:export")] + public async Task ExportExcel([FromQuery] ${replaceDto.ModelTypeName}QueryDto parm) + { +$if(genTable.TplCategory == "tree") + var list = await _${replaceDto.ModelTypeName}Service.Get${replaceDto.ModelTypeName}List(parm); + var data = list; + + // 选中数据 + if (!string.IsNullOrEmpty(parm.ids)) + { + int[] idsArr = Tools.SpitIntArrary(parm.ids); + var selectDataList = new List<${replaceDto.ModelTypeName}Vo>(); + foreach (var item in idsArr) + { + var select_data = data.Where(s => s.${replaceDto.ModelTypeName}Id == item).First(); + selectDataList.Add(select_data); + + // 查看当前数据有没有子级 + var new${replaceDto.ModelTypeName}s = data.FindAll(delegate (${replaceDto.ModelTypeName}Vo ${tool.FirstLowerCase(replaceDto.ModelTypeName)}) + { + string[] parent${replaceDto.ModelTypeName}Id = ${tool.FirstLowerCase(replaceDto.ModelTypeName)}.${replaceDto.ModelTypeName}AncestralGuid.Split(",", StringSplitOptions.RemoveEmptyEntries); + return parent${replaceDto.ModelTypeName}Id.Contains(select_data.${replaceDto.ModelTypeName}Guid.ToString()); + }); + string[] ${tool.FirstLowerCase(replaceDto.ModelTypeName)}Arr = new${replaceDto.ModelTypeName}s.Select(x => x.${replaceDto.ModelTypeName}Guid.ToString()).ToArray(); + var ancestorArr = data.Where(s => ${tool.FirstLowerCase(replaceDto.ModelTypeName)}Arr.Contains(s.${replaceDto.ModelTypeName}Guid.ToString())).ToList(); + selectDataList.AddRange(ancestorArr); + } + data = selectDataList; + } +$else + parm.PageSize = 10000; + var list = await _${replaceDto.ModelTypeName}Service.Get${replaceDto.ModelTypeName}List(parm); + var data = list.Result; + + // 选中数据 + if (!string.IsNullOrEmpty(parm.ids)) + { + int[] idsArr = Tools.SpitIntArrary(parm.ids); + var selectDataList = new List<${replaceDto.ModelTypeName}Vo>(); + foreach (var item in idsArr) + { + var select_data = data.Where(s => s.${replaceDto.ModelTypeName}Id == item).First(); + selectDataList.Add(select_data); + } + data = selectDataList; + } +$end + + + + // 导出数据处理 + var handleData = await _${replaceDto.ModelTypeName}Service.HandleExportData(data); + + string sFileName = ExportExcel(handleData, "${replaceDto.ModelTypeName}", "${genTable.FunctionName}列表"); + return SUCCESS(new { path = "/export/" + sFileName, fileName = sFileName }); + } +$end + +$if(replaceDto.ShowBtnAudit) + /// + /// 审核${genTable.FunctionName} + /// + /// + [HttpPut("audit")] + [ActionPermissionFilter(Permission = "${replaceDto.PermissionPrefix}:audit")] + [Log(Title = "审核${genTable.FunctionName}", BusinessType = BusinessType.AUDIT)] + public async Task Audit${replaceDto.ModelTypeName}([FromBody] ${replaceDto.ModelTypeName}AuditDto param) + { + var user = JwtUtil.GetLoginUser(App.HttpContext); + int[] idsArr = Tools.SpitIntArrary(param.ids); + if (idsArr.Length <= 0) { return ToResponse(ApiResult.Error($"审核失败 Id 不能为空")); } + + var msgList = new List(); + foreach (var item in idsArr) + { + var msg = await _${replaceDto.ModelTypeName}Service.Audit(item, param.${replaceDto.ModelTypeName}AuditStatus, user.UserId); + msgList.Add(msg); + } + + return SUCCESS(msgList.ToArray()); + } +$end + + + + } +} diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/TplControllersApi.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/TplControllersApi.txt new file mode 100644 index 0000000..5538416 --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/TplControllersApi.txt @@ -0,0 +1,95 @@ +using Infrastructure; +using Infrastructure.Attribute; +using Infrastructure.Enums; +using Infrastructure.Model; +using Mapster; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using ARW.Admin.WebApi.Extensions; +using ARW.Admin.WebApi.Filters; +using ARW.Common; +using ARW.Admin.WebApi.Controllers; +using ARW.Model.Dto.Api.${genTable.moduleName}; +using ARW.Service.Api.IBusinessService.${genTable.moduleName}; +using ARW.Model.Models.Business.${genTable.moduleName}; +using ARW.Model.Vo.Api.${genTable.moduleName}; +using Microsoft.AspNetCore.Authorization; +using Geocoding; + +namespace ${options.ApiControllerNamespace}.Controllers.Api.${genTable.moduleName} +{ + /// + /// ${genTable.FunctionName}控制器Api + /// + [Verify] + [Route("api/[controller]")] + public class ${replaceDto.ModelTypeName}ApiController : BaseController + { + private readonly I${replaceDto.ModelTypeName}ServiceApi _${replaceDto.ModelTypeName}ServiceApi; + + /// + /// 依赖注入 + /// + /// ${genTable.FunctionName}${genTable.FunctionName}Api服务 + public ${replaceDto.ModelTypeName}ApiController(I${replaceDto.ModelTypeName}ServiceApi ${replaceDto.ModelTypeName}ServiceApi) + { + _${replaceDto.ModelTypeName}ServiceApi = ${replaceDto.ModelTypeName}ServiceApi; + } + + +$if(genTable.TplCategory == "tree") + /// + /// 获取${genTable.FunctionName}树形列表(Api) + /// + /// 查询参数 + /// + [HttpGet("get${replaceDto.ModelTypeName}TreeList")] + public async Task Get${replaceDto.ModelTypeName}TreeListApi([FromQuery] ${replaceDto.ModelTypeName}QueryDtoApi parm) + { + var res = await _${replaceDto.ModelTypeName}ServiceApi.Get${replaceDto.ModelTypeName}TreeListApi(parm); + if (res == null) + res = new List<${replaceDto.ModelTypeName}VoApi>(); + + return SUCCESS(res); + } +$else + /// + /// 获取${genTable.FunctionName}列表(Api) + /// + /// 查询参数 + /// + [HttpGet("get${replaceDto.ModelTypeName}List")] + public async Task Get${replaceDto.ModelTypeName}ListApi([FromQuery] ${replaceDto.ModelTypeName}QueryDtoApi parm) + { + var res = await _${replaceDto.ModelTypeName}ServiceApi.Get${replaceDto.ModelTypeName}ListApi(parm); + return SUCCESS(res); + } +$end + + /// + /// 获取${replaceDto.ModelTypeName}详情(Api) + /// + /// 查询参数 + /// + [HttpGet("get${replaceDto.ModelTypeName}Details")] + public async Task Get${replaceDto.ModelTypeName}Details([FromQuery] ${replaceDto.ModelTypeName}DtoApi parm) + { + //if (parm == null) throw new CustomException("参数错误!"); + + var res = await _${replaceDto.ModelTypeName}ServiceApi.Get${replaceDto.ModelTypeName}Details(parm); + + if (res != "[]") + { + res = res.Remove(0, 1); + res = res.Substring(0, res.Length - 1); + var data = res.FromJSON<${replaceDto.ModelTypeName}ApiDetailsVo>(); + return SUCCESS(data); + } + else + { + return SUCCESS(res); + } + } + + } +} diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/TplDto.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/TplDto.txt new file mode 100644 index 0000000..31dc9c1 --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/TplDto.txt @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using ${options.ModelsNamespace}.Models.Business.${genTable.moduleName}; + +namespace ${options.DtosNamespace}.Dto.Business.${genTable.moduleName} +{ + /// + /// ${genTable.FunctionName}输入对象 + /// + public class ${replaceDto.ModelTypeName}Dto + { +$foreach(item in genTable.Columns) +$if(item.IsInit != true) +$if((item.IsInsert || item.IsEdit || item.IsPk || item.IsIncrement)) +$if(item.IsRequired) +$if(item.IsPk != true) + [Required(ErrorMessage = "${item.ColumnComment}不能为空")] +$end +$end + public $item.CsharpType$item.RequiredStr $item.CsharpField { get; set; } +$end +$end +$end + } + + + /// + /// ${genTable.FunctionName}查询对象 + /// + public class ${replaceDto.ModelTypeName}QueryDto : PagerInfo + { +$foreach(item in genTable.Columns) +$if(item.IsQuery && item.htmlType == "datetime") + public DateTime? BeginTime { get; set; } + public DateTime? EndTime { get; set; } +$elseif(item.IsQuery) + public $item.CsharpType$if(item.CsharpType != "string")?$end $item.CsharpField { get; set; } +$end +$end + + public string ids { get; set; } + } + + +$if(replaceDto.ShowBtnAudit) + /// + /// 审核对象 + /// + public class ${replaceDto.ModelTypeName}AuditDto + { + public int ${replaceDto.ModelTypeName}AuditStatus { get; set; } + public string ids { get; set; } + } +$end + + +} diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/TplDtoApi.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/TplDtoApi.txt new file mode 100644 index 0000000..2e2b21b --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/TplDtoApi.txt @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using ${options.ModelsNamespace}.Models.Business.${genTable.moduleName}; + +namespace ${options.DtosNamespace}.Dto.Api.${genTable.moduleName} +{ + + /// + /// ${genTable.FunctionName}查询对象Api + /// + public class ${replaceDto.ModelTypeName}QueryDtoApi : PagerInfo + { +$foreach(item in genTable.Columns) +$if(item.IsQuery && item.htmlType == "datetime") + public DateTime? Begin$item.CsharpField { get; set; } + public DateTime? End$item.CsharpField { get; set; } +$elseif(item.IsQuery) + public $item.CsharpType$if(item.CsharpType != "string")?$end $item.CsharpField { get; set; } +$end +$end + } + + + /// + /// ${genTable.FunctionName}详情输入对象Api + /// + public class ${replaceDto.ModelTypeName}DtoApi + { + [Required(ErrorMessage = "${replaceDto.ModelTypeName}Guid不能为空")] + public long ${replaceDto.ModelTypeName}Guid { get; set; } + } + +} diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/TplIService.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/TplIService.txt new file mode 100644 index 0000000..cf40eec --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/TplIService.txt @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ARW.Model; +using ARW.Model.Dto.Business.${genTable.moduleName}; +using ARW.Model.Models.Business.${genTable.moduleName}; +using ARW.Model.Vo.Business.${genTable.moduleName}; + +namespace ARW.Service.Business.IBusinessService.${genTable.moduleName} +{ + public interface I${replaceDto.ModelTypeName}Service : IBaseService<${replaceDto.ModelTypeName}> + { +$if(genTable.TplCategory == "tree") + /// + /// 获取${genTable.FunctionName}树形列表 + /// + /// + /// + Task> Get${replaceDto.ModelTypeName}TreeList(${replaceDto.ModelTypeName}QueryDto parm); + + /// + /// 获取${genTable.FunctionName}列表 + /// + /// + /// + Task> Get${replaceDto.ModelTypeName}List(${replaceDto.ModelTypeName}QueryDto parm); +$else + /// + /// 获取${genTable.FunctionName}分页列表 + /// + /// + /// + Task> Get${replaceDto.ModelTypeName}List(${replaceDto.ModelTypeName}QueryDto parm); +$end + + + /// + /// 添加或修改${genTable.FunctionName} + /// + /// + /// + Task AddOrUpdate${replaceDto.ModelTypeName}(${replaceDto.ModelTypeName} parm); + + +$if(replaceDto.ShowBtnImport) + /// + /// 数据导入处理 + /// + /// + /// + Task<${replaceDto.ModelTypeName}Vo> HandleImportData(${replaceDto.ModelTypeName}Vo ${replaceDto.ModelTypeName}Vo); + + + /// + /// Excel导入 + /// + /// + /// + Task ImportExcel(${replaceDto.ModelTypeName} ${replaceDto.ModelTypeName},int index,bool isUpdateSupport,string user); +$end + +$if(replaceDto.ShowBtnExport) + /// + /// Excel导出 + /// + Task> HandleExportData(List<${replaceDto.ModelTypeName}Vo> data); +$end + +$if(replaceDto.ShowBtnAudit) + /// + /// 审核 + /// + Task Audit(int idsArr, int status,long userGuid); +$end + + } +} diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/TplIServiceApi.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/TplIServiceApi.txt new file mode 100644 index 0000000..440931f --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/TplIServiceApi.txt @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ARW.Model; +using ARW.Model.Dto.Api.${genTable.moduleName}; +using ARW.Model.Models.Business.${genTable.moduleName}; +using ARW.Model.Vo.Api.${genTable.moduleName}; + +namespace ARW.Service.Api.IBusinessService.${genTable.moduleName} +{ + public interface I${replaceDto.ModelTypeName}ServiceApi : IBaseService<${replaceDto.ModelTypeName}> + { +$if(genTable.TplCategory == "tree") + /// + /// 获取${genTable.FunctionName}树形列表(Api) + /// + /// + /// + Task> Get${replaceDto.ModelTypeName}TreeListApi(${replaceDto.ModelTypeName}QueryDtoApi parm); +$else + /// + /// 获取${genTable.FunctionName}分页列表(Api) + /// + /// + /// + Task> Get${replaceDto.ModelTypeName}ListApi(${replaceDto.ModelTypeName}QueryDtoApi parm); +$end + + /// + /// 获取${genTable.FunctionName}详情(Api) + /// + /// + /// + Task Get${replaceDto.ModelTypeName}Details(${replaceDto.ModelTypeName}DtoApi parm); + + } +} diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/TplModel.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/TplModel.txt new file mode 100644 index 0000000..c509f2e --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/TplModel.txt @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using SqlSugar; +using OfficeOpenXml.Attributes; +using Newtonsoft.Json; + +namespace ${options.ModelsNamespace}.Models.Business.${genTable.moduleName} +{ + /// + /// ${genTable.FunctionName},数据实体对象 + /// + /// @author ${replaceDto.Author} + /// @date ${replaceDto.AddTime} + /// + [SugarTable("${genTable.TableName}")] + public class ${replaceDto.ModelTypeName} : BusinessBase + { +$foreach(item in genTable.Columns) +$if(item.IsInit != true) + + /// + /// 描述 :${item.ColumnComment} ${item.Remark} + /// 空值 :$if(item.IsRequired == "True") false $else true $end + /// +$if(replaceDto.ShowBtnExport) + [EpplusTableColumn(Header = "$if(item.ColumnComment == "")${item.CsharpField}${else}${item.ColumnComment}${end}"$if(item.CsharpType == "DateTime"), NumberFormat = "yyyy-MM-dd HH:mm:ss"$end)] +$end +$if(item.IsGuid) + [JsonConverter(typeof(ValueToStringConverter))] +$end +$if(item.IsPk || item.IsIncrement) + [SugarColumn(IsPrimaryKey = ${item.IsPk.ToString().ToLower()}, IsIdentity = ${item.IsIncrement.ToString().ToLower()}$if(item.CsharpField.ToLower() != item.ColumnName.ToLower()), ColumnName = "$item.ColumnName"$end)] +$elseif(item.CsharpField.ToLower() != item.ColumnName.ToLower()) + [SugarColumn(ColumnName = "$item.ColumnName")] +$end + public $item.CsharpType$item.RequiredStr $item.CsharpField { get; set; } +$end + +${end} +$if(genTable.TplCategory == "tree") + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [SugarColumn(IsIgnore = true)] + public List<${replaceDto.ModelTypeName}> Children { get; set; } +$end +$if(genTable.TplCategory == "subNav" && genTable.SubTable != null) + [Navigate(NavigateType.Dynamic, null)] //自定义关系映射 + public ${genTable.SubTable.ClassName} ${genTable.SubTable.ClassName} { get; set; } +$end +$if(genTable.TplCategory == "subNavMore" && genTable.SubTable != null) + [Navigate(NavigateType.Dynamic, null)] //自定义关系映射 + public List<${genTable.SubTable.ClassName}> ${genTable.SubTable.ClassName} { get; set; } +$end + } +} \ No newline at end of file diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/TplRepository.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/TplRepository.txt new file mode 100644 index 0000000..87f8768 --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/TplRepository.txt @@ -0,0 +1,20 @@ +using System; +using Infrastructure.Attribute; +using ${options.RepositoriesNamespace}.System; +using ${options.ModelsNamespace}.Models.Business.${genTable.moduleName}; + +namespace ${options.RepositoriesNamespace}.Business.${genTable.moduleName} +{ + /// + /// ${genTable.FunctionName}仓储 + /// + /// @author ${replaceDto.Author} + /// @date ${replaceDto.AddTime} + /// + [AppService(ServiceLifetime = LifeTime.Transient)] + public class ${replaceDto.ModelTypeName}Repository : BaseRepository<${replaceDto.ModelTypeName}> + { + #region 业务逻辑代码 + #endregion + } +} \ No newline at end of file diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/TplService.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/TplService.txt new file mode 100644 index 0000000..0d799c5 --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/TplService.txt @@ -0,0 +1,324 @@ +using Infrastructure.Attribute; +using Microsoft.AspNetCore.Http; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Infrastructure; +using ARW.Model; +using ARW.Repository; +using ARW.Repository.Business.${genTable.moduleName}; +using ARW.Service.Business.IBusinessService.${genTable.moduleName}; +using ARW.Model.Dto.Business.${genTable.moduleName}; +using ARW.Model.Models.Business.${genTable.moduleName}; +using ARW.Model.Vo.Business.${genTable.moduleName}; + +namespace ARW.Service.Business.BusinessService.${genTable.moduleName} +{ + /// + /// ${genTable.FunctionName}接口实现类 + /// + [AppService(ServiceType = typeof(I${replaceDto.ModelTypeName}Service), ServiceLifetime = LifeTime.Transient)] + public class ${replaceDto.ModelTypeName}ServiceImpl : BaseService<${replaceDto.ModelTypeName}>, I${replaceDto.ModelTypeName}Service + { + private readonly ${replaceDto.ModelTypeName}Repository _${replaceDto.ModelTypeName}Repository; + + public ${replaceDto.ModelTypeName}ServiceImpl(${replaceDto.ModelTypeName}Repository ${replaceDto.ModelTypeName}Repository) + { + this._${replaceDto.ModelTypeName}Repository = ${replaceDto.ModelTypeName}Repository; + } + + #region 业务逻辑代码 + + +$if(genTable.TplCategory == "tree") + /// + /// 查询${genTable.FunctionName}树形列表 + /// + public async Task> Get${replaceDto.ModelTypeName}TreeList(${replaceDto.ModelTypeName}QueryDto parm) + { + //开始拼装查询条件 + var predicate = Expressionable.Create<${replaceDto.ModelTypeName}>(); + +$foreach(column in genTable.Columns) +$if(column.IsQuery) +$if(column.CsharpType == "string") +$if(genTable.TplCategory != "tree") + predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.${column.CsharpField}), ${codeTool.QueryExp(column.CsharpField, column.QueryType)}; +$end +$elseif(column.CsharpType == "DateTime") + predicate = predicate.AndIF(parm.BeginTime != null && parm.EndTime != null, s => s.${column.CsharpField} >= parm.BeginTime && s.${column.CsharpField} <= parm.EndTime); +$elseif(column.CsharpType == "int" || column.CsharpType == "long") + predicate = predicate.AndIF(parm.${column.CsharpField} != null, ${codeTool.QueryExp(column.CsharpField, column.QueryType)}; +$end +$end +${end} + var query = _${replaceDto.ModelTypeName}Repository + .Queryable() + .LeftJoin<${replaceDto.ModelTypeName}>((s, c) => s.${genTable.Options.TreeParentCode} == c.${genTable.Options.TreeCode}) + .Where(predicate.ToExpression()) +$if(genTable.Options.SortField != "" && genTable.Options.SortField != null) + .OrderBy(s => s.${genTable.Options.SortField},OrderByType.${genTable.Options.SortType}) +$end + .Select((s,c) => new ${replaceDto.ModelTypeName}Vo + { + $foreach(item in genTable.Columns) + $if(item.IsInit != true) + $if((item.IsList || item.IsPk)) + ${item.CsharpField} = s.${item.CsharpField}, + $end + $end + $end + ParentName = c.${genTable.Options.TreeName}, +}); + + return await query.ToTreeAsync(it => it.Children, it => it.${genTable.Options.TreeParentCode}, 0); + } + + + /// + /// 查询${genTable.FunctionName}列表 + /// + public Task> Get${replaceDto.ModelTypeName}List(${replaceDto.ModelTypeName}QueryDto parm) + { + //开始拼装查询条件d + var predicate = Expressionable.Create<${replaceDto.ModelTypeName}>(); + +$foreach(column in genTable.Columns) +$if(column.IsQuery) +$if(column.CsharpType == "string") + predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.${column.CsharpField}), ${codeTool.QueryExp(column.CsharpField, column.QueryType)}; +$elseif(column.CsharpType == "DateTime") + predicate = predicate.AndIF(parm.BeginTime != null && parm.EndTime != null, it => it.${column.CsharpField} >= parm.BeginTime && it.${column.CsharpField} <= parm.EndTime); +$elseif(column.CsharpType == "int" || column.CsharpType == "long") + predicate = predicate.AndIF(parm.${column.CsharpField} != null, ${codeTool.QueryExp(column.CsharpField, column.QueryType)}; +$end +$end +${end} + var query = _${replaceDto.ModelTypeName}Repository + .Queryable() + .Where(predicate.ToExpression()) +$if(genTable.Options.SortField != "" && genTable.Options.SortField != null) + .OrderBy(s => s.${genTable.Options.SortField},OrderByType.${genTable.Options.SortType}) +$end + .Select(s => new ${replaceDto.ModelTypeName}Vo + { + $foreach(item in genTable.Columns) + $if(item.IsInit != true) + $if((item.IsList || item.IsPk)) + ${item.CsharpField} = s.${item.CsharpField}, + $end + $end + $end +}); + + + return query.ToListAsync(); + } +$else + /// + /// 查询${genTable.FunctionName}分页列表 + /// + public Task> Get${replaceDto.ModelTypeName}List(${replaceDto.ModelTypeName}QueryDto parm) + { + //开始拼装查询条件d + var predicate = Expressionable.Create<${replaceDto.ModelTypeName}>(); + +$foreach(column in genTable.Columns) +$if(column.IsQuery) +$if(column.CsharpType == "string") + predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.${column.CsharpField}), ${codeTool.QueryExp(column.CsharpField, column.QueryType)}; +$elseif(column.CsharpType == "DateTime") + predicate = predicate.AndIF(parm.BeginTime != null && parm.EndTime != null, it => it.${column.CsharpField} >= parm.BeginTime && it.${column.CsharpField} <= parm.EndTime); +$elseif(column.CsharpType == "int" || column.CsharpType == "long") + predicate = predicate.AndIF(parm.${column.CsharpField} != null, ${codeTool.QueryExp(column.CsharpField, column.QueryType)}; +$end +$end +${end} + var query = _${replaceDto.ModelTypeName}Repository + .Queryable() + .Where(predicate.ToExpression()) +$if(genTable.Options.SortField != "" && genTable.Options.SortField != null) + .OrderBy(s => s.${genTable.Options.SortField},OrderByType.${genTable.Options.SortType}) +$end + .Select(s => new ${replaceDto.ModelTypeName}Vo + { + $foreach(item in genTable.Columns) + $if(item.IsInit != true) + $if((item.IsList || item.IsPk)) + ${item.CsharpField} = s.${item.CsharpField}, + $end + $end + $end +}); + + + return query.ToPageAsync(parm); + } +$end + + /// + /// 添加或修改${genTable.FunctionName} + /// + public async Task AddOrUpdate${replaceDto.ModelTypeName}(${replaceDto.ModelTypeName} model) + { + if (model.${replaceDto.ModelTypeName}Id != 0) + { +$if(genTable.TplCategory == "tree") + var type = await _${replaceDto.ModelTypeName}Repository.GetListAsync(s => s.${genTable.Options.TreeParentCode} == model.${genTable.Options.TreeCode}); + if (type != null) + { + foreach (var item in type) + { + if (model.${genTable.Options.TreeParentCode} == item.${genTable.Options.TreeCode}) throw new CustomException("上级菜单不能选择自己的子级!"); + } + } + if (model.${genTable.Options.TreeParentCode} == model.${genTable.Options.TreeCode}) throw new CustomException("上级菜单不能选择与当前菜单一样的!"); +$end + var response = await _${replaceDto.ModelTypeName}Repository.UpdateAsync(model); + return "修改成功!"; + } + else + { +$if(genTable.TplCategory == "tree") + var info = _${replaceDto.ModelTypeName}Repository.GetFirst(it => it.${genTable.Options.TreeCode} == model.${genTable.Options.TreeParentCode}); + model.${replaceDto.ModelTypeName}AncestralGuid = "0"; + if (info != null) model.${replaceDto.ModelTypeName}AncestralGuid = info.${replaceDto.ModelTypeName}AncestralGuid + "," + model.${genTable.Options.TreeParentCode}; +$end + + var response = await _${replaceDto.ModelTypeName}Repository.InsertReturnSnowflakeIdAsync(model); + return "添加成功!"; + } + } + + #region Excel处理 +$if(replaceDto.ShowBtnImport) + /// + /// 数据导入处理 + /// + public async Task<${replaceDto.ModelTypeName}Vo> HandleImportData(${replaceDto.ModelTypeName}Vo ${replaceDto.ModelTypeName}) + { + return ${replaceDto.ModelTypeName}; + } + + + /// + /// Excel导入 + /// + public async Task ImportExcel(${replaceDto.ModelTypeName} ${replaceDto.ModelTypeName},int index,bool isUpdateSupport,string user) + { + try + { + // 空值判断 + // if (${replaceDto.ModelTypeName}.${replaceDto.ModelTypeName}Id == null) throw new CustomException("${genTable.FunctionName}不能为空"); + + if (isUpdateSupport) + { + // 判断唯一值 + var model = await GetFirstAsync(s => s.${replaceDto.ModelTypeName}Id == ${replaceDto.ModelTypeName}.${replaceDto.ModelTypeName}Id); + + // 如果为空就新增数据 + if (model == null) + { + // 开启事务 + var res = await UseTranAsync(async () => + { + var addRes = await AddOrUpdate${replaceDto.ModelTypeName}(${replaceDto.ModelTypeName}); + }); + var addStr = $"第 {index} 行 => ${genTable.FunctionName}:【{${replaceDto.ModelTypeName}.${replaceDto.ModelTypeName}Id}】新增成功!
"; + return addStr; + } + else + { + // 如果有数据就进行修改 + // 开启事务 + await UseTranAsync(async () => + { + ${replaceDto.ModelTypeName}.${replaceDto.ModelTypeName}Id = model.${replaceDto.ModelTypeName}Id; + ${replaceDto.ModelTypeName}.${replaceDto.ModelTypeName}Guid = model.${replaceDto.ModelTypeName}Guid; + ${replaceDto.ModelTypeName}.Update_by = user; + ${replaceDto.ModelTypeName}.Update_time = DateTime.Now; + var editRes = await AddOrUpdate${replaceDto.ModelTypeName}(${replaceDto.ModelTypeName}); + }); + var editStr = $"第 {index} 行 => ${genTable.FunctionName}:【{${replaceDto.ModelTypeName}.${replaceDto.ModelTypeName}Id}】更新成功!
"; + return editStr; + } + } + else{ + // 开启事务 + var res = await UseTranAsync(async () => + { + var addRes = await AddOrUpdate${replaceDto.ModelTypeName}(${replaceDto.ModelTypeName}); + }); + //Console.WriteLine(res.IsSuccess); + var addStr = $"第 {index} 行 => ${genTable.FunctionName}:【{${replaceDto.ModelTypeName}.${replaceDto.ModelTypeName}Id}】新增成功!
"; + return addStr; + } + } + catch (Exception ex) + { + var errorRes = $"第 {index} 行 => ${genTable.FunctionName}:【{${replaceDto.ModelTypeName}.${replaceDto.ModelTypeName}Id}】导入失败!{ex.Message}
"; + return errorRes; + throw; + } + } + +$end + +$if(replaceDto.ShowBtnExport) + + /// + /// Excel数据导出处理 + /// + public async Task> HandleExportData(List<${replaceDto.ModelTypeName}Vo> data) + { + return data; + } +$end + + #endregion + + +$if(replaceDto.ShowBtnAudit) + /// + /// 审核 + /// + public async Task Audit(int id, int status, long userGuid) + { + try + { + var res = await _${replaceDto.ModelTypeName}Repository.GetFirstAsync(s => s.${replaceDto.ModelTypeName}Id == id); + await UseTranAsync(async () => + { + await _${replaceDto.ModelTypeName}Repository.UpdateAsync(f => new ${replaceDto.ModelTypeName} { ${replaceDto.ModelTypeName}AuditStatus = status, ${replaceDto.ModelTypeName}AuditUserGuid = userGuid, Update_time = DateTime.Now, Update_by = userGuid.ToString() }, s => s.${replaceDto.ModelTypeName}Id == id); + }); + if (res.${replaceDto.ModelTypeName}AuditStatus == 2) + { + var errorRes = $"${genTable.FunctionName}:【{res.${replaceDto.ModelTypeName}Name}】已通过审核!
"; + return errorRes; + } + if (res.${replaceDto.ModelTypeName}AuditStatus == 3) + { + var errorRes = $"${genTable.FunctionName}:【{res.${replaceDto.ModelTypeName}Name}】已被驳回!
"; + return errorRes; + } + else if (res.${replaceDto.ModelTypeName}AuditStatus == 1) + { + var addStr = $"${genTable.FunctionName}:【{res.${replaceDto.ModelTypeName}Name}】审核通过!
"; + return addStr; + } + return ""; + } + catch (Exception) + { + throw; + } + } +$end + +#endregion + + } +} diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/TplServiceApi.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/TplServiceApi.txt new file mode 100644 index 0000000..740dfb8 --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/TplServiceApi.txt @@ -0,0 +1,154 @@ +using Infrastructure.Attribute; +using Microsoft.AspNetCore.Http; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ARW.Model; +using ARW.Repository; +using ARW.Repository.Business.${genTable.moduleName}; +using ARW.Service.Api.IBusinessService.${genTable.moduleName}; +using ARW.Model.Dto.Api.${genTable.moduleName}; +using ARW.Model.Models.Business.${genTable.moduleName}; +using ARW.Model.Vo.Api.${genTable.moduleName}; + +namespace ARW.Service.Api.BusinessService.${genTable.moduleName} +{ + /// + /// ${genTable.FunctionName}接口实现类 + /// + [AppService(ServiceType = typeof(I${replaceDto.ModelTypeName}ServiceApi), ServiceLifetime = LifeTime.Transient)] + public class ${replaceDto.ModelTypeName}ServiceImplApi : BaseService<${replaceDto.ModelTypeName}>, I${replaceDto.ModelTypeName}ServiceApi + { + private readonly ${replaceDto.ModelTypeName}Repository _${replaceDto.ModelTypeName}Repository; + + public ${replaceDto.ModelTypeName}ServiceImplApi(${replaceDto.ModelTypeName}Repository ${replaceDto.ModelTypeName}Repository) + { + this._${replaceDto.ModelTypeName}Repository = ${replaceDto.ModelTypeName}Repository; + } + + #region Api接口代码 + + +$if(genTable.TplCategory == "tree") + /// + /// 查询${genTable.FunctionName}树形列表(Api) + /// + /// + /// + public async Task> Get${replaceDto.ModelTypeName}TreeListApi(${replaceDto.ModelTypeName}QueryDtoApi parm) + { + //开始拼装查询条件d + var predicate = Expressionable.Create<${replaceDto.ModelTypeName}>(); + +$foreach(column in genTable.Columns) +$if(column.IsQuery) +$if(column.CsharpType == "string") + predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.${column.CsharpField}), ${codeTool.QueryExp(column.CsharpField, column.QueryType)}; +$elseif(column.CsharpType == "DateTime") + predicate = predicate.AndIF(parm.Begin${column.CsharpField} == null, it => it.${column.CsharpField} >= DateTime.Now.AddDays(-1)); + predicate = predicate.AndIF(parm.Begin${column.CsharpField} != null, it => it.${column.CsharpField} >= parm.Begin${column.CsharpField} && it.${column.CsharpField} <= parm.End${column.CsharpField}); +$elseif(column.CsharpType == "int" || column.CsharpType == "long") + predicate = predicate.AndIF(parm.${column.CsharpField} != null, ${codeTool.QueryExp(column.CsharpField, column.QueryType)}; +$end +$end +${end} + var query = _${replaceDto.ModelTypeName}Repository + .Queryable() + .Where(predicate.ToExpression()) + .LeftJoin<${replaceDto.ModelTypeName}>((s, c) => s.${genTable.Options.TreeParentCode} == c.${replaceDto.ModelTypeName}Guid) +$if(genTable.Options.SortField != "" && genTable.Options.SortField != null) + .OrderBy(s => s.${genTable.Options.SortField},OrderByType.${genTable.Options.SortType}) +$end + .Select((s,c) => new ${replaceDto.ModelTypeName}VoApi + { + $foreach(item in genTable.Columns) + $if(item.IsInit != true) + $if((item.IsList || item.IsPk)) + ${item.CsharpField} = s.${item.CsharpField}, + $end + $end + $end + ParentName = c.${replaceDto.ModelTypeName}Name, +}); + + return await query.ToTreeAsync(it => it.Children, it => it.${genTable.Options.TreeParentCode}, 0); + } +$else + /// + /// 查询${genTable.FunctionName}列表(Api) + /// + /// + /// + public async Task> Get${replaceDto.ModelTypeName}ListApi(${replaceDto.ModelTypeName}QueryDtoApi parm) + { + //开始拼装查询条件d + var predicate = Expressionable.Create<${replaceDto.ModelTypeName}>(); + +$foreach(column in genTable.Columns) +$if(column.IsQuery) +$if(column.CsharpType == "string") + predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.${column.CsharpField}), ${codeTool.QueryExp(column.CsharpField, column.QueryType)}; +$elseif(column.CsharpType == "DateTime") + predicate = predicate.AndIF(parm.Begin${column.CsharpField} == null, it => it.${column.CsharpField} >= DateTime.Now.AddDays(-1)); + predicate = predicate.AndIF(parm.Begin${column.CsharpField} != null, it => it.${column.CsharpField} >= parm.Begin${column.CsharpField} && it.${column.CsharpField} <= parm.End${column.CsharpField}); +$elseif(column.CsharpType == "int" || column.CsharpType == "long") + predicate = predicate.AndIF(parm.${column.CsharpField} != null, ${codeTool.QueryExp(column.CsharpField, column.QueryType)}; +$end +$end +${end} + var query = _${replaceDto.ModelTypeName}Repository + .Queryable() + .Where(predicate.ToExpression()) +$if(genTable.Options.SortField != "" && genTable.Options.SortField != null) + .OrderBy(s => s.${genTable.Options.SortField},OrderByType.Desc) +$end + .Select(s => new ${replaceDto.ModelTypeName}VoApi + { + $foreach(item in genTable.Columns) + $if(item.IsInit != true) + $if((item.IsList || item.IsPk)) + ${item.CsharpField} = s.${item.CsharpField}, + $end + $end + $end +}); + + + return await query.ToPageAsync(parm); + } +$end + + /// + /// 查询${genTable.FunctionName}详情(Api) + /// + /// + /// + public Task Get${replaceDto.ModelTypeName}Details(${replaceDto.ModelTypeName}DtoApi parm) + { + + var query = _${replaceDto.ModelTypeName}Repository + .Queryable() + .Where(s => s.${replaceDto.ModelTypeName}Guid == parm.${replaceDto.ModelTypeName}Guid) + .Select(s => new ${replaceDto.ModelTypeName}ApiDetailsVo + { + $foreach(item in genTable.Columns) + $if(item.IsInit != true) + $if((item.IsList || item.IsPk)) + ${item.CsharpField} = s.${item.CsharpField}, + $end + $end + $end +}).Take(1); + + + return query.ToJsonAsync(); + } + + +#endregion + + } +} diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/TplTreeVue.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/TplTreeVue.txt new file mode 100644 index 0000000..72cfae3 --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/TplTreeVue.txt @@ -0,0 +1,394 @@ + + + \ No newline at end of file diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/TplVo.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/TplVo.txt new file mode 100644 index 0000000..143af40 --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/TplVo.txt @@ -0,0 +1,52 @@ +using Newtonsoft.Json; +using OfficeOpenXml.Attributes; +using SqlSugar; +using System; +$if(genTable.TplCategory == "tree") +using ARW.Model.Models.Business.${genTable.moduleName}; +using System.Collections.Generic; +$end + +namespace ${options.DtosNamespace}.Vo.Business.${genTable.moduleName} +{ + /// + /// ${genTable.FunctionName}展示对象 + /// + public class ${replaceDto.ModelTypeName}Vo + { +$foreach(item in genTable.Columns) +$if(item.IsInit != true) + + /// + /// 描述 :${item.ColumnComment} ${item.Remark} + /// +$if((item.IsList || item.IsPk)) +$if(item.IsGuid) + [JsonConverter(typeof(ValueToStringConverter))] +$if(genTable.TplCategory == "tree") + [SugarColumn(IsTreeKey = true)] +$end +$end +$if(replaceDto.ShowBtnExport) +$if(item.IsRequired && item.IsIncrement == false && item.IsPk == false) + [EpplusTableColumn(Header = "$if(item.ColumnComment == "")${item.CsharpField}${else}${item.ColumnComment}${end}"$if(item.CsharpType == "DateTime"), NumberFormat = "yyyy-MM-dd HH:mm:ss"$end)] +$else + [EpplusIgnore] +$end +$end + public $item.CsharpType$item.RequiredStr $item.CsharpField { get; set; } +$end +$end +$end + +$if(genTable.TplCategory == "tree") + [EpplusIgnore] + public string ParentName { get; set; } + + [EpplusIgnore] + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [SugarColumn(IsIgnore = true)] + public List<${replaceDto.ModelTypeName}Vo> Children { get; set; } +$end + } +} diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/TplVoApi.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/TplVoApi.txt new file mode 100644 index 0000000..df27700 --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/TplVoApi.txt @@ -0,0 +1,87 @@ +using Newtonsoft.Json; +using OfficeOpenXml.Attributes; +using SqlSugar; +using System; +$if(genTable.TplCategory == "tree") +using ARW.Model.Models.Business.${genTable.moduleName}; +using System.Collections.Generic; +$end + +namespace ${options.DtosNamespace}.Vo.Api.${genTable.moduleName} +{ + /// + /// ${genTable.FunctionName}展示对象 + /// + public class ${replaceDto.ModelTypeName}VoApi + { +$foreach(item in genTable.Columns) +$if(item.IsInit != true) + + /// + /// 描述 :${item.ColumnComment} ${item.Remark} + /// +$if((item.IsList || item.IsPk)) +$if(item.IsGuid) + [JsonConverter(typeof(ValueToStringConverter))] +$if(genTable.TplCategory == "tree") + [SugarColumn(IsTreeKey = true)] +$end +$end +$if(replaceDto.ShowBtnExport) +$if(item.IsRequired && item.IsIncrement == false && item.IsPk == false) + [EpplusTableColumn(Header = "$if(item.ColumnComment == "")${item.CsharpField}${else}${item.ColumnComment}${end}"$if(item.CsharpType == "DateTime"), NumberFormat = "yyyy-MM-dd HH:mm:ss"$end)] +$else + [EpplusIgnore] +$end +$end + public $item.CsharpType$item.RequiredStr $item.CsharpField { get; set; } +$end +$end +$end + +$if(genTable.TplCategory == "tree") + public string ParentName { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [SugarColumn(IsIgnore = true)] + public List<${replaceDto.ModelTypeName}VoApi> Children { get; set; } +$end + } + + + /// + /// ${genTable.FunctionName}详情展示对象Api + /// + public class ${replaceDto.ModelTypeName}ApiDetailsVo + { +$foreach(item in genTable.Columns) +$if(item.IsInit != true) +$if((item.IsList || item.IsPk)) +$if(item.IsGuid) + [JsonConverter(typeof(ValueToStringConverter))] +$if(genTable.TplCategory == "tree") + [SugarColumn(IsTreeKey = true)] +$end +$end +$if(replaceDto.ShowBtnExport) +$if(item.IsRequired && item.IsIncrement == false && item.IsPk == false) + [EpplusTableColumn(Header = "$if(item.ColumnComment == "")${item.CsharpField}${else}${item.ColumnComment}${end}"$if(item.CsharpType == "DateTime"), NumberFormat = "yyyy-MM-dd HH:mm:ss"$end)] +$else + [EpplusIgnore] +$end +$end + public $item.CsharpType$item.RequiredStr $item.CsharpField { get; set; } +$end +$end +$end + +$if(genTable.TplCategory == "tree") + public string ParentName { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [SugarColumn(IsIgnore = true)] + public List<${replaceDto.ModelTypeName}VoApi> Children { get; set; } +$end + } + +} diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/TplVue.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/TplVue.txt new file mode 100644 index 0000000..fb92492 --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/TplVue.txt @@ -0,0 +1,390 @@ + + + \ No newline at end of file diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/TplVueApi.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/TplVueApi.txt new file mode 100644 index 0000000..205cd6a --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/TplVueApi.txt @@ -0,0 +1,63 @@ +import request from '@/utils/request' + +$if(genTable.TplCategory == "tree") +/** +* ${genTable.functionName}树形查询列表 +* @param {查询条件} data +*/ +export function ${tool.FirstLowerCase(genTable.BusinessName)}TreeList(query) { + return request({ + url: '/business/${genTable.BusinessName}/get${genTable.BusinessName}TreeList', + method: 'get', + params: query + }) +} +$else +// ${genTable.functionName}分页查询列表 +export function ${tool.FirstLowerCase(genTable.BusinessName)}List(query) { + return request({ + url: '/business/${genTable.BusinessName}/get${genTable.BusinessName}List', + method: 'get', + params: query + }) +} +$end + +// ${genTable.functionName}新增或修改 +export function addOrUpdate${genTable.BusinessName}(data) { + return request({ + url: '/business/${genTable.BusinessName}/addOrUpdate${genTable.BusinessName}', + method: 'post', + data: data, + }) +} + +// ${genTable.functionName}删除 +export function del${genTable.BusinessName}(ids) { + return request({ + url: '/business/${genTable.BusinessName}/'+ ids, + method: 'delete' + }) +} + +$if(replaceDto.ShowBtnExport) +// ${genTable.functionName}导出 +export function export${genTable.BusinessName}(query) { + return request({ + url: 'business/${genTable.BusinessName}/export${genTable.BusinessName}', + method: 'get', + params: query + }) +} +$end + +$if(replaceDto.ShowBtnAudit) +// ${genTable.functionName}审核 +export function audit(data) { + return request({ + url: 'business/${genTable.BusinessName}/audit', + method: 'put', + data: data + }) +} +$end diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/TplVueIndex.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/TplVueIndex.txt new file mode 100644 index 0000000..0d53722 --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/TplVueIndex.txt @@ -0,0 +1,514 @@ + + + diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/TplVueSelect.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/TplVueSelect.txt new file mode 100644 index 0000000..8849f45 --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/TplVueSelect.txt @@ -0,0 +1,263 @@ + + + \ No newline at end of file diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/Upload.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/Upload.txt new file mode 100644 index 0000000..3507c77 --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/Upload.txt @@ -0,0 +1,116 @@ + + + + \ No newline at end of file diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/old/MySqlTemplate - 副本.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/old/MySqlTemplate - 副本.txt new file mode 100644 index 0000000..481abec --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/old/MySqlTemplate - 副本.txt @@ -0,0 +1,30 @@ +use +Admin; + +-- 菜单 +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time) +VALUES ('${genTable.functionName}', ${parentId}, 999, '${genTable.BusinessName}', '${tool.FirstLowerCase(genTable.ModuleName)}/${genTable.BusinessName}', 0, 0, 'C', '0', '0', '${replaceDto.PermissionPrefix}:list', 'icon1', 'system', sysdate()); + +-- 按钮父菜单id +SELECT @menuId := LAST_INSERT_ID(); + + +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time) +VALUES ('查询', @menuId, 1, '#', NULL, 0, 0, 'F', '0', '0', '${replaceDto.PermissionPrefix}:query', '', 'system', sysdate()); + +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time) +VALUES ('新增', @menuId, 2, '#', NULL, 0, 0, 'F', '0', '0', '${replaceDto.PermissionPrefix}:add', '', 'system', sysdate()); + +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time) +VALUES ('删除', @menuId, 3, '#', NULL, 0, 0, 'F', '0', '0', '${replaceDto.PermissionPrefix}:delete', '', 'system', sysdate()); + +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time) +VALUES ('修改', @menuId, 4, '#', NULL, 0, 0, 'F', '0', '0', '${replaceDto.PermissionPrefix}:edit', '', 'system', sysdate()); + +$if(replaceDto.ShowBtnExport) +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time) +VALUES ('导出', @menuId, 5, '#', NULL, 0, 0, 'F', '0', '0', '${replaceDto.PermissionPrefix}:export', '', 'system', sysdate()); +$end + +SELECT * FROM sys_menu WHERE parentId = @menuId; +SELECT * FROM sys_menu WHERE menuId = @menuId; \ No newline at end of file diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/old/TplControllers.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/old/TplControllers.txt new file mode 100644 index 0000000..51d5983 --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/old/TplControllers.txt @@ -0,0 +1,187 @@ +using Infrastructure; +using Infrastructure.Attribute; +using Infrastructure.Enums; +using Infrastructure.Model; +using Mapster; +using Microsoft.AspNetCore.Mvc; +using ${options.ModelsNamespace}.Dto; +using ${options.ModelsNamespace}.Models; +using ${options.IServicsNamespace}.${options.SubNamespace}.I${options.SubNamespace}Service; +using ${options.ApiControllerNamespace}.Extensions; +using ${options.ApiControllerNamespace}.Filters; +using ${options.BaseNamespace}Common; + +namespace ${options.ApiControllerNamespace}.Controllers +{ + /// + /// ${genTable.functionName}Controller + /// + /// @tableName ${genTable.TableName} + /// @author ${replaceDto.Author} + /// @date ${replaceDto.AddTime} + /// + [Verify] + [Route("${genTable.ModuleName}/${genTable.BusinessName}")] + public class ${replaceDto.ModelTypeName}Controller : BaseController + { + /// + /// ${genTable.FunctionName}接口 + /// + private readonly I${replaceDto.ModelTypeName}Service _${replaceDto.ModelTypeName}Service; + + public ${replaceDto.ModelTypeName}Controller(I${replaceDto.ModelTypeName}Service ${replaceDto.ModelTypeName}Service) + { + _${replaceDto.ModelTypeName}Service = ${replaceDto.ModelTypeName}Service; + } + + /// + /// 查询${genTable.FunctionName}列表 + /// + /// + /// + [HttpGet("list")] + [ActionPermissionFilter(Permission = "${replaceDto.PermissionPrefix}:list")] + public IActionResult Query${replaceDto.ModelTypeName}([FromQuery] ${replaceDto.ModelTypeName}QueryDto parm) + { + var response = _${replaceDto.ModelTypeName}Service.GetList(parm); + return SUCCESS(response); + } + +$if(genTable.TplCategory == "tree") + /// + /// 查询${genTable.FunctionName}列表树 + /// + /// + /// + [HttpGet("treeList")] + [ActionPermissionFilter(Permission = "${replaceDto.PermissionPrefix}:list")] + public IActionResult QueryTree${replaceDto.ModelTypeName}([FromQuery] ${replaceDto.ModelTypeName}QueryDto parm) + { + var response = _${replaceDto.ModelTypeName}Service.GetTreeList(parm); + return SUCCESS(response); + } +$end + + /// + /// 查询${genTable.FunctionName}详情 + /// + /// + /// + [HttpGet("{${replaceDto.PKName}}")] + [ActionPermissionFilter(Permission = "${replaceDto.PermissionPrefix}:query")] + public IActionResult Get${replaceDto.ModelTypeName}(${replaceDto.PKType} ${replaceDto.PKName}) + { + var response = _${replaceDto.ModelTypeName}Service.GetFirst(x => x.${replaceDto.PKName} == ${replaceDto.PKName}); + + return SUCCESS(response); + } + +$if(replaceDto.ShowBtnAdd) + /// + /// 添加${genTable.FunctionName} + /// + /// + [HttpPost] + [ActionPermissionFilter(Permission = "${replaceDto.PermissionPrefix}:add")] + [Log(Title = "${genTable.FunctionName}", BusinessType = BusinessType.INSERT)] + public IActionResult Add${replaceDto.ModelTypeName}([FromBody] ${replaceDto.ModelTypeName}Dto parm) + { + if (parm == null) + { + throw new CustomException("请求参数错误"); + } + var modal = parm.Adapt<${replaceDto.ModelTypeName}>().ToCreate(HttpContext); + + var response = _${replaceDto.ModelTypeName}Service.Add${replaceDto.ModelTypeName}(modal); + + return ToResponse(response); + } +$end + +$if(replaceDto.ShowBtnEdit) + /// + /// 更新${genTable.FunctionName} + /// + /// + [HttpPut] + [ActionPermissionFilter(Permission = "${replaceDto.PermissionPrefix}:edit")] + [Log(Title = "${genTable.FunctionName}", BusinessType = BusinessType.UPDATE)] + public IActionResult Update${replaceDto.ModelTypeName}([FromBody] ${replaceDto.ModelTypeName}Dto parm) + { + if (parm == null) + { + throw new CustomException("请求实体不能为空"); + } + var modal = parm.Adapt<${replaceDto.ModelTypeName}>().ToUpdate(HttpContext); + + var response = _${replaceDto.ModelTypeName}Service.Update${replaceDto.ModelTypeName}(modal); + + return ToResponse(response); + } +$end + +$if(replaceDto.ShowBtnDelete) + /// + /// 删除${genTable.FunctionName} + /// + /// + [HttpDelete("{ids}")] + [ActionPermissionFilter(Permission = "${replaceDto.PermissionPrefix}:delete")] + [Log(Title = "${genTable.FunctionName}", BusinessType = BusinessType.DELETE)] + public IActionResult Delete${replaceDto.ModelTypeName}(string ids) + { + int[] idsArr = Tools.SpitIntArrary(ids); + if (idsArr.Length <= 0) { return ToResponse(ApiResult.Error($"删除失败Id 不能为空")); } + + var response = _${replaceDto.ModelTypeName}Service.Delete(idsArr); + + return ToResponse(response); + } +$end + +$if(replaceDto.ShowBtnExport) + /// + /// 导出${genTable.FunctionName} + /// + /// + [Log(Title = "${genTable.FunctionName}", BusinessType = BusinessType.EXPORT, IsSaveResponseData = false)] + [HttpGet("export")] + [ActionPermissionFilter(Permission = "${replaceDto.PermissionPrefix}:export")] + public IActionResult Export([FromQuery] ${replaceDto.ModelTypeName}QueryDto parm) + { + parm.PageSize = 10000; + var list = _${replaceDto.ModelTypeName}Service.GetList(parm).Result; + + string sFileName = ExportExcel(list, "${replaceDto.ModelTypeName}", "${genTable.FunctionName}"); + return SUCCESS(new { path = "/export/" + sFileName, fileName = sFileName }); + } +$end + +$if(showCustomInput) + /// + /// 保存排序 + /// + /// 主键 + /// 排序值 + /// + [ActionPermissionFilter(Permission = "${replaceDto.PermissionPrefix}:edit")] + [HttpGet("ChangeSort")] + [Log(Title = "保存排序", BusinessType = BusinessType.UPDATE)] + public IActionResult ChangeSort(int id = 0, int value = 0) + { + if (id <= 0) { return ToResponse(ApiResult.Error(101, "请求参数错误")); } + var response = _${replaceDto.ModelTypeName}Service.Update(w => w.${replaceDto.PKName} == id, it => new ${replaceDto.ModelTypeName}() + { + //Update 字段映射 +$foreach(item in genTable.Columns) +$if((item.htmlType == "customInput")) + $item.CsharpField = value, +$end +${end} + }); + + return ToResponse(response); + } +$end + } +} \ No newline at end of file diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/old/TplIService.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/old/TplIService.txt new file mode 100644 index 0000000..f30aecd --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/old/TplIService.txt @@ -0,0 +1,26 @@ +using System; +using ${options.ModelsNamespace}; +using ${options.ModelsNamespace}.Dto; +using ${options.ModelsNamespace}.Models; +using System.Collections.Generic; + +namespace ${options.IServicsNamespace}.${options.SubNamespace}.I${options.SubNamespace}Service +{ + /// + /// ${genTable.FunctionName}service接口 + /// + /// @author ${replaceDto.Author} + /// @date ${replaceDto.AddTime} + /// + public interface I${replaceDto.ModelTypeName}Service : IBaseService<${replaceDto.ModelTypeName}> + { + PagedInfo<${replaceDto.ModelTypeName}> GetList(${replaceDto.ModelTypeName}QueryDto parm); + +$if(genTable.TplCategory == "tree") + List<${replaceDto.ModelTypeName}> GetTreeList(${replaceDto.ModelTypeName}QueryDto parm); +$end + int Add${replaceDto.ModelTypeName}(${replaceDto.ModelTypeName} parm); + + int Update${replaceDto.ModelTypeName}(${replaceDto.ModelTypeName} parm); + } +} diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/old/TplService.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/old/TplService.txt new file mode 100644 index 0000000..ce428f3 --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/old/TplService.txt @@ -0,0 +1,133 @@ +using System; +using SqlSugar; +using System.Collections.Generic; +using Infrastructure; +using Infrastructure.Attribute; +using ${options.ModelsNamespace}; +using ${options.ModelsNamespace}.Dto; +using ${options.ModelsNamespace}.Models; +using ${options.IRepositoriesNamespace}; +using ${options.IServicsNamespace}.${options.SubNamespace}.I${options.SubNamespace}Service; + +namespace ${options.ServicesNamespace}.${options.SubNamespace} +{ + /// + /// ${genTable.FunctionName}Service业务层处理 + /// + /// @author ${replaceDto.Author} + /// @date ${replaceDto.AddTime} + /// + [AppService(ServiceType = typeof(I${replaceDto.ModelTypeName}Service), ServiceLifetime = LifeTime.Transient)] + public class ${replaceDto.ModelTypeName}Service : BaseService<${replaceDto.ModelTypeName}>, I${replaceDto.ModelTypeName}Service + { + private readonly ${replaceDto.ModelTypeName}Repository _${replaceDto.ModelTypeName}Repository; + public ${replaceDto.ModelTypeName}Service(${replaceDto.ModelTypeName}Repository repository) + { + _${replaceDto.ModelTypeName}Repository = repository; + } + + #region 业务逻辑代码 + + /// + /// 查询${genTable.FunctionName}列表 + /// + /// + /// + public PagedInfo<${replaceDto.ModelTypeName}> GetList(${replaceDto.ModelTypeName}QueryDto parm) + { + //开始拼装查询条件 + var predicate = Expressionable.Create<${replaceDto.ModelTypeName}>(); + + //搜索条件查询语法参考Sqlsugar +$foreach(column in genTable.Columns) +$if(column.IsQuery) +$if(column.CsharpType == "string") + predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.${column.CsharpField}), ${codeTool.QueryExp(column.CsharpField, column.QueryType)}; +$elseif(column.CsharpType == "DateTime") + predicate = predicate.AndIF(parm.Begin${column.CsharpField} == null, it => it.${column.CsharpField} >= DateTime.Now.AddDays(-1)); + predicate = predicate.AndIF(parm.Begin${column.CsharpField} != null, it => it.${column.CsharpField} >= parm.Begin${column.CsharpField} && it.${column.CsharpField} <= parm.End${column.CsharpField}); +$elseif(column.CsharpType == "int" || column.CsharpType == "long") + predicate = predicate.AndIF(parm.${column.CsharpField} != null, ${codeTool.QueryExp(column.CsharpField, column.QueryType)}; +$end +$end +$end + var response = _${replaceDto.ModelTypeName}Repository + .Queryable() +$if(null != genTable.SubTableName && "" != genTable.SubTableName) + .Includes(it => it.${genTable.SubTable.ClassName}.MappingField(z => z.${genTable.SubTableFkName}, () => it.${replaceDto.PKName})) +$end +$if(genTable.Options.SortField != "" && genTable.Options.SortField != null) + .OrderBy("${genTable.Options.SortField} ${genTable.Options.SortType}") +$end + .Where(predicate.ToExpression()) + .ToPage(parm); + + return response; + } + +$if(genTable.TplCategory == "tree") + /// + /// 查询${genTable.FunctionName}树列表 + /// + /// + /// + public List<${replaceDto.ModelTypeName}> GetTreeList(${replaceDto.ModelTypeName}QueryDto parm) + { + //开始拼装查询条件 + var predicate = Expressionable.Create<${replaceDto.ModelTypeName}>(); + + //搜索条件查询语法参考Sqlsugar +$foreach(column in genTable.Columns) +$if(column.IsQuery) +$if(column.CsharpType == "string") + predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.${column.CsharpField}), ${codeTool.QueryExp(column.CsharpField, column.QueryType)}; +$elseif(column.CsharpType == "int" || column.CsharpType == "long") + predicate = predicate.AndIF(parm.${column.CsharpField} != null, ${codeTool.QueryExp(column.CsharpField, column.QueryType)}; +$end +$end +$end + + var response = _${replaceDto.ModelTypeName}Repository.Queryable().Where(predicate.ToExpression()) + .ToTree(it => it.Children, it => it.${genTable.Options.TreeParentCode}, 0); + + return response; + } +$end + /// + /// 添加${genTable.FunctionName} + /// + /// + /// + public int Add${replaceDto.ModelTypeName}(${replaceDto.ModelTypeName} parm) + { + var response = _${replaceDto.ModelTypeName}Repository.Insert(parm, it => new + { +${foreach(item in genTable.Columns)} +$if((item.IsInsert)) + it.$item.CsharpField, +$end +${end} + }); + return response; + } + + /// + /// 修改${genTable.FunctionName} + /// + /// + /// + public int Update${replaceDto.ModelTypeName}(${replaceDto.ModelTypeName} parm) + { + var response = _${replaceDto.ModelTypeName}Repository.Update(w => w.${replaceDto.PKName} == parm.${replaceDto.PKName}, it => new ${replaceDto.ModelTypeName}() + { +$foreach(item in genTable.Columns) +$if((item.IsEdit)) + $item.CsharpField = parm.$item.CsharpField, +$end +${end} + }); + return response; + } + #endregion + } +} \ No newline at end of file diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/old/TplVueApi.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/old/TplVueApi.txt new file mode 100644 index 0000000..48d25b9 --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/old/TplVueApi.txt @@ -0,0 +1,93 @@ +import request from '@/utils/request' + +/** +* ${genTable.functionName}分页查询 +* @param {查询条件} data +*/ +export function list${genTable.BusinessName}(query) { + return request({ + url: '${genTable.ModuleName}/${genTable.BusinessName}/list', + method: 'get', + params: query, + }) +} + +$if(genTable.TplCategory == "tree") +/** +* ${genTable.functionName}tree查询 +* @param {查询条件} data +*/ +export function treelist${genTable.BusinessName}(query) { + return request({ + url: '${genTable.ModuleName}/${genTable.BusinessName}/treelist', + method: 'get', + params: query, + }) +} +$end + +/** +* 新增${genTable.functionName} +* @param data +*/ +export function add${genTable.BusinessName}(data) { + return request({ + url: '${genTable.ModuleName}/${genTable.BusinessName}', + method: 'post', + data: data, + }) +} + +/** +* 修改${genTable.functionName} +* @param data +*/ +export function update${genTable.BusinessName}(data) { + return request({ + url: '${genTable.ModuleName}/${genTable.BusinessName}', + method: 'PUT', + data: data, + }) +} + +/** +* 获取${genTable.functionName}详情 +* @param {Id} +*/ +export function get${genTable.BusinessName}(id) { + return request({ + url: '${genTable.ModuleName}/${genTable.BusinessName}/' + id, + method: 'get' + }) +} + +/** +* 删除${genTable.functionName} +* @param {主键} pid +*/ +export function del${genTable.BusinessName}(pid) { + return request({ + url: '${genTable.ModuleName}/${genTable.BusinessName}/' + pid, + method: 'delete' + }) +} + +// 导出${genTable.functionName} +export function export${genTable.BusinessName}(query) { + return request({ + url: '${genTable.ModuleName}/${genTable.BusinessName}/export', + method: 'get', + params: query + }) +} + +$if(showCustomInput) +//排序 +export function changeSort(data) { + return request({ + url: '${genTable.ModuleName}/${genTable.BusinessName}/ChangeSort', + method: 'get', + params: data + }) +} +$end \ No newline at end of file diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/v3/TreeVue.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/v3/TreeVue.txt new file mode 100644 index 0000000..dc05b23 --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/v3/TreeVue.txt @@ -0,0 +1,565 @@ + + + \ No newline at end of file diff --git a/ARW.WebApi/wwwroot/CodeGenTemplate/v3/Vue.txt b/ARW.WebApi/wwwroot/CodeGenTemplate/v3/Vue.txt new file mode 100644 index 0000000..a379219 --- /dev/null +++ b/ARW.WebApi/wwwroot/CodeGenTemplate/v3/Vue.txt @@ -0,0 +1,561 @@ + + + + + \ No newline at end of file diff --git a/ARW.WebApi/wwwroot/Customer/20221205/65F692EEF4BD7E7F.jpg b/ARW.WebApi/wwwroot/Customer/20221205/65F692EEF4BD7E7F.jpg new file mode 100644 index 0000000..6fc9ff5 Binary files /dev/null and b/ARW.WebApi/wwwroot/Customer/20221205/65F692EEF4BD7E7F.jpg differ diff --git a/ARW.WebApi/wwwroot/Customer/20221206/26C2880C544720B4.jpg b/ARW.WebApi/wwwroot/Customer/20221206/26C2880C544720B4.jpg new file mode 100644 index 0000000..8164cf3 Binary files /dev/null and b/ARW.WebApi/wwwroot/Customer/20221206/26C2880C544720B4.jpg differ diff --git a/ARW.WebApi/wwwroot/Customer/20221206/4EBF8809FE13A3B2.png b/ARW.WebApi/wwwroot/Customer/20221206/4EBF8809FE13A3B2.png new file mode 100644 index 0000000..afbe7ba Binary files /dev/null and b/ARW.WebApi/wwwroot/Customer/20221206/4EBF8809FE13A3B2.png differ diff --git a/ARW.WebApi/wwwroot/Customer/20221206/6F7FD388B5C48D45.jpg b/ARW.WebApi/wwwroot/Customer/20221206/6F7FD388B5C48D45.jpg new file mode 100644 index 0000000..8164cf3 Binary files /dev/null and b/ARW.WebApi/wwwroot/Customer/20221206/6F7FD388B5C48D45.jpg differ diff --git a/ARW.WebApi/wwwroot/Customer/20221206/BF907F248CEACFAA.png b/ARW.WebApi/wwwroot/Customer/20221206/BF907F248CEACFAA.png new file mode 100644 index 0000000..b3a073d Binary files /dev/null and b/ARW.WebApi/wwwroot/Customer/20221206/BF907F248CEACFAA.png differ diff --git a/ARW.WebApi/wwwroot/Customer/20221206/E22AD557FC2E0A9D.jpg b/ARW.WebApi/wwwroot/Customer/20221206/E22AD557FC2E0A9D.jpg new file mode 100644 index 0000000..65316c6 Binary files /dev/null and b/ARW.WebApi/wwwroot/Customer/20221206/E22AD557FC2E0A9D.jpg differ diff --git a/ARW.WebApi/wwwroot/FatPig/20230312/379BC13C3CD2EB81.jpg b/ARW.WebApi/wwwroot/FatPig/20230312/379BC13C3CD2EB81.jpg new file mode 100644 index 0000000..083e2ed Binary files /dev/null and b/ARW.WebApi/wwwroot/FatPig/20230312/379BC13C3CD2EB81.jpg differ diff --git a/ARW.WebApi/wwwroot/FatPig/20230312/952E03C0AB6DE27E.png b/ARW.WebApi/wwwroot/FatPig/20230312/952E03C0AB6DE27E.png new file mode 100644 index 0000000..200eace Binary files /dev/null and b/ARW.WebApi/wwwroot/FatPig/20230312/952E03C0AB6DE27E.png differ diff --git a/ARW.WebApi/wwwroot/FatPig/20230312/B5FF4B44D2065729.jpg b/ARW.WebApi/wwwroot/FatPig/20230312/B5FF4B44D2065729.jpg new file mode 100644 index 0000000..29cf3af Binary files /dev/null and b/ARW.WebApi/wwwroot/FatPig/20230312/B5FF4B44D2065729.jpg differ diff --git a/ARW.WebApi/wwwroot/FatPig/20230312/D467F076615D35E2.jpg b/ARW.WebApi/wwwroot/FatPig/20230312/D467F076615D35E2.jpg new file mode 100644 index 0000000..4e05ae6 Binary files /dev/null and b/ARW.WebApi/wwwroot/FatPig/20230312/D467F076615D35E2.jpg differ diff --git a/ARW.WebApi/wwwroot/FatPig/20230312/FF87CCE218F412FF.jpg b/ARW.WebApi/wwwroot/FatPig/20230312/FF87CCE218F412FF.jpg new file mode 100644 index 0000000..083e2ed Binary files /dev/null and b/ARW.WebApi/wwwroot/FatPig/20230312/FF87CCE218F412FF.jpg differ diff --git a/ARW.WebApi/wwwroot/FatPig/20230313/66D3729A165A0828.jpg b/ARW.WebApi/wwwroot/FatPig/20230313/66D3729A165A0828.jpg new file mode 100644 index 0000000..5396982 Binary files /dev/null and b/ARW.WebApi/wwwroot/FatPig/20230313/66D3729A165A0828.jpg differ diff --git a/ARW.WebApi/wwwroot/FatPig/20230313/C63B4A4378625C9B.jpg b/ARW.WebApi/wwwroot/FatPig/20230313/C63B4A4378625C9B.jpg new file mode 100644 index 0000000..cad38fb Binary files /dev/null and b/ARW.WebApi/wwwroot/FatPig/20230313/C63B4A4378625C9B.jpg differ diff --git a/ARW.WebApi/wwwroot/Open/20230520/1256BD283BB3F427.jpg b/ARW.WebApi/wwwroot/Open/20230520/1256BD283BB3F427.jpg new file mode 100644 index 0000000..4bb0e9b Binary files /dev/null and b/ARW.WebApi/wwwroot/Open/20230520/1256BD283BB3F427.jpg differ diff --git a/ARW.WebApi/wwwroot/Open/20230520/408AC668A70CFC0B.png b/ARW.WebApi/wwwroot/Open/20230520/408AC668A70CFC0B.png new file mode 100644 index 0000000..2cee6f6 Binary files /dev/null and b/ARW.WebApi/wwwroot/Open/20230520/408AC668A70CFC0B.png differ diff --git a/ARW.WebApi/wwwroot/Open/20230521/19BABB94FAC2CE98.jpg b/ARW.WebApi/wwwroot/Open/20230521/19BABB94FAC2CE98.jpg new file mode 100644 index 0000000..4bb0e9b Binary files /dev/null and b/ARW.WebApi/wwwroot/Open/20230521/19BABB94FAC2CE98.jpg differ diff --git a/ARW.WebApi/wwwroot/Open/20230521/3B2680151B011BFE.jpg b/ARW.WebApi/wwwroot/Open/20230521/3B2680151B011BFE.jpg new file mode 100644 index 0000000..40f942d Binary files /dev/null and b/ARW.WebApi/wwwroot/Open/20230521/3B2680151B011BFE.jpg differ diff --git a/ARW.WebApi/wwwroot/Open/20230521/407E393089C55540.jpg b/ARW.WebApi/wwwroot/Open/20230521/407E393089C55540.jpg new file mode 100644 index 0000000..4bb0e9b Binary files /dev/null and b/ARW.WebApi/wwwroot/Open/20230521/407E393089C55540.jpg differ diff --git a/ARW.WebApi/wwwroot/Open/20230522/0C5E63201C510AF8.png b/ARW.WebApi/wwwroot/Open/20230522/0C5E63201C510AF8.png new file mode 100644 index 0000000..4843185 Binary files /dev/null and b/ARW.WebApi/wwwroot/Open/20230522/0C5E63201C510AF8.png differ diff --git a/ARW.WebApi/wwwroot/Open/20230522/51B3F7D5C0E01DC4.png b/ARW.WebApi/wwwroot/Open/20230522/51B3F7D5C0E01DC4.png new file mode 100644 index 0000000..90292a9 Binary files /dev/null and b/ARW.WebApi/wwwroot/Open/20230522/51B3F7D5C0E01DC4.png differ diff --git a/ARW.WebApi/wwwroot/Open/20230522/9671AD0F48BB910D.png b/ARW.WebApi/wwwroot/Open/20230522/9671AD0F48BB910D.png new file mode 100644 index 0000000..7079f32 Binary files /dev/null and b/ARW.WebApi/wwwroot/Open/20230522/9671AD0F48BB910D.png differ diff --git a/ARW.WebApi/wwwroot/Open/20230522/AC0F189241B8C2EF.png b/ARW.WebApi/wwwroot/Open/20230522/AC0F189241B8C2EF.png new file mode 100644 index 0000000..7079f32 Binary files /dev/null and b/ARW.WebApi/wwwroot/Open/20230522/AC0F189241B8C2EF.png differ diff --git a/ARW.WebApi/wwwroot/Open/20230522/B1F5AEBE424925F0.jpg b/ARW.WebApi/wwwroot/Open/20230522/B1F5AEBE424925F0.jpg new file mode 100644 index 0000000..4bb0e9b Binary files /dev/null and b/ARW.WebApi/wwwroot/Open/20230522/B1F5AEBE424925F0.jpg differ diff --git a/ARW.WebApi/wwwroot/Open/20230522/B55627CBF8C19DB4.png b/ARW.WebApi/wwwroot/Open/20230522/B55627CBF8C19DB4.png new file mode 100644 index 0000000..8b28546 Binary files /dev/null and b/ARW.WebApi/wwwroot/Open/20230522/B55627CBF8C19DB4.png differ diff --git a/ARW.WebApi/wwwroot/Open/20230522/B7D166BF518FAF8F.jpg b/ARW.WebApi/wwwroot/Open/20230522/B7D166BF518FAF8F.jpg new file mode 100644 index 0000000..ca95370 Binary files /dev/null and b/ARW.WebApi/wwwroot/Open/20230522/B7D166BF518FAF8F.jpg differ diff --git a/ARW.WebApi/wwwroot/Open/20230523/76BE4D0F9D3D8ED9.png b/ARW.WebApi/wwwroot/Open/20230523/76BE4D0F9D3D8ED9.png new file mode 100644 index 0000000..2cee6f6 Binary files /dev/null and b/ARW.WebApi/wwwroot/Open/20230523/76BE4D0F9D3D8ED9.png differ diff --git a/ARW.WebApi/wwwroot/Open/20230524/118A19CEB6B112E9.png b/ARW.WebApi/wwwroot/Open/20230524/118A19CEB6B112E9.png new file mode 100644 index 0000000..8b28546 Binary files /dev/null and b/ARW.WebApi/wwwroot/Open/20230524/118A19CEB6B112E9.png differ diff --git a/ARW.WebApi/wwwroot/Open/20230524/1BC725E98C87B8A1.jpg b/ARW.WebApi/wwwroot/Open/20230524/1BC725E98C87B8A1.jpg new file mode 100644 index 0000000..39dfc13 Binary files /dev/null and b/ARW.WebApi/wwwroot/Open/20230524/1BC725E98C87B8A1.jpg differ diff --git a/ARW.WebApi/wwwroot/Open/20230524/4F32D8D44BAF74C9.jpg b/ARW.WebApi/wwwroot/Open/20230524/4F32D8D44BAF74C9.jpg new file mode 100644 index 0000000..39dfc13 Binary files /dev/null and b/ARW.WebApi/wwwroot/Open/20230524/4F32D8D44BAF74C9.jpg differ diff --git a/ARW.WebApi/wwwroot/Open/20230524/5E71D2AAB24E7092.png b/ARW.WebApi/wwwroot/Open/20230524/5E71D2AAB24E7092.png new file mode 100644 index 0000000..6cc6c9d Binary files /dev/null and b/ARW.WebApi/wwwroot/Open/20230524/5E71D2AAB24E7092.png differ diff --git a/ARW.WebApi/wwwroot/Open/20230524/FFBE5BD961106D03.jpg b/ARW.WebApi/wwwroot/Open/20230524/FFBE5BD961106D03.jpg new file mode 100644 index 0000000..e8d3855 Binary files /dev/null and b/ARW.WebApi/wwwroot/Open/20230524/FFBE5BD961106D03.jpg differ diff --git a/ARW.WebApi/wwwroot/Open/20230525/0AF2444311A3E857.png b/ARW.WebApi/wwwroot/Open/20230525/0AF2444311A3E857.png new file mode 100644 index 0000000..419a17b Binary files /dev/null and b/ARW.WebApi/wwwroot/Open/20230525/0AF2444311A3E857.png differ diff --git a/ARW.WebApi/wwwroot/Open/20230525/3B98C672FC9E4155.png b/ARW.WebApi/wwwroot/Open/20230525/3B98C672FC9E4155.png new file mode 100644 index 0000000..419a17b Binary files /dev/null and b/ARW.WebApi/wwwroot/Open/20230525/3B98C672FC9E4155.png differ diff --git a/ARW.WebApi/wwwroot/Open/20230525/67CCFDA48B6A659F.png b/ARW.WebApi/wwwroot/Open/20230525/67CCFDA48B6A659F.png new file mode 100644 index 0000000..1f736c1 Binary files /dev/null and b/ARW.WebApi/wwwroot/Open/20230525/67CCFDA48B6A659F.png differ diff --git a/ARW.WebApi/wwwroot/Open/20230526/DCD27EDED113A27D.png b/ARW.WebApi/wwwroot/Open/20230526/DCD27EDED113A27D.png new file mode 100644 index 0000000..419a17b Binary files /dev/null and b/ARW.WebApi/wwwroot/Open/20230526/DCD27EDED113A27D.png differ diff --git a/ARW.WebApi/wwwroot/Open/20230526/DE04786797F798D0.png b/ARW.WebApi/wwwroot/Open/20230526/DE04786797F798D0.png new file mode 100644 index 0000000..419a17b Binary files /dev/null and b/ARW.WebApi/wwwroot/Open/20230526/DE04786797F798D0.png differ diff --git a/ARW.WebApi/wwwroot/Open/20230528/089752A923D00ED0.jpg b/ARW.WebApi/wwwroot/Open/20230528/089752A923D00ED0.jpg new file mode 100644 index 0000000..13705ff Binary files /dev/null and b/ARW.WebApi/wwwroot/Open/20230528/089752A923D00ED0.jpg differ diff --git a/ARW.WebApi/wwwroot/Open/20230528/1ACD3195ABF7CB38.jpg b/ARW.WebApi/wwwroot/Open/20230528/1ACD3195ABF7CB38.jpg new file mode 100644 index 0000000..39dfc13 Binary files /dev/null and b/ARW.WebApi/wwwroot/Open/20230528/1ACD3195ABF7CB38.jpg differ diff --git a/ARW.WebApi/wwwroot/Open/20230528/8D8AD0FCCF366AB8.jpg b/ARW.WebApi/wwwroot/Open/20230528/8D8AD0FCCF366AB8.jpg new file mode 100644 index 0000000..40f942d Binary files /dev/null and b/ARW.WebApi/wwwroot/Open/20230528/8D8AD0FCCF366AB8.jpg differ diff --git a/ARW.WebApi/wwwroot/Open/20230528/E46A81225256BB4E.png b/ARW.WebApi/wwwroot/Open/20230528/E46A81225256BB4E.png new file mode 100644 index 0000000..693cebe Binary files /dev/null and b/ARW.WebApi/wwwroot/Open/20230528/E46A81225256BB4E.png differ diff --git a/ARW.WebApi/wwwroot/Product/20221017/9B5EF21374B3762E.jpg b/ARW.WebApi/wwwroot/Product/20221017/9B5EF21374B3762E.jpg new file mode 100644 index 0000000..926cb93 Binary files /dev/null and b/ARW.WebApi/wwwroot/Product/20221017/9B5EF21374B3762E.jpg differ diff --git a/ARW.WebApi/wwwroot/Product/20221017/CFE212EC0D1B033D.jpg b/ARW.WebApi/wwwroot/Product/20221017/CFE212EC0D1B033D.jpg new file mode 100644 index 0000000..8164cf3 Binary files /dev/null and b/ARW.WebApi/wwwroot/Product/20221017/CFE212EC0D1B033D.jpg differ diff --git a/ARW.WebApi/wwwroot/Product/20221017/D2528CA687528F52.jpg b/ARW.WebApi/wwwroot/Product/20221017/D2528CA687528F52.jpg new file mode 100644 index 0000000..8164cf3 Binary files /dev/null and b/ARW.WebApi/wwwroot/Product/20221017/D2528CA687528F52.jpg differ diff --git a/ARW.WebApi/wwwroot/Product/20221017/DCC860C1DB053A57.jpg b/ARW.WebApi/wwwroot/Product/20221017/DCC860C1DB053A57.jpg new file mode 100644 index 0000000..8164cf3 Binary files /dev/null and b/ARW.WebApi/wwwroot/Product/20221017/DCC860C1DB053A57.jpg differ diff --git a/ARW.WebApi/wwwroot/Product/20221018/036051BBE607E17D.jpg b/ARW.WebApi/wwwroot/Product/20221018/036051BBE607E17D.jpg new file mode 100644 index 0000000..ebd1e8a Binary files /dev/null and b/ARW.WebApi/wwwroot/Product/20221018/036051BBE607E17D.jpg differ diff --git a/ARW.WebApi/wwwroot/Product/20221018/1335C8AF690BABB5.jpg b/ARW.WebApi/wwwroot/Product/20221018/1335C8AF690BABB5.jpg new file mode 100644 index 0000000..05e1c88 Binary files /dev/null and b/ARW.WebApi/wwwroot/Product/20221018/1335C8AF690BABB5.jpg differ diff --git a/ARW.WebApi/wwwroot/Product/20221018/25CE98A7A85C6231.jpg b/ARW.WebApi/wwwroot/Product/20221018/25CE98A7A85C6231.jpg new file mode 100644 index 0000000..6fc9ff5 Binary files /dev/null and b/ARW.WebApi/wwwroot/Product/20221018/25CE98A7A85C6231.jpg differ diff --git a/ARW.WebApi/wwwroot/Product/20221018/2E1D6BB06C825E56.jpg b/ARW.WebApi/wwwroot/Product/20221018/2E1D6BB06C825E56.jpg new file mode 100644 index 0000000..2783f33 Binary files /dev/null and b/ARW.WebApi/wwwroot/Product/20221018/2E1D6BB06C825E56.jpg differ diff --git a/ARW.WebApi/wwwroot/Product/20221018/6F34BA210DD23E8E.jpg b/ARW.WebApi/wwwroot/Product/20221018/6F34BA210DD23E8E.jpg new file mode 100644 index 0000000..926cb93 Binary files /dev/null and b/ARW.WebApi/wwwroot/Product/20221018/6F34BA210DD23E8E.jpg differ diff --git a/ARW.WebApi/wwwroot/Product/20221018/7E177EB6FFD790BC.jpg b/ARW.WebApi/wwwroot/Product/20221018/7E177EB6FFD790BC.jpg new file mode 100644 index 0000000..ebd1e8a Binary files /dev/null and b/ARW.WebApi/wwwroot/Product/20221018/7E177EB6FFD790BC.jpg differ diff --git a/ARW.WebApi/wwwroot/Product/20221018/7E6AF34D2329F3AE.jpg b/ARW.WebApi/wwwroot/Product/20221018/7E6AF34D2329F3AE.jpg new file mode 100644 index 0000000..6fc9ff5 Binary files /dev/null and b/ARW.WebApi/wwwroot/Product/20221018/7E6AF34D2329F3AE.jpg differ diff --git a/ARW.WebApi/wwwroot/Product/20221018/83FBB687220EACA4.jpg b/ARW.WebApi/wwwroot/Product/20221018/83FBB687220EACA4.jpg new file mode 100644 index 0000000..6fc9ff5 Binary files /dev/null and b/ARW.WebApi/wwwroot/Product/20221018/83FBB687220EACA4.jpg differ diff --git a/ARW.WebApi/wwwroot/Product/20221018/85EB2F9A5A3CC32F.jpg b/ARW.WebApi/wwwroot/Product/20221018/85EB2F9A5A3CC32F.jpg new file mode 100644 index 0000000..9754520 Binary files /dev/null and b/ARW.WebApi/wwwroot/Product/20221018/85EB2F9A5A3CC32F.jpg differ diff --git a/ARW.WebApi/wwwroot/Product/20221018/99725D506AAFE44E.png b/ARW.WebApi/wwwroot/Product/20221018/99725D506AAFE44E.png new file mode 100644 index 0000000..b3a073d Binary files /dev/null and b/ARW.WebApi/wwwroot/Product/20221018/99725D506AAFE44E.png differ diff --git a/ARW.WebApi/wwwroot/Product/20221018/DCC636CE878C6763.jpg b/ARW.WebApi/wwwroot/Product/20221018/DCC636CE878C6763.jpg new file mode 100644 index 0000000..8164cf3 Binary files /dev/null and b/ARW.WebApi/wwwroot/Product/20221018/DCC636CE878C6763.jpg differ diff --git a/ARW.WebApi/wwwroot/Product/20221018/E6C6236C049D2A3D.jpg b/ARW.WebApi/wwwroot/Product/20221018/E6C6236C049D2A3D.jpg new file mode 100644 index 0000000..2783f33 Binary files /dev/null and b/ARW.WebApi/wwwroot/Product/20221018/E6C6236C049D2A3D.jpg differ diff --git a/ARW.WebApi/wwwroot/Product/20221018/E95AA948ACCE11E6.jpg b/ARW.WebApi/wwwroot/Product/20221018/E95AA948ACCE11E6.jpg new file mode 100644 index 0000000..926cb93 Binary files /dev/null and b/ARW.WebApi/wwwroot/Product/20221018/E95AA948ACCE11E6.jpg differ diff --git a/ARW.WebApi/wwwroot/Product/20221206/8DEE516816FBC2C7.png b/ARW.WebApi/wwwroot/Product/20221206/8DEE516816FBC2C7.png new file mode 100644 index 0000000..afbe7ba Binary files /dev/null and b/ARW.WebApi/wwwroot/Product/20221206/8DEE516816FBC2C7.png differ diff --git a/ARW.WebApi/wwwroot/Projectes/20230519/108408BFAE045F31.jpg b/ARW.WebApi/wwwroot/Projectes/20230519/108408BFAE045F31.jpg new file mode 100644 index 0000000..ca95370 Binary files /dev/null and b/ARW.WebApi/wwwroot/Projectes/20230519/108408BFAE045F31.jpg differ diff --git a/ARW.WebApi/wwwroot/Projectes/20230522/BFB3D4DE920F168D.jpg b/ARW.WebApi/wwwroot/Projectes/20230522/BFB3D4DE920F168D.jpg new file mode 100644 index 0000000..9409a0b Binary files /dev/null and b/ARW.WebApi/wwwroot/Projectes/20230522/BFB3D4DE920F168D.jpg differ diff --git a/ARW.WebApi/wwwroot/TestParts/20230317/411A8CAC77E10F05.png b/ARW.WebApi/wwwroot/TestParts/20230317/411A8CAC77E10F05.png new file mode 100644 index 0000000..0090f47 Binary files /dev/null and b/ARW.WebApi/wwwroot/TestParts/20230317/411A8CAC77E10F05.png differ diff --git a/ARW.WebApi/wwwroot/TestParts/20230317/4D646124ADE5DEE1.jpg b/ARW.WebApi/wwwroot/TestParts/20230317/4D646124ADE5DEE1.jpg new file mode 100644 index 0000000..8164cf3 Binary files /dev/null and b/ARW.WebApi/wwwroot/TestParts/20230317/4D646124ADE5DEE1.jpg differ diff --git a/ARW.WebApi/wwwroot/TestParts/20230317/DAAB6B82065631D7.jpg b/ARW.WebApi/wwwroot/TestParts/20230317/DAAB6B82065631D7.jpg new file mode 100644 index 0000000..44eda73 Binary files /dev/null and b/ARW.WebApi/wwwroot/TestParts/20230317/DAAB6B82065631D7.jpg differ diff --git a/ARW.WebApi/wwwroot/TestParts/20230319/D0E64E4293EAF23D.jpg b/ARW.WebApi/wwwroot/TestParts/20230319/D0E64E4293EAF23D.jpg new file mode 100644 index 0000000..8164cf3 Binary files /dev/null and b/ARW.WebApi/wwwroot/TestParts/20230319/D0E64E4293EAF23D.jpg differ diff --git a/ARW.WebApi/wwwroot/Testd/20230316/10EF12AA6595ECE6.png b/ARW.WebApi/wwwroot/Testd/20230316/10EF12AA6595ECE6.png new file mode 100644 index 0000000..6cc6c9d Binary files /dev/null and b/ARW.WebApi/wwwroot/Testd/20230316/10EF12AA6595ECE6.png differ diff --git a/ARW.WebApi/wwwroot/Testd/20230316/4B98D85856853C87.png b/ARW.WebApi/wwwroot/Testd/20230316/4B98D85856853C87.png new file mode 100644 index 0000000..6853262 Binary files /dev/null and b/ARW.WebApi/wwwroot/Testd/20230316/4B98D85856853C87.png differ diff --git a/ARW.WebApi/wwwroot/Testd/20230316/5FD5DEF20D91AACB.png b/ARW.WebApi/wwwroot/Testd/20230316/5FD5DEF20D91AACB.png new file mode 100644 index 0000000..6853262 Binary files /dev/null and b/ARW.WebApi/wwwroot/Testd/20230316/5FD5DEF20D91AACB.png differ diff --git a/ARW.WebApi/wwwroot/Testd/20230316/7431414626E70017.png b/ARW.WebApi/wwwroot/Testd/20230316/7431414626E70017.png new file mode 100644 index 0000000..993e4c1 Binary files /dev/null and b/ARW.WebApi/wwwroot/Testd/20230316/7431414626E70017.png differ diff --git a/ARW.WebApi/wwwroot/Testd/20230316/7508735A222CEC00.png b/ARW.WebApi/wwwroot/Testd/20230316/7508735A222CEC00.png new file mode 100644 index 0000000..92845c7 Binary files /dev/null and b/ARW.WebApi/wwwroot/Testd/20230316/7508735A222CEC00.png differ diff --git a/ARW.WebApi/wwwroot/Testd/20230316/BD4C9FF7BB37C803.png b/ARW.WebApi/wwwroot/Testd/20230316/BD4C9FF7BB37C803.png new file mode 100644 index 0000000..6853262 Binary files /dev/null and b/ARW.WebApi/wwwroot/Testd/20230316/BD4C9FF7BB37C803.png differ diff --git a/ARW.WebApi/wwwroot/Testd/20230316/E68A1232F07C900F.png b/ARW.WebApi/wwwroot/Testd/20230316/E68A1232F07C900F.png new file mode 100644 index 0000000..6cc6c9d Binary files /dev/null and b/ARW.WebApi/wwwroot/Testd/20230316/E68A1232F07C900F.png differ diff --git a/ARW.WebApi/wwwroot/Testd/20230317/12BD0313CD721731.jpg b/ARW.WebApi/wwwroot/Testd/20230317/12BD0313CD721731.jpg new file mode 100644 index 0000000..774d5df Binary files /dev/null and b/ARW.WebApi/wwwroot/Testd/20230317/12BD0313CD721731.jpg differ diff --git a/ARW.WebApi/wwwroot/Testd/20230317/452CBE55FB24BB98.jpg b/ARW.WebApi/wwwroot/Testd/20230317/452CBE55FB24BB98.jpg new file mode 100644 index 0000000..ab41595 Binary files /dev/null and b/ARW.WebApi/wwwroot/Testd/20230317/452CBE55FB24BB98.jpg differ diff --git a/ARW.WebApi/wwwroot/Testd/20230317/47AD7C5F66CBF796.jpeg b/ARW.WebApi/wwwroot/Testd/20230317/47AD7C5F66CBF796.jpeg new file mode 100644 index 0000000..6524a0e Binary files /dev/null and b/ARW.WebApi/wwwroot/Testd/20230317/47AD7C5F66CBF796.jpeg differ diff --git a/ARW.WebApi/wwwroot/Testd/20230317/47E837A00A5F0CBA.jpg b/ARW.WebApi/wwwroot/Testd/20230317/47E837A00A5F0CBA.jpg new file mode 100644 index 0000000..6524a0e Binary files /dev/null and b/ARW.WebApi/wwwroot/Testd/20230317/47E837A00A5F0CBA.jpg differ diff --git a/ARW.WebApi/wwwroot/Testd/20230317/645B107D6554D7C0.jpg b/ARW.WebApi/wwwroot/Testd/20230317/645B107D6554D7C0.jpg new file mode 100644 index 0000000..ab41595 Binary files /dev/null and b/ARW.WebApi/wwwroot/Testd/20230317/645B107D6554D7C0.jpg differ diff --git a/ARW.WebApi/wwwroot/Testd/20230317/880AB7044A6E397C.jpg b/ARW.WebApi/wwwroot/Testd/20230317/880AB7044A6E397C.jpg new file mode 100644 index 0000000..6524a0e Binary files /dev/null and b/ARW.WebApi/wwwroot/Testd/20230317/880AB7044A6E397C.jpg differ diff --git a/ARW.WebApi/wwwroot/Testd/20230317/9430C2F146C6B335.jpeg b/ARW.WebApi/wwwroot/Testd/20230317/9430C2F146C6B335.jpeg new file mode 100644 index 0000000..e9a0a00 Binary files /dev/null and b/ARW.WebApi/wwwroot/Testd/20230317/9430C2F146C6B335.jpeg differ diff --git a/ARW.WebApi/wwwroot/Testd/20230317/BA0A0257B439915E.png b/ARW.WebApi/wwwroot/Testd/20230317/BA0A0257B439915E.png new file mode 100644 index 0000000..92845c7 Binary files /dev/null and b/ARW.WebApi/wwwroot/Testd/20230317/BA0A0257B439915E.png differ diff --git a/ARW.WebApi/wwwroot/Testd/20230317/BCB56A600AA0DFB9.png b/ARW.WebApi/wwwroot/Testd/20230317/BCB56A600AA0DFB9.png new file mode 100644 index 0000000..9e4f5d7 Binary files /dev/null and b/ARW.WebApi/wwwroot/Testd/20230317/BCB56A600AA0DFB9.png differ diff --git a/ARW.WebApi/wwwroot/Testd/20230317/D888EFC39456BF88.png b/ARW.WebApi/wwwroot/Testd/20230317/D888EFC39456BF88.png new file mode 100644 index 0000000..ab9edda Binary files /dev/null and b/ARW.WebApi/wwwroot/Testd/20230317/D888EFC39456BF88.png differ diff --git a/ARW.WebApi/wwwroot/Testd/20230317/DBFA3C2492F3E0B7.jpg b/ARW.WebApi/wwwroot/Testd/20230317/DBFA3C2492F3E0B7.jpg new file mode 100644 index 0000000..0b99a36 Binary files /dev/null and b/ARW.WebApi/wwwroot/Testd/20230317/DBFA3C2492F3E0B7.jpg differ diff --git a/ARW.WebApi/wwwroot/Testd/20230317/ECBE290D76C238E7.jpg b/ARW.WebApi/wwwroot/Testd/20230317/ECBE290D76C238E7.jpg new file mode 100644 index 0000000..6524a0e Binary files /dev/null and b/ARW.WebApi/wwwroot/Testd/20230317/ECBE290D76C238E7.jpg differ diff --git a/ARW.WebApi/wwwroot/Testd/20230317/F3E09E2691865E09.jpg b/ARW.WebApi/wwwroot/Testd/20230317/F3E09E2691865E09.jpg new file mode 100644 index 0000000..994645d Binary files /dev/null and b/ARW.WebApi/wwwroot/Testd/20230317/F3E09E2691865E09.jpg differ diff --git a/ARW.WebApi/wwwroot/avatar/20221009/32B2AD71D8AB1DBA.jpg b/ARW.WebApi/wwwroot/avatar/20221009/32B2AD71D8AB1DBA.jpg new file mode 100644 index 0000000..1f0252f Binary files /dev/null and b/ARW.WebApi/wwwroot/avatar/20221009/32B2AD71D8AB1DBA.jpg differ diff --git a/ARW.WebApi/wwwroot/email/20220723/75FE70F994AA3573.xlsx b/ARW.WebApi/wwwroot/email/20220723/75FE70F994AA3573.xlsx new file mode 100644 index 0000000..953c46a Binary files /dev/null and b/ARW.WebApi/wwwroot/email/20220723/75FE70F994AA3573.xlsx differ diff --git a/ARW.WebApi/wwwroot/key/20230202/BE49408B286052C6.jpg b/ARW.WebApi/wwwroot/key/20230202/BE49408B286052C6.jpg new file mode 100644 index 0000000..cad38fb Binary files /dev/null and b/ARW.WebApi/wwwroot/key/20230202/BE49408B286052C6.jpg differ diff --git a/ARW.WebApi/wwwroot/key/20230202/D10B8187A4A841C8.jpg b/ARW.WebApi/wwwroot/key/20230202/D10B8187A4A841C8.jpg new file mode 100644 index 0000000..5fc1e1a Binary files /dev/null and b/ARW.WebApi/wwwroot/key/20230202/D10B8187A4A841C8.jpg differ diff --git a/ARW.WebApi/wwwroot/student/20221116/31BAA2C13B5F43A5.jpg b/ARW.WebApi/wwwroot/student/20221116/31BAA2C13B5F43A5.jpg new file mode 100644 index 0000000..0fb5651 Binary files /dev/null and b/ARW.WebApi/wwwroot/student/20221116/31BAA2C13B5F43A5.jpg differ diff --git a/ARW.WebApi/wwwroot/student/20221116/D4A55F2C4BEA1B23.jpg b/ARW.WebApi/wwwroot/student/20221116/D4A55F2C4BEA1B23.jpg new file mode 100644 index 0000000..2010ac5 Binary files /dev/null and b/ARW.WebApi/wwwroot/student/20221116/D4A55F2C4BEA1B23.jpg differ diff --git a/ARW.WebApi/wwwroot/student/20230202/D8B1F9A962B71442.jpg b/ARW.WebApi/wwwroot/student/20230202/D8B1F9A962B71442.jpg new file mode 100644 index 0000000..cad38fb Binary files /dev/null and b/ARW.WebApi/wwwroot/student/20230202/D8B1F9A962B71442.jpg differ diff --git a/ARW.WebApi/wwwroot/student/20230320/34A71A4979D2333D.png b/ARW.WebApi/wwwroot/student/20230320/34A71A4979D2333D.png new file mode 100644 index 0000000..bc17806 Binary files /dev/null and b/ARW.WebApi/wwwroot/student/20230320/34A71A4979D2333D.png differ diff --git a/ARW.WebApi/wwwroot/student/20230320/6CDEB4F345CE58EF.png b/ARW.WebApi/wwwroot/student/20230320/6CDEB4F345CE58EF.png new file mode 100644 index 0000000..bc17806 Binary files /dev/null and b/ARW.WebApi/wwwroot/student/20230320/6CDEB4F345CE58EF.png differ diff --git a/ARW.WebApi/wwwroot/student/20230320/F1CBF0822D9676EF.png b/ARW.WebApi/wwwroot/student/20230320/F1CBF0822D9676EF.png new file mode 100644 index 0000000..0e70bd9 Binary files /dev/null and b/ARW.WebApi/wwwroot/student/20230320/F1CBF0822D9676EF.png differ diff --git a/ARW.WebApi/wwwroot/wxpay/2022-12-19-FundflowBill.csv b/ARW.WebApi/wwwroot/wxpay/2022-12-19-FundflowBill.csv new file mode 100644 index 0000000..e69de29 diff --git a/ARWAdmin.sln b/ARWAdmin.sln new file mode 100644 index 0000000..5180627 --- /dev/null +++ b/ARWAdmin.sln @@ -0,0 +1,70 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.1.32210.238 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ARW.WebApi", "ARW.WebApi\ARW.WebApi.csproj", "{E5497BB4-B0C1-4794-9FAE-163F626EC399}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ARW.Model", "ARW.Model\ARW.Model.csproj", "{B35D73B1-2E22-4636-B88B-10C5E6D8E524}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ARW.Common", "ARW.Common\ARW.Common.csproj", "{42C84599-1E99-45B4-929B-417C37337EF8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Infrastructure", "Infrastructure\Infrastructure.csproj", "{5D740120-5491-4FE2-B5BE-8A9C48BFE3C5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ARW.Tasks", "ARW.Tasks\ARW.Tasks.csproj", "{B657ED99-40E5-423A-AFE7-157C4EE576CB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ARW.Service", "ARW.Service\ARW.Service.csproj", "{75ADA3C1-148D-4727-A718-79447D9B5EEE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ARW.Repository", "ARW.Repository\ARW.Repository.csproj", "{17E277BF-B2B8-4111-AE43-38246128C83C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ARW.CodeGenerator", "ARW.CodeGenerator\ARW.CodeGenerator.csproj", "{B353DE0B-12C6-4C15-909A-DB68F71D5AE9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E5497BB4-B0C1-4794-9FAE-163F626EC399}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E5497BB4-B0C1-4794-9FAE-163F626EC399}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E5497BB4-B0C1-4794-9FAE-163F626EC399}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E5497BB4-B0C1-4794-9FAE-163F626EC399}.Release|Any CPU.Build.0 = Release|Any CPU + {B35D73B1-2E22-4636-B88B-10C5E6D8E524}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B35D73B1-2E22-4636-B88B-10C5E6D8E524}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B35D73B1-2E22-4636-B88B-10C5E6D8E524}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B35D73B1-2E22-4636-B88B-10C5E6D8E524}.Release|Any CPU.Build.0 = Release|Any CPU + {42C84599-1E99-45B4-929B-417C37337EF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {42C84599-1E99-45B4-929B-417C37337EF8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {42C84599-1E99-45B4-929B-417C37337EF8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {42C84599-1E99-45B4-929B-417C37337EF8}.Release|Any CPU.Build.0 = Release|Any CPU + {5D740120-5491-4FE2-B5BE-8A9C48BFE3C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5D740120-5491-4FE2-B5BE-8A9C48BFE3C5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5D740120-5491-4FE2-B5BE-8A9C48BFE3C5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5D740120-5491-4FE2-B5BE-8A9C48BFE3C5}.Release|Any CPU.Build.0 = Release|Any CPU + {B657ED99-40E5-423A-AFE7-157C4EE576CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B657ED99-40E5-423A-AFE7-157C4EE576CB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B657ED99-40E5-423A-AFE7-157C4EE576CB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B657ED99-40E5-423A-AFE7-157C4EE576CB}.Release|Any CPU.Build.0 = Release|Any CPU + {75ADA3C1-148D-4727-A718-79447D9B5EEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {75ADA3C1-148D-4727-A718-79447D9B5EEE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {75ADA3C1-148D-4727-A718-79447D9B5EEE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {75ADA3C1-148D-4727-A718-79447D9B5EEE}.Release|Any CPU.Build.0 = Release|Any CPU + {17E277BF-B2B8-4111-AE43-38246128C83C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {17E277BF-B2B8-4111-AE43-38246128C83C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {17E277BF-B2B8-4111-AE43-38246128C83C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {17E277BF-B2B8-4111-AE43-38246128C83C}.Release|Any CPU.Build.0 = Release|Any CPU + {B353DE0B-12C6-4C15-909A-DB68F71D5AE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B353DE0B-12C6-4C15-909A-DB68F71D5AE9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B353DE0B-12C6-4C15-909A-DB68F71D5AE9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B353DE0B-12C6-4C15-909A-DB68F71D5AE9}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {60A6A299-13D7-4A17-8AB8-F1FE92657F85} + EndGlobalSection + GlobalSection(ExtensibiARWtyGlobals) = postSolution + SolutionGuid = {0469FF3A-7322-4053-94C7-881B103A57C5} + EndGlobalSection +EndGlobal diff --git a/Infrastructure/App/App.cs b/Infrastructure/App/App.cs new file mode 100644 index 0000000..91814cb --- /dev/null +++ b/Infrastructure/App/App.cs @@ -0,0 +1,69 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Security.Claims; +using static System.Net.Mime.MediaTypeNames; + +namespace Infrastructure +{ + + public static class App + { + /// + /// 服务提供器 + /// + public static IServiceProvider ServiceProvider => HttpContext?.RequestServices ?? InternalApp.ServiceProvider; + + /// + /// 获取请求上下文 + /// + public static HttpContext HttpContext => HttpContextLocal.Current(); + /// + /// 获取请求上下文用户 + /// + public static ClaimsPrincipal User => HttpContext?.User; + + /// + /// 获取请求生命周期的服务 + /// + /// + /// + public static TService GetService() + where TService : class + { + return GetService(typeof(TService)) as TService; + } + + /// + /// 获取请求生命周期的服务 + /// + /// + /// + public static object GetService(Type type) + { + return ServiceProvider.GetService(type); + } + + /// + /// 获取请求生命周期的服务 + /// + /// + /// + public static TService GetRequiredService() + where TService : class + { + return GetRequiredService(typeof(TService)) as TService; + } + + /// + /// 获取请求生命周期的服务 + /// + /// + /// + public static object GetRequiredService(Type type) + { + return ServiceProvider.GetRequiredService(type); + } + } +} diff --git a/Infrastructure/App/Web/HttpContextLocal.cs b/Infrastructure/App/Web/HttpContextLocal.cs new file mode 100644 index 0000000..8c0a96d --- /dev/null +++ b/Infrastructure/App/Web/HttpContextLocal.cs @@ -0,0 +1,59 @@ +using Microsoft.AspNetCore.Http; +using System; +using System.Linq.Expressions; +using System.Reflection; +using System.Threading; + +namespace Microsoft.AspNetCore.Http +{ + public static class HttpContextLocal + { + private static Func _asyncLocalAccessor; + private static Func _holderAccessor; + private static Func _httpContextAccessor; + + /// + /// 获取当前 HttpContext 对象 + /// + /// + public static HttpContext Current() + { + var asyncLocal = (_asyncLocalAccessor ??= CreateAsyncLocalAccessor())(); + if (asyncLocal == null) return null; + + var holder = (_holderAccessor ??= CreateHolderAccessor(asyncLocal))(asyncLocal); + if (holder == null) return null; + + return (_httpContextAccessor ??= CreateHttpContextAccessor(holder))(holder); + + // 创建异步本地访问器 + static Func CreateAsyncLocalAccessor() + { + var fieldInfo = typeof(HttpContextAccessor).GetField("_httpContextCurrent", BindingFlags.Static | BindingFlags.NonPublic); + var field = Expression.Field(null, fieldInfo); + return Expression.Lambda>(field).Compile(); + } + + // 创建常驻 HttpContext 访问器 + static Func CreateHolderAccessor(object asyncLocal) + { + var holderType = asyncLocal.GetType().GetGenericArguments()[0]; + var method = typeof(AsyncLocal<>).MakeGenericType(holderType).GetProperty("Value").GetGetMethod(); + var target = Expression.Parameter(typeof(object)); + var convert = Expression.Convert(target, asyncLocal.GetType()); + var getValue = Expression.Call(convert, method); + return Expression.Lambda>(getValue, target).Compile(); + } + + // 获取 HttpContext 访问器 + static Func CreateHttpContextAccessor(object holder) + { + var target = Expression.Parameter(typeof(object)); + var convert = Expression.Convert(target, holder.GetType()); + var field = Expression.Field(convert, "Context"); + var convertAsResult = Expression.Convert(field, typeof(HttpContext)); + return Expression.Lambda>(convertAsResult, target).Compile(); + } + } + } +} diff --git a/Infrastructure/AppSettings.cs b/Infrastructure/AppSettings.cs new file mode 100644 index 0000000..ffc7bd3 --- /dev/null +++ b/Infrastructure/AppSettings.cs @@ -0,0 +1,85 @@ +using Microsoft.Extensions.Configuration; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Infrastructure +{ + public class AppSettings + { + static IConfiguration Configuration { get; set; } + + public AppSettings(IConfiguration configuration) + { + Configuration = configuration; + } + + /// + /// 封装要操作的字符 + /// + /// 节点配置 + /// + public static string App(params string[] sections) + { + try + { + if (sections.Any()) + { + return Configuration[string.Join(":", sections)]; + } + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + + return ""; + } + + /// + /// 递归获取配置信息数组 + /// + /// + /// + /// + public static List App(params string[] sections) + { + List list = new(); + // 引用 Microsoft.Extensions.Configuration.Binder 包 + Configuration.Bind(string.Join(":", sections), list); + return list; + } + public static T Bind(string key, T t) + { + Configuration.Bind(key, t); + + return t; + } + + public static T GetAppConfig(string key, T defaultValue = default) + { + T setting = (T)Convert.ChangeType(Configuration[key], typeof(T)); + var value = setting; + if (setting == null) + value = defaultValue; + return value; + } + + /// + /// 获取配置文件 + /// + /// eg: WeChat:Token + /// + public static string GetConfig(string key) + { + return Configuration[key]; + } + } + + public class CrawlerConfig + { + public string Name { get; set; } + + public List Hosts { get; set; } + } +} diff --git a/Infrastructure/Attribute/AppServiceAttribute.cs b/Infrastructure/Attribute/AppServiceAttribute.cs new file mode 100644 index 0000000..f9ccd02 --- /dev/null +++ b/Infrastructure/Attribute/AppServiceAttribute.cs @@ -0,0 +1,34 @@ +using System; + +namespace Infrastructure.Attribute +{ + /// + /// 参考地址:https://www.cnblogs.com/kelelipeng/p/10643556.html + /// 标记服务 + /// 如何使用? + /// 1、如果服务是本身 直接在类上使用[AppService] + /// 2、如果服务是接口 在类上使用 [AppService(ServiceType = typeof(实现接口))] + /// + [AttributeUsage(AttributeTargets.Class, Inherited = false)] + public class AppServiceAttribute : System.Attribute + { + /// + /// 服务声明周期 + /// 不给默认值的话注册的是AddSingleton + /// + public LifeTime ServiceLifetime { get; set; } = LifeTime.Scoped; + /// + /// 指定服务类型 + /// + public Type ServiceType { get; set; } + /// + /// 是否可以从第一个接口获取服务类型 + /// + public bool InterfaceServiceType { get; set; } + } + + public enum LifeTime + { + Transient, Scoped, Singleton + } +} diff --git a/Infrastructure/Attribute/LogAttribute.cs b/Infrastructure/Attribute/LogAttribute.cs new file mode 100644 index 0000000..20df620 --- /dev/null +++ b/Infrastructure/Attribute/LogAttribute.cs @@ -0,0 +1,35 @@ +using Infrastructure.Enums; + +namespace Infrastructure.Attribute +{ + /// + /// 自定义操作日志记录注解 + /// + public class LogAttribute : System.Attribute + { + public string Title { get; set; } + public BusinessType BusinessType { get; set; } + /// + /// 是否保存请求数据 + /// + public bool IsSaveRequestData { get; set; } = true; + /// + /// 是否保存返回数据 + /// + public bool IsSaveResponseData { get; set; } = true; + + public LogAttribute() { } + + public LogAttribute(string name) + { + Title = name; + } + public LogAttribute(string name, BusinessType businessType, bool saveRequestData = true, bool saveResponseData = true) + { + Title = name; + BusinessType = businessType; + IsSaveRequestData = saveRequestData; + IsSaveResponseData = saveResponseData; + } + } +} diff --git a/Infrastructure/Constant/HttpStatus.cs b/Infrastructure/Constant/HttpStatus.cs new file mode 100644 index 0000000..0bc6d42 --- /dev/null +++ b/Infrastructure/Constant/HttpStatus.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Infrastructure.Constant +{ + public class HttpStatus + { + /// + /// 操作成功 + /// + public static readonly int SUCCESS = 200; + /// + /// 对象创建成功 + /// + public static readonly int CREATED = 201; + + /// + /// 请求已经被接受 + /// + public static readonly int ACCEPTED = 202; + + /// + /// 操作已经执行成功,但是没有返回数据 + /// + public static readonly int NO_CONTENT = 204; + + /// + /// 资源已被移除 + /// + public static readonly int MOVED_PERM = 301; + + /// + /// 重定向 + /// + public static readonly int SEE_OTHER = 303; + + /// + /// 资源没有被修改 + /// + public static readonly int NOT_MODIFIED = 304; + + /** + * 参数列表错误(缺少,格式不匹配) + */ + public static readonly int BAD_REQUEST = 400; + + /// + /// 未授权 + /// + public static readonly int UNAUTHORIZED = 401; + + /** + * 访问受限,授权过期 + */ + public static readonly int FORBIDDEN = 403; + + /** + * 资源,服务未找到 + */ + public static readonly int NOT_FOUND = 404; + + /** + * 不允许的http方法 + */ + public static readonly int BAD_METHOD = 405; + + /** + * 资源冲突,或者资源被锁 + */ + public static readonly int CONFARWCT = 409; + + /** + * 不支持的数据,媒体类型 + */ + public static readonly int UNSUPPORTED_TYPE = 415; + + /** + * 系统内部错误 + */ + public static readonly int ERROR = 500; + + /** + * 接口未实现 + */ + public static readonly int NOT_IMPLEMENTED = 501; + } +} diff --git a/Infrastructure/Constant/HubsConstant.cs b/Infrastructure/Constant/HubsConstant.cs new file mode 100644 index 0000000..d81b7f8 --- /dev/null +++ b/Infrastructure/Constant/HubsConstant.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Infrastructure.Constant +{ + public class HubsConstant + { + private const string V = "receiveNotice"; + public static string ReceiveNotice = V; + public static string OnlineNum = "onlineNum"; + public static string MoreNotice = "moreNotice"; + public static string OnlineUser = "onlineUser"; + } +} diff --git a/Infrastructure/CustomException/CustomException.cs b/Infrastructure/CustomException/CustomException.cs new file mode 100644 index 0000000..19f8fc5 --- /dev/null +++ b/Infrastructure/CustomException/CustomException.cs @@ -0,0 +1,37 @@ +using System; + +namespace Infrastructure +{ + public class CustomException : Exception + { + public int Code { get; set; } + public string Msg { get; set; } + public string LogMsg { get; set; } + + public CustomException(string msg) : base(msg) + { + } + public CustomException(int code, string msg) : base(msg) + { + Code = code; + Msg = msg; + } + + public CustomException(ResultCode resultCode, string msg) : base(msg) + { + Code = (int)resultCode; + } + + /// + /// 自定义异常 + /// + /// + /// + /// 用于记录详细日志到输出介质 + public CustomException(ResultCode resultCode, string msg, object errorMsg) : base(msg) + { + Code = (int)resultCode; + LogMsg = errorMsg.ToString(); + } + } +} \ No newline at end of file diff --git a/Infrastructure/CustomException/ResultCode.cs b/Infrastructure/CustomException/ResultCode.cs new file mode 100644 index 0000000..579bcf9 --- /dev/null +++ b/Infrastructure/CustomException/ResultCode.cs @@ -0,0 +1,43 @@ +using System.ComponentModel; + +namespace Infrastructure +{ + public enum ResultCode + { + [Description("success")] + SUCCESS = 200, + + [Description("参数错误")] + PARAM_ERROR = 101, + + [Description("验证码错误")] + CAPTCHA_ERROR = 103, + + [Description("登录错误")] + LOGIN_ERROR = 105, + + [Description("操作失败")] + FAIL = 1, + + [Description("服务端出错啦")] + GLOBAL_ERROR = 500, + + [Description("自定义异常")] + CUSTOM_ERROR = 110, + + [Description("非法请求")] + INVAARWD_REQUEST = 116, + + [Description("授权失败")] + OAUTH_FAIL = 201, + + [Description("未授权")] + DENY = 401, + + [Description("授权访问失败")] + FORBIDDEN = 403, + + [Description("Bad Request")] + BAD_REQUEST = 400 + } +} diff --git a/Infrastructure/Enums/BusinessType.cs b/Infrastructure/Enums/BusinessType.cs new file mode 100644 index 0000000..1ffdb6c --- /dev/null +++ b/Infrastructure/Enums/BusinessType.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Infrastructure.Enums +{ + /** + * 业务操作类型 + * 0=其它,1=新增,2=修改,3=删除,4=授权,5=导出,6=导入,7=强退,8=生成代码,9=清空数据,10=添加或修改 + * @author arw + * ry + */ + public enum BusinessType + { + /** + * 其它 + */ + OTHER = 0, + + /** + * 新增 + */ + INSERT = 1, + + /** + * 修改 + */ + UPDATE = 2, + + /** + * 删除 + */ + DELETE = 3, + + /** + * 授权 + */ + GRANT = 4, + + /** + * 导出 + */ + EXPORT = 5, + + /** + * 导入 + */ + IMPORT = 6, + + /** + * 强退 + */ + FORCE = 7, + + /** + * 生成代码 + */ + GENCODE = 8, + + /** + * 清空数据 + */ + CLEAN = 9, + + /** + * 审核 + */ + AUDIT = 9, + + /** + * 添加或修改 + */ + ADDORUPDATE = 10, + } +} diff --git a/Infrastructure/Enums/StoreType.cs b/Infrastructure/Enums/StoreType.cs new file mode 100644 index 0000000..cbdbdfc --- /dev/null +++ b/Infrastructure/Enums/StoreType.cs @@ -0,0 +1,40 @@ +using System.ComponentModel; + +namespace Infrastructure.Enums +{ + /// + /// 文件存储位置 + /// + public enum StoreType + { + /// + /// 本地 + /// + [Description("本地")] + LOCAL = 1, + + /// + /// 阿里云 + /// + [Description("阿里云")] + AARWYUN = 2, + + /// + /// 腾讯云 + /// + [Description("腾讯云")] + TENCENT = 3, + + /// + /// 七牛 + /// + [Description("七牛云")] + QINIU = 4, + + /// + /// 远程 + /// + [Description("远程")] + REMOTE = 5 + } +} diff --git a/Infrastructure/Extensions/AppServiceExtensions.cs b/Infrastructure/Extensions/AppServiceExtensions.cs new file mode 100644 index 0000000..02aa7da --- /dev/null +++ b/Infrastructure/Extensions/AppServiceExtensions.cs @@ -0,0 +1,71 @@ +using Infrastructure.Attribute; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Linq; +using System.Reflection; + +namespace Infrastructure.Extensions +{ + public static class AppServiceExtensions + { + /// + /// 注册引用程序域中所有有AppService标记的类的服务 + /// + /// + public static void AddAppService(this IServiceCollection services) + { + //var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + + string []cls = new string[] { "ARW.Repository", "ARW.Service", "ARW.Tasks" }; + foreach (var item in cls) + { + Assembly assembly = Assembly.Load(item); + Register(services, assembly); + } + } + + private static void Register(IServiceCollection services, Assembly assembly) + { + foreach (var type in assembly.GetTypes()) + { + var serviceAttribute = type.GetCustomAttribute(); + + if (serviceAttribute != null) + { + var serviceType = serviceAttribute.ServiceType; + //情况1 适用于依赖抽象编程,注意这里只获取第一个 + if (serviceType == null && serviceAttribute.InterfaceServiceType) + { + serviceType = type.GetInterfaces().FirstOrDefault(); + } + //情况2 不常见特殊情况下才会指定ServiceType,写起来麻烦 + if (serviceType == null) + { + serviceType = type; + } + + switch (serviceAttribute.ServiceLifetime) + { + case LifeTime.Singleton: + services.AddSingleton(serviceType, type); + break; + case LifeTime.Scoped: + services.AddScoped(serviceType, type); + break; + case LifeTime.Transient: + services.AddTransient(serviceType, type); + break; + default: + services.AddTransient(serviceType, type); + break; + } + //Console.WriteLine($"注册:{serviceType}"); + } + else + { + //Console.WriteLine($"注册:{serviceType}"); + } + } + } + } +} diff --git a/Infrastructure/Extensions/Extension.Convert.cs b/Infrastructure/Extensions/Extension.Convert.cs new file mode 100644 index 0000000..4710dfd --- /dev/null +++ b/Infrastructure/Extensions/Extension.Convert.cs @@ -0,0 +1,446 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Infrastructure.Extensions +{ + public static partial class Extensions + { + #region 转换为long + /// + /// 将object转换为long,若转换失败,则返回0。不抛出异常。 + /// + /// + /// + public static long ParseToLong(this object obj) + { + try + { + return long.Parse(obj.ToString()); + } + catch + { + return 0L; + } + } + + /// + /// 将object转换为long,若转换失败,则返回指定值。不抛出异常。 + /// + /// + /// + /// + public static long ParseToLong(this string str, long defaultValue) + { + try + { + return long.Parse(str); + } + catch + { + return defaultValue; + } + } + #endregion + + #region 转换为int + /// + /// 将object转换为int,若转换失败,则返回0。不抛出异常。 + /// + /// + /// + public static int ParseToInt(this object str) + { + try + { + return Convert.ToInt32(str); + } + catch + { + return 0; + } + } + + /// + /// 将object转换为int,若转换失败,则返回指定值。不抛出异常。 + /// null返回默认值 + /// + /// + /// + /// + public static int ParseToInt(this object str, int defaultValue) + { + if (str == null) + { + return defaultValue; + } + try + { + return Convert.ToInt32(str); + } + catch + { + return defaultValue; + } + } + #endregion + + #region 转换为short + /// + /// 将object转换为short,若转换失败,则返回0。不抛出异常。 + /// + /// + /// + public static short ParseToShort(this object obj) + { + try + { + return short.Parse(obj.ToString()); + } + catch + { + return 0; + } + } + + /// + /// 将object转换为short,若转换失败,则返回指定值。不抛出异常。 + /// + /// + /// + public static short ParseToShort(this object str, short defaultValue) + { + try + { + return short.Parse(str.ToString()); + } + catch + { + return defaultValue; + } + } + #endregion + + #region 转换为demical + /// + /// 将object转换为demical,若转换失败,则返回指定值。不抛出异常。 + /// + /// + /// + public static decimal ParseToDecimal(this object str, decimal defaultValue) + { + try + { + return decimal.Parse(str.ToString()); + } + catch + { + return defaultValue; + } + } + + /// + /// 将object转换为demical,若转换失败,则返回0。不抛出异常。 + /// + /// + /// + public static decimal ParseToDecimal(this object str) + { + try + { + return decimal.Parse(str.ToString()); + } + catch + { + return 0; + } + } + #endregion + + #region 转化为bool + /// + /// 将object转换为bool,若转换失败,则返回false。不抛出异常。 + /// + /// + /// + public static bool ParseToBool(this object str) + { + try + { + return bool.Parse(str.ToString()); + } + catch + { + return false; + } + } + + /// + /// 将object转换为bool,若转换失败,则返回指定值。不抛出异常。 + /// + /// + /// + public static bool ParseToBool(this object str, bool result) + { + try + { + return bool.Parse(str.ToString()); + } + catch + { + return result; + } + } + #endregion + + #region 转换为float + /// + /// 将object转换为float,若转换失败,则返回0。不抛出异常。 + /// + /// + /// + public static float ParseToFloat(this object str) + { + try + { + return float.Parse(str.ToString()); + } + catch + { + return 0; + } + } + + /// + /// 将object转换为float,若转换失败,则返回指定值。不抛出异常。 + /// + /// + /// + public static float ParseToFloat(this object str, float result) + { + try + { + return float.Parse(str.ToString()); + } + catch + { + return result; + } + } + #endregion + + #region 转换为Guid + /// + /// 将string转换为Guid,若转换失败,则返回Guid.Empty。不抛出异常。 + /// + /// + /// + public static Guid ParseToGuid(this string str) + { + try + { + return new Guid(str); + } + catch + { + return Guid.Empty; + } + } + #endregion + + #region 转换为DateTime + /// + /// 将string转换为DateTime,若转换失败,则返回日期最小值。不抛出异常。 + /// + /// + /// + public static DateTime ParseToDateTime(this string str) + { + try + { + if (string.IsNullOrWhiteSpace(str)) + { + return DateTime.MinValue; + } + if (str.Contains("-") || str.Contains("/")) + { + return DateTime.Parse(str); + } + else + { + int length = str.Length; + switch (length) + { + case 4: + return DateTime.ParseExact(str, "yyyy", System.Globalization.CultureInfo.CurrentCulture); + case 6: + return DateTime.ParseExact(str, "yyyyMM", System.Globalization.CultureInfo.CurrentCulture); + case 8: + return DateTime.ParseExact(str, "yyyyMMdd", System.Globalization.CultureInfo.CurrentCulture); + case 10: + return DateTime.ParseExact(str, "yyyyMMddHH", System.Globalization.CultureInfo.CurrentCulture); + case 12: + return DateTime.ParseExact(str, "yyyyMMddHHmm", System.Globalization.CultureInfo.CurrentCulture); + case 14: + return DateTime.ParseExact(str, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture); + default: + return DateTime.ParseExact(str, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture); + } + } + } + catch + { + return DateTime.MinValue; + } + } + + /// + /// 将string转换为DateTime,若转换失败,则返回默认值。 + /// + /// + /// + /// + public static DateTime ParseToDateTime(this string str, DateTime? defaultValue) + { + try + { + if (string.IsNullOrWhiteSpace(str)) + { + return defaultValue.GetValueOrDefault(); + } + if (str.Contains("-") || str.Contains("/")) + { + return DateTime.Parse(str); + } + else + { + int length = str.Length; + switch (length) + { + case 4: + return DateTime.ParseExact(str, "yyyy", System.Globalization.CultureInfo.CurrentCulture); + case 6: + return DateTime.ParseExact(str, "yyyyMM", System.Globalization.CultureInfo.CurrentCulture); + case 8: + return DateTime.ParseExact(str, "yyyyMMdd", System.Globalization.CultureInfo.CurrentCulture); + case 10: + return DateTime.ParseExact(str, "yyyyMMddHH", System.Globalization.CultureInfo.CurrentCulture); + case 12: + return DateTime.ParseExact(str, "yyyyMMddHHmm", System.Globalization.CultureInfo.CurrentCulture); + case 14: + return DateTime.ParseExact(str, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture); + default: + return DateTime.ParseExact(str, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture); + } + } + } + catch + { + return defaultValue.GetValueOrDefault(); + } + } + #endregion + + #region 转换为string + /// + /// 将object转换为string,若转换失败,则返回""。不抛出异常。 + /// + /// + /// + public static string ParseToString(this object obj) + { + try + { + if (obj == null) + { + return string.Empty; + } + else + { + return obj.ToString(); + } + } + catch + { + return string.Empty; + } + } + public static string ParseToStrings(this object obj) + { + try + { + var list = obj as IEnumerable; + if (list != null) + { + return string.Join(",", list); + } + else + { + return obj.ToString(); + } + } + catch + { + return string.Empty; + } + + } + #endregion + + #region 转换为double + /// + /// 将object转换为double,若转换失败,则返回0。不抛出异常。 + /// + /// + /// + public static double ParseToDouble(this object obj) + { + try + { + return double.Parse(obj.ToString()); + } + catch + { + return 0; + } + } + + /// + /// 将object转换为double,若转换失败,则返回指定值。不抛出异常。 + /// + /// + /// + /// + public static double ParseToDouble(this object str, double defaultValue) + { + try + { + return double.Parse(str.ToString()); + } + catch + { + return defaultValue; + } + } + #endregion + + #region 强制转换类型 + /// + /// 强制转换类型 + /// + /// + /// + /// + public static IEnumerable CastSuper(this IEnumerable source) + { + foreach (object item in source) + { + yield return (TResult)Convert.ChangeType(item, typeof(TResult)); + } + } + #endregion + } +} diff --git a/Infrastructure/Extensions/Extension.Enum.cs b/Infrastructure/Extensions/Extension.Enum.cs new file mode 100644 index 0000000..72710ff --- /dev/null +++ b/Infrastructure/Extensions/Extension.Enum.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +//using Newtonsoft.Json; + +namespace Infrastructure.Extensions +{ + public static partial class Extensions + { + #region 枚举成员转成dictionary类型 + /// + /// 转成dictionary类型 + /// + /// + /// + public static Dictionary EnumToDictionary(this Type enumType) + { + Dictionary dictionary = new Dictionary(); + Type typeDescription = typeof(DescriptionAttribute); + FieldInfo[] fields = enumType.GetFields(); + int sValue = 0; + string sText = string.Empty; + foreach (FieldInfo field in fields) + { + if (field.FieldType.IsEnum) + { + sValue = ((int)enumType.InvokeMember(field.Name, BindingFlags.GetField, null, null, null)); + object[] arr = field.GetCustomAttributes(typeDescription, true); + if (arr.Length > 0) + { + DescriptionAttribute da = (DescriptionAttribute)arr[0]; + sText = da.Description; + } + else + { + sText = field.Name; + } + dictionary.Add(sValue, sText); + } + } + return dictionary; + } + /// + /// 枚举成员转成键值对Json字符串 + /// + /// + /// + //public static string EnumToDictionaryString(this Type enumType) + //{ + // List> dictionaryList = EnumToDictionary(enumType).ToList(); + // var sJson = JsonConvert.SerializeObject(dictionaryList); + // return sJson; + //} + #endregion + + #region 获取枚举的描述 + /// + /// 获取枚举值对应的描述 + /// + /// + /// + public static string GetDescription(this System.Enum enumType) + { + FieldInfo EnumInfo = enumType.GetType().GetField(enumType.ToString()); + if (EnumInfo != null) + { + DescriptionAttribute[] EnumAttributes = (DescriptionAttribute[])EnumInfo.GetCustomAttributes(typeof(DescriptionAttribute), false); + if (EnumAttributes.Length > 0) + { + return EnumAttributes[0].Description; + } + } + return enumType.ToString(); + } + #endregion + + #region 根据值获取枚举的描述 + public static string GetDescriptionByEnum(this object obj) + { + var tEnum = System.Enum.Parse(typeof(T), obj.ParseToString()) as System.Enum; + var description = tEnum.GetDescription(); + return description; + } + #endregion + } +} diff --git a/Infrastructure/Extensions/Extension.Exception.cs b/Infrastructure/Extensions/Extension.Exception.cs new file mode 100644 index 0000000..4af781d --- /dev/null +++ b/Infrastructure/Extensions/Extension.Exception.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Infrastructure.Extensions +{ + public static partial class Extensions + { + public static Exception GetOriginalException(this Exception ex) + { + if (ex.InnerException == null) return ex; + + return ex.InnerException.GetOriginalException(); + } + } +} diff --git a/Infrastructure/Extensions/Extension.Linq.cs b/Infrastructure/Extensions/Extension.Linq.cs new file mode 100644 index 0000000..0c23a71 --- /dev/null +++ b/Infrastructure/Extensions/Extension.Linq.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; + +namespace Infrastructure.Extensions +{ + public static class LinqExtensions + { + public static Expression Property(this Expression expression, string propertyName) + { + return Expression.Property(expression, propertyName); + } + public static Expression AndAlso(this Expression left, Expression right) + { + return Expression.AndAlso(left, right); + } + public static Expression Call(this Expression instance, string methodName, params Expression[] arguments) + { + return Expression.Call(instance, instance.Type.GetMethod(methodName), arguments); + } + public static Expression GreaterThan(this Expression left, Expression right) + { + return Expression.GreaterThan(left, right); + } + public static Expression ToLambda(this Expression body, params ParameterExpression[] parameters) + { + return Expression.Lambda(body, parameters); + } + + public static Expression> True() { return param => true; } + + public static Expression> False() { return param => false; } + + /// + /// 组合And + /// + /// + public static Expression> And(this Expression> first, Expression> second) + { + return first.Compose(second, Expression.AndAlso); + } + /// + /// 组合Or + /// + /// + public static Expression> Or(this Expression> first, Expression> second) + { + return first.Compose(second, Expression.OrElse); + } + + /// + /// Combines the first expression with the second using the specified merge function. + /// + static Expression Compose(this Expression first, Expression second, Func merge) + { + var map = first.Parameters + .Select((f, i) => new { f, s = second.Parameters[i] }) + .ToDictionary(p => p.s, p => p.f); + var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body); + return Expression.Lambda(merge(first.Body, secondBody), first.Parameters); + } + + /// + /// ParameterRebinder + /// + private class ParameterRebinder : ExpressionVisitor + { + /// + /// The ParameterExpression map + /// + readonly Dictionary map; + /// + /// Initializes a new instance of the class. + /// + /// The map. + ParameterRebinder(Dictionary map) + { + this.map = map ?? new Dictionary(); + } + /// + /// Replaces the parameters. + /// + /// The map. + /// The exp. + /// Expression + public static Expression ReplaceParameters(Dictionary map, Expression exp) + { + return new ParameterRebinder(map).Visit(exp); + } + /// + /// Visits the parameter. + /// + /// The p. + /// Expression + protected override Expression VisitParameter(ParameterExpression p) + { + ParameterExpression replacement; + + if (map.TryGetValue(p, out replacement)) + { + p = replacement; + } + return base.VisitParameter(p); + } + } + } +} diff --git a/Infrastructure/Extensions/Extension.Validate.cs b/Infrastructure/Extensions/Extension.Validate.cs new file mode 100644 index 0000000..de3c9c9 --- /dev/null +++ b/Infrastructure/Extensions/Extension.Validate.cs @@ -0,0 +1,44 @@ +//using Microsoft.AspNetCore.Http; + +namespace Infrastructure.Extensions +{ + public static partial class Extensions + { + public static bool IsEmpty(this object value) + { + if (value != null && !string.IsNullOrEmpty(value.ParseToString())) + { + return false; + } + else + { + return true; + } + } + public static bool IsNotEmpty(this object value) + { + return !IsEmpty(value); + } + public static bool IsNullOrZero(this object value) + { + if (value == null || value.ParseToString().Trim() == "0") + { + return true; + } + else + { + return false; + } + } + + //public static bool IsAjaxRequest(this HttpRequest request) + //{ + // if (request == null) + // throw new ArgumentNullException("request"); + + // if (request.Headers != null) + // return request.Headers["X-Requested-With"] == "XMLHttpRequest"; + // return false; + //} + } +} diff --git a/Infrastructure/Extensions/StringExtension.cs b/Infrastructure/Extensions/StringExtension.cs new file mode 100644 index 0000000..d00fd7b --- /dev/null +++ b/Infrastructure/Extensions/StringExtension.cs @@ -0,0 +1,232 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; + +namespace Infrastructure.Extensions +{ + public static class StringExtension + { + + /// + /// SQL条件拼接 + /// + /// + /// + /// + public static string If(this string str, bool condition) + { + return condition ? str : string.Empty; + } + /// + /// 判断是否为空 + /// + /// + /// + public static bool IfNotEmpty(this string str) + { + return !string.IsNullOrEmpty(str); + } + + /// + /// 注意:如果替换的旧值中有特殊符号,替换将会失败,解决办法 例如特殊符号是“(”: 要在调用本方法前加oldValue=oldValue.Replace("(","//("); + /// + /// + /// + /// + /// + public static string ReplaceFirst(this string input, string oldValue, string newValue) + { + Regex regEx = new Regex(oldValue, RegexOptions.Multiline); + return regEx.Replace(input, newValue == null ? "" : newValue, 1); + } + + /// + /// 骆驼峰转下划线 + /// + /// + /// + public static string ToSmallCamelCase(string name) + { + var stringBuilder = new StringBuilder(); + stringBuilder.Append(name.Substring(0, 1).ToLower()); + + for (var i = 0; i < name.Length; i++) + { + if (i == 0) + { + stringBuilder.Append(name.Substring(0, 1).ToLower()); + } + else + { + if (name[i] >= 'A' && name[i] <= 'Z') + { + stringBuilder.Append($"_{name.Substring(i, 1).ToLower()}"); + } + else + { + stringBuilder.Append(name[i]); + } + } + } + + return stringBuilder.ToString(); + } + + /// + /// 下划线命名转驼峰命名 + /// + /// + /// + public static string UnderScoreToCamelCase(this string underscore) + { + string[] ss = underscore.Split("_"); + if (ss.Length == 1) + { + return underscore; + } + + StringBuilder sb = new StringBuilder(); + sb.Append(ss[0]); + for (int i = 1; i < ss.Length; i++) + { + sb.Append(ss[i].FirstUpperCase()); + } + + return sb.ToString(); + } + + /// + /// 首字母转大写 + /// + /// + /// + public static string FirstUpperCase(this string str) + { + return string.IsNullOrEmpty(str) ? str : str.Substring(0, 1).ToUpper() + str[1..]; + } + + /// + /// 首字母转小写 + /// + /// + /// + public static string FirstLowerCase(this string str) + { + return string.IsNullOrEmpty(str) ? str : str.Substring(0, 1).ToLower() + str[1..]; + } + + /// + /// 截取指定字符串中间内容 + /// + /// + /// + /// + /// + public static string SubstringBetween(this string sourse, string startstr, string endstr) + { + string result = string.Empty; + int startindex, endindex; + try + { + startindex = sourse.IndexOf(startstr); + if (startindex == -1) + return result; + string tmpstr = sourse.Substring(startindex + startstr.Length); + endindex = tmpstr.IndexOf(endstr); + if (endindex == -1) + return result; + result = tmpstr.Remove(endindex); + } + catch (Exception ex) + { + Console.WriteLine("MidStrEx Err:" + ex.Message); + } + return result; + } + + /// + /// 转换为Pascal风格-每一个单词的首字母大写 + /// + /// 字段名 + /// 分隔符 + /// + public static string ConvertToPascal(this string fieldName, string fieldDelimiter) + { + string result = string.Empty; + if (fieldName.Contains(fieldDelimiter)) + { + //全部小写 + string[] array = fieldName.ToLower().Split(fieldDelimiter.ToCharArray()); + foreach (var t in array) + { + //首字母大写 + result += t.Substring(0, 1).ToUpper() + t[1..]; + } + } + else if (string.IsNullOrWhiteSpace(fieldName)) + { + result = fieldName; + } + else if (fieldName.Length == 1) + { + result = fieldName.ToUpper(); + } + else if (fieldName.Length == CountUpper(fieldName)) + { + result = fieldName.Substring(0, 1).ToUpper() + fieldName[1..].ToLower(); + } + else + { + result = fieldName.Substring(0, 1).ToUpper() + fieldName[1..]; + } + return result; + } + + /// + /// 大写字母个数 + /// + /// + /// + public static int CountUpper(this string str) + { + int count1 = 0; + char[] chars = str.ToCharArray(); + foreach (char num in chars) + { + if (num >= 'A' && num <= 'Z') + { + count1++; + } + //else if (num >= 'a' && num <= 'z') + //{ + // count2++; + //} + } + return count1; + } + + /// + /// 转换为Camel风格-第一个单词小写,其后每个单词首字母大写 + /// + /// 字段名 + /// 分隔符 + /// + public static string ConvertToCamel(this string fieldName, string fieldDelimiter) + { + //先Pascal + string result = ConvertToPascal(fieldName, fieldDelimiter); + //然后首字母小写 + if (result.Length == 1) + { + result = result.ToLower(); + } + else + { + result = result.Substring(0, 1).ToLower() + result[1..]; + } + + return result; + } + } +} diff --git a/Infrastructure/GlobalConstant.cs b/Infrastructure/GlobalConstant.cs new file mode 100644 index 0000000..25fc8d0 --- /dev/null +++ b/Infrastructure/GlobalConstant.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Infrastructure +{ + /// + /// 全局静态常量 + /// + public class GlobalConstant + { + /// + /// 管理员权限 + /// + public static string AdminPerm = "*:*:*"; + /// + /// 管理员角色 + /// + public static string AdminRole = "admin"; + /// + /// 开发版本API映射路径 + /// + public static string DevApiProxy = "/dev-api/"; + /// + /// 用户权限缓存key + /// + public static string UserPermKEY = "CACHE-USER-PERM"; + + /// + /// 欢迎语 + /// + public static string[] WelcomeMessages = new string[] { + "祝你开心每一天!", + "忙碌了一周,停一停脚步!", + "世间美好,与你环环相扣!", + "永远相信美好的事情即将发生!", + "每一天,遇见更好的自己!", + "保持热爱,奔赴山海!", + "生活明朗,万物可爱!", + "愿每一天醒来都是美好的开始!", + "没有希望的地方,就没有奋斗!", + "我最珍贵的时光都行走在路上!", + "成功,往往住在失败的隔壁!", + "人只要不失去方向,就不会失去自己!", + "每条堵住的路,都有一个出口!", + "没有谁能击垮你,除非你自甘堕落!", + "微笑着的人并非没有痛苦!", + "生活变的再糟糕,也不妨碍我变得更好!", + "你要悄悄努力,然后惊艳众人!", + "人与人之间最大的信任是精诚相见", + "人生就像爬坡,要一步一步来。", + "今天的目标完成了吗?", + "高效工作,告别996", + "销售是从别人拒绝开始的!" + }; + } +} diff --git a/Infrastructure/Helper/AssemblyUtils.cs b/Infrastructure/Helper/AssemblyUtils.cs new file mode 100644 index 0000000..3934851 --- /dev/null +++ b/Infrastructure/Helper/AssemblyUtils.cs @@ -0,0 +1,36 @@ +using Microsoft.Extensions.DependencyModel; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Infrastructure.Helper +{ + public static class AssemblyUtils + { + /// + /// 获取应用中的所有程序集 + /// + /// + public static IEnumerable GetAssemblies() + { + var compilationLibrary = DependencyContext.Default + .CompileLibraries + .Where(x => !x.Serviceable && x.Type == "project") + .ToList(); + return compilationLibrary.Select(p => Assembly.Load(new AssemblyName(p.Name))); + } + + /// + /// 获取应用中的所有Type + /// + /// + public static IEnumerable GetAllTypes() + { + var assemblies = GetAssemblies(); + return assemblies.SelectMany(p => p.GetTypes()); + } + } +} diff --git a/Infrastructure/Helper/ComputerHelper.cs b/Infrastructure/Helper/ComputerHelper.cs new file mode 100644 index 0000000..52fa318 --- /dev/null +++ b/Infrastructure/Helper/ComputerHelper.cs @@ -0,0 +1,261 @@ +using Infrastructure.Extensions; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +namespace Infrastructure +{ + public class ComputerHelper + { + /// + /// 内存使用情况 + /// + /// + public static MemoryMetrics GetComputerInfo() + { + try + { + MemoryMetricsClient client = new(); + MemoryMetrics memoryMetrics = IsUnix() ? client.GetUnixMetrics() : client.GetWindowsMetrics(); + + memoryMetrics.FreeRam = Math.Round(memoryMetrics.Free / 1024, 2) + "GB"; + memoryMetrics.UsedRam = Math.Round(memoryMetrics.Used / 1024, 2) + "GB"; + memoryMetrics.TotalRAM = Math.Round(memoryMetrics.Total / 1024, 2) + "GB"; + memoryMetrics.RAMRate = Math.Ceiling(100 * memoryMetrics.Used / memoryMetrics.Total).ToString() + "%"; + memoryMetrics.CPURate = Math.Ceiling(GetCPURate().ParseToDouble()) + "%"; + return memoryMetrics; + } + catch (Exception ex) + { + Console.WriteLine("获取内存使用出错,msg=" + ex.Message + "," + ex.StackTrace); + } + return new MemoryMetrics(); + } + + /// + /// 获取内存大小 + /// + /// + public static List GetDiskInfos() + { + List diskInfos = new(); + + if (IsUnix()) + { + try + { + string output = ShellHelper.Bash("df -m / | awk '{print $2,$3,$4,$5,$6}'"); + var arr = output.Split('\n', StringSplitOptions.RemoveEmptyEntries); + if (arr.Length == 0) return diskInfos; + + var rootDisk = arr[1].Split(' ', (char)StringSplitOptions.RemoveEmptyEntries); + if (rootDisk == null || rootDisk.Length == 0) + { + return diskInfos; + } + DiskInfo diskInfo = new() + { + DiskName = "/", + TotalSize = long.Parse(rootDisk[0]) / 1024, + Used = long.Parse(rootDisk[1]) / 1024, + AvailableFreeSpace = long.Parse(rootDisk[2]) / 1024, + AvailablePercent = decimal.Parse(rootDisk[3].Replace("%", "")) + }; + diskInfos.Add(diskInfo); + } + catch (Exception ex) + { + Console.WriteLine("获取磁盘信息出错了" + ex.Message); + } + } + else + { + var driv = DriveInfo.GetDrives(); + foreach (var item in driv) + { + try + { + var obj = new DiskInfo() + { + DiskName = item.Name, + TypeName = item.DriveType.ToString(), + TotalSize = item.TotalSize / 1024 / 1024 / 1024, + AvailableFreeSpace = item.AvailableFreeSpace / 1024 / 1024 / 1024, + }; + obj.Used = obj.TotalSize - obj.AvailableFreeSpace; + obj.AvailablePercent = decimal.Ceiling(obj.Used / (decimal)obj.TotalSize * 100); + diskInfos.Add(obj); + } + catch (Exception ex) + { + Console.WriteLine("获取磁盘信息出错了" + ex.Message); + continue; + } + } + } + + return diskInfos; + } + + public static bool IsUnix() + { + var isUnix = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux); + return isUnix; + } + + public static string GetCPURate() + { + string cpuRate; + if (IsUnix()) + { + string output = ShellHelper.Bash("top -b -n1 | grep \"Cpu(s)\" | awk '{print $2 + $4}'"); + cpuRate = output.Trim(); + } + else + { + string output = ShellHelper.Cmd("wmic", "cpu get LoadPercentage"); + cpuRate = output.Replace("LoadPercentage", string.Empty).Trim(); + } + return cpuRate; + } + + /// + /// 获取系统运行时间 + /// + /// + public static string GetRunTime() + { + string runTime = string.Empty; + try + { + if (IsUnix()) + { + string output = ShellHelper.Bash("uptime -s").Trim(); + runTime = DateTimeHelper.FormatTime((DateTime.Now - output.ParseToDateTime()).TotalMilliseconds.ToString().Split('.')[0].ParseToLong()); + } + else + { + string output = ShellHelper.Cmd("wmic", "OS get LastBootUpTime/Value"); + string[] outputArr = output.Split('=', (char)StringSplitOptions.RemoveEmptyEntries); + if (outputArr.Length == 2) + { + runTime = DateTimeHelper.FormatTime((DateTime.Now - outputArr[1].Split('.')[0].ParseToDateTime()).TotalMilliseconds.ToString().Split('.')[0].ParseToLong()); + } + } + } + catch (Exception ex) + { + Console.WriteLine("获取runTime出错" + ex.Message); + } + return runTime; + } + } + + /// + /// 内存信息 + /// + public class MemoryMetrics + { + [JsonIgnore] + public double Total { get; set; } + [JsonIgnore] + public double Used { get; set; } + [JsonIgnore] + public double Free { get; set; } + + public string UsedRam { get; set; } + /// + /// CPU使用率% + /// + public string CPURate { get; set; } + /// + /// 总内存 GB + /// + public string TotalRAM { get; set; } + /// + /// 内存使用率 % + /// + public string RAMRate { get; set; } + /// + /// 空闲内存 + /// + public string FreeRam { get; set; } + } + + public class DiskInfo + { + /// + /// 磁盘名 + /// + public string DiskName { get; set; } + public string TypeName { get; set; } + public long TotalFree { get; set; } + public long TotalSize { get; set; } + /// + /// 已使用 + /// + public long Used { get; set; } + /// + /// 可使用 + /// + public long AvailableFreeSpace { get; set; } + public decimal AvailablePercent { get; set; } + } + + public class MemoryMetricsClient + { + #region 获取内存信息 + + /// + /// windows系统获取内存信息 + /// + /// + public MemoryMetrics GetWindowsMetrics() + { + string output = ShellHelper.Cmd("wmic", "OS get FreePhysicalMemory,TotalVisibleMemorySize /Value"); + var metrics = new MemoryMetrics(); + var lines = output.Trim().Split('\n', (char)StringSplitOptions.RemoveEmptyEntries); + + if (lines.Length <= 0) return metrics; + + var freeMemoryParts = lines[0].Split('=', (char)StringSplitOptions.RemoveEmptyEntries); + var totalMemoryParts = lines[1].Split('=', (char)StringSplitOptions.RemoveEmptyEntries); + + metrics.Total = Math.Round(double.Parse(totalMemoryParts[1]) / 1024, 0); + metrics.Free = Math.Round(double.Parse(freeMemoryParts[1]) / 1024, 0);//m + metrics.Used = metrics.Total - metrics.Free; + + return metrics; + } + + /// + /// Unix系统获取 + /// + /// + public MemoryMetrics GetUnixMetrics() + { + string output = ShellHelper.Bash("free -m | awk '{print $2,$3,$4,$5,$6}'"); + var metrics = new MemoryMetrics(); + var lines = output.Split('\n', (char)StringSplitOptions.RemoveEmptyEntries); + + if (lines.Length <= 0) return metrics; + + if (lines != null && lines.Length > 0) + { + var memory = lines[1].Split(' ', (char)StringSplitOptions.RemoveEmptyEntries); + if (memory.Length >= 3) + { + metrics.Total = double.Parse(memory[0]); + metrics.Used = double.Parse(memory[1]); + metrics.Free = double.Parse(memory[2]);//m + } + } + return metrics; + } + #endregion + } +} \ No newline at end of file diff --git a/Infrastructure/Helper/DateTimeHelper.cs b/Infrastructure/Helper/DateTimeHelper.cs new file mode 100644 index 0000000..37aa6b9 --- /dev/null +++ b/Infrastructure/Helper/DateTimeHelper.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Infrastructure +{ + public class DateTimeHelper + { + /// + /// + /// + /// + /// + public static DateTime GetBeginTime(DateTime? dateTime, int days = 0) + { + if (dateTime == DateTime.MinValue || dateTime == null) + { + return DateTime.Now.AddDays(days); + } + return dateTime ?? DateTime.Now; + } + #region 时间戳转换 + + /// + /// 时间戳转本地时间-时间戳精确到秒 + /// + public static DateTime ToLocalTimeDateBySeconds(long unix) + { + var dto = DateTimeOffset.FromUnixTimeSeconds(unix); + return dto.ToLocalTime().DateTime; + } + + /// + /// 时间转时间戳Unix-时间戳精确到秒 + /// + public static long ToUnixTimestampBySeconds(DateTime dt) + { + DateTimeOffset dto = new DateTimeOffset(dt); + return dto.ToUnixTimeSeconds(); + } + + /// + /// 时间戳转本地时间-时间戳精确到毫秒 + /// + public static DateTime ToLocalTimeDateByMilliseconds(long unix) + { + var dto = DateTimeOffset.FromUnixTimeMilliseconds(unix); + return dto.ToLocalTime().DateTime; + } + + /// + /// 时间转时间戳Unix-时间戳精确到毫秒 + /// + public static long ToUnixTimestampByMilliseconds(DateTime dt) + { + DateTimeOffset dto = new DateTimeOffset(dt); + return dto.ToUnixTimeMilliseconds(); + } + + #endregion + + #region 毫秒转天时分秒 + /// + /// 毫秒转天时分秒 + /// + /// + /// + public static string FormatTime(long ms) + { + int ss = 1000; + int mi = ss * 60; + int hh = mi * 60; + int dd = hh * 24; + + long day = ms / dd; + long hour = (ms - day * dd) / hh; + long minute = (ms - day * dd - hour * hh) / mi; + long second = (ms - day * dd - hour * hh - minute * mi) / ss; + long milliSecond = ms - day * dd - hour * hh - minute * mi - second * ss; + + string sDay = day < 10 ? "0" + day : "" + day; //天 + string sHour = hour < 10 ? "0" + hour : "" + hour;//小时 + string sMinute = minute < 10 ? "0" + minute : "" + minute;//分钟 + string sSecond = second < 10 ? "0" + second : "" + second;//秒 + string sMilliSecond = milliSecond < 10 ? "0" + milliSecond : "" + milliSecond;//毫秒 + sMilliSecond = milliSecond < 100 ? "0" + sMilliSecond : "" + sMilliSecond; + + return string.Format("{0} 天 {1} 小时 {2} 分 {3} 秒", sDay, sHour, sMinute, sSecond); + } + #endregion + + #region 获取unix时间戳 + /// + /// 获取unix时间戳 + /// + /// + /// + public static long GetUnixTimeStamp(DateTime dt) + { + long unixTime = ((DateTimeOffset)dt).ToUnixTimeMilliseconds(); + return unixTime; + } + #endregion + + #region 获取日期天的最小时间 + public static DateTime GetDayMinDate(DateTime dt) + { + DateTime min = new DateTime(dt.Year, dt.Month, dt.Day, 0, 0, 0); + return min; + } + #endregion + + #region 获取日期天的最大时间 + public static DateTime GetDayMaxDate(DateTime dt) + { + DateTime max = new DateTime(dt.Year, dt.Month, dt.Day, 23, 59, 59); + return max; + } + #endregion + + #region 获取日期天的最大时间 + public static string FormatDateTime(DateTime? dt) + { + if (dt != null) + { + if (dt.Value.Year == DateTime.Now.Year) + { + return dt.Value.ToString("MM-dd HH:mm"); + } + else + { + return dt.Value.ToString("yyyy-MM-dd HH:mm"); + } + } + return string.Empty; + } + #endregion + } +} diff --git a/Infrastructure/Helper/FileUtil.cs b/Infrastructure/Helper/FileUtil.cs new file mode 100644 index 0000000..0d85003 --- /dev/null +++ b/Infrastructure/Helper/FileUtil.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Security.Cryptography; +using System.Text; + +namespace Infrastructure +{ + public class FileUtil + { + /// + /// 按时间来创建文件夹 + /// + /// + /// eg: /{yourPath}/2020/11/3/ + public static string GetdirPath(string path = "") + { + DateTime date = DateTime.Now; + string timeDir = date.ToString("yyyyMMdd");// date.ToString("yyyyMM/dd/HH/"); + + if (!string.IsNullOrEmpty(path)) + { + timeDir = Path.Combine(path, timeDir); + } + return timeDir; + } + + /// + /// 取文件名的MD5值(16位) + /// + /// 文件名,不包括扩展名 + /// + public static string HashFileName(string str = null) + { + if (string.IsNullOrEmpty(str)) + { + str = Guid.NewGuid().ToString(); + } + MD5 md5 = MD5.Create(); + return BitConverter.ToString(md5.ComputeHash(Encoding.Default.GetBytes(str)), 4, 8).Replace("-", ""); + } + } +} diff --git a/Infrastructure/Helper/HttpHelper.cs b/Infrastructure/Helper/HttpHelper.cs new file mode 100644 index 0000000..a42482b --- /dev/null +++ b/Infrastructure/Helper/HttpHelper.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +namespace Infrastructure +{ + public class HttpHelper + { + /// + /// 发起POST同步请求 + /// + /// + /// + /// + /// application/xml、application/json、application/text、application/x-www-form-urlencoded + /// 填充消息头 + /// + public static string HttpPost(string url, string postData = null, string contentType = null, int timeOut = 30, Dictionary headers = null) + { + postData = postData ?? ""; + using (HttpClient client = new HttpClient()) + { + if (headers != null) + { + foreach (var header in headers) + client.DefaultRequestHeaders.Add(header.Key, header.Value); + } + using (HttpContent httpContent = new StringContent(postData, Encoding.UTF8)) + { + if (contentType != null) + httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType); + + HttpResponseMessage response = client.PostAsync(url, httpContent).Result; + return response.Content.ReadAsStringAsync().Result; + } + } + } + + + /// + /// 发起POST异步请求 + /// + /// + /// + /// application/xml、application/json、application/text、application/x-www-form-urlencoded + /// 填充消息头 + /// + public static async Task HttpPostAsync(string url, string postData = null, string contentType = null, int timeOut = 30, Dictionary headers = null) + { + postData = postData ?? ""; + using (HttpClient client = new HttpClient()) + { + client.Timeout = new TimeSpan(0, 0, timeOut); + if (headers != null) + { + foreach (var header in headers) + client.DefaultRequestHeaders.Add(header.Key, header.Value); + } + using (HttpContent httpContent = new StringContent(postData, Encoding.UTF8)) + { + if (contentType != null) + httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType); + + HttpResponseMessage response = await client.PostAsync(url, httpContent); + return await response.Content.ReadAsStringAsync(); + } + } + } + + /// + /// 发起GET同步请求 + /// + /// + /// + /// + /// + public static string HttpGet(string url, Dictionary headers = null) + { + using (HttpClient client = new HttpClient()) + { + if (headers != null) + { + foreach (var header in headers) + client.DefaultRequestHeaders.Add(header.Key, header.Value); + } + else + { + client.DefaultRequestHeaders.Add("ContentType", "application/x-www-form-urlencoded"); + client.DefaultRequestHeaders.Add("UserAgent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)"); + } + try + { + HttpResponseMessage response = client.GetAsync(url).Result; + return response.Content.ReadAsStringAsync().Result; + } + catch (Exception ex) + { + //TODO 打印日志 + Console.WriteLine($"[Http请求出错]{url}|{ex.Message}"); + } + return ""; + } + } + + /// + /// 发起GET异步请求 + /// + /// + /// + /// + /// + public static async Task HttpGetAsync(string url, Dictionary headers = null) + { + using (HttpClient client = new HttpClient()) + { + if (headers != null) + { + foreach (var header in headers) + client.DefaultRequestHeaders.Add(header.Key, header.Value); + } + HttpResponseMessage response = await client.GetAsync(url); + return await response.Content.ReadAsStringAsync(); + } + } + } +} diff --git a/Infrastructure/Helper/ShellHelper.cs b/Infrastructure/Helper/ShellHelper.cs new file mode 100644 index 0000000..6c56ad1 --- /dev/null +++ b/Infrastructure/Helper/ShellHelper.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; + +namespace Infrastructure +{ + public class ShellHelper + { + /// + /// linux 系统命令 + /// + /// + /// + public static string Bash(string command) + { + var escapedArgs = command.Replace("\"", "\\\""); + var process = new Process() + { + StartInfo = new ProcessStartInfo + { + FileName = "/bin/bash", + Arguments = $"-c \"{escapedArgs}\"", + RedirectStandardOutput = true, + UseShellExecute = false, + CreateNoWindow = true, + } + }; + process.Start(); + string result = process.StandardOutput.ReadToEnd(); + process.WaitForExit(); + process.Dispose(); + return result; + } + + /// + /// windows系统命令 + /// + /// + /// + /// + public static string Cmd(string fileName, string args) + { + string output = string.Empty; + + var info = new ProcessStartInfo(); + info.FileName = fileName; + info.Arguments = args; + info.RedirectStandardOutput = true; + + using (var process = Process.Start(info)) + { + output = process.StandardOutput.ReadToEnd(); + } + return output; + } + } +} diff --git a/Infrastructure/Infrastructure.csproj b/Infrastructure/Infrastructure.csproj new file mode 100644 index 0000000..2d3ff4a --- /dev/null +++ b/Infrastructure/Infrastructure.csproj @@ -0,0 +1,25 @@ + + + + net6.0 + + + + + + + + + + + + + + + + + + + + + diff --git a/Infrastructure/InternalApp.cs b/Infrastructure/InternalApp.cs new file mode 100644 index 0000000..fcfa9fc --- /dev/null +++ b/Infrastructure/InternalApp.cs @@ -0,0 +1,32 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using System; +using static System.Net.Mime.MediaTypeNames; + +namespace Infrastructure +{ + public static class InternalApp + { + /// + /// 应用服务 + /// + public static IServiceProvider ServiceProvider; + + /// + /// 全局配置构建器 + /// + //public static IConfigurationBuilder ConfigurationBuilder; + + /// + /// 获取Web主机环境 + /// + //internal static IWebHostEnvironment WebHostEnvironment; + + /// + /// 获取泛型主机环境 + /// + //public static IHostEnvironment HostEnvironment; + } +} diff --git a/Infrastructure/Model/ApiResult.cs b/Infrastructure/Model/ApiResult.cs new file mode 100644 index 0000000..d322029 --- /dev/null +++ b/Infrastructure/Model/ApiResult.cs @@ -0,0 +1,125 @@ +using Infrastructure.Constant; +using Newtonsoft.Json; + +namespace Infrastructure.Model +{ + public class ApiResult + { + public int Code { get; set; } + public string Msg { get; set; } + /// + /// 如果data值为null,则忽略序列化将不会返回data字段 + /// + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public object Data { get; set; } + + /// + /// 初始化一个新创建的APIResult对象,使其表示一个空消息 + /// + public ApiResult() + { + } + + /// + /// 初始化一个新创建的 ApiResult 对象 + /// + /// + /// + public ApiResult(int code, string msg) + { + Code = code; + Msg = msg; + } + + /// + /// 初始化一个新创建的 ApiResult 对象 + /// + /// + /// + public ApiResult(int code, string msg, object data) + { + Code = code; + Msg = msg; + if (data != null) + { + Data = data; + } + } + + /// + /// 返回成功消息 + /// + /// + public ApiResult Success() + { + Code = (int)ResultCode.SUCCESS; + Msg = "success"; + return this; + } + + /// + /// 返回成功消息 + /// + /// 数据对象 + /// 成功消息 + public static ApiResult Success(object data) { return new ApiResult(HttpStatus.SUCCESS, "success", data); } + + /// + /// 返回成功消息 + /// + /// 返回内容 + /// 成功消息 + public static ApiResult Success(string msg) { return new ApiResult(HttpStatus.SUCCESS, msg, null); } + + /// + /// 返回成功消息 + /// + /// 返回内容 + /// 数据对象 + /// 成功消息 + public static ApiResult Success(string msg, object data) { return new ApiResult(HttpStatus.SUCCESS, msg, data); } + + /// + /// 访问被拒 + /// + /// + /// + public ApiResult On401() + { + Code = (int)ResultCode.DENY; + Msg = "access denyed"; + return this; + } + public ApiResult Error(ResultCode resultCode, string msg = "") + { + Code = (int)resultCode; + Msg = msg; + return this; + } + + /// + /// 返回失败消息 + /// + /// + /// + /// + public static ApiResult Error(int code, string msg) { return new ApiResult(code, msg); } + + /// + /// 返回失败消息 + /// + /// + /// + public static ApiResult Error(string msg) { return new ApiResult((int)ResultCode.CUSTOM_ERROR, msg); } + + public override string ToString() + { + return $"msg={Msg},data={Data}"; + } + } + + public class ApiResult : ApiResult + { + public T Result { get; set; } + } +} diff --git a/Infrastructure/Model/SendEmailDto.cs b/Infrastructure/Model/SendEmailDto.cs new file mode 100644 index 0000000..7408dcf --- /dev/null +++ b/Infrastructure/Model/SendEmailDto.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Infrastructure.Model +{ + public class SendEmailDto + { + public string FileUrl { get; set; } = ""; + public string Subject { get; set; } + public string ToUser { get; set; } + public string Content { get; set; } = ""; + public string HtmlContent { get; set; } + /// + /// 是否发送给自己 + /// + public bool SendMe { get; set; } + public DateTime AddTime { get; set; } + } +} diff --git a/Infrastructure/OptionsSetting.cs b/Infrastructure/OptionsSetting.cs new file mode 100644 index 0000000..dd9944a --- /dev/null +++ b/Infrastructure/OptionsSetting.cs @@ -0,0 +1,69 @@ + +namespace Infrastructure +{ + /// + /// 获取配置文件POCO实体类 + /// + public class OptionsSetting + { + /// + /// 是否演示模式 + /// + public bool DemoMode { get; set; } + public MailOptions MailOptions { get; set; } + public Upload Upload { get; set; } + public ALYUN_OCS ALYUN_OCS { get; set; } + public JwtSettings JwtSettings { get; set; } + } + /// + /// 发送邮件数据配置 + /// + public class MailOptions + { + public string From { get; set; } + public string Password { get; set; } + public string Smtp { get; set; } + public int Port { get; set; } + public string Signature { get; set; } + } + /// + /// 上传 + /// + public class Upload + { + public string UploadUrl { get; set; } + public string LocalSavePath { get; set; } + } + /// + /// 阿里云存储 + /// + public class ALYUN_OCS + { + public string REGIONID { get; set; } + public string KEY { get; set; } + public string SECRET { get; set; } + } + + /// + /// Jwt + /// + public class JwtSettings + { + /// + /// token是谁颁发的 + /// + public string Issuer { get; set; } + /// + /// token可以给那些客户端使用 + /// + public string Audience { get; set; } + /// + /// 加密的key(SecretKey必须大于16个,是大于,不是大于等于) + /// + public string SecretKey { get; set; } + /// + /// token时间(分) + /// + public int Expire { get; set; } = 4320; + } +} diff --git a/Infrastructure/WeChat/Login/WeChatLogin.cs b/Infrastructure/WeChat/Login/WeChatLogin.cs new file mode 100644 index 0000000..617f747 --- /dev/null +++ b/Infrastructure/WeChat/Login/WeChatLogin.cs @@ -0,0 +1,273 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace Infrastructure.WeChat.Login +{ + + public class WeChatLogin + { + /// + /// 小程序 appId + /// + public string appid { get; set; } + /// + /// 小程序 appSecret + /// + public string secret { get; set; } + + public class Code2SessionParamter + { + /// + /// 小程序 appId + /// + public string appid { get; set; } + /// + /// 小程序 appSecret + /// + public string secret { get; set; } + /// + /// 登录时获取的 code + /// + public string js_code { get; set; } + /// + /// 授权类型,此处只需填写 authorization_code + /// + public string grant_type { get; set; } = "authorization_code"; + + public Code2SessionParamter(string js_code) + { + this.js_code = js_code; + } + + public Code2SessionParamter(string appid, string secret, string js_code) + { + this.appid = appid; + this.secret = secret; + this.js_code = js_code; + } + } + public class Code2SessionResult + { + /// + /// 用户唯一标识 + /// + public string openId { get; set; } + /// + /// 会话密钥 + /// + public string session_key { get; set; } + + /// + /// 用户在开放平台的唯一标识符,若当前小程序已绑定到微信开放平台帐号下会返回,详见 UnionID 机制说明。 + /// + public string unionid { get; set; } + /// + /// 错误码 + /// + public int errcode { get; set; } + /// + /// 错误信息 + /// + public string errmsg { get; set; } + } + + public enum Gender + { + unkown = 0, + man = 1, + woman = 2 + } + public class UserInfo + { + public string openId { get; set; } + /// + /// 用户昵称 + /// + public string nickName { get; set; } + /// + /// 用户性别 + /// + public Gender gender { get; set; } + /// + /// 用户所在国家 + /// + public string country { get; set; } + /// + /// 用户所在省份。 + /// + public string province { get; set; } + /// + /// 用户所在城市。 + /// + public string city { get; set; } + /// + /// 用户在开放平台的唯一标识符,若当前小程序已绑定到微信开放平台帐号下会返回,详见 UnionID 机制说明。 + /// + public string unionId { get; set; } + /// + /// 用户头像图片的 URL。URL 最后一个数值代表正方形头像大小(有 0、46、64、96、132 数值可选,0 代表 640x640 的正方形头像,46 表示 46x46 的正方形头像,剩余数值以此类推。默认132),用户没有头像时该项为空。若用户更换头像,原有头像 URL 将失效。 + /// + public string avatarUrl { get; set; } + /// + /// + /// + public Watermark watermark { get; set; } + } + public class Watermark + { + /// + /// 敏感数据归属 appId,开发者可校验此参数与自身 appId 是否一致 + /// + public string appid { get; set; } + /// + /// 敏感数据获取的时间戳, 开发者可以用于数据时效性校验 + /// + public string timestamp { get; set; } + } + + public WeChatLogin(string appid, string secret) + { + this.appid = appid; + this.secret = secret; + } + + /// + /// 登录凭证校验。通过 wx.login 接口获得临时登录凭证 code 后传到开发者服务器调用此接口完成登录流程。更多使用方法详见 小程序登录。 + /// https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html + /// + /// 参数 + /// + public async Task GetCode2Session(Code2SessionParamter code2SessionParamter) + { + if (string.IsNullOrEmpty(code2SessionParamter.appid)) code2SessionParamter.appid = appid; + if (string.IsNullOrEmpty(code2SessionParamter.secret)) code2SessionParamter.secret = secret; + var result = await Get($"https://api.weixin.qq.com/sns/jscode2session?appid={code2SessionParamter.appid}&secret={code2SessionParamter.secret}&js_code={code2SessionParamter.js_code}&grant_type={code2SessionParamter.grant_type}"); + return JsonConvert.DeserializeObject(result); + } + + /// + /// 内部使用的通用方法 + /// + /// + /// + static async Task Get(string url) + { + try + { + var httpClient = new HttpClient(); + HttpResponseMessage response = await httpClient.GetAsync(url); + return response.IsSuccessStatusCode ? await response.Content.ReadAsStringAsync() : ""; ; + } + catch (Exception ex) + { + throw new Exception("Get 请求出错:" + ex.Message); + } + } + + /// + /// 解密获取用户信息 (不验证签名) + /// + /// 加密算法的初始向量 + /// 包括敏感数据在内的完整用户信息的加密数据 + /// 会话密钥 + /// + public UserInfo? GetUserInfo(string iv, string encryptedData, string session_key,string openId) + { + var user = JsonConvert.DeserializeObject(AESDecrypt(encryptedData, session_key, iv)); + user.openId = openId; + return user; + } + /// + /// 解密获取用户信息 (验证签名) + /// + /// 加密算法的初始向量 + /// 包括敏感数据在内的完整用户信息的加密数据 + /// 会话密钥 + /// 不包括敏感信息的原始数据字符串,用于计算签名 + /// 使用 sha1( rawData + sessionkey ) 得到字符串,用于校验用户信息 + /// + public UserInfo? GetUserInfo(string iv, string encryptedData, string session_key, string rawData, string signature) + { + CheckSignature(rawData, session_key, signature); + return GetUserInfo(iv, encryptedData, session_key,""); + } + + + /// + /// 检查签名 + /// + /// 不包括敏感信息的原始数据字符串,用于计算签名 + /// + /// 使用 sha1( rawData + sessionkey ) 得到字符串,用于校验用户信息 + /// + void CheckSignature(string rawData, string session_key, string signature) + { + Console.WriteLine(SHA1Encryption(rawData + session_key)); + Console.WriteLine(signature); + if (SHA1Encryption(rawData + session_key).ToUpper() != signature.ToUpper()) + { + throw new Exception("CheckSignature 签名校验失败,数据可能损坏。"); + } + } + + + /// + /// SHA1 加密,返回大写字符串 + /// + /// 需要加密字符串 + /// 指定加密编码 + /// 返回40位大写字符串 + string SHA1Encryption(string content, Encoding encode = null) + { + try + { + if (encode == null) encode = Encoding.UTF8; + SHA1 sha1 = SHA1.Create(); + byte[] bytes_in = encode.GetBytes(content); + byte[] bytes_out = sha1.ComputeHash(bytes_in); + sha1.Dispose(); + string result = BitConverter.ToString(bytes_out); + result = result.Replace("-", ""); + return result; + } + catch (Exception ex) + { + throw new Exception("SHA1Encryption加密出错:" + ex.Message); + } + } + /// + /// Aes 解密 + /// + /// + /// + /// + /// + string AESDecrypt(string encryptedData, string sessionKey, string iv) + { + try + { + var encryptedDataByte = Convert.FromBase64String(encryptedData); + var aes = Aes.Create(); + aes.Key = Convert.FromBase64String(sessionKey); + aes.IV = Convert.FromBase64String(iv); + aes.Mode = CipherMode.CBC; + aes.Padding = PaddingMode.PKCS7; + var transform = aes.CreateDecryptor(); + var plainText = transform.TransformFinalBlock(encryptedDataByte, 0, encryptedDataByte.Length); + var result = Encoding.Default.GetString(plainText); + return result; + } + catch (Exception ex) + { + throw new Exception("AESDecrypt解密出错:" + ex.Message); + } + } + } + +} diff --git a/Infrastructure/WeChat/SubScribe/Subscribe.cs b/Infrastructure/WeChat/SubScribe/Subscribe.cs new file mode 100644 index 0000000..c964c81 --- /dev/null +++ b/Infrastructure/WeChat/SubScribe/Subscribe.cs @@ -0,0 +1,114 @@ +using Microsoft.AspNetCore.Mvc; +using Senparc.Weixin.Entities.TemplateMessage; +using Senparc.Weixin.MP.AdvancedAPIs; +using Senparc.Weixin; +using Senparc.Weixin.MP; +using Senparc.Weixin.WxOpen.AdvancedAPIs; +using Infrastructure; +using Senparc.Weixin.WxOpen.AdvancedAPIs.Template; +using System.Threading.Tasks; +using System; + +namespace Infrastructure.WeChat.SubScribe +{ + public static class Subscribe + { + private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + + /// + /// 订阅消息 + /// + /// + /// + public static async Task SubscribeMessage(string templateId,string openId, TemplateMessageData templateMessageData) + { + await Task.Delay(1000);//停1秒钟,实际开发过程中可以将权限存入数据库,任意时间发送。 + + var page = "pages/index/index"; + var wxOpenAppId = AppSettings.GetConfig("SenparcWeixinSetting:TenPayV3_AppId"); + //templateId也可以由后端指定 + + try + { + var result = await MessageApi.SendSubscribeAsync(wxOpenAppId, openId, templateId, templateMessageData, page); + if (result.errcode == ReturnCode.请求成功) + { + return "消息已发送,请注意查收" ; + } + else + { + return "发送失败:" + result.errmsg; + } + } + catch (Exception ex) + { + logger.Error(ex,"推送失败"); + throw new CustomException("推送失败:"+ex); + } + + } + + /// + /// 下发小程序和公众号统一的服务消息 + /// + /// + /// + public static async Task UniformSend(string mpTemplateId, string openId,string pagePath, object templateData) + { + + await Task.Delay(1000);//停1秒钟,实际开发过程中可以将权限存入数据库,任意时间发送。 + + try + { + var mpAppId = Config.SenparcWeixinSetting.MpSetting.WeixinAppId;//公众号ID + + + //{"touser":"oeaTy0DgoGq-lyqvTauWVjbIVuP0","weapp_template_msg":null,"mp_template_msg":{"appid":"wx669ef95216eef885","template_id":null,"url":"https://dev.senparc.com","miniprogram":{"appid":"wx12b4f63276b14d4c","pagepath":"websocket/websocket"},"data":{"first":{"value":"小程序和公众号统一的服务消息","color":"#173177"},"keyword1":{"value":"2022/1/20 23:22:12","color":"#173177"},"keyword2":{"value":"dev.senparc.com","color":"#173177"},"keyword3":{"value":"小程序接口测试","color":"#173177"},"keyword4":{"value":"正常","color":"#173177"},"keyword5":{"value":"测试“小程序和公众号统一的服务消息”接口,服务正常","color":"#173177"},"remark":{"value":"您的 OpenId:oeaTy0DgoGq-lyqvTauWVjbIVuP0","color":"#173177"},"TemplateId":"ur6TqESOo-32FEUk4qJxeWZZVt4KEOPjqbAFDGWw6gg","Url":"https://dev.senparc.com","TemplateName":"系统异常告警通知"}}} + + + + var wxOpenAppId = AppSettings.GetConfig("SenparcWeixinSetting:TenPayV3_AppId"); + var miniprogram = new Miniprogram_PagePath(wxOpenAppId, pagePath);//使用 pagepath 参数 + //var miniprogram = new Miniprogram_Page(WxOpenAppId, pagePath);// 使用 page 参数 + //https://weixin.senparc.com/QA-17333 + + UniformSendData msgData = new( + openId, + new Mp_Template_Msg(mpAppId, + mpTemplateId, + "https://dev.senparc.com", + miniprogram, + templateData) + ); + + var result = await Senparc.Weixin.WxOpen.AdvancedAPIs.Template.TemplateApi.UniformSendAsync(mpAppId, msgData); + + if (result.errcode == ReturnCode.请求成功) + { + return "服务消息已发送,请注意查收"; + } + else + { + string msg; + + if (result.errmsg.Contains("require subscribe")) + { + msg = "您需要关注公众号【盛派网络小助手】才能收到公众号内的模板消息!"; + } + else + { + msg = result.errmsg; + } + + return "出错啦!"; + } + } + catch (Exception ex) + { + throw new Exception("推送报错:"+ex); + } + } + + + } +} diff --git a/Infrastructure/WeChat/SubScribe/SubscribeDto.cs b/Infrastructure/WeChat/SubScribe/SubscribeDto.cs new file mode 100644 index 0000000..f33d0c4 --- /dev/null +++ b/Infrastructure/WeChat/SubScribe/SubscribeDto.cs @@ -0,0 +1,19 @@ +namespace Infrastructure.WeChat.SubScribe +{ + /// + /// 微信订阅推送Dto + /// + public class SubscribeDto + { + /// + /// 小程序用户openId + /// + public string openId { get; set; } + + /// + /// 模板消息Id + /// + public string templateId { get; set; } + + } +} diff --git a/Infrastructure/WeChat/TenPay/Pay.cs b/Infrastructure/WeChat/TenPay/Pay.cs new file mode 100644 index 0000000..03b98fc --- /dev/null +++ b/Infrastructure/WeChat/TenPay/Pay.cs @@ -0,0 +1,514 @@ +using Infrastructure; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Senparc.CO2NET.Extensions; +using Senparc.CO2NET.HttpUtility; +using Senparc.CO2NET.Utilities; +using Senparc.Weixin; +using Senparc.Weixin.Entities; +using Senparc.Weixin.Exceptions; +using Senparc.Weixin.Helpers; +using Senparc.Weixin.MP.AdvancedAPIs.MerChant; +using Senparc.Weixin.TenPayV3; +using Senparc.Weixin.TenPayV3.Apis; +using Senparc.Weixin.TenPayV3.Apis.BasePay; +using Senparc.Weixin.TenPayV3.Apis.Entities; +using Senparc.Weixin.TenPayV3.Entities; +using Senparc.Weixin.TenPayV3.Helpers; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Senparc.Weixin.TenPayV3.Apis.BasePay.Entities; + +namespace Infrastructure.WeChat.TenPay +{ + + /// + /// 微信支付基础类 + /// + public class Pay + { + private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + /// + /// 用于初始化BasePayApis + /// + private readonly ISenparcWeixinSettingForTenpayV3 _tenpayV3Setting; + public static HttpContext HttpContext => HttpContextLocal.Current(); + private readonly BasePayApis _basePayApis; + private readonly SenparcHttpClient _httpClient; + + /// + /// trade_no 和 transaction_id 对照表 + /// TODO:可以放入缓存,设置有效时间 + /// + //public static ConcurrentDictionary TradeNumberToTransactionId = new ConcurrentDictionary(); + + public TenPayV3Info TenPayV3Info; + + + public Pay(SenparcHttpClient httpClient) + { + var TenPayV3_AppId = AppSettings.GetConfig("SenparcWeixinSetting:TenPayV3_AppId"); + var TenPayV3_AppSecret = AppSettings.GetConfig("SenparcWeixinSetting:TenPayV3_AppSecret"); + var TenPayV3_MchId = AppSettings.GetConfig("SenparcWeixinSetting:TenPayV3_MchId"); + var TenPayV3_Key = AppSettings.GetConfig("SenparcWeixinSetting:TenPayV3_Key"); + var TenPayV3_CertPath = AppSettings.GetConfig("SenparcWeixinSetting:TenPayV3_CertPath"); + var TenPayV3_CertSecret = AppSettings.GetConfig("SenparcWeixinSetting:TenPayV3_CertPath"); + var TenPayV3_TenpayNotify = AppSettings.GetConfig("SenparcWeixinSetting:TenPayV3_TenpayNotify"); + var TenPayV3_WxOpenNotify = AppSettings.GetConfig("SenparcWeixinSetting:TenPayV3_WxOpenNotify"); + var TenPayV3_PrivateKey = AppSettings.GetConfig("SenparcWeixinSetting:TenPayV3_PrivateKey"); + var TenPayV3_SerialNumber = AppSettings.GetConfig("SenparcWeixinSetting:TenPayV3_SerialNumber"); + var TenPayV3_ApiV3Key = AppSettings.GetConfig("SenparcWeixinSetting:TenPayV3_ApiV3Key"); + + + var tenPayV3Info = new TenPayV3Info(TenPayV3_AppId, TenPayV3_AppSecret, TenPayV3_MchId, TenPayV3_Key, TenPayV3_CertPath, TenPayV3_CertSecret,TenPayV3_TenpayNotify, TenPayV3_WxOpenNotify,TenPayV3_PrivateKey, TenPayV3_SerialNumber, TenPayV3_ApiV3Key); + TenPayV3InfoCollection.Register(tenPayV3Info, "测试"); + this.TenPayV3Info = tenPayV3Info; + + _tenpayV3Setting = Senparc.Weixin.Config.SenparcWeixinSetting.TenpayV3Setting; + _basePayApis = new BasePayApis(_tenpayV3Setting); + this._httpClient = httpClient; + } + + + public async Task PrePay(long productGuid, string openId,string orderNo,int type,int price) + { + string sp_billno = orderNo;//out_trade_no + + //调用下单接口下单 + var name = "测试"; + + try + { + var appId = TenPayV3Info.AppId; + + var notifyUrl = TenPayV3Info.TenPayV3_WxOpenNotify; + + //请求信息 + TransactionsRequestData jsApiRequestData = new( + appId, + TenPayV3Info.MchId, + name + " - 微信支付 V3", + sp_billno, + new TenpayDateTime(DateTime.Now.AddMinutes(1), false), + null, + notifyUrl, + null, + new() { currency = "CNY", total = price }, + new(openId), + null, + null, + null + ); + + logger.Info("支付参数:{0}", jsApiRequestData.ToJson()); + + + //请求接口 + var basePayApis2 = new Senparc.Weixin.TenPayV3.TenPayHttpClient.BasePayApis2(_httpClient, _tenpayV3Setting); + var result = await basePayApis2.JsApiAsync(jsApiRequestData); + + logger.Info("支付结果:{@UnifiedorderResult}", result); + + + if (result.VerifySignSuccess != true) + { + throw new WeixinException("获取 prepay_id 结果校验出错!"); + } + + //获取 UI 信息包 + var jsApiUiPackage = TenPaySignHelper.GetJsApiUiPackage(appId, result.prepay_id); + + + return jsApiUiPackage; + } + catch (Exception) + { + + throw; + } + + + } + + /// + /// JS-SDK支付回调地址(在下单接口中设置的 notify_url) + /// + /// + public async Task PayNotifyUrl() + { + try + { + //获取微信服务器异步发送的支付通知信息 + var resHandler = new TenPayNotifyHandler(HttpContext); + + var orderReturnJson = await resHandler.AesGcmDecryptGetObjectAsync(); + + //演示记录 transaction_id,实际开发中需要记录到数据库,以便退款和后续跟踪 + //TradeNumberToTransactionId[orderReturnJson.out_trade_no] = orderReturnJson.transaction_id; + + //获取支付状态 + string trade_state = orderReturnJson.trade_state; + + //验证请求是否从微信发过来(安全) + NotifyReturnData returnData = new(); + + //验证可靠的支付状态 + if (orderReturnJson.VerifySignSuccess == true && trade_state == "SUCCESS") + { + returnData.code = "SUCCESS";//正确的订单处理 + logger.Info("回调成功啦!", returnData.code.ToString()); + /* 提示: + * 1、直到这里,才能认为交易真正成功了,可以进行数据库操作,但是别忘了返回规定格式的消息! + * 2、上述判断已经具有比较高的安全性以外,还可以对访问 IP 进行判断进一步加强安全性。 + * 3、下面演示的是发送支付成功的模板消息提示,非必须。 + */ + } + else + { + returnData.code = "FAILD";//错误的订单处理 + returnData.message = "验证失败"; + //此处可以给用户发送支付失败提示等 + } + + #region 记录日志(也可以记录到数据库审计日志中) + var notifyJson = orderReturnJson.ToJson().ToString(); + + await payLog("WechatPay", "支付通知信息:" + notifyJson + ""); + + #endregion + + //https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_5.shtml + return orderReturnJson; + } + catch (Exception ex) + { + WeixinTrace.WeixinExceptionLog(new WeixinException(ex.Message, ex)); + throw; + } + } + + + /// + /// 订单查询 + /// + /// + public async Task OrderQuery(string out_trade_no = null, string transaction_id = null) + { + //out_trade_no transaction_id 两个参数不能都为空 + if (out_trade_no is null && transaction_id is null) + { + throw new ArgumentNullException(nameof(out_trade_no) + " or " + nameof(transaction_id)); + } + + OrderReturnJson result = null; + + //选择方式查询订单 + if (out_trade_no is not null) + { + result = await _basePayApis.OrderQueryByOutTradeNoAsync(out_trade_no, TenPayV3Info.MchId); + } + if (transaction_id is not null) + { + result = await _basePayApis.OrderQueryByTransactionIdAsync(transaction_id, TenPayV3Info.MchId); + } + + return result; + } + + + /// + /// 关闭订单 + /// + /// + public async Task CloseOrder(string out_trade_no) + { + + //out_trade_no transaction_id 两个参数不能都为空 + if (out_trade_no is null) + { + throw new ArgumentNullException(nameof(out_trade_no)); + } + + ReturnJsonBase result = null; + result = await _basePayApis.CloseOrderAsync(out_trade_no, TenPayV3Info.MchId); + + return result; + } + + + + /// + /// 退款申请接口 + /// + /// + public async Task Refund(string transactionId, decimal totalFee,string? paymentRefundNumber) + { + try + { + string outRefundNo; + await payLog("WechatRefund", "1"); + + string nonceStr = TenPayV3Util.GetNoncestr(); + + await payLog("WechatRefund", "2 退款微信单号transactionId:" + transactionId); + + if (!string.IsNullOrEmpty(paymentRefundNumber)) + { + outRefundNo = paymentRefundNumber; + } + else + { + outRefundNo = CreateNo_Recharge(); + } + int refundFee = Convert.ToInt32(totalFee); + string opUserId = TenPayV3Info.MchId; + var notifyUrl = "http://aerwen.net/prod-api/api/WxPay/refundNotifyUrl"; + //var dataInfo = new TenPayV3RefundRequestData(TenPayV3Info.AppId, TenPayV3Info.MchId, TenPayV3Info.Key, + // null, nonceStr, null, outTradeNo, outRefundNo, totalFee, refundFee, opUserId, null, notifyUrl: notifyUrl); + //TODO:该接口参数二选一传入 + var dataInfo = new RefundRequsetData(transactionId, null, outRefundNo, "Senparc TenPayV3 demo退款测试", notifyUrl, null, new RefundRequsetData.Amount(refundFee, null, refundFee, "CNY"), null); + + + //#region 新方法(Senparc.Weixin v6.4.4+) + //var result = TenPayOldV3.Refund(_serviceProvider, dataInfo);//证书地址、密码,在配置文件中设置,并在注册微信支付信息时自动记录 + //#endregion + var result = await _basePayApis.RefundAsync(dataInfo); + + await payLog("WechatRefund", "3 退款结果Result:" + result.ToJson()); + return result; + //return Json(result, JsonRequestBehavior.AllowGet); + } + catch (Exception ex) + { + WeixinTrace.WeixinExceptionLog(new WeixinException(ex.Message, ex)); + + throw; + } + } + + /// + /// 退款通知地址 + /// + /// + public async Task RefundNotifyUrl() + { + await payLog("WechatRefund", "允许被访问IP" + HttpContext.UserHostAddress()?.ToString()); + + NotifyReturnData returnData = new(); + var resHandler = new TenPayNotifyHandler(HttpContext); + var refundNotifyJson = await resHandler.AesGcmDecryptGetObjectAsync(); + try + { + await payLog("WechatRefund", "退款支付结果:" + refundNotifyJson.ToJson()); + + string refund_status = refundNotifyJson.refund_status; + if (/*refundNotifyJson.VerifySignSuccess == true &*/ refund_status == "SUCCESS") + { + returnData.code = "SUCCESS"; + returnData.message = "OK"; + + //填写逻辑 + await payLog("WechatRefund", "验证通过"); + } + else + { + returnData.code = "FAILD"; + returnData.message = "验证失败"; + await payLog("WechatRefund", "验证失败"); + + } + return refundNotifyJson; + + //进行后续业务处理 + } + catch (Exception ex) + { + returnData.code = "FAILD"; + returnData.message = ex.Message; + WeixinTrace.WeixinExceptionLog(new WeixinException(ex.Message, ex)); + } + + return refundNotifyJson; + + //https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay3_3.shtml + } + + + #region 参数模型 + /// + /// 小程序支付返回的参数 + /// + public class PayParams + { + /// + /// 产品Guid + /// + public JsApiUiPackage jsApiUiPackage { get; set; } + + /// + /// 系统订单号 + /// + public string outTradeNo { get; set; } + + /// + ///订单下单时间 + /// + public DateTime CreateTime { get; set; } + + /// + ///订单结束时间 + /// + public DateTime OverTime { get; set; } + } + + /// + /// 小程序支付接口的参数 + /// + public class PayDto + { + /// + /// 产品Guid + /// + public long ProductGuid { get; set; } + + /// + /// 支付类型 + /// + public int type { get; set; } + + /// + /// 小程序用户OpenId + /// + public string openId { get; set; } + } + + /// + /// 小程序支付订单查询的参数 + /// + public class OrderQueryDto + { + /// + /// 系统订单号 + /// + public string? outTradeNo { get; set; } + + /// + /// 微信支付订单号 + /// + public string? transactionId { get; set; } + + } + + + /// + /// 小程序支付需要的参数 + /// + public class PayRequesEntity + { + /// + /// 时间戳从1970年1月1日00:00:00至今的秒数,即当前的时间 + /// + public string timeStamp { get; set; } + + /// + /// 随机字符串,长度为32个字符以下。 + /// + public string nonceStr { get; set; } + + /// + /// 统一下单接口返回的 prepay_id 参数值 + /// + public string package { get; set; } + + /// + /// 签名算法 + /// + public string signType { get; set; } + + /// + /// 签名 + /// + public string paySign { get; set; } + } + #endregion + + + #region 微信支付日志操作 + /// + /// 微信支付日志 + /// + /// + public async Task payLog(string dirName,string data) + { + var logDir = ServerUtility.ContentRootMapPath(string.Format("~/App_Data/{0}/{1}", dirName , SystemTime.Now.ToString("yyyyMMdd"))); + if (!Directory.Exists(logDir)) + { + Directory.CreateDirectory(logDir); + } + + var logPath = Path.Combine(logDir, string.Format("{0}-{1}-{2}.txt", SystemTime.Now.ToString("yyyyMMdd"), SystemTime.Now.ToString("HHmmss"), Guid.NewGuid().ToString("n").Substring(0, 8))); + + using (var fileStream = System.IO.File.OpenWrite(logPath)) + { + await fileStream.WriteAsync(Encoding.Default.GetBytes(data), 0, Encoding.Default.GetByteCount(data)); + fileStream.Close(); + } + } + #endregion + + + /// + /// 申请资金账单接口 + /// + /// 日期,格式如:2021-08-27 + /// + public async Task FundflowBill(string date) + { + var filePath = $"{date}-FundflowBill.csv"; + Console.WriteLine("FilePath:" + filePath); + using (var fs = new FileStream(filePath, FileMode.OpenOrCreate)) + { + BasePayApis basePayApis = new BasePayApis(); + + var result = await _basePayApis.FundflowBillQueryAsync(date, fs); + + fs.Flush(); + } + return "已经下载倒指定目录,文件名:" + filePath; + } + + + public static object _lock = new object(); + + public static int count = 1; + /// + /// 退款订单号生成 + /// + /// + public static string CreateNo_Recharge() + { + lock (_lock) + { + if (count >= 10000) + { + count = 1; + } + + var number = "R" + DateTime.Now.ToString("yyMMddHHmmssfff") + count.ToString("0000"); + + count++; + + return number; + } + } + + + } +} diff --git a/Infrastructure/WeChat/TenPay/PayParameters.cs b/Infrastructure/WeChat/TenPay/PayParameters.cs new file mode 100644 index 0000000..22a24cb --- /dev/null +++ b/Infrastructure/WeChat/TenPay/PayParameters.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Infrastructure.WeChat.TenPay +{ + public class PayParameters + { + /// + /// 小程序ID + /// + public string appid { get { return "wx5e6ee16752b633c4"; } } + /// + /// 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用 + /// + public string attach { get { return "支付测试"; } } + /// + /// 商户号 + /// + public string mchid { get { return "1632347502"; } } + /// + /// 随机字符串,长度要求在32位以内。推荐随机数生成算法 + /// + public string nonce { get { return Senparc.Weixin.MP.Helpers.JSSDKHelper.GetNoncestr(); } } + /// + /// 异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。 + /// + public string notify_url { get { return "https://192.168.1.102/api/weiXinPay/Notify"; } } + /// + /// 商品简单描述,该字段请按照规范传递,具体请见参数规定 + /// + public string body { get { return "JSAPI支付测试"; } } + /// + /// 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*且在同一个商户号下唯一。详见商户订单号 + /// + public string out_trade_no { get; set; } + /// + /// 支持IPV4和IPV6两种格式的IP地址。调用微信支付API的机器IP + /// + public string spbill_create_ip { get { return "192.168.1.102"; } } + /// + /// 订单总金额,单位为分,详见支付金额 + /// + public int total_fee { get { return 10; } } + /// + /// 小程序取值如下:JSAPI,详细说明见参数规定 + /// + public string trade_type { get { return "JSAPI"; } } + /// + /// 交易过程生成签名的密钥,仅保留在商户系统和微信支付后台, + /// 不会在网络中传播。商户妥善保管该Key,切勿在网络中传输, + /// 不能在其他客户端中存储,保证key不会被泄漏。商户可根据邮件 + /// 提示登录微信商户平台进行设置。也可按以下路径设置: + /// 微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置 + /// + public string key { get { return "oDjIVWvPHBmjo5fH6p1q5ZkWEcJfKWfT"; } } + /// + /// AppSecret是APPID对应的接口密码,用于获取接口调用凭证时使用 + /// + public string secret { get { return "0666e1b9071ce6baacca2adf5945319d"; } } + /// + /// 是否需要分账 Y-是,需要分账 N-否,不分账 字母要求大写,不传默认不分账 + /// + public string profit_sharing { get; set; } + + } +} diff --git a/Infrastructure/WeChat/certificate/apiclient_cert.p12 b/Infrastructure/WeChat/certificate/apiclient_cert.p12 new file mode 100644 index 0000000..0671458 Binary files /dev/null and b/Infrastructure/WeChat/certificate/apiclient_cert.p12 differ diff --git a/Infrastructure/WeChat/certificate/apiclient_cert.pem b/Infrastructure/WeChat/certificate/apiclient_cert.pem new file mode 100644 index 0000000..df0d7dc --- /dev/null +++ b/Infrastructure/WeChat/certificate/apiclient_cert.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID8zCCAtugAwIBAgIUG9VGyXv6O/cWcsaRWsTp4erpyQ4wDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg +Q0EwHhcNMjIwNTMxMDEyNDQ5WhcNMjcwNTMwMDEyNDQ5WjCBhDETMBEGA1UEAwwK +MTYyNjQxODM4MzEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMTAwLgYDVQQL +DCfkvZvlsbHluILnvZHliY3kvZPogrLmlofljJbmnInpmZDlhazlj7gxCzAJBgNV +BAYMAkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAN9WNqA3cukHoR1THVhC8qUixWEnIuSl7NZF3xKrsbrmLRn1ieHM +ngsDlgKB93PDLCsWPL8OmzrRhhtLy99W+7Kuhs/ljXjcgP2LacHyhk4FkREkofBz +ex1gove6k5BTH7aT5J3XmJaVQIZJ2xTwoT+Tpqmu8CQqOF0ZF1DCAR3wrJw5OMYg +9gzUygdwAjslON6USiCBwILEodEdfcBIbDZZluPTEAQBabEEZD34o+sW2DiuoUHr +2yT9X1xvmUX+HLmwl/jgVhL9SjAf3Eit/SeILmPlE5IBs8jicJr83ouk0VDMsdDR +o4lZ1K2NnB1TeKqjlYy1eu4/C/52voV7wMECAwEAAaOBgTB/MAkGA1UdEwQCMAAw +CwYDVR0PBAQDAgTwMGUGA1UdHwReMFwwWqBYoFaGVGh0dHA6Ly9ldmNhLml0cnVz +LmNvbS5jbi9wdWJsaWMvaXRydXNjcmw/Q0E9MUJENDIyMEU1MERCQzA0QjA2QUQz +OTc1NDk4NDZDMDFDM0U4RUJEMjANBgkqhkiG9w0BAQsFAAOCAQEARkZVCrbJOerV +Y3McUubfBjqhbfusJDEt5ciqDs2mz5SfGRpOpXKuKqo8moOKFG6qvGVwdgznrDbz +fR9yuuHr7rJpdNaYk8tF3ursVUzkGObLw6QKVOwRHjMuu9cWwOeSQQ3SuzKhVhlf +o8l7rWxLx2azFSmLNF8V+aZhxpAXk2eAU2ZZa1sEb2PMac/Zmpulf2Zqbg2hMk7f +muh5bhSs2rC/0nv4MH39R3gTke2ZiXaM8q1wTcclIcy9C4jjq4KCSt9AfIjWzhQ5 +9AJ9miTYaFX7dlQTEH24M8UW/OeTG+7TTjmtbb4+N93JjpAJfvAFAaqxgbbr8LWs +LGMMvJWekQ== +-----END CERTIFICATE----- diff --git a/Infrastructure/WeChat/certificate/apiclient_key.pem b/Infrastructure/WeChat/certificate/apiclient_key.pem new file mode 100644 index 0000000..71929d1 --- /dev/null +++ b/Infrastructure/WeChat/certificate/apiclient_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDfVjagN3LpB6Ed +Ux1YQvKlIsVhJyLkpezWRd8Sq7G65i0Z9YnhzJ4LA5YCgfdzwywrFjy/Dps60YYb +S8vfVvuyrobP5Y143ID9i2nB8oZOBZERJKHwc3sdYKL3upOQUx+2k+Sd15iWlUCG +SdsU8KE/k6aprvAkKjhdGRdQwgEd8KycOTjGIPYM1MoHcAI7JTjelEoggcCCxKHR +HX3ASGw2WZbj0xAEAWmxBGQ9+KPrFtg4rqFB69sk/V9cb5lF/hy5sJf44FYS/Uow +H9xIrf0niC5j5ROSAbPI4nCa/N6LpNFQzLHQ0aOJWdStjZwdU3iqo5WMtXruPwv+ +dr6Fe8DBAgMBAAECggEARUwr8PSjjBjY7g9vCIblYUXztpx9IDM31JijidiKcjKf +hfGBEfX6h/JZ5ndLP7ksiEYDHUk78zk2Alw3axpDSQMMQ4+3oOvSfll2vD4zXBww +EgCq2sAKUGg+yN00klCog29KPYu7BeZTuhdKiinL7r0ytm3Yh3AuQvzZFi7MR+xk +K6wwcGlMdnK3WkwOsAb4g77xg0Iek4TC150RK5jLbAOW/9/jaz/QSjJZzgbqpUNM +JaeXjT0rUx8cGOSXpRxziSJNFGcX5BwozcdIhp3PHx/VugfliPcfr7HP6FVMLX3j +hNAKE32UQyaq/2bCSy9mnbaRubho6jDur5vp+vBVAQKBgQD5wfjFUavsEBsbt0Dj +Xw6D2Qjj67U9ccgqQjzUPFbeYb+awmXOPCqb5as1dkaZ71f+whv7nWKL+P6f3TIs +M1Pz8nL/lm0LxjLO50n/JxjIR6GGQ/vCGtJb84c+gavJ49y3SjsMAVWTvTHZYUj/ +mYYZ7Urnuz0nb1hJqlahWb1VEQKBgQDk6zE0QzL/fbYYc7fQQ8O2ddvnSuwwNZDj +asXpuWXAYNTqGNrhIdLBiEpj9uIO3Z7UhCjoh+mFWhDcbUQ+G0l6rQHE3Z7IMFBO +HZDCGoQgWuwsMuz8tGXIa5nrdZ4ep2DB4VxsGGFJqRiopj7f5IDRbNlifmr2Cfzx +VGHcDJTwsQKBgCdvhURCvQ6tDFq3+LruC3CuGEVEtn1ZNe3WP5yTWnQKoyJgh4qk +3WV4QixS3Jr5u78yDxEPrLvFOQ8s8fsgr6TZJ2dL7TPqu6MHyhtLpRIanVqB6YKg +kY6LSVOJTgK2w+b9BY3DuCt3uCNGxSv2pcH6QdWNLv7HCf23s64OaWLBAoGAF/OH +tWkmh9bWW56X5+F/M7MHLB8JsU2ZeEHurTKps8Qt4sRw+kc4rukcp3LoWhfUC3Y8 +dX/q7fnrc7S3BCyEtqItYjSx7U4oyNONFtIBawU4WrOFWjdhwuOHOjyXK6vlksOK +kQDIBRX9L4Adaf2VgNP7trN1a4LGBVYH2ycx2jECgYBM/Ge2QKkRXaVkfmbnJ6ZP +g0KIAZJ7tL7GxAICVeqZ4OeqyQP9cFvaJjdvGnE2B0xo2ApZhLgzno+pZRd4tnV3 +IHXBeHyMhAGZ5I4r4shwzF4U84FZk7bg/CeyNyyv7Ljflw7erlDMDCr/xvloerwz +wggxHc35JUCiT5FI02jWhQ== +-----END PRIVATE KEY----- diff --git a/Infrastructure/WeChat/certificate/wechatpay_41EAA204B2DE9CE2D8AB4CF39975EFE81709340C.pem b/Infrastructure/WeChat/certificate/wechatpay_41EAA204B2DE9CE2D8AB4CF39975EFE81709340C.pem new file mode 100644 index 0000000..5f564f4 --- /dev/null +++ b/Infrastructure/WeChat/certificate/wechatpay_41EAA204B2DE9CE2D8AB4CF39975EFE81709340C.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID3DCCAsSgAwIBAgIUQeqiBLLenOLYq0zzmXXv6BcJNAwwDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg +Q0EwHhcNMjIwNTMxMDEyNDQ4WhcNMjcwNTMwMDEyNDQ4WjBuMRgwFgYDVQQDDA9U +ZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRl +bnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGDAJDTjERMA8GA1UEBwwIU2hlblpo +ZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCoM97NW6snqyZorpXM +RiyZqwQuU33xJuTFJGM834DkonTS/BidExuk0AqqlrLdcydCJILYoxcvs8pY8Kp2 +RkJiwwyNHdYpDMBNO7HJjMyWZkr03t0yFOivCRlvu8kZcMpTdK8BsyWAk2AiuNgU +tK9R91Huz9UCbK2+2lLSD1Xy38S6XYSlFEiA1gfSOm1N8b9v8qqwy7vbHJbt/t1d +hbF9ZLp1+lOAF9tA86zibFjUDM1wBBtQkcJkZnnLAvEgKFyTTh7jLO1NBb9plDC3 +w1/sAl8XMHny6U6YP9nx9lt1/uFETX5RFfPRzXKlRA5hBx0waTaZRhFHOVr8W0su +zcRnAgMBAAGjgYEwfzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIE8DBlBgNVHR8EXjBc +MFqgWKBWhlRodHRwOi8vZXZjYS5pdHJ1cy5jb20uY24vcHVibGljL2l0cnVzY3Js +P0NBPTFCRDQyMjBFNTBEQkMwNEIwNkFEMzk3NTQ5ODQ2QzAxQzNFOEVCRDIwDQYJ +KoZIhvcNAQELBQADggEBALIbd1/T7mpVqCkz9KIAXbLtTUTcxYVAta7Cyggh9df/ +jOM+cTJCdYX87x00OwmNRX20xCwJ36Tu3QVVrfGY3gOs9vTsi0MlmOrv/1Pk5+CZ +cwN6UqSp8jJvZlc42dGfBvzCIdt+yMouF1eXeN/8B1vDIfA2gxI7al2K5c6RtvSU +9taTSFfgJ0E+qNMKSUVSZiNRGiMfXdC6WvL7/7dL0vA3am4/bjgiYeqrdhUHdVPE +xdfa14XG/FiNkdqviP8a/xfCjZeRi5b3iV1n8K9hkdKp+Rd06FpuJi/Nv+mvNUiS +fnua5+Lq4r2KedMpDQrXIWsvt+V8wztZW6fGgqjxknk= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/Infrastructure/WeChat/certificate/微信支付平台证书操作/README.md b/Infrastructure/WeChat/certificate/微信支付平台证书操作/README.md new file mode 100644 index 0000000..ff40403 --- /dev/null +++ b/Infrastructure/WeChat/certificate/微信支付平台证书操作/README.md @@ -0,0 +1,81 @@ +# Certificate Downloader + +Certificate Downloader 是 PHP版 微信支付 APIv3 平台证书的命令行下载工具。该工具可从 `https://api.mch.weixin.qq.com/v3/certificates` 接口获取商户可用证书,并使用 [APIv3 密钥](https://wechatpay-api.gitbook.io/wechatpay-api-v3/ren-zheng/api-v3-mi-yao) 和 AES_256_GCM 算法进行解密,并把解密后证书下载到指定位置。 + +## 使用 +使用方法与 [Java版Certificate Downloader](https://github.com/wechatpay-apiv3/CertificateDownloader) 一致,参数与常见问题请参考[其文档](https://github.com/wechatpay-apiv3/CertificateDownloader/blob/master/README.md)。 + +```shell +> bin/CertificateDownloader.php + +Usage: 微信支付平台证书下载工具 [-hV] + -f= -k= -m= + -s= -o=[outputFilePath] -u=[baseUri] +Options: + -m, --mchid= 商户号 + -s, --serialno= 商户证书的序列号 + -f, --privatekey= + 商户的私钥文件 + -k, --key= ApiV3Key + -o, --output=[outputFilePath] + 下载成功后保存证书的路径,可选参数,默认为临时文件目录夹 + -u, --baseuri=[baseUri] 接入点,默认为 https://api.mch.weixin.qq.com/ + -V, --version Print version information and exit. + -h, --help Show this help message and exit. +``` + +完整命令示例: + +```shell +./bin/CertificateDownloader.php -k ${apiV3key} -m ${mchId} -f ${mchPrivateKeyFilePath} -s ${mchSerialNo} -o ${outputFilePath} +``` + +或 + +```shell +php -f ./bin/CertificateDownloader.php -- -k ${apiV3key} -m ${mchId} -f ${mchPrivateKeyFilePath} -s ${mchSerialNo} -o ${outputFilePath} +``` + +或 + +```shell +php ./bin/CertificateDownloader.php -k ${apiV3key} -m ${mchId} -f ${mchPrivateKeyFilePath} -s ${mchSerialNo} -o ${outputFilePath} +``` + +使用`composer`安装的软件包,可以通过如下命令下载: + +```shell +vendor/bin/CertificateDownloader.php -k ${apiV3key} -m ${mchId} -f ${mchPrivateKeyFilePath} -s ${mchSerialNo} -o ${outputFilePath} +``` + +或 + +```shell +composer exec CertificateDownloader.php -- -k ${apiV3key} -m ${mchId} -f ${mchPrivateKeyFilePath} -s ${mchSerialNo} -o ${outputFilePath} +``` + +使用源码克隆版本,也可以使用`composer`通过以下命令下载: + +```shell +composer v3-certificates -k ${apiV3key} -m ${mchId} -f ${mchPrivateKeyFilePath} -s ${mchSerialNo} -o ${outputFilePath} +``` + +支持从海外接入点下载,命令如下: + +```shell +composer v3-certificates -k ${apiV3key} -m ${mchId} -f ${mchPrivateKeyFilePath} -s ${mchSerialNo} -o ${outputFilePath} -u https://apihk.mch.weixin.qq.com/ +``` + +**注:** 示例命令行上的`${}`是变量表达方法,运行时请替换(包括`${}`)为对应的实际值。 + +## 常见问题 + +### 如何保证证书正确 +请参见CertificateDownloader文档中[关于如何保证证书正确的说明](https://github.com/wechatpay-apiv3/CertificateDownloader#%E5%A6%82%E4%BD%95%E4%BF%9D%E8%AF%81%E8%AF%81%E4%B9%A6%E6%AD%A3%E7%A1%AE)。 + +### 如何使用信任链验证平台证书 +请参见CertificateDownloader文档中[关于如何使用信任链验证平台证书的说明](https://github.com/wechatpay-apiv3/CertificateDownloader#%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8%E4%BF%A1%E4%BB%BB%E9%93%BE%E9%AA%8C%E8%AF%81%E5%B9%B3%E5%8F%B0%E8%AF%81%E4%B9%A6)。 + +### 第一次下载证书 + +请参见CertificateDownloader文档中[相关说明](https://github.com/wechatpay-apiv3/CertificateDownloader#%E7%AC%AC%E4%B8%80%E6%AC%A1%E4%B8%8B%E8%BD%BD%E8%AF%81%E4%B9%A6)。 diff --git a/Infrastructure/WeChat/certificate/微信支付平台证书操作/cmd操作.txt b/Infrastructure/WeChat/certificate/微信支付平台证书操作/cmd操作.txt new file mode 100644 index 0000000..a569a50 --- /dev/null +++ b/Infrastructure/WeChat/certificate/微信支付平台证书操作/cmd操作.txt @@ -0,0 +1,2 @@ + +php -f ./bin/CertificateDownloader.php -- -k CHOFVQJOXBJEWZJEJKUWTHUBOSVQBRIW -m 1626418383 -f D:/phpstudy_pro/WWW/fitness/api/certificate/apiclient_key.pem -s 1BD546C97BFA3BF71672C6915AC4E9E1EAE9C90E -o D:\phpstudy_pro\WWW\fitness\api\certificate\ \ No newline at end of file diff --git a/Infrastructure/WeChat/certificate/璇佷功浣跨敤璇存槑.txt b/Infrastructure/WeChat/certificate/璇佷功浣跨敤璇存槑.txt new file mode 100644 index 0000000..9a0aab1 --- /dev/null +++ b/Infrastructure/WeChat/certificate/璇佷功浣跨敤璇存槑.txt @@ -0,0 +1,18 @@ +欢迎使用微信支付! +附件中的三份文件(证书pkcs12格式、证书pem格式、证书密钥pem格式),为接口中强制要求时需携带的证书文件。 +证书属于敏感信息,请妥善保管不要泄露和被他人复制。 +不同开发语言下的证书格式不同,以下为说明指引: + 证书pkcs12格式(apiclient_cert.p12) + 包含了私钥信息的证书文件,为p12(pfx)格式,由微信支付签发给您用来标识和界定您的身份 + 部分安全性要求较高的API需要使用该证书来确认您的调用身份 + windows上可以直接双击导入系统,导入过程中会提示输入证书密码,证书密码默认为您的商户号(如:1900006031) + 证书pem格式(apiclient_cert.pem) + 从apiclient_cert.p12中导出证书部分的文件,为pem格式,请妥善保管不要泄漏和被他人复制 + 部分开发语言和环境,不能直接使用p12文件,而需要使用pem,所以为了方便您使用,已为您直接提供 + 您也可以使用openssl命令来自己导出:openssl pkcs12 -clcerts -nokeys -in apiclient_cert.p12 -out apiclient_cert.pem + 证书密钥pem格式(apiclient_key.pem) + 从apiclient_cert.p12中导出密钥部分的文件,为pem格式 + 部分开发语言和环境,不能直接使用p12文件,而需要使用pem,所以为了方便您使用,已为您直接提供 + 您也可以使用openssl命令来自己导出:openssl pkcs12 -nocerts -in apiclient_cert.p12 -out apiclient_key.pem +备注说明: + 由于绝大部分操作系统已内置了微信支付服务器证书的根CA证书, 2018年3月6日后, 不再提供CA证书文件(rootca.pem)下载 \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..365fbfe --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 zrry + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..63d7c69 --- /dev/null +++ b/README.md @@ -0,0 +1,404 @@ +# .NET后端开发流程 + + + +基于.NET6 + vue3 前后端分离的.net快速开发框架 + + + +## 🍟 概述 + +- 本项目适合有一定**NetCore**和 **vue基础**的开发人员 +- 基于**.NET6**实现的通用权限管理平台(RBAC模式)。整合最新技术高效快速开发,前后端分离模式,开箱即用。 + + + +## 🍀 后端技术 + +- 核心框架:.Net6.0 + **Web API** + **sqlsugar** + **swagger** + signalR + IpRateARWmit + Quartz.net + Redis +- 定时计划任务:Quartz.Net组件,支持执行程序集或者http网络请求,**备份数据库** +- 安全支持:过滤器(数据权限过滤)、Sql注入、请求伪造 +- 日志管理:NLog、登录日志、操作日志、定时任务日志 +- 工具类:验证码、丰富公共功能 +- 接口限流:支持接口限流,避免恶意请求导致服务层压力过大 +- 代码生成:高效率开发,代码生成器可以一键生成所有前后端代码 +- 数据字典:支持数据字典,可以方便对一些状态进行管理 +- 分库分表:使用orm sqlsugar可以很轻松的实现分库分库性能优越 +- 多 租 户:支持多租户功能 +- 缓存数据:内置内存缓存和Redis + + + +## 🔧 配置 + +1. 用 Vs 打开项目解决方案文件 `ARWAdmin.sln` + + 下载地址:https://visualstudio.microsoft.com/zh-hans/ + +2. 连接服务器数据库 (navicat) + +3. 修改数据库连接配置 `ARW.WebApi` 目录下的 `appsettings.json` 配置 + +```json +{ + "ConnectionStrings": { + "conn_db": "Data Source=localhost;Initial Catalog=ARWAdmin;User ID=sa;Password=ARWadmin123;Trusted_Connection=SSPI", //当前项目连接数据库, + "conn_db_type": 1, //选择对应的数据库类型MySql = 0, SqlServer = 1。其他数据库自行添加基础数据 + } +``` + +​ 现在尝试启动项目吧 ~ + + + +## 🍻项目结构 + +``` +├─Infrastructure ->[基础设施]:提供基础系统工具类。 +├─ARW.WebApi ->[webapi接口]:为Vue版或其他三方系统提供接口服务。 +├─ARW.Model ->[实体层类库]:提供项目中的数据库表、数据传输对象; +├─ARW.Common ->[常用工具]:提供项目中常用方法; +├─ARW.Repository ->[仓库层类库]:方便提供有执行存储过程的操作; +├─ARW.Service ->[服务层类库]:提供WebApi接口调用; +├─ARW.Tasks ->[定时任务类库]:提供项目定时任务实现功能; +├─ARW.CodeGenerator ->[代码生成功能]:包含代码生成的模板、方法、代码生成的下载。 +``` + + + +## 🔍 开发规范 + +>开发时 不管是 哪一个层 +> +>都要 **按模块** **分好文件夹** +> +>都要 **写好注释!!!!** +> +>/// 使用这个注释 + + + +## 🧬 开发流程 + +![1](https://drive.kongwu.top/image/image/c3ffb787475b88c557b271414ef67c12.png) + + + +------ + + + +### 1、创建模型 (Model层) + +#### 1.1 Model (数据交互) + +数据交互:与**数据库**打交道的类,最后接收数据返回到这个类, + +​ 然后映射到数据库 ,数据库再把结果返回 (详细去了解ORM) + + + +这里我们使用的是 **SqlSugar** 作为 ORM + +官方文档:https://www.donet5.com/Home/Doc?typeId=1182 + +[实体常用属性](https://blog.csdn.net/weixin_60435181/article/details/125729548?spm=1001.2014.3001.5502) + +> 具体如何写实体类,可以参考实例实体 +> +> ARW.Model -> Models -> Business -> Student 或者 Class + +* 需要注意的是: + * 业务表的前缀是 : tb_ + * 系统表的前缀是 : sys_ + * 记得继承 :BusinessBase + * Id 使用的是 **雪花ID** + * **时间(DateTime)**的需要进行转换 + * excel导出 表头特要标记 EpplusTableColumn[ ] + +​ + + + +#### 1.2 Dto (数据传输) + +只接收指定参数,更加**清晰**知道传入什么参数 + +```c# +// 接受的参数 是 Dto类型的 +// [FromBody] 是 json请求体 +public IActionResult AddStudent([FromBody] StudentDto parm) +``` + +**传统Model层:** + +![](https://drive.kongwu.top/image/image/bacbca5d023bccae0233070ce7aaa297.jpg) + +**Dto层:更加清晰 知道传入什么值,方便前端对接~** + +![](https://drive.kongwu.top/image/image/14fe22617c61d6fc7dca9cd8b22763e4.jpg) + + + + + +#### 1.3 Vo (数据展示) + +![](https://drive.kongwu.top/image/image/04228d577e85b9906a8ce1f90c1f6676.png) + +**展现需要的字段:** + +![](https://drive.kongwu.top/image/image/4f04bcaf9ce79eee0b52ba5af51be3b0.jpg) + + + +定义一个新的类,**只展示我们需要的字段** + +使用 **Select()** 把实体值 赋值给 新的类就可以了。 + +```c# +var query = _studentRepository + .Queryable() + .LeftJoin((s, c) => s.ClassId == c.ClassId) + .Where(predicate.ToExpression()) + .Select((s, c) => new StudentVo + { + StudentId = s.StudentId, + ClassId = c.ClassId, + ClassName = c.ClassName, + StudentName = s.StudentName, + Sex = s.Sex, + Age = s.Age, + StudentImg = s.StudentImg, + StudentTag = s.StudentTag, + StudentService= s.StudentService.ToString(), + StudentDescribe = s.StudentDescribe + }); + +``` + + + +------ + + + +### 2、创建接口和实现类 (Service层) + +作用: + +1、代码整洁 + +2、分层,好维护 + +3、可以注册服务,不需要实例化 + + + +#### 2.1 创建接口 + +在 `ARW.Service` -> `Business` -> `IBusinessService` 中 创建**接口** (interface) + +注意:记得 继承 **IBaseService<对应的数据实体类>** + +* 命名规范:**IxxxService** + * 前缀 I + * 后缀 Service + + + +**Interface(接口):** + +```c# + public interface IStudentService : IBaseService + { + /// + /// 获取学生分页列表 + /// + /// + /// + PagedInfo GetStudentList(StudentQueryDto parm); + + } +``` + + + +#### 2.2 创建实现类 + +在 `ARW.Service` -> `Business` -> `BusinessService` 中 创建**实现类** (Impl) + +注意:记得 继承 **BaseService<对应的数据实体类>,相对应的接口** + +​ **添加服务到容器**( 特性 ): [AppService(ServiceType = typeof( `相对应的接口` ), ServiceLifetime = LifeTime.Transient)] + +```c# +[AppService(ServiceType = typeof(IStudentService), ServiceLifetime = LifeTime.Transient)] +public class StudentServiceImpl : BaseService, IStudentService +``` + + + +`实现类要实现 接口所定义的方法` + +```c# + // 写业务方法 + + public PagedInfo GetStudentList(StudentQueryDto parm) + { + //开始拼装查询条件d + var predicate = Expressionable.Create(); + + //搜索条件查询语法参考Sqlsugar + predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.StudentName), s => s.StudentName.Contains(parm.StudentName)); + predicate = predicate.AndIF(parm.ClassId != null, s => s.ClassId == parm.ClassId); + + var query = _studentRepository + .Queryable() + .LeftJoin((s, c) => s.ClassId == c.ClassId) + .Where(predicate.ToExpression()) + .Select((s, c) => new StudentVo + { + StudentId = s.StudentId, + ClassId = c.ClassId, + ClassName = c.ClassName, + StudentName = s.StudentName, + Sex = s.Sex, + Age = s.Age, + StudentImg = s.StudentImg, + StudentTag = s.StudentTag, + StudentService= s.StudentService.ToString(), + StudentDescribe = s.StudentDescribe + }); + + + return query.ToPage(parm); + } +``` + + + +### 3、创建仓储层(Repository层) + +在 `ARW.Repository` -> `Business` 中 创建**仓储类** (Repository)、 + +作用:用于超级复杂的业务逻辑,当 `接口实现类 ` 都写的很乱时,可以使用这个层 + +一般走流程需要创建一个,所以参考以下模板创建: + +```c# +[AppService(ServiceLifetime = LifeTime.Transient)] +public class StudentRepository : BaseRepository +{ + /* + * 复杂的业务逻辑代码 + */ +} +``` + + + +------ + + + +### 4、创建控制层 (Controller层) + +**-- 这里细节比较多,请注意看 --** + + + +**控制器头部:** + +```c# + [Verify] // 身份认证 + [Route("business/[controller]")] // 路由 + public class StudentController : BaseController // 继承 BaseController +``` + + + +**依赖注入(构造函数注入):** + +```c# + /// + /// 依赖注入 + /// + /// 学生服务 + /// 班级服务 + public StudentController(IStudentService studentService, IClassService classService) + { + _studentService = studentService; + _classService = classService; + } +``` + + + +**方法:** + +* 请求参数格式: + +​ **[FromBody]:**json请求体 + +​ **[FromQuery]:** url 获取参数 + +​ **[FromForm(Name = "xxx")] :**获取From表单中的参数 + +* 抛出异常: + + ​ **throw new CustomException(" ")** + +* 返回结果: + +​ **SUCCESS("消息")** + +​ **ToResponse(数据,"消息")** + + + +```c# +// 头部规范: +[HttpPost("addStudent")] // [请求方法("请求路由")] +[ActionPermissionFilter(Permission = "business:student:add")] // 权限标识符 +[Log(Title = "学生添加", BusinessType = BusinessType.INSERT)] // 日志 +public IActionResult AddStudent([FromBody] StudentDto parm) +{ + // 抛出异常 + if (parm == null) + { + throw new CustomException("请求参数错误"); + } + + // 模型映射:Dto层需要把接受的数据 给到 Model层,才能和数据库交互 + var modal = parm.Adapt().ToCreate(HttpContext); + + var response = _studentService.Insertable(modal).ExecuteReturnSnowflakeId(); + return SUCCESS("添加成功!"); +} +``` + + + +>查询分页(联表) +> +>查询树形 +> +>查询单条 +> +>添加 +> +>修改 +> +>删除 +> +>导入Excel +> +>导出Excel +> +>下载模板Excel + +具体操作方法可参考: + +`ARW.WebApi` -> `Business` -> `StudentController(基础方法)` / `ProductTypeController(树形)` + diff --git a/document/admin-mysql.sql b/document/admin-mysql.sql new file mode 100644 index 0000000..098f5bf --- /dev/null +++ b/document/admin-mysql.sql @@ -0,0 +1,854 @@ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for sys_tasks +-- ---------------------------- +DROP TABLE IF EXISTS `sys_tasks`; +CREATE TABLE `sys_tasks` ( + `Id` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'UID', + `Name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '任务名称', + `JobGroup` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '任务分组', + `Cron` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '运行时间表达式', + `AssemblyName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '程序集名称', + `ClassName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '任务所在类', + `Remark` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '任务描述', + `RunTimes` int(11) NOT NULL COMMENT '执行次数', + `BeginTime` datetime(0) NULL DEFAULT NULL COMMENT '开始时间', + `EndTime` datetime(0) NULL DEFAULT NULL COMMENT '结束时间', + `TriggerType` int(11) NOT NULL COMMENT '触发器类型(0、simple 1、cron)', + `IntervalSecond` int(11) NOT NULL COMMENT '执行间隔时间(单位:秒)', + `IsStart` tinyint(4) NOT NULL COMMENT '是否启动', + `JobParams` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '传入参数', + `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime(0) NULL DEFAULT NULL COMMENT '最后更新时间', + `create_by` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人编码', + `update_by` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '更新人编码', + `lastRunTime` datetime(0) NULL DEFAULT NULL COMMENT '最后执行时间', + `apiUrl` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'api执行地址', + `taskType` int(4) NULL DEFAULT 1 COMMENT '任务类型1程序集任务 2网络请求', + PRIMARY KEY (`ID`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '计划任务' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Table structure for sys_tasks_log +-- ---------------------------- +DROP TABLE IF EXISTS `sys_tasks_log`; +CREATE TABLE `sys_tasks_log` ( + `jobLogId` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '任务日志ID', + `jobId` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '任务id', + `jobName` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '任务名称', + `jobGroup` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '任务组名', + `jobMessage` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '日志信息', + `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '执行状态(0正常 1失败)', + `exception` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '异常信息', + `createTime` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + `invokeTarget` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '调用目标', + `elapsed` double(10, 0) NULL DEFAULT NULL COMMENT '作业用时', + PRIMARY KEY (`jobLogId`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 198 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '定时任务调度日志表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- 通知公告表 +-- ---------------------------- +drop table if exists sys_notice; +create table sys_notice ( + notice_id int(4) not null auto_increment comment '公告ID', + notice_title varchar(50) not null comment '公告标题', + notice_type char(1) not null comment '公告类型(1通知 2公告)', + notice_content varchar(500) default null comment '公告内容', + status char(1) default '0' comment '公告状态(0正常 1关闭)', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(255) default null comment '备注', + primary key (notice_id) +) engine=innodb auto_increment=10 comment = '通知公告表'; + + +-- ---------------------------- +-- Table structure for sys_dept +-- ---------------------------- +DROP TABLE IF EXISTS `sys_dept`; +CREATE TABLE `sys_dept` ( + `deptId` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '部门id', + `parentId` bigint(20) NULL DEFAULT 0 COMMENT '父部门id', + `ancestors` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '祖级列表', + `deptName` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '部门名称', + `orderNum` int(4) NULL DEFAULT 0 COMMENT '显示顺序', + `leader` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '负责人', + `phone` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '联系电话', + `email` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱', + `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '部门状态(0正常 1停用)', + `delFlag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`deptId`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 204 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '部门表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_dept +-- ---------------------------- +INSERT INTO `sys_dept` VALUES (100, 0, '0', 'A公司', 0, 'zr', '', '', '0', '0', 'admin', NULL, '', NULL, NULL); +INSERT INTO `sys_dept` VALUES (101, 100, '0,100', '研发部门', 1, 'zr', '', '', '0', '0', 'admin', NULL, '', NULL, NULL); +INSERT INTO `sys_dept` VALUES (102, 100, '0,100', '市场部门', 2, 'zr', '', '', '0', '0', 'admin', NULL, '', NULL, NULL); +INSERT INTO `sys_dept` VALUES (103, 100, '0,100', '测试部门', 3, 'zr', '', '', '0', '0', 'admin', NULL, '', NULL, NULL); +INSERT INTO `sys_dept` VALUES (104, 100, '0,100', '财务部门', 4, 'zr', '', '', '0', '0', 'admin', NULL, '', NULL, NULL); + +INSERT INTO `sys_dept` VALUES (200, 0, '0', 'B公司', 0, 'zr', '', '', '0', '0', 'admin', NULL, '', NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_dict_data +-- ---------------------------- +DROP TABLE IF EXISTS `sys_dict_data`; +CREATE TABLE `sys_dict_data` ( + `dictCode` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '字典编码', + `dictSort` int(4) NULL DEFAULT 0 COMMENT '字典排序', + `dictLabel` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '字典标签', + `dictValue` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '字典键值', + `dictType` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '字典类型', + `cssClass` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '样式属性(其他样式扩展)', + `listClass` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '表格回显样式', + `isDefault` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'N' COMMENT '是否默认(Y是 N否)', + `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '状态(0正常 1停用)', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`dictCode`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 31 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '字典数据表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_dict_data +-- ---------------------------- +INSERT INTO `sys_dict_data` VALUES (1, 1, '男', '0', 'sys_user_sex', '', '', 'Y', '0', 'admin', '2021-02-24 10:56:21', '', NULL, '性别男'); +INSERT INTO `sys_dict_data` VALUES (2, 2, '女', '1', 'sys_user_sex', '', '', 'N', '0', 'admin', '2021-02-24 10:56:21', '', NULL, '性别女'); +INSERT INTO `sys_dict_data` VALUES (3, 3, '未知', '2', 'sys_user_sex', '', '', 'N', '0', 'admin', '2021-02-24 10:56:21', '', NULL, '性别未知'); +INSERT INTO `sys_dict_data` VALUES (4, 1, '显示', '0', 'sys_show_hide', '', 'primary', 'Y', '0', 'admin', '2021-02-24 10:56:21', '', NULL, '显示菜单'); +INSERT INTO `sys_dict_data` VALUES (5, 2, '隐藏', '1', 'sys_show_hide', '', 'danger', 'N', '0', 'admin', '2021-02-24 10:56:21', '', NULL, '隐藏菜单'); +INSERT INTO `sys_dict_data` VALUES (6, 1, '正常', '0', 'sys_normal_disable', '', 'primary', 'Y', '0', 'admin', '2021-02-24 10:56:21', '', NULL, '正常状态'); +INSERT INTO `sys_dict_data` VALUES (7, 2, '停用', '1', 'sys_normal_disable', '', 'danger', 'N', '0', 'admin', '2021-02-24 10:56:21', '', NULL, '停用状态'); +INSERT INTO `sys_dict_data` VALUES (8, 1, '正常', '0', 'sys_job_status', '', 'primary', 'Y', '0', 'admin', '2021-02-24 10:56:21', '', NULL, '正常状态'); +INSERT INTO `sys_dict_data` VALUES (9, 2, '异常', '1', 'sys_job_status', '', 'danger', 'N', '0', 'admin', '2021-02-24 10:56:21', '', '2021-07-02 14:09:09', '停用状态'); +INSERT INTO `sys_dict_data` VALUES (10, 1, '默认', 'DEFAULT', 'sys_job_group', '', '', 'Y', '0', 'admin', '2021-02-24 10:56:21', '', NULL, '默认分组'); +INSERT INTO `sys_dict_data` VALUES (11, 2, '系统', 'SYSTEM', 'sys_job_group', '', '', 'N', '0', 'admin', '2021-02-24 10:56:21', '', NULL, '系统分组'); +INSERT INTO `sys_dict_data` VALUES (12, 1, '是', 'Y', 'sys_yes_no', '', 'primary', 'Y', '0', 'admin', '2021-02-24 10:56:21', '', NULL, '系统默认是'); +INSERT INTO `sys_dict_data` VALUES (13, 2, '否', 'N', 'sys_yes_no', '', 'danger', 'N', '0', 'admin', '2021-02-24 10:56:21', '', NULL, '系统默认否'); +INSERT INTO `sys_dict_data` VALUES (14, 1, '通知', '1', 'sys_notice_type', '', 'warning', 'Y', '0', 'admin', '2021-02-24 10:56:22', '', NULL, '通知'); +INSERT INTO `sys_dict_data` VALUES (15, 2, '公告', '2', 'sys_notice_type', '', 'success', 'N', '0', 'admin', '2021-02-24 10:56:22', '', NULL, '公告'); +INSERT INTO `sys_dict_data` VALUES (16, 1, '正常', '0', 'sys_notice_status', '', 'primary', 'Y', '0', 'admin', '2021-02-24 10:56:22', '', NULL, '正常状态'); +INSERT INTO `sys_dict_data` VALUES (17, 2, '关闭', '1', 'sys_notice_status', '', 'danger', 'N', '0', 'admin', '2021-02-24 10:56:22', '', NULL, '关闭状态'); +INSERT INTO `sys_dict_data` VALUES (18, 0, '其他', '0', 'sys_oper_type', '', 'info', 'N', '0', 'admin', '2021-02-24 10:56:22', '', NULL, '其他操作'); +INSERT INTO `sys_dict_data` VALUES (19, 1, '新增', '1', 'sys_oper_type', '', 'info', 'N', '0', 'admin', '2021-02-24 10:56:22', '', NULL, '新增操作'); +INSERT INTO `sys_dict_data` VALUES (20, 2, '修改', '2', 'sys_oper_type', '', 'info', 'N', '0', 'admin', '2021-02-24 10:56:22', '', NULL, '修改操作'); +INSERT INTO `sys_dict_data` VALUES (21, 3, '删除', '3', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2021-02-24 10:56:22', '', NULL, '删除操作'); +INSERT INTO `sys_dict_data` VALUES (22, 4, '授权', '4', 'sys_oper_type', '', 'primary', 'N', '0', 'admin', '2021-02-24 10:56:22', '', NULL, '授权操作'); +INSERT INTO `sys_dict_data` VALUES (23, 5, '导出', '5', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2021-02-24 10:56:22', '', NULL, '导出操作'); +INSERT INTO `sys_dict_data` VALUES (24, 6, '导入', '6', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2021-02-24 10:56:22', '', NULL, '导入操作'); +INSERT INTO `sys_dict_data` VALUES (25, 7, '强退', '7', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2021-02-24 10:56:22', '', NULL, '强退操作'); +INSERT INTO `sys_dict_data` VALUES (26, 8, '生成代码', '8', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2021-02-24 10:56:22', '', NULL, '生成操作'); +INSERT INTO `sys_dict_data` VALUES (27, 9, '清空数据', '9', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2021-02-24 10:56:22', '', NULL, '清空操作'); +INSERT INTO `sys_dict_data` VALUES (28, 1, '成功', '0', 'sys_common_status', '', 'primary', 'N', '0', 'admin', '2021-02-24 10:56:23', '', NULL, '正常状态'); +INSERT INTO `sys_dict_data` VALUES (29, 2, '失败', '1', 'sys_common_status', '', 'danger', 'N', '0', 'admin', '2021-02-24 10:56:23', '', NULL, '停用状态'); +INSERT INTO `sys_dict_data` VALUES (30, 1, '发布', '1', 'sys_article_status', NULL, NULL, NULL, '0', 'admin', '2021-08-19 10:34:56', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (31, 2, '草稿', '2', 'sys_article_status', NULL, NULL, NULL, '0', 'admin', '2021-08-19 10:35:06', '', NULL, NULL); + +INSERT INTO `sys_dict_data` VALUES (32, 1, '中文', 'zh-cn', 'sys_lang_type', NULL, NULL, NULL, '0', 'admin', '2021-08-19 10:35:06', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (33, 2, '英文', 'en', 'sys_lang_type', NULL, NULL, NULL, '0', 'admin', '2021-08-19 10:35:06', '', NULL, NULL); +INSERT INTO `sys_dict_data` VALUES (34, 3, '繁体', 'zh-tw', 'sys_lang_type', NULL, NULL, NULL, '0', 'admin', '2021-08-19 10:35:06', '', NULL, NULL); + + +SET FOREIGN_KEY_CHECKS = 1; + +-- ---------------------------- +-- Table structure for sys_dict_type +-- ---------------------------- +DROP TABLE IF EXISTS `sys_dict_type`; +CREATE TABLE `sys_dict_type` ( + `dictId` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '字典主键', + `dictName` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '字典名称', + `dictType` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '字典类型', + `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '状态(0正常 1停用)', + `type` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'N' COMMENT '系统内置(Y是 N否)', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`dictId`) USING BTREE, + UNIQUE INDEX `dictType`(`dictType`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '字典类型表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_dict_type +-- ---------------------------- +INSERT INTO `sys_dict_type` VALUES (1, '用户性别', 'sys_user_sex', '0', 'Y', 'admin', SYSDATE(), '', NULL, '用户性别列表'); +INSERT INTO `sys_dict_type` VALUES (2, '菜单状态', 'sys_show_hide', '0', 'Y', 'admin', SYSDATE(), '', NULL, '菜单状态列表'); +INSERT INTO `sys_dict_type` VALUES (3, '系统开关', 'sys_normal_disable', '0', 'Y', 'admin', SYSDATE(), '', NULL, '系统开关列表'); +INSERT INTO `sys_dict_type` VALUES (4, '任务状态', 'sys_job_status', '0', 'Y', 'admin', SYSDATE(), '', NULL, '任务状态列表'); +INSERT INTO `sys_dict_type` VALUES (5, '任务分组', 'sys_job_group', '0', 'Y', 'admin', SYSDATE(), '', NULL, '任务分组列表'); +INSERT INTO `sys_dict_type` VALUES (6, '系统是否', 'sys_yes_no', '0', 'Y', 'admin', SYSDATE(), '', NULL, '系统是否列表'); +INSERT INTO `sys_dict_type` VALUES (7, '通知类型', 'sys_notice_type', '0', 'Y', 'admin', SYSDATE(), '', NULL, '通知类型列表'); +INSERT INTO `sys_dict_type` VALUES (8, '通知状态', 'sys_notice_status', '0', 'Y', 'admin', SYSDATE(), '', NULL, '通知状态列表'); +INSERT INTO `sys_dict_type` VALUES (9, '操作类型', 'sys_oper_type', '0', 'Y', 'admin', SYSDATE(), '', NULL, '操作类型列表'); +INSERT INTO `sys_dict_type` VALUES (10, '系统状态', 'sys_common_status', '0', 'Y', 'admin', SYSDATE(), '', NULL, '登录状态列表'); +INSERT INTO `sys_dict_type` VALUES (11, '文章状态', 'sys_article_status', '0', 'Y', 'admin', SYSDATE(), '', NULL, NULL); +INSERT INTO `sys_dict_type` VALUES (12, '多语言类型', 'sys_lang_type', '0', 'Y', 'admin', SYSDATE(), '', NULL, '多语言字典类型'); + +SET FOREIGN_KEY_CHECKS = 1; + + +-- ---------------------------- +-- Table structure for sys_logininfor +-- ---------------------------- +DROP TABLE IF EXISTS `sys_logininfor`; +CREATE TABLE `sys_logininfor` ( + `infoId` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '访问ID', + `userName` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '用户账号', + `ipaddr` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '登录IP地址', + `loginLocation` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '登录地点', + `browser` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '浏览器类型', + `os` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '操作系统', + `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '登录状态(0成功 1失败)', + `msg` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '提示消息', + `loginTime` datetime(0) NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '访问时间', + PRIMARY KEY (`infoId`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 17 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统访问记录' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Table structure for sys_menu +-- ---------------------------- +DROP TABLE IF EXISTS `sys_menu`; +CREATE TABLE `sys_menu` ( + `menuId` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '菜单ID', + `menuName` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单名称', + `parentId` bigint(20) NULL DEFAULT 0 COMMENT '父菜单ID', + `orderNum` int(4) NULL DEFAULT 0 COMMENT '显示顺序', + `path` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '路由地址', + `component` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '组件路径', + `isFrame` int(1) NULL DEFAULT 0 COMMENT '是否外链(0 否 1 是)', + `isCache` int(1) NULL DEFAULT 0 COMMENT '是否缓存(0缓存 1不缓存)', + `menuType` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '菜单类型(M目录 C菜单 F按钮 L链接)', + `visible` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '菜单状态(0显示 1隐藏)', + `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '菜单状态(0正常 1停用)', + `perms` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '权限标识', + `icon` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '#' COMMENT '菜单图标', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '备注', + `menuName_key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '菜单名翻译字典名', + PRIMARY KEY (`menuId`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 2000 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '菜单权限表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_menu +-- ---------------------------- +-- 一级菜单 +INSERT INTO sys_menu VALUES (1, '系统管理', 0, 1, 'system', NULL, 0, 0, 'M', '0', '0', '', 'system', '', SYSDATE(), '', NULL, '系统管理目录', 'menu.system'); +INSERT INTO sys_menu VALUES (2, '系统监控', 0, 2, 'monitor', NULL, 0, 0, 'M', '0', '0', '', 'monitor', '', SYSDATE(), '', NULL, '系统监控目录', 'menu.monitoring'); +INSERT INTO sys_menu VALUES (3, '系统工具', 0, 3, 'tool', NULL, 0, 0, 'M', '0', '0', '', 'tool', '', SYSDATE(), '', NULL, '系统工具目录', 'menu.systemTools'); +INSERT INTO sys_menu VALUES (5, '官网地址', 0, 5, 'http://www.izhaorui.cn', NULL, 1, 0, 'M', '0', '0', '', 'link', '', SYSDATE(), '', NULL, 'Zr官网地址', 'menu.officialWebsite'); +INSERT INTO sys_menu VALUES (6, '控制台', 0, 0, 'dashboard', 'index_v1', 0, 0, 'C', '0', '0', '', 'dashboard', '', SYSDATE(), '', NULL, '', 'menu.dashboard'); + +-- 二级菜单 +INSERT INTO sys_menu VALUES (100, '用户管理', 1, 1, 'user', 'system/user/index', 0, 0, 'C', '0', '0', 'system:user:list', 'user', '', SYSDATE(), '', NULL, '用户管理菜单', 'menu.systemUser'); +INSERT INTO sys_menu VALUES (101, '角色管理', 1, 2, 'role', 'system/role/index', 0, 0, 'C', '0', '0', 'system:role:list', 'peoples', '', SYSDATE(), '', NULL, '角色管理菜单', 'menu.systemRole'); +INSERT INTO sys_menu VALUES (102, '菜单管理', 1, 3, 'menu', 'system/menu/index', 0, 0, 'C', '0', '0', 'system:menu:list', 'tree-table', '', SYSDATE(), '', NULL, '菜单管理菜单', 'menu.systemMenu'); +INSERT INTO sys_menu VALUES (103, '部门管理', 1, 4, 'dept', 'system/dept/index', 0, 0, 'C', '0', '0', 'system:dept:list', 'tree', '', SYSDATE(), '', NULL, '部门管理菜单', 'menu.systemDept'); +INSERT INTO sys_menu VALUES (104, '岗位管理', 1, 5, 'post', 'system/post/index', 0, 0, 'C', '0', '0', 'system:post:list', 'post', '', SYSDATE(), '', NULL, '岗位管理菜单', 'menu.systemPost'); +INSERT INTO sys_menu VALUES (105, '字典管理', 1, 6, 'dict', 'system/dict/index', 0, 0, 'C', '0', '0', 'system:dict:list', 'dict', '', SYSDATE(), '', NULL, '', 'menu.systemDic'); +INSERT INTO sys_menu VALUES (106, '角色分配', 1, 2, 'roleusers', 'system/roleusers/index', 0, 0, 'C', '1', '0', 'system:roleusers:list', 'people', '', SYSDATE(), '', NULL, NULL, ''); +INSERT into sys_menu VALUES (107, '参数设置', 1, 8, 'config','system/config/index', 0, 0, 'C', '0', '0', 'system:config:list','edit', '', SYSDATE(), '', NULL, '', 'menu.systemParam'); +INSERT INTO sys_menu VALUES (108, '日志管理', 1, 10, 'log', '' , 0, 0, 'M', '0', '0', '', 'log', '', SYSDATE(), '', NULL, '日志管理菜单', 'menu.systemLog'); +INSERT INTO sys_menu VALUES (109, '通知公告', 1, 9, 'notice', 'system/notice/index', 0, 0, 'C', '0', '0', 'system:notice:list', 'message', '', SYSDATE(), '', NULL, '通知公告菜单', 'menu.systemNotice'); +INSERT INTO sys_menu VALUES (110, '定时任务', 2, 10, 'job', 'monitor/job/index', 0, 0, 'C', '0', '0', '', 'job', '', SYSDATE(), '', NULL, '定时任务菜单', 'menu.timedTask'); +INSERT INTO sys_menu VALUES (112, '服务监控', 2, 11, 'server', 'monitor/server/index', 0, 0, 'C', '0', '0', 'monitor:server:list', 'server', '', SYSDATE(), '', NULL, '服务监控菜单', 'menu.serviceMonitor'); +INSERT INTO sys_menu VALUES (113, '缓存监控', 2, 12, 'cache', 'monitor/cache/index', 0, 0, 'C', '1', '1', 'monitor:cache:list', 'redis', '', SYSDATE(), '', NULL, '缓存监控菜单', 'menu.cacheMonitor'); + +INSERT INTO sys_menu VALUES (114, '表单构建', 3, 13, 'build', 'tool/build/index', 0, 0, 'C', '0', '0', 'tool:build:list', 'build', '', SYSDATE(), '', NULL, '表单构建菜单', 'menu.formBuild'); +INSERT INTO sys_menu VALUES (115, '代码生成', 3, 14, 'gen', 'tool/gen/index', 0, 0, 'C', '0', '0', 'tool:gen:list', 'code', '', SYSDATE(), '', NULL, '代码生成菜单', 'menu.codeGeneration'); +INSERT INTO sys_menu VALUES (116, '系统接口', 3, 15, 'swagger', 'tool/swagger/index', 0, 0, 'C', '0', '0', 'tool:swagger:list', 'swagger', '', SYSDATE(), '', NULL, '系统接口菜单', 'menu.systemInterface'); +INSERT INTO sys_menu VALUES (117, '发送邮件', 3, 16, 'sendEmail', 'tool/email/sendEmail', 0, 0, 'C', '0', '0', 'tool:email:send', 'email', '', SYSDATE(), '', NULL, '发送邮件菜单', 'menu.sendEmail'); +INSERT INTO sys_menu VALUES (118, '文章管理', 3, 18, 'article', NULL, 0, 0, 'M', '0', '0', NULL, 'documentation', '', SYSDATE(), '', NULL, NULL, 'menu.systemArticle'); + + +INSERT INTO sys_menu VALUES (1047, '发布文章', 3, 2, '/article/publish', 'system/article/publish', 0, 0, 'C', '1', '0', 'system:article:publish', 'log', '', SYSDATE(), '', NULL, NULL, ''); +INSERT INTO sys_menu VALUES (119, '文章列表', 118, 1, 'index', 'system/article/manager', 0, 0, 'C', '0', '0', 'system:article:list', 'list', '', SYSDATE(), '', NULL, NULL, 'menu.articleList'); +-- 三级菜单日志管理 +INSERT INTO sys_menu VALUES (500, '操作日志', 108, 1, 'operlog', 'monitor/operlog/index', 0, 0, 'C', '0', '0', 'monitor:operlog:list', 'form', '', SYSDATE(), '', NULL, '操作日志菜单', 'menu.operLog'); +INSERT INTO sys_menu VALUES (501, '登录日志', 108, 2, 'logininfor', 'monitor/logininfor/index', 0, 0, 'C', '0', '0', 'monitor:logininfor:list', 'logininfor', '', SYSDATE(), '', NULL, '登录日志菜单', 'menu.loginLog'); + + +-- 用户管理 按钮 +INSERT INTO sys_menu VALUES (1001, '用户查询', 100, 1, '', '', 0, 0, 'F', '0', '0', 'system:user:query', '', '', SYSDATE(), '', NULL, '', NULL); +INSERT INTO sys_menu VALUES (1002, '用户添加', 100, 2, '', '', 0, 0, 'F', '0', '0', 'system:user:add', '', '', SYSDATE(), '', NULL, '', NULL); +INSERT INTO sys_menu VALUES (1003, '用户修改', 100, 3, '', '', 0, 0, 'F', '0', '0', 'system:user:edit', '', '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1004, '用户删除', 100, 4, '', '', 0, 0, 'F', '0', '0', 'system:user:delete', '', '', SYSDATE(), '', NULL, '', NULL); +INSERT INTO sys_menu VALUES (1005, '用户导出', 100, 5, '', '', 0, 0, 'F', '0', '0', 'system:user:export', '#', '', SYSDATE(), '', NULL, '', NULL); +INSERT INTO sys_menu VALUES (1006, '用户导入', 100, 6, '', '', 0, 0, 'F', '0', '0', 'system:user:import', '#', '', SYSDATE(), '', NULL, '', NULL); +INSERT INTO sys_menu VALUES (1007, '重置密码', 100, 7, '', '', 0, 0, 'F', '0', '0', 'system:user:resetPwd', '#', '', SYSDATE(), '', NULL, '', NULL); +-- 权限管理 按钮 +INSERT INTO sys_menu VALUES (1008, '角色查询', 101, 1, '', '', 0, 0, 'F', '0', '0', 'system:role:query', '#', '', SYSDATE(), '', NULL, '', NULL); +INSERT INTO sys_menu VALUES (1009, '角色新增', 101, 2, '', '', 0, 0, 'F', '0', '0', 'system:role:add', '#', '', SYSDATE(), '', NULL, '', NULL); +INSERT INTO sys_menu VALUES (1010, '角色修改', 101, 3, '', '', 0, 0, 'F', '0', '0', 'system:role:edit', '#', '', SYSDATE(), '', NULL, '', NULL); +INSERT INTO sys_menu VALUES (1011, '角色删除', 101, 4, '', '', 0, 0, 'F', '0', '0', 'system:role:remove', '#', '', SYSDATE(), '', NULL, '', NULL); +INSERT INTO sys_menu VALUES (1012, '角色授权', 101, 5, '', '', 0, 0, 'F', '0', '0', 'system:role:authorize', '#', '', SYSDATE(), '', NULL, '', NULL); +-- 分配用户 按钮 +INSERT INTO sys_menu VALUES (1029, '新增用户', 106, 2, '', '', 0, 0, 'F', '0', '0', 'system:roleusers:add', NULL, '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1030, '删除用户', 106, 3, '', '', 0, 0, 'F', '0', '0', 'system:roleusers:remove', NULL, '', SYSDATE(), '', NULL, NULL, NULL); +-- 菜单管理 按钮 +INSERT INTO sys_menu VALUES (1013, '菜单查询', 102, 1, '', '', 0, 0, 'F', '0', '0', 'system:menu:query', '#', '', SYSDATE(), '', NULL, '', NULL); +INSERT INTO sys_menu VALUES (1014, '菜单新增', 102, 2, '', '', 0, 0, 'F', '0', '0', 'system:menu:add', '#', '', SYSDATE(), '', NULL, '', NULL); +INSERT INTO sys_menu VALUES (1015, '菜单修改', 102, 3, '', '', 0, 0, 'F', '0', '0', 'system:menu:edit', '#', '', SYSDATE(), '', NULL, '', NULL); +INSERT INTO sys_menu VALUES (1016, '菜单删除', 102, 4, '', '', 0, 0, 'F', '0', '0', 'system:menu:remove', '#', '', SYSDATE(), '', NULL, '', NULL); +INSERT INTO sys_menu VALUES (1017, '修改排序', 102, 5, '', '', 0, 0, 'F', '0', '0', 'system:menu:changeSort', '', '', SYSDATE(), '', NULL, NULL, NULL); +-- 部门管理 按钮 +INSERT INTO sys_menu VALUES (1018, '部门查询', 103, 1, '', '', 0, 0, 'F', '0', '0', 'system:dept:query', '', '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1019, '部门新增', 103, 2, '', '', 0, 0, 'F', '0', '0', 'system:dept:add', NULL, '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1020, '部门修改', 103, 3, '', '', 0, 0, 'F', '0', '0', 'system:dept:update', NULL, '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1021, '部门删除', 103, 4, '', '', 0, 0, 'F', '0', '0', 'system:dept:remove', NULL, '', SYSDATE(), '', NULL, NULL, NULL); +-- 岗位管理 按钮 +INSERT INTO sys_menu VALUES (1022, '岗位查询', 104, 1, '', '', 0, 0, 'F', '0', '0', 'system:post:list', NULL, '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1023, '岗位添加', 104, 2, '', '', 0, 0, 'F', '0', '0', 'system:post:add', NULL, '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1024, '岗位删除', 104, 3, '', '', 0, 0, 'F', '0', '0', 'system:post:remove', NULL, '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1025, '岗位编辑', 104, 4, '', '', 0, 0, 'F', '0', '0', 'system:post:edit', '', '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1070, '岗位导出', 104, 4, '', '', 0, 0, 'F', '0', '0', 'system:post:export', '', '', SYSDATE(), '', NULL, NULL, NULL); +-- 字典管理 按钮 +INSERT INTO sys_menu VALUES (1026, '字典新增', 105, 1, '', '', 0, 0, 'F', '0', '0', 'system:dict:add', NULL, '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1027, '字典修改', 105, 2, '', '', 0, 0, 'F', '0', '0', 'system:dict:edit', NULL, '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1028, '字典删除', 105, 3, '', '', 0, 0, 'F', '0', '0', 'system:dict:remove', NULL, '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1071, '字典导出', 105, 3, '', '', 0, 0, 'F', '0', '0', 'system:dict:export', NULL, '', SYSDATE(), '', NULL, NULL, NULL); + +-- 定时任务 按钮 +INSERT INTO sys_menu values (1032, '任务查询', 110, 1, '#', NULL, 0, 0, 'F', '0', '0', 'monitor:job:list', '#', '', sysdate(), '', null, '', NULL); +INSERT INTO sys_menu VALUES (1033, '任务新增', 110, 2, '#', NULL, 0, 0, 'F', '0', '0', 'monitor:job:add', '', '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1034, '任务删除', 110, 3, '#', NULL, 0, 0, 'F', '0', '0', 'monitor:job:delete', '', '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1035, '任务修改', 110, 4, '#', NULL, 0, 0, 'F', '0', '0', 'monitor:job:edit', '', '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1036, '任务启动', 110, 5, '#', NULL, 0, 0, 'F', '0', '0', 'monitor:job:start', '', '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1037, '任务运行', 110, 7, '#', NULL, 0, 0, 'F', '0', '0', 'monitor:job:run', NULL, '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1038, '任务停止', 110, 8, '#', NULL, 0, 0, 'F', '0', '0', 'monitor:job:stop', NULL, '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1039, '任务日志', 2, 0, 'job/log', 'monitor/job/log', 0, 0, 'C', '1', '0', 'monitor:job:query', 'log', '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1040, '任务导出', 110, 10, '#', NULL, 0, 0, 'F', '0', '0', 'monitor:job:export', NULL, '', SYSDATE(), '', NULL, NULL, NULL); +-- 操作日志 按钮 +INSERT INTO sys_menu values (1041, '操作查询', 500, 1, '#', NULL, 0, 0, 'F', '0', '0', 'monitor:operlog:query', '', '', sysdate(), '', null, NULL, NULL); +INSERT INTO sys_menu VALUES (1042, '操作删除', 500, 2, '#', NULL, 0, 0, 'F', '0', '0', 'monitor:operlog:remove', '', '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1043, '操作日志导出', 500,3, '#', NULL, 0, 0, 'F', '0', '0', 'monitor:operlog:export', '', '', SYSDATE(), '', NULL, NULL, NULL); +-- 登录日志 按钮 +INSERT INTO sys_menu values (1044, '登录查询', 501, 1, '#', NULL, 0, 0, 'F', '0', '0', 'monitor:logininfor:query', '', '', sysdate(), '', null, NULL, NULL); +INSERT INTO sys_menu VALUES (1045, '登录删除', 501, 1, '#', NULL, 0, 0, 'F', '0', '0', 'monitor:logininfor:remove', '', '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1046, '登录日志导出', 501, 1, '#', NULL, 0, 0, 'F', '0', '0', 'monitor:logininfor:export', '', '', SYSDATE(), '', NULL, NULL, NULL); +-- 文章管理 按钮 +INSERT INTO sys_menu VALUES (1048, '文章新增', 118, 3, '#', NULL, 0, 0, 'F', '0', '0', 'system:article:add', '', '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1049, '文章修改', 118, 4, '#', NULL, 0, 0, 'F', '0', '0', 'system:article:update', '', '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1050, '文章删除', 118, 5, '#', NULL, 0, 0, 'F', '0', '0', 'system:article:delete', '', '', SYSDATE(), '', NULL, NULL, NULL); +-- 通知公告 按钮 +INSERT INTO sys_menu VALUES (1051, '查询公告', 109, 1, '#', NULL, 0, 0, 'F', '0', '0', 'system:notice:query', '', '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1052, '新增公告', 109, 2, '#', NULL, 0, 0, 'F', '0', '0', 'system:notice:add', '', '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1053, '删除公告', 109, 3, '#', NULL, 0, 0, 'F', '0', '0', 'system:notice:delete', '', '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1054, '修改公告', 109, 4, '#', NULL, 0, 0, 'F', '0', '0', 'system:notice:update', '', '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1055, '导出公告', 109, 5, '#', NULL, 0, 0, 'F', '0', '0', 'system:notice:export', '', '', SYSDATE(), '', NULL, NULL, NULL); +-- 代码生成 按钮 +INSERT INTO sys_menu VALUES (1060, '生成修改', 3, 1, '/gen/editTable', 'tool/gen/editTable', 0, 0, 'C', '1', '0', 'tool:gen:edit', '', '', SYSDATE(), '', NULL, NULL, NULL); +insert into sys_menu VALUES (1061, '生成查询', 115, 1, '#', NULL, 0, 0, 'F', '0', '0', 'tool:gen:query', '', '', sysdate(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1062, '生成删除', 115, 1, '#', NULL, 0, 0, 'F', '0', '0', 'tool:gen:remove', '', '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1063, '导入代码', 115, 1, '#', NULL, 0, 0, 'F', '0', '0', 'tool:gen:import', '', '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1064, '生成代码', 115, 1, '#', NULL, 0, 0, 'F', '0', '0', 'tool:gen:code', '', '', SYSDATE(), '', NULL, NULL, NULL); +INSERT INTO sys_menu VALUES (1065, '预览代码', 115, 1, '#', NULL, 0, 0, 'F', '0', '0', 'tool:gen:preview', '', '', SYSDATE(), '', NULL, NULL, NULL); + + +-- 文件存储菜单 +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time, remark, menuName_key) +VALUES ('文件存储', 3, 17, 'file', 'tool/file/index', 0, 0, 'C', '0', '0', 'tool:file:list', 'upload', '', sysdate(), '文件存储菜单', 'menu.fileStorage'); + +-- 按钮父菜单id +SELECT @fileMenuId := LAST_INSERT_ID(); + +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_time) +VALUES ('查询', @fileMenuId, 1, '#', NULL, 0, 0, 'F', '0', '0', 'tool:file:query', '', sysdate()); + +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_time) +VALUES ('新增', @fileMenuId, 2, '#', NULL, 0, 0, 'F', '0', '0', 'tool:file:add', '', sysdate()); + +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_time) +VALUES ('删除', @fileMenuId, 3, '#', NULL, 0, 0, 'F', '0', '0', 'tool:file:delete', '', sysdate()); + +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_time) +VALUES ('修改', @fileMenuId, 4, '#', NULL, 0, 0, 'F', '0', '0', 'tool:file:update', '', sysdate()); + +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_time) +VALUES ('导出', @fileMenuId, 5, '#', NULL, 0, 0, 'F', '0', '0', 'tool:file:export', '', sysdate()); + +-- 多语言配置菜单 +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time, menuName_key) +VALUES ('多语言配置', 1, 20, 'CommonLang', 'system/commonLang/index', 0, 0, 'C', '0', '0', 'system:lang:list', 'language', 'system', sysdate(), 'menu.systemLang'); + +SELECT @langMenuId := LAST_INSERT_ID(); + +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time) +VALUES ('查询', @langMenuId, 1, '#', NULL, 0, 0, 'F', '0', '0', 'system:lang:query', '', 'system', sysdate()); + +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time) +VALUES ('新增', @langMenuId, 2, '#', NULL, 0, 0, 'F', '0', '0', 'system:lang:add', '', 'system', sysdate()); + +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time) +VALUES ('删除', @langMenuId, 3, '#', NULL, 0, 0, 'F', '0', '0', 'system:lang:delete', '', 'system', sysdate()); + +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time) +VALUES ('修改', @langMenuId, 4, '#', NULL, 0, 0, 'F', '0', '0', 'system:lang:edit', '', 'system', sysdate()); + + +-- 文章目录菜单 +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time) +VALUES ('文章目录', 118, 999, 'ArticleCategory', 'system/article/articleCategory', 0, 0, 'C', '0', '0', 'articlecategory:list', 'tree-table', 'system', sysdate()); +-- 按钮父菜单id +SELECT @cmenuId := LAST_INSERT_ID(); + +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time) +VALUES ('查询', @cmenuId, 1, '#', NULL, 0, 0, 'F', '0', '0', 'articlecategory:query', '', 'system', sysdate()); + +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time) +VALUES ('新增', @cmenuId, 2, '#', NULL, 0, 0, 'F', '0', '0', 'articlecategory:add', '', 'system', sysdate()); + +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time) +VALUES ('删除', @cmenuId, 3, '#', NULL, 0, 0, 'F', '0', '0', 'articlecategory:delete', '', 'system', sysdate()); + +INSERT INTO sys_menu(menuName, parentId, orderNum, path, component, isFrame, isCache, menuType, visible, status, perms, icon, create_by, create_time) +VALUES ('修改', @cmenuId, 4, '#', NULL, 0, 0, 'F', '0', '0', 'articlecategory:edit', '', 'system', sysdate()); + +-- ---------------------------- +-- Table structure for sys_oper_log +-- ---------------------------- +DROP TABLE IF EXISTS `sys_oper_log`; +CREATE TABLE `sys_oper_log` ( + `operId` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '日志主键', + `title` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '模块标题', + `businessType` int(2) NULL DEFAULT 0 COMMENT '业务类型(0其它 1新增 2修改 3删除)', + `method` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '方法名称', + `requestMethod` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '请求方式', + `operatorType` int(1) NULL DEFAULT 0 COMMENT '操作类别(0其它 1后台用户 2手机端用户)', + `operName` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '操作人员', + `deptName` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '部门名称', + `operUrl` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '请求URL', + `operIP` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '主机地址', + `operLocation` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '操作地点', + `operParam` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '请求参数', + `jsonResult` varchar(5000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '返回参数', + `status` int(1) NULL DEFAULT 0 COMMENT '操作状态(0正常 1异常)', + `errorMsg` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '错误消息', + `operTime` datetime(0) NULL DEFAULT NULL COMMENT '操作时间', + `elapsed` bigint(20) NULL DEFAULT NULL COMMENT '请求用时', + PRIMARY KEY (`operId`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '操作日志记录' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Table structure for sys_post +-- ---------------------------- +DROP TABLE IF EXISTS `sys_post`; +CREATE TABLE `sys_post` ( + `postId` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '岗位ID', + `postCode` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '岗位编码', + `postName` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '岗位名称', + `postSort` int(4) NOT NULL COMMENT '显示顺序', + `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '状态(0正常 1停用)', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`postId`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 15 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '岗位信息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_post +-- ---------------------------- +INSERT INTO `sys_post` VALUES (1, 'CEO', '董事长', 1, '0', '', SYSDATE(), '', NULL, ''); +INSERT INTO `sys_post` VALUES (2, 'SE', '项目经理', 2, '0', '', SYSDATE(), '', NULL, ''); +INSERT INTO `sys_post` VALUES (3, 'HR', '人力资源', 3, '0', '', SYSDATE(), '', NULL, ''); +INSERT INTO `sys_post` VALUES (4, 'USER', '普通员工', 4, '0', '', SYSDATE(), '', NULL, ''); +INSERT INTO `sys_post` VALUES (6, 'PM', '人事经理', 0, '0', NULL, SYSDATE(), '', NULL, NULL); +INSERT INTO `sys_post` VALUES (7, 'GM', '总经理', 0, '0', NULL, SYSDATE(), '', NULL, NULL); +INSERT INTO `sys_post` VALUES (8, 'COO', '首席运营官', 0, '0', NULL, SYSDATE(), '', NULL, NULL); +INSERT INTO `sys_post` VALUES (9, 'CFO', '首席财务官', 0, '0', NULL, SYSDATE(), '', NULL, NULL); +INSERT INTO `sys_post` VALUES (10, 'CTO', '首席技术官', 0, '0', NULL, SYSDATE(), '', NULL, NULL); +INSERT INTO `sys_post` VALUES (11, 'HRD', '人力资源总监', 0, '0', NULL, SYSDATE(), '', NULL, NULL); +INSERT INTO `sys_post` VALUES (12, 'VP', '副总裁', 0, '0', NULL, SYSDATE(), '', NULL, NULL); +INSERT INTO `sys_post` VALUES (13, 'OD', '运营总监', 0, '0', NULL, SYSDATE(), '', NULL, NULL); +INSERT INTO `sys_post` VALUES (14, 'MD', '市场总监', 0, '0', NULL, SYSDATE(), '', NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_role +-- ---------------------------- +DROP TABLE IF EXISTS `sys_role`; +CREATE TABLE `sys_role` ( + `roleId` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '角色ID', + `roleName` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色名称', + `roleKey` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色权限字符串', + `roleSort` int(4) NOT NULL COMMENT '显示顺序', + `dataScope` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '1' COMMENT '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 )', + `menu_check_strictly` tinyint(1) NULL DEFAULT 1 COMMENT '菜单树选择项是否关联显示', + `dept_check_strictly` tinyint(1) NOT NULL DEFAULT 1 COMMENT '部门树选择项是否关联显示', + `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色状态(0正常 1停用)', + `delFlag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`roleId`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 117 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '角色信息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_role +-- ---------------------------- +INSERT INTO `sys_role` VALUES (1, '超级管理员', 'admin', 1, '1', 1, 0, '0', '0', 'admin', SYSDATE(), 'system', NULL, '超级管理员'); +INSERT INTO `sys_role` VALUES (2, '普通角色', 'common', 2, '2', 1, 0, '0', '0', 'admin', SYSDATE(), 'system', NULL, '普通角色'); + +-- ---------------------------- +-- Table structure for sys_role_dept +-- ---------------------------- +DROP TABLE IF EXISTS `sys_role_dept`; +CREATE TABLE `sys_role_dept` ( + `roleId` bigint(20) NOT NULL COMMENT '角色ID', + `deptId` bigint(20) NOT NULL COMMENT '部门ID', + PRIMARY KEY (`roleId`, `deptId`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '角色和部门关联表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_role_dept +-- ---------------------------- +INSERT INTO `sys_role_dept` VALUES (2, 100); +INSERT INTO `sys_role_dept` VALUES (2, 101); +INSERT INTO `sys_role_dept` VALUES (2, 105); + +-- ---------------------------- +-- Table structure for sys_role_menu +-- ---------------------------- +DROP TABLE IF EXISTS `sys_role_menu`; +CREATE TABLE `sys_role_menu` ( + `role_id` bigint(20) NOT NULL COMMENT '角色ID', + `menu_id` bigint(20) NOT NULL COMMENT '菜单ID', + `create_by` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, + `create_time` datetime(0) NULL DEFAULT NULL, + PRIMARY KEY (`role_id`, `menu_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '角色和菜单关联表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_role_menu +-- ---------------------------- + +INSERT INTO `sys_role_menu` VALUES (2, 1, NULL, SYSDATE()); +INSERT INTO `sys_role_menu` VALUES (2, 3, NULL, SYSDATE()); +INSERT INTO `sys_role_menu` VALUES (2, 5, NULL, SYSDATE()); +INSERT INTO `sys_role_menu` VALUES (2, 6, NULL, SYSDATE()); + +INSERT INTO `sys_role_menu` VALUES (2, 100, 'admin', SYSDATE()); +INSERT INTO `sys_role_menu` VALUES (2, 101, 'admin', SYSDATE()); +INSERT INTO `sys_role_menu` VALUES (2, 102, 'admin', SYSDATE()); +INSERT INTO `sys_role_menu` VALUES (2, 103, 'admin', SYSDATE()); +INSERT INTO `sys_role_menu` VALUES (2, 104, 'admin', SYSDATE()); +INSERT INTO `sys_role_menu` VALUES (2, 106, 'admin', SYSDATE()); +INSERT INTO `sys_role_menu` VALUES (2, 108, 'admin', SYSDATE()); +INSERT INTO `sys_role_menu` VALUES (2, 109, 'admin', SYSDATE()); +INSERT INTO `sys_role_menu` VALUES (2, 114, 'admin', SYSDATE()); +INSERT INTO `sys_role_menu` VALUES (2, 500, 'admin', SYSDATE()); +INSERT INTO `sys_role_menu` VALUES (2, 501, 'admin', SYSDATE()); +INSERT INTO `sys_role_menu` VALUES (2, 1001, 'admin', SYSDATE()); +INSERT INTO `sys_role_menu` VALUES (2, 1008, 'admin', SYSDATE()); +INSERT INTO `sys_role_menu` VALUES (2, 1013, 'admin', SYSDATE()); +INSERT INTO `sys_role_menu` VALUES (2, 1018, 'admin', SYSDATE()); +INSERT INTO `sys_role_menu` VALUES (2, 1022, 'admin', SYSDATE()); +INSERT INTO `sys_role_menu` VALUES (2, 1031, 'admin', SYSDATE()); +INSERT INTO `sys_role_menu` VALUES (2, 1044, 'admin', SYSDATE()); +INSERT INTO `sys_role_menu` VALUES (2, 1051, 'admin', SYSDATE()); + +-- 编辑者 +INSERT INTO `sys_role_menu` VALUES (3, 4 , NULL, SYSDATE()); +INSERT INTO `sys_role_menu` VALUES (3, 118 , NULL, SYSDATE()); +INSERT INTO `sys_role_menu` VALUES (3, 1047, NULL, SYSDATE()); +INSERT INTO `sys_role_menu` VALUES (3, 1048, NULL, SYSDATE()); +INSERT INTO `sys_role_menu` VALUES (3, 1049, NULL, SYSDATE()); +INSERT INTO `sys_role_menu` VALUES (3, 1050, NULL, SYSDATE()); + +SET FOREIGN_KEY_CHECKS = 1; + +-- ---------------------------- +-- Table structure for sys_user +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user`; +CREATE TABLE `sys_user` ( + `userId` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID', + `deptId` bigint(20) NULL DEFAULT NULL COMMENT '部门ID', + `userName` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户账号', + `nickName` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户昵称', + `userType` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '用户类型(00系统用户)', + `email` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '用户邮箱', + `phonenumber` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '手机号码', + `sex` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '用户性别(0男 1女 2未知)', + `avatar` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '头像地址', + `password` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '密码', + `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '帐号状态(0正常 1停用)', + `delFlag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', + `loginIP` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '最后登录IP', + `loginDate` datetime(0) NULL DEFAULT NULL COMMENT '最后登录时间', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`userId`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户信息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_user +-- ---------------------------- +INSERT INTO `sys_user`(`userId`, `deptId`, `userName`, `nickName`, `userType`, `email`, `phonenumber`, `sex`, `avatar`, `password`, `status`, `delFlag`, `loginIP`, `loginDate`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (1, 0, 'admin', '管理员', '0', '', '', '0', '', 'e10adc3949ba59abbe56e057f20f883e', '0', '0', '127.0.0.1', '2021-08-23 14:03:17', 'admin', '2020-11-26 11:52:59', 'admin', '2021-08-03 10:11:24', '管理员'); +INSERT INTO `sys_user`(`userId`, `deptId`, `userName`, `nickName`, `userType`, `email`, `phonenumber`, `sex`, `avatar`, `password`, `status`, `delFlag`, `loginIP`, `loginDate`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (2, 0, 'zr', 'zr', '0', NULL, NULL, '0', '', 'e10adc3949ba59abbe56e057f20f883e', '0', '0', '', '0001-01-01 00:00:00', 'admin', '2021-07-05 17:29:13', 'admin', '2021-08-02 16:53:04', '普通用户'); +INSERT INTO `sys_user`(`userId`, `deptId`, `userName`, `nickName`, `userType`, `email`, `phonenumber`, `sex`, `avatar`, `password`, `status`, `delFlag`, `loginIP`, `loginDate`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (3, 100, 'editor', '编辑人员', '0', NULL, NULL, '2', '', 'E10ADC3949BA59ABBE56E057F20F883E', '0', '0', '127.0.0.1', '2021-08-19 09:27:46', 'admin', '2021-08-18 18:24:53', '', NULL, NULL); + + +SET FOREIGN_KEY_CHECKS = 1; + +-- ---------------------------- +-- Table structure for sys_user_post +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_post`; +CREATE TABLE `sys_user_post` ( + `userId` bigint(20) NOT NULL COMMENT '用户ID', + `postId` bigint(20) NOT NULL COMMENT '岗位ID', + PRIMARY KEY (`userId`, `postId`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户与岗位关联表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_user_post +-- ---------------------------- +INSERT INTO `sys_user_post` VALUES (1, 1); + +-- ---------------------------- +-- Table structure for sys_user_role +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_role`; +CREATE TABLE `sys_user_role` ( + `user_id` bigint(20) NOT NULL COMMENT '用户ID', + `role_id` bigint(20) NOT NULL COMMENT '角色ID', + PRIMARY KEY (`user_id`, `role_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户和角色关联表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_user_role +-- ---------------------------- +INSERT INTO `sys_user_role` VALUES (1, 1); +INSERT INTO `sys_user_role` VALUES (2, 2); +INSERT INTO `sys_user_role` VALUES (3, 3); +INSERT INTO `sys_user_role` VALUES (101, 2); +INSERT INTO `sys_user_role` VALUES (109, 116); +INSERT INTO `sys_user_role` VALUES (110, 2); + +SET FOREIGN_KEY_CHECKS = 1; + +-- ---------------------------- +-- Table structure for article +-- ---------------------------- +DROP TABLE IF EXISTS `article`; +CREATE TABLE `article` ( + `cid` int(11) NOT NULL AUTO_INCREMENT, + `title` varchar(254) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文章标题', + `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '文章内容', + `userId` bigint(11) NULL DEFAULT NULL COMMENT '用户id', + `status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文章状态1、已发布 2、草稿', + `fmt_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '编辑器类型markdown,html', + `tags` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文章标签', + `hits` int(11) NULL DEFAULT NULL COMMENT '点击量', + `category_id` int(11) NULL DEFAULT NULL COMMENT '目录id', + `createTime` datetime(6) NULL DEFAULT NULL COMMENT '创建时间', + `updateTime` datetime(6) NULL DEFAULT NULL COMMENT '修改时间', + `authorName` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '作者名', + `coverUrl` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '封面', + PRIMARY KEY (`cid`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 28 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; + +SET FOREIGN_KEY_CHECKS = 1; + +-- ---------------------------- +-- Table structure for articleCategory +-- ---------------------------- +DROP TABLE IF EXISTS `articleCategory`; +CREATE TABLE `articleCategory` ( + `category_id` int(4) NOT NULL AUTO_INCREMENT COMMENT '目录id', + `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '目录名', + `create_time` datetime(6) NULL DEFAULT NULL COMMENT '创建时间', + `parentId` int(10) UNSIGNED NULL DEFAULT 0 COMMENT '父级ID', + PRIMARY KEY (`category_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of articleCategory +-- ---------------------------- +INSERT INTO `articleCategory` VALUES (1, 'C#', '2021-08-13 00:00:00.000000', 0); +INSERT INTO `articleCategory` VALUES (2, 'java', '2021-08-18 00:00:00.000000', 0); +INSERT INTO `articleCategory` VALUES (3, '前端', '2021-08-18 00:00:00.000000', 0); +INSERT INTO `articleCategory` VALUES (4, '数据库', '2021-08-18 00:00:00.000000', 0); +INSERT INTO `articleCategory` VALUES (5, '其他', '2021-08-19 00:00:00.000000', 0); +INSERT INTO `articleCategory` VALUES (6, '羽毛球', '2021-08-19 00:00:00.000000', 5); +INSERT INTO `articleCategory` VALUES (7, 'vue', '2021-08-19 00:00:00.000000', 3); +INSERT INTO `articleCategory` VALUES (8, 'sqlserver', '2021-08-19 00:00:00.000000', 4); + +SET FOREIGN_KEY_CHECKS = 1; + + +-- ---------------------------- +-- 13、参数配置表 +-- ---------------------------- +drop table if exists sys_config; +create table sys_config ( + configId int(5) not null auto_increment comment '参数主键', + configName varchar(100) default '' comment '参数名称', + configKey varchar(100) default '' comment '参数键名', + configValue varchar(500) default '' comment '参数键值', + configType char(1) default 'N' comment '系统内置(Y是 N否)', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (configId) +) engine=innodb auto_increment=100 comment = '参数配置表'; + +INSERT INTO `sys_config`(`configId`, `configName`, `configKey`, `configValue`, `configType`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) +VALUES (1, '主框架页-默认皮肤样式名称', 'sys.index.skinName', 'skin-blue', 'Y', 'admin', '2021-12-26 13:14:57', '', NULL, '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow'); +INSERT INTO `sys_config`(`configId`, `configName`, `configKey`, `configValue`, `configType`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) +VALUES (2, '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 'admin', '2021-12-26 13:14:57', '', NULL, '初始化密码 123456'); +INSERT INTO `sys_config`(`configId`, `configName`, `configKey`, `configValue`, `configType`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) +VALUES (3, '主框架页-侧边栏主题', 'sys.index.sideTheme', 'theme-dark', 'Y', 'admin', '2021-12-26 13:14:57', '', NULL, '深色主题theme-dark,浅色主题theme-light'); +INSERT INTO `sys_config`(`configId`, `configName`, `configKey`, `configValue`, `configType`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) +VALUES (4, '账号自助-验证码开关', 'sys.account.captchaOnOff', '1', 'Y', 'admin', '2021-12-26 13:14:57', 'admin', '2022-03-30 12:43:48', '是否开启验证码功能(off、关闭,1、动态验证码 2、动态gif泡泡 3、泡泡 4、静态验证码)'); +INSERT INTO `sys_config`(`configId`, `configName`, `configKey`, `configValue`, `configType`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) +VALUES (5, '本地文件上传访问域名', 'sys.file.uploadurl', 'http://localhost:8888', 'Y', '', sysdate(), '', NULL, NULL); +INSERT INTO `sys_config`(`configId`, `configName`, `configKey`, `configValue`, `configType`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) +VALUES (6, '开启注册功能', 'sys.account.register', 'true', 'Y', 'admin', sysdate(), 'admin', NULL, NULL); +INSERT INTO `sys_config`(`configId`, `configName`, `configKey`, `configValue`, `configType`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) +VALUES (7, '文章预览地址', 'sys.article.preview.url', 'http://www.izhaorui.cn/article/details/', 'Y', 'admin', sysdate(), '', NULL, '格式:http://www.izhaorui.cn/article/details/{aid},其中{aid}为文章的id'); + +-- ---------------------------- +-- 18、代码生成业务表 +-- ---------------------------- +drop table if exists gen_table; +create table gen_table ( + tableId bigint(20) not null auto_increment comment '编号', + tableName varchar(200) default '' comment '表名称', + tableComment varchar(500) default '' comment '表描述', + subTableName varchar(64) default null comment '关联子表的表名', + subTableFkName varchar(64) default null comment '子表关联的外键名', + className varchar(100) default '' comment '实体类名称', + tplCategory varchar(200) default 'crud' comment '使用的模板(crud单表操作 tree树表操作)', + baseNameSpace varchar(100) comment '生成命名空间前缀', + moduleName varchar(30) comment '生成模块名', + businessName varchar(30) comment '生成业务名', + functionName varchar(50) comment '生成功能名', + functionAuthor varchar(50) comment '生成功能作者', + genType char(1) default '0' comment '生成代码方式(0zip压缩包 1自定义路径)', + genPath varchar(200) default '/' comment '生成路径(不填默认项目路径)', + options varchar(1000) comment '其它生成选项', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + dbName VARCHAR(100) comment '数据库名', + PRIMARY key (tableId) +) engine=innodb auto_increment=1 comment = '代码生成业务表'; + + +-- ---------------------------- +-- 19、代码生成业务表字段 +-- ---------------------------- +drop table if exists gen_table_column; +CREATE TABLE `gen_table_column` ( + `columnId` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号', + `tableName` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '表名', + `tableId` bigint(20) NULL DEFAULT NULL COMMENT '归属表编号', + `columnName` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '列名称', + `columnComment` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '列描述', + `columnType` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '列类型', + `csharpType` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'C#类型', + `csharpField` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'C#字段名', + `isPk` tinyint(1) NULL DEFAULT NULL COMMENT '是否主键(1是)', + `isIncrement` tinyint(1) NULL DEFAULT NULL COMMENT '是否自增(1是)', + `isRequired` tinyint(1) NULL DEFAULT NULL COMMENT '是否必填(1是)', + `isInsert` tinyint(1) NULL DEFAULT NULL COMMENT '是否为插入字段(1是)', + `isEdit` tinyint(1) NULL DEFAULT NULL COMMENT '是否编辑字段(1是)', + `isList` tinyint(1) NULL DEFAULT NULL COMMENT '是否列表字段(1是)', + `isQuery` tinyint(4) NULL DEFAULT NULL COMMENT '是否查询字段(1是)', + `isSort` tinyint(4) NULL DEFAULT NULL COMMENT '是否排序字段(1是)', + `queryType` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'EQ' COMMENT '查询方式(等于、不等于、大于、小于、范围)', + `htmlType` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)', + `dictType` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '字典类型', + `sort` int(11) NULL DEFAULT NULL COMMENT '排序', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, + PRIMARY KEY (`columnId`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 63 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '代码生成业务表字段' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- 代码生成测试 +-- Table structure for gen_demo +-- ---------------------------- +DROP TABLE IF EXISTS `gen_demo`; +CREATE TABLE `gen_demo` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增id', + `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '名称', + `icon` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '图片', + `showStatus` int(4) NOT NULL COMMENT '显示状态', + `addTime` datetime(0) NULL DEFAULT NULL COMMENT '添加时间', + `sex` int(4) NULL DEFAULT NULL COMMENT '用户性别', + `sort` int(4) NULL DEFAULT 0 COMMENT '排序', + `remark` VARCHAR(200) COMMENT '备注', + `beginTime` datetime(0) NULL DEFAULT NULL COMMENT '开始时间', + `endTime` datetime(0) NULL DEFAULT NULL COMMENT '结束时间', + `feature` varchar(100) NULL COMMENT '特征', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Table structure for sys_file 文件存储 +-- ---------------------------- +DROP TABLE IF EXISTS `sys_file`; +CREATE TABLE `sys_file` ( + `id` BIGINT(11) NOT NULL, + `realName` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件真实名', + `fileName` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件名', + `fileUrl` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件存储地址', + `storePath` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '仓库位置', + `accessUrl` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '访问路径', + `fileSize` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件大小', + `fileType` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件类型', + `fileExt` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件扩展名', + `create_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人', + `create_time` datetime(0) NULL DEFAULT NULL COMMENT '上传时间', + `storeType` int(4) NULL DEFAULT NULL COMMENT '存储类型', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; + + +-- ---------------------------- +-- Table structure for sys_common_lang +-- ---------------------------- +DROP TABLE IF EXISTS `sys_common_lang`; +CREATE TABLE `sys_common_lang` ( + `id` bigint(20) NOT NULL COMMENT 'id', + `lang_code` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '语言code eg:zh-cn', + `lang_key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '翻译key值', + `lang_name` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '翻译内容', + `addtime` datetime(0) NULL DEFAULT NULL COMMENT '添加时间', + PRIMARY KEY (`Id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; diff --git a/document/admin-sqlserver-表字段说明导入.sql b/document/admin-sqlserver-表字段说明导入.sql new file mode 100644 index 0000000..83f7396 --- /dev/null +++ b/document/admin-sqlserver-表字段说明导入.sql @@ -0,0 +1,652 @@ +--CREATE DATABASE ZrAdmin +GO +USE ZrAdmin +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'定时任务表' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_tasks' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'任务ID', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_tasks', @level2type=N'COLUMN',@level2name=N'ID' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'任务名', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_tasks', @level2type=N'COLUMN',@level2name=N'Name' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'任务分组', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_tasks', @level2type=N'COLUMN',@level2name=N'JobGroup' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'运行时间表达式', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_tasks', @level2type=N'COLUMN',@level2name=N'Cron' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'程序集名称', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_tasks', @level2type=N'COLUMN',@level2name=N'AssemblyName' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'任务所在类', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_tasks', @level2type=N'COLUMN',@level2name=N'ClassName' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'任务描述', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_tasks', @level2type=N'COLUMN',@level2name=N'Remark' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'执行次数', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_tasks', @level2type=N'COLUMN',@level2name=N'RunTimes' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'开始时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_tasks', @level2type=N'COLUMN',@level2name=N'BeginTime' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'结束时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_tasks', @level2type=N'COLUMN',@level2name=N'EndTime' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'触发器类型(0、simple 1、cron)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_tasks', @level2type=N'COLUMN',@level2name=N'TriggerType' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'执行间隔时间(单位:秒)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_tasks', @level2type=N'COLUMN',@level2name=N'IntervalSecond' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'是否启动', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_tasks', @level2type=N'COLUMN',@level2name=N'IsStart' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'传入参数', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_tasks', @level2type=N'COLUMN',@level2name=N'JobParams' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_tasks', @level2type=N'COLUMN',@level2name=N'create_time' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'最后更新时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_tasks', @level2type=N'COLUMN',@level2name=N'update_time' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建人编码', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_tasks', @level2type=N'COLUMN',@level2name=N'create_by' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'更新人编码', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_tasks', @level2type=N'COLUMN',@level2name=N'update_by' + + +-- 定时任务 +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'定时任务调度日志表' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_Tasks_log' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'任务日志ID', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_Tasks_log', @level2type=N'COLUMN',@level2name=N'jobLogId' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'任务id', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_Tasks_log', @level2type=N'COLUMN',@level2name=N'jobId' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'任务名称', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_Tasks_log', @level2type=N'COLUMN',@level2name=N'jobName' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'任务组名', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_Tasks_log', @level2type=N'COLUMN',@level2name=N'jobGroup' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'日志信息', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_Tasks_log', @level2type=N'COLUMN',@level2name=N'jobMessage' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'执行状态(0正常 1失败)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_Tasks_log', @level2type=N'COLUMN',@level2name=N'status' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'异常信息', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_Tasks_log', @level2type=N'COLUMN',@level2name=N'exception' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_Tasks_log', @level2type=N'COLUMN',@level2name=N'createTime' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'调用目标', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_Tasks_log', @level2type=N'COLUMN',@level2name=N'invokeTarget' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'作业用时', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_Tasks_log', @level2type=N'COLUMN',@level2name=N'elapsed' + +GO + +/*部门表*/ +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'部门表' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dept' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'部门id', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dept', @level2type=N'COLUMN',@level2name=N'deptId' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'父部门id', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dept', @level2type=N'COLUMN',@level2name=N'parentId' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'祖级列表', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dept', @level2type=N'COLUMN',@level2name=N'ancestors' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'部门名称', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dept', @level2type=N'COLUMN',@level2name=N'deptName' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'显示顺序', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dept', @level2type=N'COLUMN',@level2name=N'orderNum' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'负责人', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dept', @level2type=N'COLUMN',@level2name=N'leader' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'联系电话', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dept', @level2type=N'COLUMN',@level2name=N'phone' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'部门状态(0正常 1停用)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dept', @level2type=N'COLUMN',@level2name=N'email' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'备注', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dept', @level2type=N'COLUMN',@level2name=N'status' + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'备注', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dept', @level2type=N'COLUMN',@level2name=N'remark' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'删除标志(0代表存在 2代表删除)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dept', @level2type=N'COLUMN',@level2name=N'delFlag' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dept', @level2type=N'COLUMN',@level2name=N'create_time' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'最后更新时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dept', @level2type=N'COLUMN',@level2name=N'update_time' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建人编码', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dept', @level2type=N'COLUMN',@level2name=N'create_by' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'更新人编码', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dept', @level2type=N'COLUMN',@level2name=N'update_by' + +GO + +--字典类型表 +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'字典类型表' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dict_type' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'字典主键', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dict_type', @level2type=N'COLUMN',@level2name=N'dictId' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'字典名称', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dict_type', @level2type=N'COLUMN',@level2name=N'dictName' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'字典类型', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dict_type', @level2type=N'COLUMN',@level2name=N'dictType' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'状态(0正常 1停用)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dict_type', @level2type=N'COLUMN',@level2name=N'status' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'备注', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dict_type', @level2type=N'COLUMN',@level2name=N'remark' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dict_type', @level2type=N'COLUMN',@level2name=N'create_time' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'最后更新时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dict_type', @level2type=N'COLUMN',@level2name=N'update_time' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建人编码', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dict_type', @level2type=N'COLUMN',@level2name=N'create_by' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'更新人编码', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dict_type', @level2type=N'COLUMN',@level2name=N'update_by' +GO + +/**字典数据表*/ +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'字典数据表' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dict_data' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'字典编码', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dict_data', @level2type=N'COLUMN',@level2name=N'dictCode' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'字典排序', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dict_data', @level2type=N'COLUMN',@level2name=N'dictSort' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'字典标签', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dict_data', @level2type=N'COLUMN',@level2name=N'dictLabel' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'字典键值', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dict_data', @level2type=N'COLUMN',@level2name=N'dictValue' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'字典类型', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dict_data', @level2type=N'COLUMN',@level2name=N'dictType' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'样式属性(其他样式扩展)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dict_data', @level2type=N'COLUMN',@level2name=N'cssClass' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'表格回显样式', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dict_data', @level2type=N'COLUMN',@level2name=N'listClass' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'是否默认(Y是 N否)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dict_data', @level2type=N'COLUMN',@level2name=N'isDefault' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'状态(0正常 1停用)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dict_data', @level2type=N'COLUMN',@level2name=N'status' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'备注', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dict_data', @level2type=N'COLUMN',@level2name=N'remark' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dict_data', @level2type=N'COLUMN',@level2name=N'create_time' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'最后更新时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dict_data', @level2type=N'COLUMN',@level2name=N'update_time' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建人编码', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dict_data', @level2type=N'COLUMN',@level2name=N'create_by' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'更新人编码', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_dict_data', @level2type=N'COLUMN',@level2name=N'update_by' +GO + +--登录日志表 +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'用户登录记录表' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_logininfor' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'访问ID', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_logininfor', @level2type=N'COLUMN',@level2name=N'infoId' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'用户账号', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_logininfor', @level2type=N'COLUMN',@level2name=N'userName' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'登录IP地址', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_logininfor', @level2type=N'COLUMN',@level2name=N'ipaddr' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'登录地点', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_logininfor', @level2type=N'COLUMN',@level2name=N'loginLocation' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'浏览器类型', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_logininfor', @level2type=N'COLUMN',@level2name=N'browser' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'操作系统', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_logininfor', @level2type=N'COLUMN',@level2name=N'os' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'登录状态(0成功 1失败)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_logininfor', @level2type=N'COLUMN',@level2name=N'status' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'提示消息', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_logininfor', @level2type=N'COLUMN',@level2name=N'msg' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'访问时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_logininfor', @level2type=N'COLUMN',@level2name=N'loginTime' +GO +-- 菜单表 +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'菜单表' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_menu' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'菜单ID', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_menu', @level2type=N'COLUMN',@level2name=N'menuId' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'菜单名称', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_menu', @level2type=N'COLUMN',@level2name=N'menuName' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'父菜单ID', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_menu', @level2type=N'COLUMN',@level2name=N'parentId' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'显示顺序', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_menu', @level2type=N'COLUMN',@level2name=N'orderNum' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'路由地址', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_menu', @level2type=N'COLUMN',@level2name=N'path' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'组件路径', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_menu', @level2type=N'COLUMN',@level2name=N'component' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'是否外链(0 否 1 是)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_menu', @level2type=N'COLUMN',@level2name=N'isFrame' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'是否缓存(0缓存 1不缓存)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_menu', @level2type=N'COLUMN',@level2name=N'isCache' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'菜单类型(M目录 C菜单 F按钮 L链接)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_menu', @level2type=N'COLUMN',@level2name=N'menuType' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'菜单状态(0显示 1隐藏)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_menu', @level2type=N'COLUMN',@level2name=N'visible' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'菜单状态(0正常 1停用)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_menu', @level2type=N'COLUMN',@level2name=N'status' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'权限标识', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_menu', @level2type=N'COLUMN',@level2name=N'perms' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'菜单图标', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_menu', @level2type=N'COLUMN',@level2name=N'icon' + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_menu', @level2type=N'COLUMN',@level2name=N'create_time' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'最后更新时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_menu', @level2type=N'COLUMN',@level2name=N'update_time' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建人编码', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_menu', @level2type=N'COLUMN',@level2name=N'create_by' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'更新人编码', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_menu', @level2type=N'COLUMN',@level2name=N'update_by' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'备注', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_menu', @level2type=N'COLUMN',@level2name=N'remark' +GO + +-- 操作日志记录 +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'操作日志记录' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_oper_log' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'日志主键', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_oper_log', @level2type=N'COLUMN',@level2name=N'operId' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'模块标题', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_oper_log', @level2type=N'COLUMN',@level2name=N'title' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'业务类型(0其它 1新增 2修改 3删除)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_oper_log', @level2type=N'COLUMN',@level2name=N'businessType' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'方法名称', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_oper_log', @level2type=N'COLUMN',@level2name=N'method' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'请求方式', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_oper_log', @level2type=N'COLUMN',@level2name=N'requestMethod' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'操作类别(0其它 1后台用户 2手机端用户)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_oper_log', @level2type=N'COLUMN',@level2name=N'operatorType' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'操作人员', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_oper_log', @level2type=N'COLUMN',@level2name=N'operName' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'部门名称', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_oper_log', @level2type=N'COLUMN',@level2name=N'deptName' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'请求URL', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_oper_log', @level2type=N'COLUMN',@level2name=N'operUrl' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'主机地址', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_oper_log', @level2type=N'COLUMN',@level2name=N'operIP' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'操作地点', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_oper_log', @level2type=N'COLUMN',@level2name=N'operLocation' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'请求参数', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_oper_log', @level2type=N'COLUMN',@level2name=N'operParam' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'返回参数', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_oper_log', @level2type=N'COLUMN',@level2name=N'jsonResult' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'操作状态(0正常 1异常)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_oper_log', @level2type=N'COLUMN',@level2name=N'status' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'错误消息', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_oper_log', @level2type=N'COLUMN',@level2name=N'errorMsg' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'操作时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_oper_log', @level2type=N'COLUMN',@level2name=N'operTime' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'请求用时', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_oper_log', @level2type=N'COLUMN',@level2name=N'elapsed' +GO + +-- 岗位信息表 +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'岗位信息表' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_post' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'岗位ID', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_post', @level2type=N'COLUMN',@level2name=N'postId' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'岗位编码', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_post', @level2type=N'COLUMN',@level2name=N'postCode' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'岗位名称', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_post', @level2type=N'COLUMN',@level2name=N'postName' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'显示顺序', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_post', @level2type=N'COLUMN',@level2name=N'postSort' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'状态(0正常 1停用)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_post', @level2type=N'COLUMN',@level2name=N'status' + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_post', @level2type=N'COLUMN',@level2name=N'create_time' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'最后更新时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_post', @level2type=N'COLUMN',@level2name=N'update_time' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建人编码', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_post', @level2type=N'COLUMN',@level2name=N'create_by' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'更新人编码', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_post', @level2type=N'COLUMN',@level2name=N'update_by' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'备注', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_post', @level2type=N'COLUMN',@level2name=N'remark' +GO + +/**用户表*/ +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'用户表' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_user' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'用户ID', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_user', @level2type=N'COLUMN',@level2name=N'userId' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'部门ID', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_user', @level2type=N'COLUMN',@level2name=N'deptId' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'用户账号', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_user', @level2type=N'COLUMN',@level2name=N'userName' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'用户昵称', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_user', @level2type=N'COLUMN',@level2name=N'nickName' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'用户类型(00系统用户)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_user', @level2type=N'COLUMN',@level2name=N'userType' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'用户邮箱', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_user', @level2type=N'COLUMN',@level2name=N'email' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'手机号码', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_user', @level2type=N'COLUMN',@level2name=N'phonenumber' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'用户性别(0男 1女 2未知)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_user', @level2type=N'COLUMN',@level2name=N'sex' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'头像地址', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_user', @level2type=N'COLUMN',@level2name=N'avatar' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'密码', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_user', @level2type=N'COLUMN',@level2name=N'password' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'帐号状态(0正常 1停用)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_user', @level2type=N'COLUMN',@level2name=N'status' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'删除标志(0代表存在 2代表删除)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_user', @level2type=N'COLUMN',@level2name=N'delFlag' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'最后登录IP', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_user', @level2type=N'COLUMN',@level2name=N'loginIP' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'最后登录时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_user', @level2type=N'COLUMN',@level2name=N'loginDate' + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_user', @level2type=N'COLUMN',@level2name=N'create_time' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'最后更新时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_user', @level2type=N'COLUMN',@level2name=N'update_time' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建人编码', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_user', @level2type=N'COLUMN',@level2name=N'create_by' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'更新人编码', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_user', @level2type=N'COLUMN',@level2name=N'update_by' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'备注', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_user', @level2type=N'COLUMN',@level2name=N'remark' +GO + + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'用户岗位绑定表' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_user_post' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'用户ID', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_user_post', @level2type=N'COLUMN',@level2name=N'userId' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'岗位ID', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_user_post', @level2type=N'COLUMN',@level2name=N'postId' +GO + + +-- ---------------------------- +-- '角色信息表' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'角色信息表' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_role' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'角色ID', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_role', @level2type=N'COLUMN',@level2name=N'roleId' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'角色名称', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_role', @level2type=N'COLUMN',@level2name=N'roleName' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'角色权限字符串', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_role', @level2type=N'COLUMN',@level2name=N'roleKey' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'显示顺序', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_role', @level2type=N'COLUMN',@level2name=N'roleSort' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 )', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_role', @level2type=N'COLUMN',@level2name=N'dataScope' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'菜单树选择项是否关联显示', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_role', @level2type=N'COLUMN',@level2name=N'menu_check_strictly' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'部门树选择项是否关联显示', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_role', @level2type=N'COLUMN',@level2name=N'dept_check_strictly' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'角色状态(0正常 1停用)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_role', @level2type=N'COLUMN',@level2name=N'status' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'删除标志(0代表存在 2代表删除)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_role', @level2type=N'COLUMN',@level2name=N'delFlag' + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_role', @level2type=N'COLUMN',@level2name=N'create_time' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'最后更新时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_role', @level2type=N'COLUMN',@level2name=N'update_time' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建人编码', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_role', @level2type=N'COLUMN',@level2name=N'create_by' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'更新人编码', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_role', @level2type=N'COLUMN',@level2name=N'update_by' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'备注', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_role', @level2type=N'COLUMN',@level2name=N'remark' +GO + + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'用户和角色关联表' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_user_role' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'用户ID', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_user_role', @level2type=N'COLUMN',@level2name=N'user_id' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'角色ID', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_user_role', @level2type=N'COLUMN',@level2name=N'role_id' + +go + +-- 角色和菜单关联表 +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'角色和菜单关联表' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_role_menu' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'角色ID', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_role_menu', @level2type=N'COLUMN',@level2name=N'role_id' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'菜单ID', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_role_menu', @level2type=N'COLUMN',@level2name=N'menu_id' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建人编码', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_role_menu', @level2type=N'COLUMN',@level2name=N'create_by' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_role_menu', @level2type=N'COLUMN',@level2name=N'create_time' +GO + +-- 通知公告表 +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'公告ID' , @level0type=N'SCHEMA',@level0name=N'dbo', +@level1type=N'TABLE',@level1name=N'sys_notice', @level2type=N'COLUMN',@level2name=N'notice_id' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'公告标题' , @level0type=N'SCHEMA',@level0name=N'dbo', +@level1type=N'TABLE',@level1name=N'sys_notice', @level2type=N'COLUMN',@level2name=N'notice_title' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'公告类型 (1通知 2公告)' , @level0type=N'SCHEMA',@level0name=N'dbo', +@level1type=N'TABLE',@level1name=N'sys_notice', @level2type=N'COLUMN',@level2name=N'notice_type' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'公告内容' , @level0type=N'SCHEMA',@level0name=N'dbo', +@level1type=N'TABLE',@level1name=N'sys_notice', @level2type=N'COLUMN',@level2name=N'notice_content' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'公告状态' , @level0type=N'SCHEMA',@level0name=N'dbo', +@level1type=N'TABLE',@level1name=N'sys_notice', @level2type=N'COLUMN',@level2name=N'status' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建者' , @level0type=N'SCHEMA',@level0name=N'dbo', +@level1type=N'TABLE',@level1name=N'sys_notice', @level2type=N'COLUMN',@level2name=N'create_by' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建时间' , @level0type=N'SCHEMA',@level0name=N'dbo', +@level1type=N'TABLE',@level1name=N'sys_notice', @level2type=N'COLUMN',@level2name=N'create_time' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'更新者' , @level0type=N'SCHEMA',@level0name=N'dbo', +@level1type=N'TABLE',@level1name=N'sys_notice', @level2type=N'COLUMN',@level2name=N'update_by' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'更新时间' , @level0type=N'SCHEMA',@level0name=N'dbo', +@level1type=N'TABLE',@level1name=N'sys_notice', @level2type=N'COLUMN',@level2name=N'update_time' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'备注' , @level0type=N'SCHEMA',@level0name=N'dbo', +@level1type=N'TABLE',@level1name=N'sys_notice', @level2type=N'COLUMN',@level2name=N'remark' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'通知公告表' , @level0type=N'SCHEMA',@level0name=N'dbo', +@level1type=N'TABLE',@level1name=N'sys_notice' +GO + +-- 文章表 +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'文章表' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'article' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'文章id', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'article', @level2type=N'COLUMN',@level2name=N'cid' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'文章标题', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'article', @level2type=N'COLUMN',@level2name=N'title' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'用户id', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'article', @level2type=N'COLUMN',@level2name=N'userId' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'文章状态1、已发布 2、草稿', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'article', @level2type=N'COLUMN',@level2name=N'status' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'编辑器类型markdown,html', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'article', @level2type=N'COLUMN',@level2name=N'fmt_type' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'文章标签', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'article', @level2type=N'COLUMN',@level2name=N'tags' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'点击量', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'article', @level2type=N'COLUMN',@level2name=N'hits' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'目录id', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'article', @level2type=N'COLUMN',@level2name=N'category_id' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'article', @level2type=N'COLUMN',@level2name=N'createTime' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'修改时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'article', @level2type=N'COLUMN',@level2name=N'updateTime' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'article', @level2type=N'COLUMN',@level2name=N'authorName' +GO + +-- +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'目录表' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'articleCategory' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'目录id', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'articleCategory', @level2type=N'COLUMN',@level2name=N'category_id' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'目录名', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'articleCategory', @level2type=N'COLUMN',@level2name=N'name' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'articleCategory', @level2type=N'COLUMN',@level2name=N'create_time' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'父级ID', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'articleCategory', @level2type=N'COLUMN',@level2name=N'parentId' +GO + + +-- 18、代码生成业务表 +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'代码生成业务表' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'编号', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table', @level2type=N'COLUMN',@level2name=N'tableId' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'表名称', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table', @level2type=N'COLUMN',@level2name=N'tableName' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'表描述', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table', @level2type=N'COLUMN',@level2name=N'tableComment' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'关联子表的表名', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table', @level2type=N'COLUMN',@level2name=N'subTableName' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'子表关联的外键名', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table', @level2type=N'COLUMN',@level2name=N'subTableFkName' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'实体类名称', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table', @level2type=N'COLUMN',@level2name=N'className' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'使用的模板(crud单表操作 tree树表操作)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table', @level2type=N'COLUMN',@level2name=N'tplCategory' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'生成命名空间前缀', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table', @level2type=N'COLUMN',@level2name=N'baseNameSpace' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'生成模块名', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table', @level2type=N'COLUMN',@level2name=N'moduleName' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'生成业务名', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table', @level2type=N'COLUMN',@level2name=N'businessName' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'生成功能名', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table', @level2type=N'COLUMN',@level2name=N'functionName' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'生成功能作者', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table', @level2type=N'COLUMN',@level2name=N'functionAuthor' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'生成代码方式(0zip压缩包 1自定义路径)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table', @level2type=N'COLUMN',@level2name=N'genType' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'生成路径(不填默认项目路径)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table', @level2type=N'COLUMN',@level2name=N'genPath' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'其它生成选项', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table', @level2type=N'COLUMN',@level2name=N'options' + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table', @level2type=N'COLUMN',@level2name=N'create_time' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'最后更新时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table', @level2type=N'COLUMN',@level2name=N'update_time' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建人编码', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table', @level2type=N'COLUMN',@level2name=N'create_by' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'更新人编码', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table', @level2type=N'COLUMN',@level2name=N'update_by' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'备注', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table', @level2type=N'COLUMN',@level2name=N'remark' + +GO + + +-- 代码生成业务表字段 +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'代码生成业务表字段' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table_column' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'编号', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table_column', @level2type=N'COLUMN',@level2name=N'columnId' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'归属表编号', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table_column', @level2type=N'COLUMN',@level2name=N'tableId' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'表名', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table_column', @level2type=N'COLUMN',@level2name=N'tableName' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'列名称', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table_column', @level2type=N'COLUMN',@level2name=N'columnName' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'列描述', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table_column', @level2type=N'COLUMN',@level2name=N'columnComment' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'列类型', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table_column', @level2type=N'COLUMN',@level2name=N'columnType' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'C#类型', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table_column', @level2type=N'COLUMN',@level2name=N'csharpType' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'C#字段名', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table_column', @level2type=N'COLUMN',@level2name=N'csharpField' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'是否主键(1是)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table_column', @level2type=N'COLUMN',@level2name=N'isPk' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'是否自增(1是)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table_column', @level2type=N'COLUMN',@level2name=N'isIncrement' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'是否必填(1是)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table_column', @level2type=N'COLUMN',@level2name=N'isRequired' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'是否为插入字段(1是)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table_column', @level2type=N'COLUMN',@level2name=N'isInsert' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'是否编辑字段(1是)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table_column', @level2type=N'COLUMN',@level2name=N'isEdit' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'是否列表字段(1是)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table_column', @level2type=N'COLUMN',@level2name=N'isList' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'是否查询字段(1是)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table_column', @level2type=N'COLUMN',@level2name=N'isQuery' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'查询方式(等于、不等于、大于、小于、范围)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table_column', @level2type=N'COLUMN',@level2name=N'queryType' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table_column', @level2type=N'COLUMN',@level2name=N'htmlType' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'字典类型', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table_column', @level2type=N'COLUMN',@level2name=N'dictType' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'排序', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table_column', @level2type=N'COLUMN',@level2name=N'sort' + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table_column', @level2type=N'COLUMN',@level2name=N'create_time' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'最后更新时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table_column', @level2type=N'COLUMN',@level2name=N'update_time' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建人编码', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table_column', @level2type=N'COLUMN',@level2name=N'create_by' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'更新人编码', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table_column', @level2type=N'COLUMN',@level2name=N'update_by' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'备注', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'gen_table_column', @level2type=N'COLUMN',@level2name=N'remark' +GO + +-- 参数配置表 +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'参数配置表' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_config' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'参数主键', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_config', @level2type=N'COLUMN',@level2name=N'configId' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'参数名称', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_config', @level2type=N'COLUMN',@level2name=N'configName' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'参数键名', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_config', @level2type=N'COLUMN',@level2name=N'configKey' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'参数键值', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_config', @level2type=N'COLUMN',@level2name=N'configValue' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'系统内置(Y是 N否)', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_config', @level2type=N'COLUMN',@level2name=N'configType' + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_config', @level2type=N'COLUMN',@level2name=N'create_time' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'最后更新时间', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_config', @level2type=N'COLUMN',@level2name=N'update_time' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建人编码', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_config', @level2type=N'COLUMN',@level2name=N'create_by' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'更新人编码', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_config', @level2type=N'COLUMN',@level2name=N'update_by' +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'备注', @level0type=N'SCHEMA', +@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'sys_config', @level2type=N'COLUMN',@level2name=N'remark' + +GO + +-- 代码生成测试 + +EXEC sp_addextendedproperty +'MS_Description', N'自增id', +'SCHEMA', N'dbo', +'TABLE', N'gen_demo', +'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'名称', +'SCHEMA', N'dbo', +'TABLE', N'gen_demo', +'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'图片', +'SCHEMA', N'dbo', +'TABLE', N'gen_demo', +'COLUMN', N'icon' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'显示状态', +'SCHEMA', N'dbo', +'TABLE', N'gen_demo', +'COLUMN', N'showStatus' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'添加时间', +'SCHEMA', N'dbo', +'TABLE', N'gen_demo', +'COLUMN', N'addTime' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'用户性别', +'SCHEMA', N'dbo', +'TABLE', N'gen_demo', +'COLUMN', N'sex' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'排序', +'SCHEMA', N'dbo', +'TABLE', N'gen_demo', +'COLUMN', N'sort' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'开始时间', +'SCHEMA', N'dbo', +'TABLE', N'gen_demo', +'COLUMN', N'beginTime' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'结束时间', +'SCHEMA', N'dbo', +'TABLE', N'gen_demo', +'COLUMN', N'endTime' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'备注', +'SCHEMA', N'dbo', +'TABLE', N'gen_demo', +'COLUMN', N'remark' +GO diff --git a/document/admin-sqlserver.sql b/document/admin-sqlserver.sql new file mode 100644 index 0000000..f6626d5 --- /dev/null +++ b/document/admin-sqlserver.sql @@ -0,0 +1,2 @@ +宝塔 镜像 +https://www.its203.com/article/u011092458/119864675 \ No newline at end of file diff --git a/document/excel/classes/班级导入模板模板.xlsx b/document/excel/classes/班级导入模板模板.xlsx new file mode 100644 index 0000000..cfde0c3 Binary files /dev/null and b/document/excel/classes/班级导入模板模板.xlsx differ diff --git a/document/excel/key/关键词导入模板模板 (10) - 副本.xlsx b/document/excel/key/关键词导入模板模板 (10) - 副本.xlsx new file mode 100644 index 0000000..2293863 Binary files /dev/null and b/document/excel/key/关键词导入模板模板 (10) - 副本.xlsx differ diff --git a/document/excel/key/关键词导入模板模板 (10).xlsx b/document/excel/key/关键词导入模板模板 (10).xlsx new file mode 100644 index 0000000..f05b52a Binary files /dev/null and b/document/excel/key/关键词导入模板模板 (10).xlsx differ diff --git a/document/excel/news/新闻导入模板模板 (1).xlsx b/document/excel/news/新闻导入模板模板 (1).xlsx new file mode 100644 index 0000000..5424dd9 Binary files /dev/null and b/document/excel/news/新闻导入模板模板 (1).xlsx differ diff --git a/document/excel/student/学生列表0720205233.xlsx b/document/excel/student/学生列表0720205233.xlsx new file mode 100644 index 0000000..073a4b5 Binary files /dev/null and b/document/excel/student/学生列表0720205233.xlsx differ diff --git a/document/excel/student/学生列表0721140932.xlsx b/document/excel/student/学生列表0721140932.xlsx new file mode 100644 index 0000000..cd7e388 Binary files /dev/null and b/document/excel/student/学生列表0721140932.xlsx differ diff --git a/document/excel/student/学生列表模板 (1).xlsx b/document/excel/student/学生列表模板 (1).xlsx new file mode 100644 index 0000000..cec05e4 Binary files /dev/null and b/document/excel/student/学生列表模板 (1).xlsx differ diff --git a/document/excel/student/学生列表模板 (15).xlsx b/document/excel/student/学生列表模板 (15).xlsx new file mode 100644 index 0000000..269bc11 Binary files /dev/null and b/document/excel/student/学生列表模板 (15).xlsx differ diff --git a/document/excel/student/学生列表模板 (4).xlsx b/document/excel/student/学生列表模板 (4).xlsx new file mode 100644 index 0000000..953c46a Binary files /dev/null and b/document/excel/student/学生列表模板 (4).xlsx differ diff --git a/document/excel/testd/测试导入模板模板 (2).xlsx b/document/excel/testd/测试导入模板模板 (2).xlsx new file mode 100644 index 0000000..b701057 Binary files /dev/null and b/document/excel/testd/测试导入模板模板 (2).xlsx differ diff --git a/document/excel/testparts/测试配件导入模板模板 (1).xlsx b/document/excel/testparts/测试配件导入模板模板 (1).xlsx new file mode 100644 index 0000000..8cb001f Binary files /dev/null and b/document/excel/testparts/测试配件导入模板模板 (1).xlsx differ diff --git a/document/excel/testtype/测试类型导入模板模板 (8).xlsx b/document/excel/testtype/测试类型导入模板模板 (8).xlsx new file mode 100644 index 0000000..3fe3182 Binary files /dev/null and b/document/excel/testtype/测试类型导入模板模板 (8).xlsx differ diff --git a/document/images/1.png b/document/images/1.png new file mode 100644 index 0000000..7086dd7 Binary files /dev/null and b/document/images/1.png differ diff --git a/document/images/10.png b/document/images/10.png new file mode 100644 index 0000000..66d5672 Binary files /dev/null and b/document/images/10.png differ diff --git a/document/images/11.png b/document/images/11.png new file mode 100644 index 0000000..f08a25a Binary files /dev/null and b/document/images/11.png differ diff --git a/document/images/12.png b/document/images/12.png new file mode 100644 index 0000000..d56b24b Binary files /dev/null and b/document/images/12.png differ diff --git a/document/images/13.png b/document/images/13.png new file mode 100644 index 0000000..d52f449 Binary files /dev/null and b/document/images/13.png differ diff --git a/document/images/14.png b/document/images/14.png new file mode 100644 index 0000000..5af9de6 Binary files /dev/null and b/document/images/14.png differ diff --git a/document/images/15.png b/document/images/15.png new file mode 100644 index 0000000..123fade Binary files /dev/null and b/document/images/15.png differ diff --git a/document/images/16.png b/document/images/16.png new file mode 100644 index 0000000..3ac56dd Binary files /dev/null and b/document/images/16.png differ diff --git a/document/images/17.png b/document/images/17.png new file mode 100644 index 0000000..c77cf17 Binary files /dev/null and b/document/images/17.png differ diff --git a/document/images/18.png b/document/images/18.png new file mode 100644 index 0000000..87b36d4 Binary files /dev/null and b/document/images/18.png differ diff --git a/document/images/19.png b/document/images/19.png new file mode 100644 index 0000000..c8fddf8 Binary files /dev/null and b/document/images/19.png differ diff --git a/document/images/2.png b/document/images/2.png new file mode 100644 index 0000000..a467cb0 Binary files /dev/null and b/document/images/2.png differ diff --git a/document/images/20.png b/document/images/20.png new file mode 100644 index 0000000..db04516 Binary files /dev/null and b/document/images/20.png differ diff --git a/document/images/3.png b/document/images/3.png new file mode 100644 index 0000000..e6b83e1 Binary files /dev/null and b/document/images/3.png differ diff --git a/document/images/4.png b/document/images/4.png new file mode 100644 index 0000000..3e7dd59 Binary files /dev/null and b/document/images/4.png differ diff --git a/document/images/5.png b/document/images/5.png new file mode 100644 index 0000000..a815565 Binary files /dev/null and b/document/images/5.png differ diff --git a/document/images/6.png b/document/images/6.png new file mode 100644 index 0000000..a192acf Binary files /dev/null and b/document/images/6.png differ diff --git a/document/images/7.png b/document/images/7.png new file mode 100644 index 0000000..c6062ef Binary files /dev/null and b/document/images/7.png differ diff --git a/document/images/8.png b/document/images/8.png new file mode 100644 index 0000000..829ec1c Binary files /dev/null and b/document/images/8.png differ diff --git a/document/images/9.png b/document/images/9.png new file mode 100644 index 0000000..abf0f6b Binary files /dev/null and b/document/images/9.png differ diff --git a/document/images/pay.jpg b/document/images/pay.jpg new file mode 100644 index 0000000..5a075f1 Binary files /dev/null and b/document/images/pay.jpg differ diff --git a/document/zradmin.ini b/document/zradmin.ini new file mode 100644 index 0000000..1d8e00f --- /dev/null +++ b/document/zradmin.ini @@ -0,0 +1,38 @@ +server { + #修改要监听的端口 + listen 8080; + #修改要绑定的域名或IP地址 + server_name localhost; + + # charset koi8-r; + access_log logs/logs.access.log main; + + # 后端接口 生产环境 + location /prod-api/ { + proxy_pass http://localhost:8888/; + + # 后端的Web服务器可以通过X-Forwarded-For获取用户真实IP + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # 如果请求被负载均衡的服务器返回类似500这样的,将继续请求下一台应用服务器,默认 对post,lock,patch的请求不进行重试,如果要设置在后面添加 non_idemponent + # proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; + } + + # vue项目配置 + location / { + #将xxxxx路径改成你的发布路径 + root html/zradmin_vue; + index index.html; + try_files $uri $uri/ /index.html; + } + + error_page 404 /404.html; + + # redirect server error pages to the static page /50x.html + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root html; + } +} \ No newline at end of file diff --git a/startup.bat b/startup.bat new file mode 100644 index 0000000..995577c --- /dev/null +++ b/startup.bat @@ -0,0 +1 @@ +dotnet watch --project ZR.Admin.WebApi run \ No newline at end of file