commit 1845017b67b3de3d12fad0238f5493235f70a93d
Author: izory <791736813@qq.com>
Date: Mon Aug 23 16:57:25 2021 +0800
first 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..c516947
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,264 @@
+## 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
+/ZRAdmin/Properties/launchSettings.json
+/ZRAdmin/Properties/PublishProfiles
+/ZR.Admin.WebApi/appsettings.Stage.json
diff --git a/Infrastructure/App/App.cs b/Infrastructure/App/App.cs
new file mode 100644
index 0000000..2806111
--- /dev/null
+++ b/Infrastructure/App/App.cs
@@ -0,0 +1,65 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Security.Claims;
+
+namespace Infrastructure
+{
+ public static class App
+ {
+ ///
+ /// 服务提供器
+ ///
+ public static IServiceProvider ServiceProvider => HttpContext?.RequestServices ?? InternalApp.InternalServices.BuildServiceProvider();
+ ///
+ /// 获取请求上下文
+ ///
+ 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/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..9250287
--- /dev/null
+++ b/Infrastructure/Attribute/LogAttribute.cs
@@ -0,0 +1,25 @@
+using Infrastructure.Enums;
+
+namespace Infrastructure.Attribute
+{
+ ///
+ /// 自定义操作日志记录注解
+ ///
+ public class LogAttribute : System.Attribute
+ {
+ public string Title { get; set; }
+ public BusinessType BusinessType { get; set; }
+
+ public LogAttribute() { }
+
+ public LogAttribute(string name)
+ {
+ Title = name;
+ }
+ public LogAttribute(string name, BusinessType businessType)
+ {
+ Title = name;
+ BusinessType = businessType;
+ }
+ }
+}
diff --git a/Infrastructure/ConfigUtils.cs b/Infrastructure/ConfigUtils.cs
new file mode 100644
index 0000000..617875d
--- /dev/null
+++ b/Infrastructure/ConfigUtils.cs
@@ -0,0 +1,75 @@
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using System;
+
+///
+/// 需要引用包
+/// Microsoft.Extensions.Configuration;
+/// Microsoft.Extensions.DependencyInjection;
+namespace Infrastructure
+{
+ public class ConfigUtils
+ {
+ #region 单例访问
+
+ static ConfigUtils()
+ {
+ Config = App.ServiceProvider.GetRequiredService();
+
+ if (Instance == null)
+ Instance = new ConfigUtils();
+ }
+
+ public static ConfigUtils Instance { get; private set; }
+ #endregion
+
+ private static IConfiguration Config { get; set; }
+
+ ///
+ /// 泛型读取配置文件
+ /// 目前还不能绑定到实体类
+ ///
+ /// 获取不到配置文件设定默认值
+ /// 要获取的配置文件节点名称
+ ///
+ //public T GetConfig(string key, T defaultValue = default)
+ //{
+ // //GetValue扩展包需要安装Microsoft.Extensions.Configuration
+ // var setting = Config.GetValue(key, defaultValue);
+
+ // Console.WriteLine($"获取配置文件值key={key},value={setting}");
+ // return setting;
+ //}
+
+ public T GetAppConfig(string key, T defaultValue = default(T))
+ {
+ T setting = (T)Convert.ChangeType(Config[key], typeof(T));
+ var value = setting;
+ if (setting == null)
+ value = defaultValue;
+ //Console.WriteLine($"获取配置文件值key={key},value={value}");
+ return value;
+ }
+
+ ///
+ /// 获取配置文件
+ ///
+ /// eg: WeChat:Token
+ ///
+ public string GetConfig(string key)
+ {
+ return Config[key];
+ }
+
+ ///
+ /// 获取数据库字符串连接串
+ ///
+ ///
+ ///
+ public string GetConnectionStrings(string key)
+ {
+ return Config.GetConnectionString(key);
+
+ }
+ }
+}
diff --git a/Infrastructure/Constant/HttpStatus.cs b/Infrastructure/Constant/HttpStatus.cs
new file mode 100644
index 0000000..3643b82
--- /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 CONFLICT = 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/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..4c670da
--- /dev/null
+++ b/Infrastructure/CustomException/ResultCode.cs
@@ -0,0 +1,51 @@
+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("NO_DATA")]
+ NODATA = 106,
+
+ FAIL = 1,
+
+ [Description("服务端出错啦")]
+ GLOBAL_ERROR = 500,
+
+ [Description("请先绑定手机号")]
+ NOBIND_PHONENUM = 102,
+
+ [Description("自定义异常")]
+ CUSTOM_ERROR = 110,
+
+ [Description("非法签名")]
+ SIGN_ERROR = 110,
+
+ [Description("非法请求")]
+ INVALID_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..5f4195a
--- /dev/null
+++ b/Infrastructure/Enums/BusinessType.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Infrastructure.Enums
+{
+ /**
+ * 业务操作类型
+ * 0=其它,1=新增,2=修改,3=删除,4=授权,5=导出,6=导入,7=强退,8=生成代码,9=清空数据
+ * @author zrry
+ */
+ public enum BusinessType
+ {
+ /**
+ * 其它
+ */
+ OTHER = 0,
+
+ /**
+ * 新增
+ */
+ INSERT = 1,
+
+ /**
+ * 修改
+ */
+ UPDATE = 2,
+
+ /**
+ * 删除
+ */
+ DELETE = 3,
+
+ /**
+ * 授权
+ */
+ GRANT = 4,
+
+ /**
+ * 导出
+ */
+ EXPORT = 5,
+
+ /**
+ * 导入
+ */
+ IMPORT = 6,
+
+ /**
+ * 强退
+ */
+ FORCE = 7,
+
+ /**
+ * 生成代码
+ */
+ GENCODE = 8,
+
+ /**
+ * 清空数据
+ */
+ CLEAN = 9,
+ }
+}
diff --git a/Infrastructure/Extensions/AppServiceExtensions.cs b/Infrastructure/Extensions/AppServiceExtensions.cs
new file mode 100644
index 0000000..98545c7
--- /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[] { "ZR.Repository", "ZR.Service", "ZR.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/StringExtension.cs b/Infrastructure/Extensions/StringExtension.cs
new file mode 100644
index 0000000..75885c8
--- /dev/null
+++ b/Infrastructure/Extensions/StringExtension.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+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);
+ }
+ }
+}
diff --git a/Infrastructure/GlobalConstant.cs b/Infrastructure/GlobalConstant.cs
new file mode 100644
index 0000000..6139938
--- /dev/null
+++ b/Infrastructure/GlobalConstant.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Infrastructure
+{
+ ///
+ /// 全局静态常量
+ ///
+ public class GlobalConstant
+ {
+ ///
+ /// 管理员权限
+ ///
+ public static string AdminPerm = "*:*:*";
+ }
+}
diff --git a/Infrastructure/Infrastructure.csproj b/Infrastructure/Infrastructure.csproj
new file mode 100644
index 0000000..d878cb3
--- /dev/null
+++ b/Infrastructure/Infrastructure.csproj
@@ -0,0 +1,14 @@
+
+
+
+ net5.0
+
+
+
+
+
+
+
+
+
+
diff --git a/Infrastructure/InternalApp.cs b/Infrastructure/InternalApp.cs
new file mode 100644
index 0000000..302f855
--- /dev/null
+++ b/Infrastructure/InternalApp.cs
@@ -0,0 +1,29 @@
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+
+namespace Infrastructure
+{
+ public static class InternalApp
+ {
+ ///
+ /// 应用服务
+ ///
+ internal static IServiceCollection InternalServices;
+
+ ///
+ /// 全局配置构建器
+ ///
+ internal static IConfigurationBuilder ConfigurationBuilder;
+
+ ///
+ /// 获取Web主机环境
+ ///
+ //internal static IWebHostEnvironment WebHostEnvironment;
+
+ ///
+ /// 获取泛型主机环境
+ ///
+ internal static IHostEnvironment HostEnvironment;
+ }
+}
diff --git a/Infrastructure/Model/ApiResult.cs b/Infrastructure/Model/ApiResult.cs
new file mode 100644
index 0000000..672b0dc
--- /dev/null
+++ b/Infrastructure/Model/ApiResult.cs
@@ -0,0 +1,120 @@
+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 class ApiResult : ApiResult
+ {
+ public T Result { get; set; }
+ }
+}
diff --git a/Infrastructure/Model/PagedInfo.cs b/Infrastructure/Model/PagedInfo.cs
new file mode 100644
index 0000000..ff5c285
--- /dev/null
+++ b/Infrastructure/Model/PagedInfo.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Infrastructure.Model
+{
+ ///
+ /// 分页参数
+ ///
+ public class PagedInfo
+ {
+ ///
+ /// 每页行数
+ ///
+ public int PageSize { get; set; } = 10;
+ ///
+ /// 当前页
+ ///
+ public int PageIndex { get; set; } = 1;
+ ///
+ /// 排序列
+ ///
+ //public string Sort { get; set; }
+ ///
+ /// 排序类型
+ ///
+ //public string SortType { get; set; }
+ ///
+ /// 总记录数
+ ///
+ public int TotalCount { get; set; }
+ ///
+ /// 总页数
+ ///
+ //public int TotalPage
+ //{
+ // get
+ // {
+ // if (TotalCount > 0)
+ // {
+ // return TotalCount % this.PageSize == 0 ? TotalCount / this.PageSize : TotalCount / this.PageSize + 1;
+ // }
+ // else
+ // {
+ // return 0;
+ // }
+ // }
+ // set { }
+ //}
+ public int TotalPage { get; set; }
+ public List Result { get; set; }
+
+ public PagedInfo()
+ {
+ }
+
+
+ public PagedInfo(List source, int pageIndex, int pageSize)
+ {
+ PageIndex = pageIndex;
+ PageSize = pageSize;
+ TotalCount = source.Count;
+ TotalPage = (int)Math.Ceiling(TotalCount / (double)PageSize);//计算总页数
+ }
+
+ }
+}
diff --git a/Infrastructure/OptionsSetting.cs b/Infrastructure/OptionsSetting.cs
new file mode 100644
index 0000000..4aa2b2e
--- /dev/null
+++ b/Infrastructure/OptionsSetting.cs
@@ -0,0 +1,59 @@
+
+namespace Infrastructure
+{
+ ///
+ /// 获取配置文件POCO实体类
+ ///
+ public class OptionsSetting
+ {
+ public static string ConnAdmin = "Conn_admin";
+ public static string DbType = "DbType";
+ public static string DbKey = "DbKey";
+
+ public string Conn_Admin { get; set; }
+
+ public string AppName { get; set; }
+ ///
+ /// 主库
+ ///
+ public string Master { get; set; }
+
+ public string Redis { get; set; }
+
+ public string Database { get; set; }
+ ///
+ /// 是否演示模式
+ ///
+ public bool DemoMode { get; set; }
+ public MailOptions MailOptions { get; set; }
+ public Upload Upload { get; set; }
+ public ALYUN_OCS ALYUN_OCS { get; set; }
+ }
+ ///
+ /// 发送邮件数据配置
+ ///
+ public class MailOptions
+ {
+ public string From { get; set; }
+ public string Password { get; set; }
+ public string Host { get; set; }
+ public int Port { get; set; }
+ }
+ ///
+ /// 上传
+ ///
+ public class Upload
+ {
+ public string UploadDirectory { get; set; }
+ public string UploadUrl { get; set; }
+ }
+ ///
+ /// 阿里云存储
+ ///
+ public class ALYUN_OCS
+ {
+ public string REGIONID { get; set; }
+ public string KEY { get; set; }
+ public string SECRET { get; set; }
+ }
+}
diff --git a/Infrastructure/Startups/HostBuilderExtensions.cs b/Infrastructure/Startups/HostBuilderExtensions.cs
new file mode 100644
index 0000000..9f6a6ef
--- /dev/null
+++ b/Infrastructure/Startups/HostBuilderExtensions.cs
@@ -0,0 +1,54 @@
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+
+namespace Infrastructure.Startups
+{
+ ///
+ /// Program.cs里面的HostBuilder扩展
+ ///
+ public static class HostBuilderExtensions
+ {
+ ///
+ /// Web 主机注入
+ ///
+ /// Web主机构建器
+ /// 外部程序集名称,如果HostingStartup存在多个程序集中可以使用;分隔,比如HostStartupLib;HostStartupLib2
+ /// IWebHostBuilder
+ public static IWebHostBuilder Init(this IWebHostBuilder hostBuilder, string assemblyName)
+ {
+ hostBuilder.UseSetting(WebHostDefaults.HostingStartupAssembliesKey, assemblyName);
+ return hostBuilder;
+ }
+
+ ///
+ /// 初始化程序扩展
+ ///
+ ///
+ public static void UseAppStartup(this IWebHostBuilder hostBuilder)
+ {
+ System.Console.WriteLine("启动类执行了");
+ // 自动装载配置
+ hostBuilder.ConfigureAppConfiguration((hostingContext, config) =>
+ {
+ // 存储环境对象
+ InternalApp.HostEnvironment = (IHostEnvironment)hostingContext.HostingEnvironment;
+
+ // 加载配置
+ //InternalApp.AddConfigureFiles(config, InternalApp.WebHostEnvironment);
+ });
+ // 自动注入 AddApp() 服务
+ hostBuilder.ConfigureServices((services) =>
+ {
+ // 注册 Startup 过滤器
+ //services.AddTransient();
+
+ // 添加全局配置和存储服务提供器
+ InternalApp.InternalServices = services;
+
+ // 初始化应用服务
+ //services.AddApp();
+ });
+ }
+ }
+}
diff --git a/Infrastructure/Startups/HostingStartup.cs b/Infrastructure/Startups/HostingStartup.cs
new file mode 100644
index 0000000..fbc99f3
--- /dev/null
+++ b/Infrastructure/Startups/HostingStartup.cs
@@ -0,0 +1,40 @@
+using Infrastructure.Startups;
+using Microsoft.AspNetCore.Hosting;
+
+//通过HostingStartup指定要启动的类型
+[assembly: HostingStartup(typeof(HostingStartup))]
+
+namespace Infrastructure.Startups
+{
+ public class HostingStartup : IHostingStartup
+ {
+ public void Configure(IWebHostBuilder builder)
+ {
+ System.Console.WriteLine("启动类执行了");
+ // 自动装载配置
+ builder.ConfigureAppConfiguration((hostingContext, config) =>
+ {
+ // 存储环境对象
+ //InternalApp.HostEnvironment = hostingContext.HostingEnvironment;
+ //InternalApp.HostEnvironment = (Microsoft.Extensions.Hosting.IHostEnvironment)hostingContext.HostingEnvironment;
+ // 加载配置
+ //InternalApp.AddConfigureFiles(config, InternalApp.WebHostEnvironment);
+ InternalApp.ConfigurationBuilder = config;
+ });
+
+ // 自动注入 AddApp() 服务
+ builder.ConfigureServices(services =>
+ {
+ // 注册 Startup 过滤器
+ //services.AddTransient();
+
+ // 添加全局配置和存储服务提供器
+ InternalApp.InternalServices = services;
+
+ // 初始化应用服务
+ //services.AddApp();
+ });
+
+ }
+ }
+}
diff --git a/Quartz.NET.WindowsService/App.config b/Quartz.NET.WindowsService/App.config
new file mode 100644
index 0000000..1e4951b
--- /dev/null
+++ b/Quartz.NET.WindowsService/App.config
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Quartz.NET.WindowsService/Install.bat b/Quartz.NET.WindowsService/Install.bat
new file mode 100644
index 0000000..5e8a60f
--- /dev/null
+++ b/Quartz.NET.WindowsService/Install.bat
@@ -0,0 +1,5 @@
+%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\installutil.exe G:\live_zhaorui\ZrryAdmin\ZrryAdmin_api\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe
+
+Net Start Quartz.Net
+
+sc config Quartz.Net start= auto
\ No newline at end of file
diff --git a/Quartz.NET.WindowsService/InstallUtil.InstallLog b/Quartz.NET.WindowsService/InstallUtil.InstallLog
new file mode 100644
index 0000000..207894f
--- /dev/null
+++ b/Quartz.NET.WindowsService/InstallUtil.InstallLog
@@ -0,0 +1,316 @@
+
+正在运行事务处理安装。
+
+正在开始安装的“安装”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+“安装”阶段已成功完成,正在开始“提交”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+“提交”阶段已成功完成。
+
+已完成事务处理安装。
+
+
+正在开始卸载。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+卸载完成。
+
+正在运行事务处理安装。
+
+正在开始安装的“安装”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+“安装”阶段已成功完成,正在开始“提交”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+“提交”阶段已成功完成。
+
+已完成事务处理安装。
+
+
+正在开始卸载。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+卸载完成。
+
+正在运行事务处理安装。
+
+正在开始安装的“安装”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+“安装”阶段已成功完成,正在开始“提交”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+“提交”阶段已成功完成。
+
+已完成事务处理安装。
+
+
+正在开始卸载。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+卸载完成。
+
+正在运行事务处理安装。
+
+正在开始安装的“安装”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+“安装”阶段已成功完成,正在开始“提交”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+“提交”阶段已成功完成。
+
+已完成事务处理安装。
+
+
+正在开始卸载。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+卸载完成。
+
+正在运行事务处理安装。
+
+正在开始安装的“安装”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+“安装”阶段已成功完成,正在开始“提交”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+“提交”阶段已成功完成。
+
+已完成事务处理安装。
+
+正在运行事务处理安装。
+
+正在开始安装的“安装”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+在“安装”阶段发生异常。
+System.ComponentModel.Win32Exception: 指定的服务已存在。
+
+正在开始安装的“回退”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+“回退”阶段已成功完成。
+
+已完成事务处理安装。
+
+
+正在开始卸载。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+卸载完成。
+
+正在运行事务处理安装。
+
+正在开始安装的“安装”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+“安装”阶段已成功完成,正在开始“提交”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+“提交”阶段已成功完成。
+
+已完成事务处理安装。
+
+正在运行事务处理安装。
+
+正在开始安装的“安装”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+在“安装”阶段发生异常。
+System.ComponentModel.Win32Exception: 指定的服务已存在。
+
+正在开始安装的“回退”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+“回退”阶段已成功完成。
+
+已完成事务处理安装。
+
+
+正在开始卸载。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+卸载完成。
+
+正在运行事务处理安装。
+
+正在开始安装的“安装”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+“安装”阶段已成功完成,正在开始“提交”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+“提交”阶段已成功完成。
+
+已完成事务处理安装。
+
+
+正在开始卸载。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+卸载完成。
+
+正在运行事务处理安装。
+
+正在开始安装的“安装”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+“安装”阶段已成功完成,正在开始“提交”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+“提交”阶段已成功完成。
+
+已完成事务处理安装。
+
+
+正在开始卸载。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+卸载完成。
+
+正在运行事务处理安装。
+
+正在开始安装的“安装”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+“安装”阶段已成功完成,正在开始“提交”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+“提交”阶段已成功完成。
+
+已完成事务处理安装。
+
+正在运行事务处理安装。
+
+正在开始安装的“安装”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+在“安装”阶段发生异常。
+System.ComponentModel.Win32Exception: 指定的服务已存在。
+
+正在开始安装的“回退”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+“回退”阶段已成功完成。
+
+已完成事务处理安装。
+
+
+正在开始卸载。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+卸载完成。
+
+正在运行事务处理安装。
+
+正在开始安装的“安装”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+“安装”阶段已成功完成,正在开始“提交”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+“提交”阶段已成功完成。
+
+已完成事务处理安装。
+
+
+正在开始卸载。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+卸载完成。
+
+正在运行事务处理安装。
+
+正在开始安装的“安装”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+“安装”阶段已成功完成,正在开始“提交”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+“提交”阶段已成功完成。
+
+已完成事务处理安装。
+
+正在运行事务处理安装。
+
+正在开始安装的“安装”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+在“安装”阶段发生异常。
+System.ComponentModel.Win32Exception: 指定的服务已存在。
+
+正在开始安装的“回退”阶段。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+“回退”阶段已成功完成。
+
+已完成事务处理安装。
+
+
+正在开始卸载。
+查看日志文件的内容以获得 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+卸载完成。
+
+正在运行事务处理安装。
+
+正在开始安装的“安装”阶段。
+查看日志文件的内容以获得 G:\live_zhaorui\ZrryAdmin\ZrryAdmin_api\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 G:\live_zhaorui\ZrryAdmin\ZrryAdmin_api\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+在“安装”阶段发生异常。
+System.Security.SecurityException: 未找到源,但未能搜索某些或全部事件日志。 不可访问的日志: Security。
+
+正在开始安装的“回退”阶段。
+查看日志文件的内容以获得 G:\live_zhaorui\ZrryAdmin\ZrryAdmin_api\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe 程序集的进度。
+该文件位于 G:\live_zhaorui\ZrryAdmin\ZrryAdmin_api\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.InstallLog。
+
+“回退”阶段已成功完成。
+
+已完成事务处理安装。
diff --git a/Quartz.NET.WindowsService/Program.cs b/Quartz.NET.WindowsService/Program.cs
new file mode 100644
index 0000000..41d4d3b
--- /dev/null
+++ b/Quartz.NET.WindowsService/Program.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.ServiceProcess;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Quartz.NET.WindowsService
+{
+ static class Program
+ {
+ ///
+ /// 应用程序的主入口点。
+ ///
+ static void Main()
+ {
+ ServiceBase[] ServicesToRun;
+ ServicesToRun = new ServiceBase[]
+ {
+ new Service1()
+ };
+ ServiceBase.Run(ServicesToRun);
+ }
+ }
+}
diff --git a/Quartz.NET.WindowsService/ProjectInstaller.Designer.cs b/Quartz.NET.WindowsService/ProjectInstaller.Designer.cs
new file mode 100644
index 0000000..16c343d
--- /dev/null
+++ b/Quartz.NET.WindowsService/ProjectInstaller.Designer.cs
@@ -0,0 +1,57 @@
+namespace Quartz.NET.WindowsService
+{
+ partial class ProjectInstaller
+ {
+ ///
+ /// 必需的设计器变量。
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// 清理所有正在使用的资源。
+ ///
+ /// 如果应释放托管资源,为 true;否则为 false。
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region 组件设计器生成的代码
+
+ ///
+ /// 设计器支持所需的方法 - 不要修改
+ /// 使用代码编辑器修改此方法的内容。
+ ///
+ private void InitializeComponent()
+ {
+ this.serviceProcessInstaller1 = new System.ServiceProcess.ServiceProcessInstaller();
+ this.Quartz定时作业 = new System.ServiceProcess.ServiceInstaller();
+ //
+ // serviceProcessInstaller1
+ //
+ this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalService;
+ this.serviceProcessInstaller1.Password = null;
+ this.serviceProcessInstaller1.Username = null;
+ //
+ // Quartz定时作业
+ //
+ this.Quartz定时作业.ServiceName = "Quartz.Net";
+ //
+ // ProjectInstaller
+ //
+ this.Installers.AddRange(new System.Configuration.Install.Installer[] {
+ this.serviceProcessInstaller1,
+ this.Quartz定时作业});
+
+ }
+
+ #endregion
+
+ private System.ServiceProcess.ServiceProcessInstaller serviceProcessInstaller1;
+ private System.ServiceProcess.ServiceInstaller Quartz定时作业;
+ }
+}
\ No newline at end of file
diff --git a/Quartz.NET.WindowsService/ProjectInstaller.cs b/Quartz.NET.WindowsService/ProjectInstaller.cs
new file mode 100644
index 0000000..44e798c
--- /dev/null
+++ b/Quartz.NET.WindowsService/ProjectInstaller.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Configuration.Install;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Quartz.NET.WindowsService
+{
+ [RunInstaller(true)]
+ public partial class ProjectInstaller : System.Configuration.Install.Installer
+ {
+ public ProjectInstaller()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/Quartz.NET.WindowsService/ProjectInstaller.resx b/Quartz.NET.WindowsService/ProjectInstaller.resx
new file mode 100644
index 0000000..4cff6ae
--- /dev/null
+++ b/Quartz.NET.WindowsService/ProjectInstaller.resx
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 17, 17
+
+
+ 243, 17
+
+
+ False
+
+
\ No newline at end of file
diff --git a/Quartz.NET.WindowsService/Properties/AssemblyInfo.cs b/Quartz.NET.WindowsService/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..77e1722
--- /dev/null
+++ b/Quartz.NET.WindowsService/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 有关程序集的一般信息由以下
+// 控制。更改这些特性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("Quartz.NET.WindowsService")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("Quartz.NET.WindowsService")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 将 ComVisible 设置为 false 会使此程序集中的类型
+//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
+//请将此类型的 ComVisible 特性设置为 true。
+[assembly: ComVisible(false)]
+
+// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
+[assembly: Guid("3040dd22-663e-44cb-909b-3d0043867361")]
+
+// 程序集的版本信息由下列四个值组成:
+//
+// 主版本
+// 次版本
+// 生成号
+// 修订号
+//
+// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
+// 方法是按如下所示使用“*”: :
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Quartz.NET.WindowsService/Quartz.NET.WindowsService.csproj b/Quartz.NET.WindowsService/Quartz.NET.WindowsService.csproj
new file mode 100644
index 0000000..8cfb182
--- /dev/null
+++ b/Quartz.NET.WindowsService/Quartz.NET.WindowsService.csproj
@@ -0,0 +1,108 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {3040DD22-663E-44CB-909B-3D0043867361}
+ WinExe
+ Quartz.NET.WindowsService
+ Quartz.NET.WindowsService
+ v4.6.1
+ 512
+ true
+ true
+ false
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ true
+ 0
+ 1.0.0.%2a
+ false
+ true
+ SAK
+ SAK
+ SAK
+ SAK
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Component
+
+
+ ProjectInstaller.cs
+
+
+ Component
+
+
+ Service1.cs
+
+
+
+
+
+
+
+
+
+
+ ProjectInstaller.cs
+
+
+
+
+ False
+ Microsoft .NET Framework 4.6.1 %28x86 和 x64%29
+ true
+
+
+ False
+ .NET Framework 3.5 SP1
+ false
+
+
+
+
\ No newline at end of file
diff --git a/Quartz.NET.WindowsService/Service1.Designer.cs b/Quartz.NET.WindowsService/Service1.Designer.cs
new file mode 100644
index 0000000..6e8203e
--- /dev/null
+++ b/Quartz.NET.WindowsService/Service1.Designer.cs
@@ -0,0 +1,37 @@
+namespace Quartz.NET.WindowsService
+{
+ partial class Service1
+ {
+ ///
+ /// 必需的设计器变量。
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// 清理所有正在使用的资源。
+ ///
+ /// 如果应释放托管资源,为 true;否则为 false。
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region 组件设计器生成的代码
+
+ ///
+ /// 设计器支持所需的方法 - 不要修改
+ /// 使用代码编辑器修改此方法的内容。
+ ///
+ private void InitializeComponent()
+ {
+ components = new System.ComponentModel.Container();
+ this.ServiceName = "Service1";
+ }
+
+ #endregion
+ }
+}
diff --git a/Quartz.NET.WindowsService/Service1.cs b/Quartz.NET.WindowsService/Service1.cs
new file mode 100644
index 0000000..a346aac
--- /dev/null
+++ b/Quartz.NET.WindowsService/Service1.cs
@@ -0,0 +1,94 @@
+using System;
+using System.Configuration;
+using System.IO;
+using System.Net;
+using System.ServiceProcess;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Quartz.NET.WindowsService
+{
+ public partial class Service1 : ServiceBase
+ {
+ public Service1()
+ {
+ InitializeComponent();
+ }
+
+ protected override void OnStart(string[] args)
+ {
+ Task.Run(() =>
+ {
+ Start();
+ });
+ }
+ private void Start()
+ {
+ string path = AppDomain.CurrentDomain.BaseDirectory + "\\log\\";
+ //默认1分钟调用一次
+ int interval = 1;
+ string message = "";
+ string url = "";
+ while (true)
+ {
+ try
+ {
+ ConfigurationManager.RefreshSection("appSettings");
+ url = ConfigurationManager.AppSettings["url"];
+ interval = Convert.ToInt32(ConfigurationManager.AppSettings["interval"]);
+
+ HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
+ using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
+ {
+ Stream responseStream = response.GetResponseStream();
+ StreamReader streamReader = new StreamReader(responseStream, Encoding.UTF8);
+ message = streamReader.ReadToEnd();
+ }
+ }
+ catch (Exception ex)
+ {
+ message= url+ ",interval:["+ interval + "],"+ ex.Message;
+ }
+ finally
+ {
+ try
+ {
+ message = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "__" + message + "\r\n";
+ WriteFile(path, DateTime.Now.ToString("yyyy-MM-dd") + ".txt", message, true);
+ }
+ catch (Exception ex)
+ {
+ }
+ Thread.Sleep(new TimeSpan(0,interval,0));
+ }
+ }
+ }
+
+ private static void WriteFile(string path, string fileName, string content, bool appendToLast = false)
+ {
+ if (!Directory.Exists(path))//如果不存在就创建file文件夹
+ {
+ Directory.CreateDirectory(path);
+ }
+
+ using (FileStream stream = File.Open(path + fileName, FileMode.OpenOrCreate, FileAccess.Write))
+ {
+ byte[] by = Encoding.Default.GetBytes(content);
+ if (appendToLast)
+ {
+ stream.Position = stream.Length;
+ }
+ else
+ {
+ stream.SetLength(0);
+ }
+ stream.Write(by, 0, by.Length);
+ }
+ }
+
+ protected override void OnStop()
+ {
+ }
+ }
+}
diff --git a/Quartz.NET.WindowsService/Uninstall.bat b/Quartz.NET.WindowsService/Uninstall.bat
new file mode 100644
index 0000000..6890df3
--- /dev/null
+++ b/Quartz.NET.WindowsService/Uninstall.bat
@@ -0,0 +1 @@
+%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\installutil.exe /u E:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe
\ No newline at end of file
diff --git a/Quartz.NET.WindowsService/packages.config b/Quartz.NET.WindowsService/packages.config
new file mode 100644
index 0000000..3dc6218
--- /dev/null
+++ b/Quartz.NET.WindowsService/packages.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Quartz.NET.WindowsService/使用说明.txt b/Quartz.NET.WindowsService/使用说明.txt
new file mode 100644
index 0000000..2eda9c4
--- /dev/null
+++ b/Quartz.NET.WindowsService/使用说明.txt
@@ -0,0 +1,9 @@
+Èç¹ûÄãֻÊǽ«quartz.net·¢²¼µ½IIS£¬IISӦÓóػØÊպó¾Ͳ»ÄÜִÐÐÈÎÎñÁˣ¬ÄÇô¿ÉÒÔʹÓôËwindows·þÎñÆ÷¶¨ʱµ÷ÓÃquartz.netվµã
+
+1¡¢ÐÄApp.configÖеÄurlÊôÐÔvalueֵΪÄ㵱ǰ²¿ÊðµÄquertz.netµÄվµã+/Health/index£¨עÒ⣺Èç¹ûÊDZàÒëºóµÄÏîĿ£¬һ¶¨ҪÐÄbin/Debug/Quartz.NET.WindowsService.exe.configµÄÅäÖÃurl£©
+2¡¢ÓüÇʱ¾´ò¿ªInstall.batÎļþÐÄE:\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe
+¸ÄΪ£º(ÕâÀïÌîдÄãÏîĿËùÔÚ·¾¶)\Quartz.NET\Quartz.NET.WindowsService\bin\Debug\Quartz.NET.WindowsService.exe
+3¡¢±àÒëÏîĿ
+4¡¢µã»÷Install.bat°²װwindows·þÎñ
+
+жÔطþÎñ£ºÔËÐÐUninstall.bat(ÔËÐÐǰ°´ÉÏÃæһÑù½«ÐÄQuartz.NET.WindowsService.exe·¾¶)
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..0c6c790
--- /dev/null
+++ b/README.md
@@ -0,0 +1,107 @@
+# ZRAdmin.NET
+
+## 🍟概述
+* 本项目适合有一定NetCore和 vue基础的开发人员
+* 基于.NET 5实现的通用权限管理平台(RBAC模式)。整合最新技术高效快速开发,前后端分离模式,开箱即用。
+* 模块化架构设计,层次清晰,业务层推荐写到单独模块,框架升级不影响业务!
+* 代码量少、通俗易懂、功能强大、易扩展,轻松开发从现在开始!
+* 前端采用Vue2.0、Element UI。
+* 后端采用Net5、Sqlsugar、MySQL。
+* 权限认证使用Jwt,支持多终端认证系统。
+* 支持加载动态权限菜单,多方式轻松权限控制
+* 基于若依vue分离版本(java版本)修改
+
+~ 如果对您有帮助,您可以点右上角 “Star” 收藏一下 ,获取第一时间更新,谢谢!~
+
+## 🍿在线体验
+体验地址:http://www.izory.cn:8080/
+管理员:admin
+密 码:123456
+
+**由于是个人项目,资金有限,体验服是低配,请大家爱惜,轻戳,不胜感激!!!**
+
+## 🥼前端技术
+Vue版前端技术栈 :基于vue、vuex、vue-router 、vue-cli 、axios 和 element-ui,前端采用vscode工具开发
+
+## 🥼后端技术
+核心框架:.Net5.0 + Web API + sqlsugar + swagger
+
+定时计划任务:Quartz.Net组件
+
+安全支持:过滤器、Sql注入、请求伪造
+
+日志管理:NLog、登录日志、操作日志
+
+工具类:验证码、丰富公共功能
+
+## 🍄快速启动
+需要安装:VS2019(最新版)、npm或yarn(最新版)
+准备工作:将document文件夹下面的admin.sql脚本导入到数据库中,修改ZRAdmin项目里面的Conn_Admin数据库连接字符串以及DbType选择对应的数据库类型,目前仅MySQL验证了
+启动后台:打开项目根目录的startup.bat即可启动(数据库默认MySQL)
+启动前端:打开ZR.Vue文件夹,运行npm install命令,再运行npm run serve启动
+浏览器访问:http://localhost:8887 (默认前端端口为:8887,后台端口为:8888)
+
+
+## 🍖内置功能
+
+1. [X] 用户管理:用户是系统操作者,该功能主要完成系统用户配置。
+2. [X] 部门管理:配置系统组织机构(公司、部门、小组),树结构展现。
+3. [X] 岗位管理:配置系统用户所属担任职务。
+4. [X] 菜单管理:配置系统菜单,操作权限,按钮权限标识等。
+5. [X] 角色管理:角色菜单权限分配。
+6. [X] 字典管理:对系统中经常使用的一些较为固定的数据进行维护。
+7. [ ] 参数管理:对系统动态配置常用参数。
+8. [X] 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。
+9. [X] 登录日志:系统登录日志记录查询包含登录异常。
+10. [ ] 在线用户:当前系统中活跃用户状态监控。
+11. [X] 系统接口:使用swagger生成相关api接口文档。
+12. [X] 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。
+13. [X] 在线构建器:拖动表单元素生成相应的VUE代码。
+14. [X] 任务系统:基于Quartz.NET定时任务执行。
+15. [X] 文章管理:可以写文章记录。
+
+## 🍎演示图
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## 🎉优势
+
+1. 前台系统不用编写登录、授权、认证模块;只负责编写业务模块即可
+2. 后台系统无需任何二次开发,直接发布即可使用
+3. 前台与后台系统分离,分别为不同的系统(域名可独立)
+4. 全局异常统一处理
+
+## 💐 特别鸣谢
+- 👉Ruoyi.vue:[Ruoyi](http://www.ruoyi.vip/)
+- 👉SqlSugar:https://gitee.com/dotnetchina/SqlSugar
+
+## 🍻参与贡献
+- Fork 本项目
+- 新建 Feat_xxx 分支
+- 提交代码
+- 新建 Pull Request
+
+## 🎀捐赠
+如果这个项目对您有所帮助,请扫下方二维码打赏一杯咖啡。
+
\ No newline at end of file
diff --git a/ZR.Admin.WebApi/.config/dotnet-tools.json b/ZR.Admin.WebApi/.config/dotnet-tools.json
new file mode 100644
index 0000000..c735fef
--- /dev/null
+++ b/ZR.Admin.WebApi/.config/dotnet-tools.json
@@ -0,0 +1,12 @@
+{
+ "version": 1,
+ "isRoot": true,
+ "tools": {
+ "dotnet-ef": {
+ "version": "5.0.0",
+ "commands": [
+ "dotnet-ef"
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/ZR.Admin.WebApi/Controllers/BaseController.cs b/ZR.Admin.WebApi/Controllers/BaseController.cs
new file mode 100644
index 0000000..49413f1
--- /dev/null
+++ b/ZR.Admin.WebApi/Controllers/BaseController.cs
@@ -0,0 +1,101 @@
+using Infrastructure;
+using Infrastructure.Model;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Serialization;
+using ZR.Admin.WebApi.Filters;
+
+namespace ZR.Admin.WebApi.Controllers
+{
+ [LogActionFilter]
+ public class BaseController : ControllerBase
+ {
+ private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
+
+ public static string TIME_FORMAT_FULL = "yyyy-MM-dd HH:mm:ss";
+ public static string TIME_FORMAT_FULL_2 = "MM-dd HH:mm:ss";
+
+ protected IActionResult SUCCESS(object data, string timeFormatStr = "MM-dd HH:mm:ss")
+ {
+ string jsonStr = GetJsonStr(GetApiResult(data != null ? ResultCode.SUCCESS : ResultCode.FAIL, data), timeFormatStr);
+ return Content(jsonStr, "application/json");
+ }
+
+ ///
+ /// json输出带时间格式的
+ ///
+ ///
+ ///
+ ///
+ protected IActionResult OutputJson(ApiResult apiResult, string timeFormatStr = "MM-dd HH:mm:ss")
+ {
+ string jsonStr = GetJsonStr(apiResult, timeFormatStr);
+
+ return Content(jsonStr, "application/json");
+ }
+ protected IActionResult OutputJson(long rows, string timeFormatStr = "MM-dd HH:mm:ss")
+ {
+ string jsonStr = GetJsonStr(ToJson(rows), timeFormatStr);
+
+ return Content(jsonStr, "application/json");
+ }
+ protected string SerializeObject(object obj)
+ {
+ return JsonConvert.SerializeObject(obj);
+ }
+
+ ///
+ /// 响应返回结果
+ ///
+ /// 受影响行数
+ ///
+ 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)
+ {
+ 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);
+ }
+
+ protected IActionResult CustomError(ResultCode resultCode, string msg = "")
+ {
+ return OutputJson(GetApiResult(resultCode, msg));
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/Controllers/HomeController.cs b/ZR.Admin.WebApi/Controllers/HomeController.cs
new file mode 100644
index 0000000..96bb587
--- /dev/null
+++ b/ZR.Admin.WebApi/Controllers/HomeController.cs
@@ -0,0 +1,53 @@
+using Infrastructure;
+using Infrastructure.Attribute;
+using Microsoft.AspNetCore.Mvc;
+using System;
+
+namespace ZR.Admin.WebApi.Controllers
+{
+ public class HomeController : BaseController
+ {
+ ///
+ /// 心跳
+ ///
+ ///
+ [HttpGet, Route("health/index")]
+ [Log()]
+ public IActionResult Health()
+ {
+ return SUCCESS(true);
+ }
+
+ ///
+ /// 加密
+ ///
+ ///
+ ///
+ public IActionResult Encrypt(string content)
+ {
+ if (string.IsNullOrEmpty(content))
+ {
+ throw new Exception("content不能为空");
+ }
+ string key = ConfigUtils.Instance.GetConfig("DbKey");
+ string encryptTxt = NETCore.Encrypt.EncryptProvider.DESEncrypt(content, key);
+ return Ok(new { content, encryptTxt });
+ }
+
+ ///
+ /// 解密
+ ///
+ ///
+ ///
+ public IActionResult Decrypt(string content)
+ {
+ if (string.IsNullOrEmpty(content))
+ {
+ throw new Exception("content不能为空");
+ }
+ string key = ConfigUtils.Instance.GetConfig("DbKey");
+ string encryptTxt = NETCore.Encrypt.EncryptProvider.DESDecrypt(content, key);
+ return Ok(new { content, encryptTxt });
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/Controllers/System/ArticleController.cs b/ZR.Admin.WebApi/Controllers/System/ArticleController.cs
new file mode 100644
index 0000000..4cd19b3
--- /dev/null
+++ b/ZR.Admin.WebApi/Controllers/System/ArticleController.cs
@@ -0,0 +1,169 @@
+
+//------------------------------------------------------------------------------
+//
+// 此代码已从模板生成。
+//
+// 手动更改此文件可能导致应用程序出现意外的行为。
+// 如果重新生成代码,将覆盖对此文件的手动更改。
+//
+//------------------------------------------------------------------------------
+
+using Infrastructure.Attribute;
+using Microsoft.AspNetCore.Mvc;
+using ZR.Admin.WebApi.Filters;
+using ZR.Model.System;
+using ZR.Service.IService;
+using Infrastructure.Model;
+using SqlSugar;
+using Mapster;
+using ZR.Model.Dto.System;
+using Infrastructure.Enums;
+using Infrastructure;
+using ZR.Admin.WebApi.Extensions;
+using System.Reflection;
+using System;
+
+namespace ZR.Admin.WebApi.Controllers
+{
+ ///
+ /// T4代码自动生成
+ ///
+ [Verify]
+ [Route("article")]
+ public class ArticleController : BaseController
+ {
+ ///
+ /// 文章接口
+ ///
+ private readonly IArticleService _ArticleService;
+ private readonly IArticleCategoryService _ArticleCategoryService;
+
+ public ArticleController(IArticleService ArticleService, IArticleCategoryService articleCategoryService)
+ {
+ _ArticleService = ArticleService;
+ _ArticleCategoryService = articleCategoryService;
+ }
+
+ ///
+ /// 查询文章列表
+ ///
+ ///
+ [HttpGet("list")]
+ [ActionPermissionFilter(Permission = "system:article:list")]
+ public IActionResult Query([FromQuery] ArticleQueryDto parm)
+ {
+ //开始拼装查询条件
+ var predicate = Expressionable.Create();
+
+ //搜索条件
+ predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.Title), m => m.Title.Contains(parm.Title));
+ predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.Status), m => m.Status == parm.Status);
+
+ var response = _ArticleService.GetPages(predicate.ToExpression(), parm, f => f.Cid, "Desc");
+
+ return SUCCESS(response);
+ }
+
+ ///
+ /// 获取文章目录,前端没用到
+ ///
+ ///
+ [HttpGet("CategoryList")]
+ public IActionResult CategoryList()
+ {
+ var response = _ArticleCategoryService.GetAll();
+ return SUCCESS(response);
+ }
+
+ ///
+ /// 获取文章目录树
+ ///
+ ///
+ [HttpGet("CategoryTreeList")]
+ public IActionResult CategoryTreeList()
+ {
+ var response = _ArticleCategoryService.BuildCategoryTree(_ArticleCategoryService.GetAll());
+ return SUCCESS(response);
+ }
+
+ ///
+ /// 查询文章详情
+ ///
+ ///
+ ///
+ [HttpGet("{id}")]
+ public IActionResult Get(int id)
+ {
+ var response = _ArticleService.GetId(id);
+
+ return SUCCESS(response);
+ }
+
+ ///
+ /// 添加文章
+ ///
+ ///
+ [HttpPost("add")]
+ [ActionPermissionFilter(Permission = "system:article:add")]
+ [Log(Title = "文章添加", BusinessType = BusinessType.INSERT)]
+ public IActionResult Create([FromBody] Article parm)
+ {
+ if (parm == null)
+ {
+ throw new CustomException("请求参数错误");
+ }
+ //从 Dto 映射到 实体
+ var addModel = parm.Adapt().ToCreate(context: HttpContext);
+ addModel.AuthorName = User.Identity.Name;
+
+ return SUCCESS(_ArticleService.Add(addModel));
+ }
+
+ ///
+ /// 更新文章
+ ///
+ ///
+ [HttpPut("edit")]
+ [ActionPermissionFilter(Permission = "system:article:update")]
+ [Log(Title = "文章修改", BusinessType = BusinessType.UPDATE)]
+ public IActionResult Update([FromBody] Article parm)
+ {
+ //从 Dto 映射到 实体
+ var addModel = parm.Adapt().ToCreate(context: HttpContext);
+ addModel.AuthorName = User.Identity.Name;
+
+ var response = _ArticleService.Update(it => it.Cid == addModel.Cid,
+ f => new Article
+ {
+ Title = addModel.Title,
+ Content = addModel.Content,
+ Tags = addModel.Tags,
+ Category_id = addModel.Category_id,
+ UpdateTime = addModel.UpdateTime
+ }).ToCreate();
+
+ return SUCCESS(response);
+ }
+
+ ///
+ /// 删除文章
+ ///
+ ///
+ [HttpDelete("{id}")]
+ [ActionPermissionFilter(Permission = "system:article:delete")]
+ [Log(Title = "文章删除", BusinessType = BusinessType.DELETE)]
+ public IActionResult Delete(int id = 0)
+ {
+ if (id <= 0)
+ {
+ return OutputJson(ApiResult.Error($"删除失败Id 不能为空"));
+ }
+
+ // 删除文章
+ var response = _ArticleService.Delete(id);
+
+ return SUCCESS(response);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/ZR.Admin.WebApi/Controllers/System/SysConfigController.cs b/ZR.Admin.WebApi/Controllers/System/SysConfigController.cs
new file mode 100644
index 0000000..a29eccd
--- /dev/null
+++ b/ZR.Admin.WebApi/Controllers/System/SysConfigController.cs
@@ -0,0 +1,23 @@
+using Microsoft.AspNetCore.Mvc;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using ZR.Admin.WebApi.Filters;
+
+namespace ZR.Admin.WebApi.Controllers.System
+{
+ ///
+ /// 配置文件
+ ///
+ [Verify]
+ [Route("system/config")]
+ public class SysConfigController : BaseController
+ {
+ [HttpGet("list")]
+ public IActionResult Index()
+ {
+ return SUCCESS(1);
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/Controllers/System/SysDeptController.cs b/ZR.Admin.WebApi/Controllers/System/SysDeptController.cs
new file mode 100644
index 0000000..8dec679
--- /dev/null
+++ b/ZR.Admin.WebApi/Controllers/System/SysDeptController.cs
@@ -0,0 +1,149 @@
+using Infrastructure;
+using Infrastructure.Attribute;
+using Infrastructure.Enums;
+using Microsoft.AspNetCore.Mvc;
+using System.Collections;
+using ZR.Admin.WebApi.Filters;
+using ZR.Common;
+using ZR.Model.System;
+using ZR.Service;
+using ZR.Service.IService;
+
+namespace ZR.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("{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 OutputJson(GetApiResult(ResultCode.CUSTOM_ERROR, $"新增部门{dept.DeptName}失败,部门名称已存在"));
+ }
+ dept.Create_by = User.Identity.Name;
+ return OutputJson(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 OutputJson(GetApiResult(ResultCode.CUSTOM_ERROR, $"修改部门{dept.DeptName}失败,部门名称已存在"));
+ }
+ else if (dept.ParentId.Equals(dept.DeptId))
+ {
+ return OutputJson(GetApiResult(ResultCode.CUSTOM_ERROR, $"修改部门{dept.DeptName}失败,上级部门不能是自己"));
+ }
+ dept.Update_by = User.Identity.Name;
+ return OutputJson(ToJson(DeptService.UpdateDept(dept)));
+ }
+
+ ///
+ /// 删除部门
+ ///
+ ///
+ [HttpDelete("{deptId}")]
+ [ActionPermissionFilter(Permission = "system:dept:remove")]
+ [Log(Title = "部门管理", BusinessType = BusinessType.DELETE)]
+ public IActionResult Remove(long deptId)
+ {
+ if (DeptService.GetCount(it => it.ParentId == deptId && it.DelFlag == "0") > 0)
+ {
+ return OutputJson(GetApiResult(ResultCode.CUSTOM_ERROR, $"存在下级部门,不允许删除"));
+ }
+ if (UserService.GetCount(it => it.DeptId == deptId && it.DelFlag == "0") > 0)
+ {
+ return OutputJson(GetApiResult(ResultCode.CUSTOM_ERROR, $"部门存在用户,不允许删除"));
+ }
+
+ return SUCCESS(DeptService.Delete(deptId));
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/Controllers/System/SysDictDataController.cs b/ZR.Admin.WebApi/Controllers/System/SysDictDataController.cs
new file mode 100644
index 0000000..d0968af
--- /dev/null
+++ b/ZR.Admin.WebApi/Controllers/System/SysDictDataController.cs
@@ -0,0 +1,115 @@
+using Infrastructure.Attribute;
+using Infrastructure.Enums;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using System;
+using ZR.Admin.WebApi.Filters;
+using ZR.Model;
+using ZR.Model.System;
+using ZR.Model.Vo;
+using ZR.Service.IService;
+
+namespace ZR.Admin.WebApi.Controllers.System
+{
+ ///
+ /// 数据字典信息
+ /// @author zr
+ ///
+ [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.TotalNum = list.Count;
+ var vm = new VMPageResult(list, pagerInfo);
+ return SUCCESS(vm);
+ }
+
+ ///
+ /// 根据字典类型查询字典数据信息
+ ///
+ ///
+ ///
+ [AllowAnonymous]
+ [HttpGet("type/{dictType}")]
+ public IActionResult DictType(string dictType)
+ {
+ return SUCCESS(SysDictDataService.SelectDictDataByType(dictType));
+ }
+
+ ///
+ /// 查询字典数据详细
+ ///
+ ///
+ ///
+ [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 = User.Identity.Name;
+ 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 = User.Identity.Name;
+ return SUCCESS(SysDictDataService.UpdateDictData(dict));
+ }
+
+ ///
+ /// 删除字典类型
+ ///
+ ///
+ ///
+ [ActionPermissionFilter(Permission = "system:dict:remove")]
+ [Log(Title = "字典类型", BusinessType = BusinessType.DELETE)]
+ [HttpDelete("{dictCode}")]
+ public IActionResult Remove(string dictCode)
+ {
+ long[] dictCodes = ZR.Common.Tools.SpitLongArrary(dictCode);
+
+ return SUCCESS(SysDictDataService.DeleteDictDataByIds(dictCodes));
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/Controllers/System/SysDictTypeController.cs b/ZR.Admin.WebApi/Controllers/System/SysDictTypeController.cs
new file mode 100644
index 0000000..d9c1289
--- /dev/null
+++ b/ZR.Admin.WebApi/Controllers/System/SysDictTypeController.cs
@@ -0,0 +1,111 @@
+using Infrastructure.Attribute;
+using Infrastructure.Enums;
+using Infrastructure.Model;
+using Microsoft.AspNetCore.Mvc;
+using System;
+using ZR.Admin.WebApi.Filters;
+using ZR.Common;
+using ZR.Model;
+using ZR.Model.System;
+using ZR.Model.Vo;
+using ZR.Service.IService;
+
+namespace ZR.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.TotalNum = list.Count;
+ var vm = new VMPageResult(list, pagerInfo);
+ return SUCCESS(vm, TIME_FORMAT_FULL);
+ }
+
+ ///
+ /// 查询字典类型详细
+ ///
+ ///
+ ///
+ [HttpGet("{dictId}")]
+ [ActionPermissionFilter(Permission = "system:dict:query")]
+ public IActionResult GetInfo(long dictId = 0)
+ {
+ return SUCCESS(SysDictService.SelectDictTypeById(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 OutputJson(ApiResult.Error($"新增字典'{dict.DictName}'失败,字典类型已存在"));
+ }
+ //设置添加人
+ dict.Create_by = HttpContext.User.Identity.Name;
+ 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 OutputJson(ApiResult.Error($"修改字典'{dict.DictName}'失败,字典类型已存在"));
+ }
+ //设置添加人
+ dict.Update_by = HttpContext.User.Identity.Name;
+ 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));
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/Controllers/System/SysLoginController.cs b/ZR.Admin.WebApi/Controllers/System/SysLoginController.cs
new file mode 100644
index 0000000..b363ab8
--- /dev/null
+++ b/ZR.Admin.WebApi/Controllers/System/SysLoginController.cs
@@ -0,0 +1,148 @@
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using ZR.Admin.WebApi.Extensions;
+using ZR.Admin.WebApi.Filters;
+using ZR.Admin.WebApi.Framework;
+using Infrastructure.Model;
+using Infrastructure;
+using Infrastructure.Attribute;
+using ZR.Model.System;
+using ZR.Model.Dto.System;
+using ZR.Service.IService;
+using Hei.Captcha;
+using ZR.Common;
+
+namespace ZR.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;
+
+ public SysLoginController(
+ IHttpContextAccessor contextAccessor,
+ ISysMenuService sysMenuService,
+ ISysUserService sysUserService,
+ ISysLoginService sysLoginService,
+ ISysPermissionService permissionService,
+ SecurityCodeHelper captcha)
+ {
+ httpContextAccessor = contextAccessor;
+ SecurityCodeHelper = captcha;
+ this.sysMenuService = sysMenuService;
+ this.sysUserService = sysUserService;
+ this.sysLoginService = sysLoginService;
+ this.permissionService = permissionService;
+ }
+
+
+ ///
+ /// 登录
+ ///
+ /// 登录对象
+ ///
+ [Route("login")]
+ [HttpPost]
+ [Log(Title = "登录")]
+ public IActionResult Login([FromBody] LoginBodyDto loginBody)
+ {
+ if (loginBody == null) { throw new CustomException("请求参数错误"); }
+ loginBody.LoginIP = HttpContextExtension.GetClientUserIp(HttpContext);
+ if (CacheHelper.Get(loginBody.Uuid) is string str && !str.ToLower().Equals(loginBody.Code.ToLower()))
+ {
+ throw new CustomException(ResultCode.CAPTCHA_ERROR, "验证码错误");
+ }
+
+ var user = sysLoginService.Login(loginBody, AsyncFactory.RecordLogInfo(httpContextAccessor.HttpContext, "0", "login"));
+ #region 存入cookie Action校验权限使用
+ //角色集合 eg: admin,yunying,common
+ List roles = permissionService.GetRolePermission(user);
+ //权限集合 eg *:*:*,system:user:list
+ List permissions = permissionService.GetMenuPermission(user);
+ #endregion
+ LoginUser loginUser = new LoginUser(user.UserId, user.UserName, roles, permissions);
+
+ return SUCCESS(JwtUtil.GenerateJwtToken(HttpContext.WriteCookies(loginUser)));
+ }
+
+ ///
+ /// 注销
+ ///
+ ///
+ [Log(Title = "注销")]
+ [HttpPost("logout")]
+ public IActionResult LogOut()
+ {
+ Task.Run(async () =>
+ {
+ //注销登录的用户,相当于ASP.NET中的FormsAuthentication.SignOut
+ await HttpContext.SignOutAsync();
+ }).Wait();
+
+ return SUCCESS(1);
+ }
+
+ ///
+ /// 获取用户信息
+ ///
+ ///
+ [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);
+
+ return SUCCESS(new { user, roles, permissions });
+ }
+
+ ///
+ /// 获取路由信息
+ ///
+ ///
+ [Verify]
+ [HttpGet("getRouters")]
+ public IActionResult GetRouters()
+ {
+ long uid = HttpContext.GetUId();
+ var menus = sysMenuService.SelectMenuTreeByUserId(uid);
+
+ return OutputJson(ToJson(1, sysMenuService.BuildMenus(menus)));
+ }
+
+ ///
+ /// 生成图片验证码
+ ///
+ ///
+ [HttpGet("captchaImage")]
+ public ApiResult CaptchaImage()
+ {
+ string uuid = Guid.NewGuid().ToString().Replace("-", "");
+ var code = SecurityCodeHelper.GetRandomEnDigitalText(4);
+ var imgByte = SecurityCodeHelper.GetGifEnDigitalCodeByte(code);
+ string base64Str = Convert.ToBase64String(imgByte);
+ CacheHelper.SetCache(uuid, code);
+ var obj = new { uuid, img = base64Str };// File(stream, "image/png")
+
+ return ToJson(1, obj);
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/Controllers/System/SysMenuController.cs b/ZR.Admin.WebApi/Controllers/System/SysMenuController.cs
new file mode 100644
index 0000000..27dd846
--- /dev/null
+++ b/ZR.Admin.WebApi/Controllers/System/SysMenuController.cs
@@ -0,0 +1,181 @@
+using Infrastructure;
+using Infrastructure.Attribute;
+using Infrastructure.Enums;
+using Infrastructure.Model;
+using Microsoft.AspNetCore.Mvc;
+using ZR.Admin.WebApi.Extensions;
+using ZR.Admin.WebApi.Filters;
+using ZR.Model.Dto.System;
+using ZR.Model.System;
+using ZR.Service;
+using ZR.Service.IService;
+
+namespace ZR.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 MenuList([FromQuery] SysMenu menu)
+ {
+ long userId = HttpContext.GetUId();
+ return SUCCESS(sysMenuService.SelectMenuList(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("treeSelect")]
+ public IActionResult TreeSelect()
+ {
+ long userId = HttpContext.GetUId();
+ var list = sysMenuService.SelectMenuList(new SysMenu(), userId).FindAll(f => f.visible == "0");
+ var treeMenus = sysMenuService.BuildMenuTreeSelect(list);
+
+ return SUCCESS(treeMenus);
+ }
+
+ ///
+ /// 获取角色菜单信息
+ /// 加载对应角色菜单列表树
+ ///
+ ///
+ ///
+ [HttpGet("roleMenuTreeselect/{roleId}")]
+ public IActionResult RoleMenuTreeselect(int roleId)
+ {
+ long userId = HttpContext.GetUId();
+ var menus = sysMenuService.SelectMenuList(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] SysMenu MenuDto)
+ {
+ if (MenuDto == null) { return OutputJson(ApiResult.Error(101, "请求参数错误")); }
+ //if (UserConstants.NOT_UNIQUE.Equals(sysMenuService.CheckMenuNameUnique(MenuDto)))
+ //{
+ // return OutputJson(ApiResult.Error($"修改菜单'{MenuDto.menuName}'失败,菜单名称已存在"));
+ //}
+ if (UserConstants.YES_FRAME.Equals(MenuDto.isFrame) && !MenuDto.path.StartsWith("http"))
+ {
+ return OutputJson(ApiResult.Error($"修改菜单'{MenuDto.menuName}'失败,地址必须以http(s)://开头"));
+ }
+ if (MenuDto.menuId.Equals(MenuDto.parentId))
+ {
+ return OutputJson(ApiResult.Error($"修改菜单'{MenuDto.menuName}'失败,上级菜单不能选择自己"));
+ }
+ MenuDto.Update_by = User.Identity.Name;
+ int result = sysMenuService.EditMenu(MenuDto);
+
+ return OutputJson(result);
+ }
+
+ ///
+ /// 添加菜单 √
+ ///
+ ///
+ ///
+ [HttpPut("add")]
+ [Log(Title = "菜单管理", BusinessType = BusinessType.INSERT)]
+ [ActionPermissionFilter(Permission = "system:menu:add")]
+ public IActionResult MenuAdd([FromBody] SysMenu MenuDto)
+ {
+ if (MenuDto == null) { return OutputJson(ApiResult.Error(101, "请求参数错误")); }
+ if (UserConstants.NOT_UNIQUE.Equals(sysMenuService.CheckMenuNameUnique(MenuDto)))
+ {
+ return OutputJson(ApiResult.Error($"新增菜单'{MenuDto.menuName}'失败,菜单名称已存在"));
+ }
+ if (UserConstants.YES_FRAME.Equals(MenuDto.isFrame) && !MenuDto.path.StartsWith("http"))
+ {
+ return OutputJson(ApiResult.Error($"新增菜单'{MenuDto.menuName}'失败,地址必须以http(s)://开头"));
+ }
+
+ MenuDto.Create_by = User.Identity.Name;
+ int result = sysMenuService.AddMenu(MenuDto);
+
+ return OutputJson(result);
+ }
+
+ ///
+ /// 菜单删除 √
+ ///
+ ///
+ ///
+ [HttpDelete("{menuId}")]
+ [Log(Title = "菜单管理", BusinessType = BusinessType.DELETE)]
+ [ActionPermissionFilter(Permission = "system:menu:remove")]
+ public IActionResult Remove(int menuId = 0)
+ {
+ if (sysMenuService.HasChildByMenuId(menuId))
+ {
+ return CustomError(ResultCode.CUSTOM_ERROR, "存在子菜单,不允许删除");
+ }
+ if (sysMenuService.CheckMenuExistRole(menuId))
+ {
+ return CustomError(ResultCode.CUSTOM_ERROR, "菜单已分配,不允许删除");
+ }
+ int result = sysMenuService.DeleteMenuById(menuId);
+
+ return OutputJson(result);
+ }
+
+ ///
+ /// 保存排序
+ ///
+ ///
+ ///
+ [ActionPermissionFilter(Permission = "system:menu:update")]
+ [HttpPost("ChangeSort")]
+ [Log(Title = "保存排序", BusinessType = BusinessType.UPDATE)]
+ public IActionResult ChangeSort([FromBody] MenuDto MenuDto)
+ {
+ if (MenuDto == null) { return OutputJson(ApiResult.Error(101, "请求参数错误")); }
+
+ int result = sysMenuService.ChangeSortMenu(MenuDto);
+ return OutputJson(result);
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/Controllers/System/SysNoticeController.cs b/ZR.Admin.WebApi/Controllers/System/SysNoticeController.cs
new file mode 100644
index 0000000..4608c15
--- /dev/null
+++ b/ZR.Admin.WebApi/Controllers/System/SysNoticeController.cs
@@ -0,0 +1,18 @@
+using Microsoft.AspNetCore.Mvc;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace ZR.Admin.WebApi.Controllers.System
+{
+ [Route("system/notice")]
+ public class SysNoticeController : BaseController
+ {
+ [HttpGet("list")]
+ public IActionResult Index()
+ {
+ return SUCCESS(null);
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/Controllers/System/SysPostController.cs b/ZR.Admin.WebApi/Controllers/System/SysPostController.cs
new file mode 100644
index 0000000..477ee60
--- /dev/null
+++ b/ZR.Admin.WebApi/Controllers/System/SysPostController.cs
@@ -0,0 +1,123 @@
+using Microsoft.AspNetCore.Mvc;
+using SqlSugar;
+using System.Collections.Generic;
+using ZR.Admin.WebApi.Filters;
+using ZR.Model;
+using ZR.Model.System;
+using Infrastructure.Extensions;
+using Infrastructure.Attribute;
+using Infrastructure.Enums;
+using Infrastructure;
+using ZR.Service.IService;
+
+namespace ZR.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);
+
+ 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.Update_by = User.Identity.Name;
+ return OutputJson(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 = User.Identity.Name;
+ return OutputJson(ToJson(PostService.Update(post)));
+ }
+
+ ///
+ /// 岗位删除
+ ///
+ ///
+ ///
+ [HttpDelete("{id}")]
+ [ActionPermissionFilter(Permission = "system:post:remove")]
+ [Log(Title = "岗位删除", BusinessType = BusinessType.DELETE)]
+ public IActionResult Delete(int id = 0)
+ {
+ return OutputJson(ToJson(PostService.Delete(id)));
+ }
+
+ ///
+ /// 获取岗位选择框列表
+ ///
+ [HttpGet("optionselect")]
+ public IActionResult Optionselect()
+ {
+ List posts = PostService.GetAll();
+ return SUCCESS(posts);
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/Controllers/System/SysProfileController.cs b/ZR.Admin.WebApi/Controllers/System/SysProfileController.cs
new file mode 100644
index 0000000..d1e2172
--- /dev/null
+++ b/ZR.Admin.WebApi/Controllers/System/SysProfileController.cs
@@ -0,0 +1,155 @@
+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.IO;
+using ZR.Admin.WebApi.Extensions;
+using ZR.Admin.WebApi.Filters;
+using ZR.Common;
+using ZR.Model.Dto.System;
+using ZR.Model.System;
+using ZR.Service.IService;
+
+namespace ZR.Admin.WebApi.Controllers.System
+{
+ [Verify]
+ [Route("system/user/profile")]
+ public class SysProfileController : BaseController
+ {
+ private NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
+ private readonly ISysUserService UserService;
+ private readonly ISysRoleService RoleService;
+ private readonly ISysUserPostService UserPostService;
+ private readonly ISysDeptService DeptService;
+ private OptionsSetting OptionsSetting;
+ private IWebHostEnvironment hostEnvironment;
+
+ public SysProfileController(
+ ISysUserService userService,
+ ISysRoleService roleService,
+ ISysUserPostService postService,
+ ISysDeptService deptService,
+ IOptions options,
+ IWebHostEnvironment hostEnvironment)
+ {
+ UserService = userService;
+ RoleService = roleService;
+ UserPostService = postService;
+ DeptService = deptService;
+ OptionsSetting = options.Value;
+ this.hostEnvironment = hostEnvironment;
+ }
+
+ ///
+ /// 个人中心用户信息获取
+ ///
+ ///
+ [HttpGet]
+ public IActionResult Profile()
+ {
+ long userId = HttpContext.GetUId();
+ var user = UserService.SelectUserById(userId);
+
+ user.Roles = RoleService.SelectUserRoleListByUserId(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 = "system")]
+ [Log(Title = "修改信息", BusinessType = BusinessType.UPDATE)]
+ public IActionResult UpdateProfile([FromBody] SysUserDto userDto)
+ {
+ if (userDto == null)
+ {
+ throw new CustomException(ResultCode.PARAM_ERROR, "请求参数错误");
+ }
+ //从 Dto 映射到 实体
+ var user = userDto.Adapt();
+ user.Update_by = User.Identity.Name;
+ user.Update_time = DateTime.Now;
+
+ int result = UserService.ChangeUser(user);
+ return OutputJson(result);
+ }
+
+ ///
+ /// 修改密码
+ ///
+ ///
+ [HttpPut("updatePwd")]
+ [ActionPermissionFilter(Permission = "system")]
+ [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 != oldMd5)
+ {
+ return OutputJson(ApiResult.Error("修改密码失败,旧密码错误"));
+ }
+ if (user.Password == newMd5)
+ {
+ return OutputJson(ApiResult.Error("新密码不能和旧密码相同"));
+ }
+ if (UserService.ResetPwd(loginUser.UserId, newMd5) > 0)
+ {
+ //TODO 更新缓存
+
+ return SUCCESS(1);
+ }
+
+ return OutputJson(ApiResult.Error("修改密码异常,请联系管理员"));
+ }
+
+ ///
+ /// 修改头像
+ ///
+ ///
+ [HttpPost("Avatar")]
+ [ActionPermissionFilter(Permission = "system")]
+ //[Log(Title = "修改头像", BusinessType = BusinessType.UPDATE)]
+ public IActionResult Avatar([FromForm(Name = "picture")] IFormFile formFile)
+ {
+ LoginUser loginUser = Framework.JwtUtil.GetLoginUser(HttpContext);
+
+ if (formFile == null) throw new CustomException("请选择文件");
+
+ string fileExt = Path.GetExtension(formFile.FileName);
+ string savePath = Path.Combine("wwwroot", FileUtil.GetdirPath("uploads"));
+
+ Console.WriteLine(savePath);
+ if (!Directory.Exists(savePath)) { Directory.CreateDirectory(savePath); }
+
+ string fileName = FileUtil.HashFileName() + fileExt;
+ string finalFilePath = savePath + fileName;
+
+ using (var stream = new FileStream(finalFilePath, FileMode.Create))
+ {
+ formFile.CopyToAsync(stream);
+ }
+ string accessUrl = $"{OptionsSetting.Upload.UploadUrl}/{FileUtil.GetdirPath("uploads")}{fileName}";
+
+ UserService.UpdatePhoto(new SysUser() { Avatar = accessUrl, UserId = loginUser.UserId });
+ logger.Info("修改头像:" + accessUrl);
+ return SUCCESS(new { imgUrl = accessUrl });
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/Controllers/System/SysRoleController.cs b/ZR.Admin.WebApi/Controllers/System/SysRoleController.cs
new file mode 100644
index 0000000..1b92d24
--- /dev/null
+++ b/ZR.Admin.WebApi/Controllers/System/SysRoleController.cs
@@ -0,0 +1,172 @@
+using Infrastructure;
+using Infrastructure.Attribute;
+using Infrastructure.Enums;
+using Infrastructure.Model;
+using Microsoft.AspNetCore.Mvc;
+using ZR.Common;
+using ZR.Admin.WebApi.Filters;
+using ZR.Model;
+using ZR.Model.System;
+using ZR.Model.Vo;
+using ZR.Service.IService;
+using ZR.Admin.WebApi.Extensions;
+
+namespace ZR.Admin.WebApi.Controllers.System
+{
+ ///
+ /// 角色信息
+ ///
+ [Verify]
+ [Route("system/role")]
+ public class SysRoleController : BaseController
+ {
+ readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
+
+ 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);
+
+ VMPageResult vMPageResult = new(list, pager);
+
+ return SUCCESS(vMPageResult, 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 OutputJson(ApiResult.Error(101, "请求参数错误"));
+
+ if (UserConstants.NOT_UNIQUE.Equals(sysRoleService.CheckRoleKeyUnique(sysRoleDto)))
+ {
+ return OutputJson(ApiResult.Error((int)ResultCode.CUSTOM_ERROR, $"新增角色'{sysRoleDto.RoleName}'失败,角色权限已存在"));
+ }
+
+ sysRoleDto.Create_by = User.Identity.Name;
+ long roleId = sysRoleService.InsertRole(sysRoleDto);
+
+ return OutputJson(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 OutputJson(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 OutputJson(ApiResult.Error($"编辑角色'{sysRoleDto.RoleName}'失败,角色权限已存在"));
+ }
+ }
+
+ sysRoleDto.Update_by = User.Identity.Name;
+ int upResult = sysRoleService.UpdateRole(sysRoleDto);
+ if (upResult > 0)
+ {
+ //TODO 更新缓存用户权限信息
+
+ return SUCCESS(upResult);
+ }
+ return OutputJson(ApiResult.Error($"修改角色'{sysRoleDto.RoleName}'失败,请联系管理员"));
+ }
+
+ ///
+ /// 根据角色分配菜单
+ ///
+ ///
+ ///
+ [HttpPut("dataScope")]
+ [ActionPermissionFilter(Permission = "system:role:update")]
+ [Log(Title = "角色管理", BusinessType = BusinessType.UPDATE)]
+ public IActionResult DataScope([FromBody] SysRole sysRoleDto)
+ {
+ if (sysRoleDto == null || sysRoleDto.RoleId <= 0) return OutputJson(ApiResult.Error(101, "请求参数错误"));
+
+ sysRoleDto.Create_by = HttpContextExtension.GetName(HttpContext);
+ //删除角色菜单
+ sysRoleService.DeleteRoleMenuByRoleId(sysRoleDto.RoleId);
+ sysRoleService.InsertRoleMenu(sysRoleDto);
+
+ return SUCCESS(true);
+ }
+
+ ///
+ /// 角色删除 √
+ ///
+ ///
+ ///
+ [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 OutputJson(ToJson(result));
+ }
+
+ ///
+ /// 修改角色状态 √
+ ///
+ /// 角色对象
+ ///
+ [HttpPut("changeStatus")]
+ [Log(Title = "修改角色状态", BusinessType = BusinessType.UPDATE)]
+ [ActionPermissionFilter(Permission = "system:role:update")]
+ public IActionResult ChangeStatus([FromBody] SysRole roleDto)
+ {
+ int result = sysRoleService.UpdateRoleStatus(roleDto);
+
+ return OutputJson(ToJson(result));
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/Controllers/System/SysUserController.cs b/ZR.Admin.WebApi/Controllers/System/SysUserController.cs
new file mode 100644
index 0000000..649738f
--- /dev/null
+++ b/ZR.Admin.WebApi/Controllers/System/SysUserController.cs
@@ -0,0 +1,208 @@
+using Infrastructure.Attribute;
+using Infrastructure.Enums;
+using Infrastructure.Model;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Npoi.Mapper;
+using System.Collections.Generic;
+using System.IO;
+using ZR.Admin.WebApi.Filters;
+using ZR.Model;
+using ZR.Model.System;
+using ZR.Model.Vo;
+using ZR.Service.IService;
+
+namespace ZR.Admin.WebApi.Controllers.System
+{
+ [Verify]
+ [Route("system/user")]
+ public class SysUserController : BaseController
+ {
+ private readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
+
+ 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);
+
+ var vm = new VMPageResult(list, pager);
+
+ return SUCCESS(vm, 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("posts", PostService.GetAll());
+
+ //编辑
+ if (userId > 0)
+ {
+ dic.Add("user", UserService.SelectUserById(userId));
+ dic.Add("postIds", UserPostService.GetUserPostsByUserId(userId));
+ dic.Add("roleIds", RoleService.SelectUserRoles(userId));
+ }
+
+ return OutputJson(ApiResult.Success(dic));
+ }
+
+ ///
+ /// 添加用户
+ ///
+ ///
+ ///
+ [HttpPost("edit")]
+ [Log(Title = "用户管理", BusinessType = BusinessType.INSERT)]
+ [ActionPermissionFilter(Permission = "system:user:add")]
+ public IActionResult AddUser([FromBody] SysUser user)
+ {
+ if (user == null) { return OutputJson(ApiResult.Error(101, "请求参数错误")); }
+ if (UserConstants.NOT_UNIQUE.Equals(UserService.CheckUserNameUnique(user.UserName)))
+ {
+ return OutputJson(ApiResult.Error($"新增用户 '{user.UserName}'失败,登录账号已存在"));
+ }
+
+ user.Create_by = User.Identity.Name;
+ user.Password = NETCore.Encrypt.EncryptProvider.Md5(user.Password);
+
+ return OutputJson(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 OutputJson(ApiResult.Error(101, "请求参数错误")); }
+
+ user.Update_by = User.Identity.Name;
+ int upResult = UserService.UpdateUser(user);
+
+ return OutputJson(upResult);
+ }
+
+ ///
+ /// 改变用户状态
+ ///
+ ///
+ ///
+ [HttpPut("changeStatus")]
+ [Log(Title = "修改用户状态", BusinessType = BusinessType.UPDATE)]
+ [ActionPermissionFilter(Permission = "system:user:update")]
+ public IActionResult ChangeStatus([FromBody] SysUser user)
+ {
+ if (user == null) { return OutputJson(ApiResult.Error(101, "请求参数错误")); }
+
+ int result = UserService.ChangeUserStatus(user);
+ return OutputJson(ToJson(result));
+ }
+
+ ///
+ /// 删除用户
+ ///
+ ///
+ ///
+ [HttpDelete("{userId}")]
+ [Log(Title = "用户管理", BusinessType = BusinessType.DELETE)]
+ [ActionPermissionFilter(Permission = "system:user:remove")]
+ public IActionResult Remove(int userid = 0)
+ {
+ if (userid <= 0) { return OutputJson(ApiResult.Error(101, "请求参数错误")); }
+
+ int result = UserService.DeleteUser(userid);
+
+ return OutputJson(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 OutputJson(ToJson(result));
+ }
+
+ ///
+ /// 导入 ok
+ ///
+ /// 使用IFromFile必须使用name属性否则获取不到文件
+ ///
+ [HttpPost("importData")]
+ [Log(Title = "用户导入", BusinessType = BusinessType.IMPORT)]
+ [ActionPermissionFilter(Permission = "system:user:import")]
+ public IActionResult ImportData([FromForm(Name = "file")] IFormFile formFile)
+ {
+ var mapper = new Mapper(formFile.OpenReadStream());// 从流获取
+ //读取的sheet信息
+ var rows = mapper.Take(0);
+ foreach (var item in rows)
+ {
+ SysUser u = item.Value;
+ }
+ //TODO 业务逻辑
+ return SUCCESS(1);
+ }
+
+ ///
+ /// 用户模板 ok
+ ///
+ ///
+ [HttpGet("importTemplate")]
+ [Log(Title = "用户模板", BusinessType = BusinessType.EXPORT)]
+ [ActionPermissionFilter(Permission = "system:user:export")]
+ public IActionResult ImportTemplateExcel()
+ {
+ List user = new List();
+ var mapper = new Mapper();
+ MemoryStream stream = new MemoryStream();
+ mapper.Save(stream, user, "sheel1", overwrite: true, xlsx: true);
+ //Response.Headers.Append("content-disposition", "attachment;filename=sysUser.xlsx");
+ return File(stream.ToArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "sysUser.xlsx");
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/Controllers/System/SysUserRoleController.cs b/ZR.Admin.WebApi/Controllers/System/SysUserRoleController.cs
new file mode 100644
index 0000000..a801832
--- /dev/null
+++ b/ZR.Admin.WebApi/Controllers/System/SysUserRoleController.cs
@@ -0,0 +1,94 @@
+using Infrastructure;
+using Infrastructure.Attribute;
+using Microsoft.AspNetCore.Mvc;
+using System;
+using System.Linq;
+using ZR.Admin.WebApi.Filters;
+using ZR.Model;
+using ZR.Model.Dto.System;
+using ZR.Model.System;
+using ZR.Service.IService;
+
+namespace ZR.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("get/{roleId}")]
+ [ActionPermissionFilter(Permission = "system:roleusers:query")]
+ public IActionResult GetList(long roleId = 0)
+ {
+ var list = SysUserRoleService.GetSysUsersByRoleId(roleId);
+
+ 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:del")]
+ [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(long roleId = 0)
+ {
+ if (roleId <= 0)
+ {
+ throw new CustomException(ResultCode.PARAM_ERROR, "roleId不能为空");
+ }
+ // 取得该角色所有添加的用户
+ var userIds = SysUserRoleService.GetSysUsersByRoleId(roleId).Select(f => f.UserId);
+
+ SysUser userQuery = new();
+ userQuery.Status = "0";
+ PagerInfo pager = new(1, 50);
+
+ // 获取未添加用户
+ var list = UserService.SelectUserList(userQuery, pager).Where(m => !userIds.Contains(m.UserId));
+ return SUCCESS(list, TIME_FORMAT_FULL);
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/Controllers/System/TasksController.cs b/ZR.Admin.WebApi/Controllers/System/TasksController.cs
new file mode 100644
index 0000000..ad60385
--- /dev/null
+++ b/ZR.Admin.WebApi/Controllers/System/TasksController.cs
@@ -0,0 +1,270 @@
+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 ZR.Admin.WebApi.Extensions;
+using ZR.Admin.WebApi.Filters;
+using ZR.Model;
+using ZR.Model.Dto.System;
+using ZR.Model.System;
+using ZR.Service.IService;
+using ZR.Tasks;
+
+namespace ZR.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 = "system:task: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, "Desc");
+
+ return SUCCESS(response, TIME_FORMAT_FULL);
+ }
+
+ ///
+ /// 查询单个计划任务
+ ///
+ /// 编码
+ ///
+ [HttpGet("{id}")]
+ public IActionResult Get(string id)
+ {
+ if (!string.IsNullOrEmpty(id))
+ {
+ return SUCCESS(_tasksQzService.GetId(id));
+ }
+ return SUCCESS(_tasksQzService.GetAll());
+ }
+
+
+ ///
+ /// 添加任务
+ ///
+ ///
+ [HttpPost("create")]
+ [ActionPermissionFilter(Permission = "system:task: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表达式不正确");
+ }
+
+ //从 Dto 映射到 实体
+ var tasksQz = parm.Adapt().ToCreate();
+ tasksQz.IsStart = false;
+ tasksQz.Create_by = User.Identity.Name;
+
+ return SUCCESS(_tasksQzService.Add(tasksQz));
+ }
+
+ ///
+ /// 更新任务
+ ///
+ ///
+ [HttpPost("update")]
+ [ActionPermissionFilter(Permission = "system:task:edit")]
+ [Log(Title = "修改任务", BusinessType = BusinessType.UPDATE)]
+ public async Task Update([FromBody] TasksUpdateDto parm)
+ {
+ //判断是否已经存在
+ if (_tasksQzService.Any(m => m.Name == parm.Name && m.ID != parm.ID))
+ {
+ throw new CustomException($"更新 {parm.Name} 失败,该用任务存在,不能重复!");
+ }
+ if (string.IsNullOrEmpty(parm.Cron))
+ {
+ throw new CustomException($"触发器 Corn 模式下,运行时间表达式必须填写");
+ }
+ if (!CronExpression.IsValidExpression(parm.Cron))
+ {
+ throw new CustomException($"cron表达式不正确");
+ }
+ var tasksQz = _tasksQzService.GetFirst(m => m.ID == parm.ID);
+
+ if (tasksQz.IsStart)
+ {
+ throw new CustomException($"该任务正在运行中,请先停止在更新");
+ }
+
+ var response = _tasksQzService.Update(m => m.ID == parm.ID, 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 = User.Identity.Name,
+ Update_time = DateTime.Now
+ });
+ if (response > 0)
+ {
+ //先暂停原先的任务
+ var respon = await _schedulerServer.UpdateTaskScheduleAsync(tasksQz, tasksQz.JobGroup);
+ }
+
+ return SUCCESS(response);
+ }
+
+ ///
+ /// 删除任务
+ ///
+ ///
+ [HttpDelete("delete")]
+ [ActionPermissionFilter(Permission = "system:task: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 == id))
+ {
+ throw new CustomException("任务不存在");
+ }
+
+ var tasksQz = _tasksQzService.GetFirst(m => m.ID == id);
+ var taskResult = await _schedulerServer.DeleteTaskScheduleAsync(tasksQz);
+
+ if (taskResult.Code == 200)
+ {
+ _tasksQzService.Delete(id);
+ }
+ return OutputJson(taskResult);
+ }
+
+ ///
+ /// 启动任务
+ ///
+ ///
+ [HttpGet("start")]
+ [ActionPermissionFilter(Permission = "system:task: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 == id))
+ {
+ throw new CustomException("任务不存在");
+ }
+
+ var tasksQz = _tasksQzService.GetFirst(m => m.ID == id);
+ var taskResult = await _schedulerServer.AddTaskScheduleAsync(tasksQz);
+
+ if (taskResult.Code == 200)
+ {
+ tasksQz.IsStart = true;
+ _tasksQzService.Update(tasksQz);
+ }
+
+ return OutputJson(taskResult);
+ }
+
+ ///
+ /// 停止任务
+ ///
+ ///
+ [HttpGet("stop")]
+ [ActionPermissionFilter(Permission = "system:task: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 == id))
+ {
+ throw new CustomException("任务不存在");
+ }
+
+ var tasksQz = _tasksQzService.GetFirst(m => m.ID == id);
+ var taskResult = await _schedulerServer.DeleteTaskScheduleAsync(tasksQz);//await _schedulerServer.PauseTaskScheduleAsync(tasksQz);
+
+ if (taskResult.Code == 200)
+ {
+ tasksQz.IsStart = false;
+ _tasksQzService.Update(tasksQz);
+ }
+
+ return OutputJson(taskResult);
+ }
+
+ ///
+ /// 定时任务立即执行一次
+ ///
+ ///
+ ///
+ [HttpGet("run")]
+ [ActionPermissionFilter(Permission = "system:task:run")]
+ [Log(Title = "执行任务", BusinessType = BusinessType.OTHER)]
+ public async Task Run(string id)
+ {
+ if (!_tasksQzService.Any(m => m.ID == id))
+ {
+ throw new CustomException("任务不存在");
+ }
+ var tasksQz = _tasksQzService.GetFirst(m => m.ID == id);
+ var taskResult = await _schedulerServer.RunTaskScheduleAsync(tasksQz);
+
+ if (taskResult.Code == 200)
+ {
+ //_tasksQzService.Update(tasksQz);
+ }
+
+ return OutputJson(taskResult);
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/Controllers/System/TasksLogController.cs b/ZR.Admin.WebApi/Controllers/System/TasksLogController.cs
new file mode 100644
index 0000000..ca842ca
--- /dev/null
+++ b/ZR.Admin.WebApi/Controllers/System/TasksLogController.cs
@@ -0,0 +1,79 @@
+using Microsoft.AspNetCore.Mvc;
+using SqlSugar;
+using ZR.Model;
+using ZR.Model.Dto.System;
+using ZR.Model.System;
+using Infrastructure.Extensions;
+using Infrastructure.Attribute;
+using ZR.Admin.WebApi.Filters;
+using ZR.Common;
+using Infrastructure.Enums;
+using ZR.Service.IService;
+
+namespace ZR.Admin.WebApi.Controllers.System
+{
+ [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, -1);
+ queryDto.EndTime = DateTimeHelper.GetBeginTime(queryDto.EndTime, 1);
+
+ 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, "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 OutputJson(ToJson(result, result));
+ }
+
+ ///
+ /// 清空日志
+ ///
+ ///
+ [HttpDelete("clean")]
+ [ActionPermissionFilter(Permission = "PRIV_JOBLOG_REMOVE")]
+ [Log(Title = "清空任务日志", BusinessType = BusinessType.CLEAN)]
+ public IActionResult Clean()
+ {
+ tasksLogService.DeleteTable();
+ return SUCCESS(1);
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/Controllers/System/monitor/MonitorController.cs b/ZR.Admin.WebApi/Controllers/System/monitor/MonitorController.cs
new file mode 100644
index 0000000..b5ea834
--- /dev/null
+++ b/ZR.Admin.WebApi/Controllers/System/monitor/MonitorController.cs
@@ -0,0 +1,81 @@
+using Infrastructure;
+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;
+using ZR.Admin.WebApi.Filters;
+using ZR.Common;
+
+namespace ZR.Admin.WebApi.Controllers.monitor
+{
+ //[Verify]
+ public class MonitorController : BaseController
+ {
+ private OptionsSetting Options;
+ private IWebHostEnvironment HostEnvironment;
+
+ public MonitorController(IOptions options, IWebHostEnvironment hostEnvironment)
+ {
+ this.HostEnvironment = hostEnvironment;
+ this.Options = options.Value;
+ }
+
+ ///
+ /// 获取缓存监控数据
+ ///
+ ///
+ [HttpGet("monitor/cache")]
+ public ApiResult GetCache()
+ {
+ string redis_connString = Options.Redis;
+ var rs = new CSRedis.CSRedisClient(redis_connString);
+
+ RedisHelper.Initialization(rs);//初始化Redis
+
+ 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 runTime = Process.GetCurrentProcess().StartTime.ToString("yyyy-MM-dd HH:mm:ss");
+ string serverIP = (Request.HttpContext.Connection.LocalIpAddress.MapToIPv4().ToString() + ":" + Request.HttpContext.Connection.LocalPort);//获取服务器IP
+
+ var data = new
+ {
+ cpu = ComputerHelper.GetComputerInfo(),
+ sys = new { cpuNum, computerName, osName, osArch, serverIP },
+ app = new
+ {
+ name = HostEnvironment.EnvironmentName,
+ rootPath = HostEnvironment.ContentRootPath,
+ webRootPath = HostEnvironment.WebRootPath,
+ version,
+ appRAM,
+ startTime,
+ runTime,
+ host = serverIP
+ }
+ };
+
+ return SUCCESS(data);
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/Controllers/System/monitor/SysLogininforController.cs b/ZR.Admin.WebApi/Controllers/System/monitor/SysLogininforController.cs
new file mode 100644
index 0000000..74a4139
--- /dev/null
+++ b/ZR.Admin.WebApi/Controllers/System/monitor/SysLogininforController.cs
@@ -0,0 +1,71 @@
+using Infrastructure.Attribute;
+using Microsoft.AspNetCore.Mvc;
+using ZR.Admin.WebApi.Filters;
+using ZR.Common;
+using ZR.Model;
+using ZR.Model.System;
+using ZR.Model.Vo;
+using ZR.Service.IService;
+
+namespace ZR.Admin.WebApi.Controllers.monitor
+{
+ ///
+ /// 系统访问记录
+ ///
+ [Verify]
+ [Route("/monitor/logininfor")]
+ public class SysLogininforController : BaseController
+ {
+ private ISysLoginService sysLoginService;
+
+ public SysLogininforController(ISysLoginService sysLoginService)
+ {
+ this.sysLoginService = sysLoginService;
+ }
+
+ ///
+ /// 查询登录日志
+ /// /monitor/logininfor/list
+ ///
+ ///
+ ///
+ ///
+ [HttpGet("list")]
+ public IActionResult LoignLogList([FromQuery] SysLogininfor sysLogininfoDto, [FromQuery] PagerInfo pagerInfo)
+ {
+ var list = sysLoginService.GetLoginLog(sysLogininfoDto, pagerInfo);
+ var vMPage = new VMPageResult(list, pagerInfo);
+
+ return OutputJson(ToJson(vMPage.TotalNum, vMPage), TIME_FORMAT_FULL_2);
+ }
+
+ ///
+ /// 清空登录日志
+ /// /monitor/logininfor/clean
+ ///
+ ///
+ [Log(Title = "清空登录日志")]
+ [ActionPermissionFilter(Permission = "monitor:logininfor:remove")]
+ [HttpDelete("clean")]
+ public IActionResult CleanLoginInfo()
+ {
+ sysLoginService.TruncateLogininfo();
+ return SUCCESS(1);
+ }
+
+ ///
+ /// /monitor/logininfor/1
+ ///
+ ///
+ ///
+ [Log(Title = "删除登录日志")]
+ [HttpDelete("{infoIds}")]
+ [ActionPermissionFilter(Permission = "monitor:logininfor:remove")]
+ public IActionResult Remove(string infoIds)
+ {
+ long[] infoIdss = Tools.SpitLongArrary(infoIds);
+ return SUCCESS(sysLoginService.DeleteLogininforByIds(infoIdss));
+ }
+
+ }
+}
diff --git a/ZR.Admin.WebApi/Controllers/System/monitor/SysOperlogController.cs b/ZR.Admin.WebApi/Controllers/System/monitor/SysOperlogController.cs
new file mode 100644
index 0000000..fd76f8f
--- /dev/null
+++ b/ZR.Admin.WebApi/Controllers/System/monitor/SysOperlogController.cs
@@ -0,0 +1,71 @@
+using Infrastructure.Attribute;
+using Infrastructure.Enums;
+using Infrastructure.Model;
+using Microsoft.AspNetCore.Mvc;
+using ZR.Admin.WebApi.Filters;
+using ZR.Common;
+using ZR.Model;
+using ZR.Model.Dto.System;
+using ZR.Model.System;
+using ZR.Model.Vo;
+using ZR.Service.IService;
+
+namespace ZR.Admin.WebApi.Controllers.monitor
+{
+ [Verify]
+ [Route("/monitor/operlog")]
+ public class SysOperlogController : BaseController
+ {
+ private ISysOperLogService sysOperLogService;
+
+ public SysOperlogController(ISysOperLogService sysOperLogService)
+ {
+ this.sysOperLogService = sysOperLogService;
+ }
+
+ ///
+ /// 查询操作日志
+ ///
+ ///
+ ///
+ [HttpGet("list")]
+ public IActionResult OperList([FromQuery] SysOperLogDto sysOperLog)
+ {
+ PagerInfo pagerInfo = new PagerInfo(sysOperLog.pageNum);
+
+ var list = sysOperLogService.SelectOperLogList(sysOperLog, pagerInfo);
+ var vMPage = new VMPageResult(list, pagerInfo);
+
+ return OutputJson(ToJson(vMPage.TotalNum, vMPage), TIME_FORMAT_FULL_2);
+ }
+
+ ///
+ /// 删除操作日志
+ ///
+ ///
+ ///
+ [Log(Title = "操作日志", BusinessType = BusinessType.DELETE)]
+ [ActionPermissionFilter(Permission = "monitor:operlog:delete")]
+ [HttpDelete("{operIds}")]
+ public IActionResult Remove(string operIds)
+ {
+ 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()
+ {
+ sysOperLogService.CleanOperLog();
+
+ return ToJson(1);
+ }
+
+ }
+}
diff --git a/ZR.Admin.WebApi/Controllers/System/monitor/SysUserOnlineController.cs b/ZR.Admin.WebApi/Controllers/System/monitor/SysUserOnlineController.cs
new file mode 100644
index 0000000..0134f54
--- /dev/null
+++ b/ZR.Admin.WebApi/Controllers/System/monitor/SysUserOnlineController.cs
@@ -0,0 +1,16 @@
+using Microsoft.AspNetCore.Mvc;
+using ZR.Admin.WebApi.Filters;
+
+namespace ZR.Admin.WebApi.Controllers.monitor
+{
+ [Verify]
+ [Route("monitor/online")]
+ public class SysUserOnlineController : BaseController
+ {
+ [HttpGet("list")]
+ public IActionResult Index()
+ {
+ return SUCCESS(null);
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/Controllers/UploadController.cs b/ZR.Admin.WebApi/Controllers/UploadController.cs
new file mode 100644
index 0000000..aa14a79
--- /dev/null
+++ b/ZR.Admin.WebApi/Controllers/UploadController.cs
@@ -0,0 +1,47 @@
+using Infrastructure;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Options;
+using System;
+using System.IO;
+using ZR.Common;
+
+namespace ZR.Admin.WebApi.Controllers
+{
+ [Route("[controller]/[action]")]
+ public class UploadController : BaseController
+ {
+ private NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
+ private OptionsSetting OptionsSetting;
+
+ public UploadController(IOptions optionsSetting)
+ {
+ OptionsSetting = optionsSetting.Value;
+ }
+ ///
+ /// 存储文件
+ ///
+ ///
+ ///
+ [HttpPost]
+ public IActionResult SaveFile([FromForm(Name = "file")] IFormFile formFile)
+ {
+ if (formFile == null) throw new CustomException(ResultCode.PARAM_ERROR, "上传图片不能为空");
+ string fileExt = Path.GetExtension(formFile.FileName);
+ string savePath = Path.Combine("wwwroot", FileUtil.GetdirPath("uploads"));
+
+ if (!Directory.Exists(savePath)) { Directory.CreateDirectory(savePath); }
+
+ string fileName = FileUtil.HashFileName(Guid.NewGuid().ToString()).ToLower() + fileExt;
+ string finalFilePath = Path.Combine(savePath, fileName);
+
+ using (var stream = new FileStream(finalFilePath, FileMode.Create))
+ {
+ formFile.CopyToAsync(stream);
+ }
+
+ string accessPath = $"{OptionsSetting.Upload.UploadUrl}/{finalFilePath.Replace("wwwroot", "").Replace("\\", "/")}";
+ return OutputJson(ToJson(1, accessPath));
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/DataProtection/key-b6498f45-218a-4853-a182-0e86942ab496.xml b/ZR.Admin.WebApi/DataProtection/key-b6498f45-218a-4853-a182-0e86942ab496.xml
new file mode 100644
index 0000000..71c92b8
--- /dev/null
+++ b/ZR.Admin.WebApi/DataProtection/key-b6498f45-218a-4853-a182-0e86942ab496.xml
@@ -0,0 +1,16 @@
+
+
+ 2021-08-02T06:58:41.3050198Z
+ 2021-08-02T06:58:41.2698484Z
+ 2021-10-31T06:58:41.2698484Z
+
+
+
+
+
+
+ gmFBOJQxBXoKTqyvLeEnS6IDsf61vG/s0krHG1MfcZwQlu/D2XUaCms+xzpFc2c2JGdaJh5LiLIyJuoRR20Mug==
+
+
+
+
\ No newline at end of file
diff --git a/ZR.Admin.WebApi/Dockerfile b/ZR.Admin.WebApi/Dockerfile
new file mode 100644
index 0000000..91f4597
--- /dev/null
+++ b/ZR.Admin.WebApi/Dockerfile
@@ -0,0 +1,19 @@
+FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base
+#´´½¨ /appÎļþ¼Ð
+WORKDIR /app
+#´´½¨¹ÒÔØĿ¼,ÓÃÓڽ«³ÌÐò²¿ÊðÔڷþÎñÆ÷±¾µØ
+#VOLUME /app
+#ÉèÖÃdockerÈÝÆ÷¶ÔÍⱩ¶¶˿Ú
+EXPOSE 5000
+VOLUME /app/logs
+#COPY bin/Release/net5.0/publish/ app/
+COPY . app/
+
+#ÉèÖÃÈÝÆ÷ÄڵÄʱÇø£¬Èç¹û²»ÉèÖã¬ĬÈÏʱÇøÊDZêʱ¼ä±ȱ±¾©ʱ¼äÍí8¸öСʱ
+RUN echo "Asia/shanghai" > /etc/timezone
+RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
+
+# ¸´ÖƷ¢²¼Îļþµ½¹¤×÷Ŀ¼
+#COPY . app/
+
+ENTRYPOINT ["dotnet", "ZR.Admin.WebApi.dll"]
\ No newline at end of file
diff --git a/ZR.Admin.WebApi/Extensions/EntityExtension.cs b/ZR.Admin.WebApi/Extensions/EntityExtension.cs
new file mode 100644
index 0000000..d518656
--- /dev/null
+++ b/ZR.Admin.WebApi/Extensions/EntityExtension.cs
@@ -0,0 +1,75 @@
+using Microsoft.AspNetCore.Http;
+using Snowflake.Core;
+using System;
+
+namespace ZR.Admin.WebApi.Extensions
+{
+ public static class EntityExtension
+ {
+ public static TSource ToCreate(this TSource source, HttpContext context = null)
+ {
+ var types = source.GetType();
+
+ var worker = new IdWorker(1, 1);
+ if (types.GetProperty("ID") != null)
+ {
+ long id = worker.NextId();
+
+ types.GetProperty("ID").SetValue(source, id.ToString(), null);
+ }
+
+ if (types.GetProperty("CreateTime") != null)
+ {
+ types.GetProperty("CreateTime").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);
+
+ // types.GetProperty("CreateName").SetValue(source, userSession.UserName, null);
+ }
+ if (types.GetProperty("UserId") != null && context != null)
+ {
+ types.GetProperty("UserId").SetValue(source, context.GetUId(), null);
+ }
+ //if (types.GetProperty("UpdateID") != null)
+ //{
+ // types.GetProperty("UpdateID").SetValue(source, userSession.UserID, null);
+
+ // types.GetProperty("UpdateName").SetValue(source, userSession.UserName, null);
+ //}
+
+
+ return source;
+ }
+
+ //public static TSource ToUpdate(this TSource source, UserSessionVM userSession)
+ //{
+ // var types = source.GetType();
+
+ // if (types.GetProperty("UpdateTime") != null)
+ // {
+ // types.GetProperty("UpdateTime").SetValue(source, DateTime.Now, null);
+ // }
+
+ // if (types.GetProperty("UpdateID") != null)
+ // {
+ // types.GetProperty("UpdateID").SetValue(source, userSession.UserID, null);
+ // }
+
+ // if (types.GetProperty("UpdateName") != null)
+ // {
+ // types.GetProperty("UpdateName").SetValue(source, userSession.UserName, null);
+ // }
+
+ // return source;
+ //}
+
+ }
+}
diff --git a/ZR.Admin.WebApi/Extensions/HttpContextExtension.cs b/ZR.Admin.WebApi/Extensions/HttpContextExtension.cs
new file mode 100644
index 0000000..0720d47
--- /dev/null
+++ b/ZR.Admin.WebApi/Extensions/HttpContextExtension.cs
@@ -0,0 +1,160 @@
+using Infrastructure;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.Cookies;
+using Microsoft.AspNetCore.Http;
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Claims;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using UAParser;
+using ZR.Model.System;
+
+namespace ZR.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 int GetRole(this HttpContext context)
+ //{
+ // var roleid = context.User.FindFirstValue(ClaimTypes.Role) ?? "0";
+
+ // return int.Parse(roleid);
+ //}
+
+ public static string GetUserAgent(this HttpContext context)
+ {
+ var str = context.Request.Headers["User-Agent"];
+
+ return str;
+ }
+
+ ///
+ /// 获取请求令牌
+ ///
+ ///
+ ///
+ public static string GetToken(this HttpContext context)
+ {
+ var str = context.Request.Headers["Token"];
+
+ return str;
+ }
+
+ 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 : "";
+ }
+
+ ///
+ /// 登录cookie写入
+ ///
+ ///
+ ///
+ ///
+ public static List WriteCookies(this HttpContext context, LoginUser user)
+ {
+ //1、创建Cookie保存用户信息,使用claim
+ var claims = new List()
+ {
+ new Claim(ClaimTypes.PrimarySid, user.UserId.ToString()),
+ new Claim(ClaimTypes.Name, user.UserName),
+ new Claim(ClaimTypes.UserData, JsonConvert.SerializeObject(user))
+ };
+ if (user.RoleIds != null)
+ {
+ claims.Add(new Claim(ClaimTypes.Role, string.Join(",", user.RoleIds)));
+ }
+ if (user.Permissions != null)
+ {
+ claims.Add(new Claim("perm", string.Join(",", user.Permissions)));
+ }
+ //2.创建声明主题 指定认证方式 这里使用cookie
+ var claimsIdentity = new ClaimsIdentity(claims, "Login");
+
+ Task.Run(async () =>
+ {
+ await context.SignInAsync(
+ CookieAuthenticationDefaults.AuthenticationScheme,//这里要注意的是HttpContext.SignInAsync(AuthenticationType,…) 所设置的Scheme一定要与前面的配置一样,这样对应的登录授权才会生效。
+ new ClaimsPrincipal(claimsIdentity),
+ new AuthenticationProperties()
+ {
+ IsPersistent = true,
+ AllowRefresh = true,
+ ExpiresUtc = DateTimeOffset.Now.AddDays(1),//有效时间
+ });
+ }).Wait();
+ return claims;
+ }
+ }
+
+}
diff --git a/ZR.Admin.WebApi/Extensions/TasksExtension.cs b/ZR.Admin.WebApi/Extensions/TasksExtension.cs
new file mode 100644
index 0000000..dda6ba7
--- /dev/null
+++ b/ZR.Admin.WebApi/Extensions/TasksExtension.cs
@@ -0,0 +1,53 @@
+using Infrastructure;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.Extensions.DependencyInjection;
+using Quartz.Spi;
+using System;
+using ZR.Service.IService;
+using ZR.Tasks;
+
+namespace ZR.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));
+
+ //此写法不通过有待研究
+ //var _tasksQzService2 = (ISysTasksQzService)services.GetRequiredService(typeof(SysTasksQzService));
+ ITaskSchedulerServer _schedulerServer = App.GetRequiredService();
+
+ var tasks = _tasksQzService.GetWhere(m => m.IsStart);
+
+ //程序启动后注册所有定时任务
+ foreach (var task in tasks)
+ {
+ _schedulerServer.AddTaskScheduleAsync(task);
+ }
+
+ return app;
+ }
+
+ }
+}
diff --git a/ZR.Admin.WebApi/Filters/ActionPermissionFilter.cs b/ZR.Admin.WebApi/Filters/ActionPermissionFilter.cs
new file mode 100644
index 0000000..88258d7
--- /dev/null
+++ b/ZR.Admin.WebApi/Filters/ActionPermissionFilter.cs
@@ -0,0 +1,72 @@
+using Infrastructure;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Filters;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using ZR.Model.System;
+
+namespace ZR.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; }
+
+ 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;
+ if (perms.Exists(f => f.Equals(GlobalConstant.AdminPerm)))
+ {
+ HasPermi = true;
+ }
+ else if (!string.IsNullOrEmpty(Permission))
+ {
+ HasPermi = perms.Exists(f => f.ToLower() == Permission.ToLower());
+ }
+
+ bool isDemoMode = ConfigUtils.Instance.GetAppConfig("DemoMode", false);
+
+ //演示公开环境屏蔽权限
+ string[] denyPerms = new string[] { "update", "add", "remove", "add", "edit", "delete", "import", "run", "start", "stop", "clear" };
+ if (isDemoMode && (denyPerms.Any(f => Permission.ToLower().Contains(f.ToLower())) || Permission.Equals("system")))
+ {
+ context.Result = new JsonResult(new { code = ResultCode.FORBIDDEN, msg = "演示模式 , 不允许操作" });
+ }
+ if (!HasPermi)
+ {
+ logger.Info($"用户{info.NickName}没有权限访问{context.HttpContext.Request.Path},当前权限[{Permission}]");
+ context.Result = new JsonResult(new { code = ResultCode.FORBIDDEN, msg = "你没有权限访问" });
+ }
+ }
+
+ return base.OnActionExecutionAsync(context, next);
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/Filters/GlobalActionMonitor.cs b/ZR.Admin.WebApi/Filters/GlobalActionMonitor.cs
new file mode 100644
index 0000000..7ed2ab1
--- /dev/null
+++ b/ZR.Admin.WebApi/Filters/GlobalActionMonitor.cs
@@ -0,0 +1,54 @@
+using Infrastructure;
+using Infrastructure.Model;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Filters;
+using NLog;
+using System;
+
+namespace ZR.Admin.WebApi.Filters
+{
+ public class GlobalActionMonitor : Attribute, IActionFilter
+ {
+ static readonly Logger logger = LogManager.GetCurrentClassLogger();
+
+ ///
+ /// OnActionExecuting是在Action执行之前运行的方法。
+ ///
+ ///
+ public void OnActionExecuting(ActionExecutingContext context)
+ {
+ if (context.ModelState.IsValid) return;
+ ApiResult response = new ApiResult();
+ response.Code = (int)ResultCode.PARAM_ERROR;
+
+ //var keys = context.ModelState.Keys;
+ var values = context.ModelState.Values;
+ foreach (var item in values)
+ {
+ foreach (var err in item.Errors)
+ {
+ if (err.ErrorMessage.Contains("JSON"))
+ {
+ return;
+ }
+ if (!string.IsNullOrEmpty(response.Msg))
+ {
+ response.Msg += " | ";
+ }
+
+ response.Msg += err.ErrorMessage;
+ }
+ }
+ logger.Info($"请求参数错误,{response.Msg}");
+ context.Result = new JsonResult(response);
+ }
+
+ ///
+ /// OnActionExecuted是在Action中的代码执行之后运行的方法。
+ ///
+ ///
+ public void OnActionExecuted(ActionExecutedContext context)
+ {
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/Filters/GlobalExceptionFilter.cs b/ZR.Admin.WebApi/Filters/GlobalExceptionFilter.cs
new file mode 100644
index 0000000..b0f205d
--- /dev/null
+++ b/ZR.Admin.WebApi/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 ZRAdmin.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/ZR.Admin.WebApi/Filters/LogActionFilter.cs b/ZR.Admin.WebApi/Filters/LogActionFilter.cs
new file mode 100644
index 0000000..0d9df95
--- /dev/null
+++ b/ZR.Admin.WebApi/Filters/LogActionFilter.cs
@@ -0,0 +1,131 @@
+using Infrastructure;
+using Infrastructure.Attribute;
+using IPTools.Core;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Controllers;
+using Microsoft.AspNetCore.Mvc.Filters;
+using NLog;
+using System;
+using System.IO;
+using System.Linq;
+using System.Text;
+using ZR.Admin.WebApi.Extensions;
+using ZR.Model.System;
+using ZR.Service.IService;
+
+namespace ZR.Admin.WebApi.Filters
+{
+ ///
+ /// 记录请求,输出日志
+ ///
+ public class LogActionFilter : ActionFilterAttribute
+ {
+ static readonly Logger logger = LogManager.GetCurrentClassLogger();
+
+ ///
+ /// 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();
+ }
+ //获取当前执行方法的类名
+ //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 SysOperLog
+ {
+ 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
+ };
+ if (logAttribute != null)
+ {
+ sysOperLog.title = logAttribute?.Title;
+ sysOperLog.businessType = (int)logAttribute?.BusinessType;
+ }
+ GetRequestValue(sysOperLog, context.HttpContext);
+
+ var sysOperLogService = (ISysOperLogService)App.GetRequiredService(typeof(ISysOperLogService));
+
+ sysOperLogService.InsertOperlog(sysOperLog);
+
+ LogEventInfo ei = new(LogLevel.Info, "GlobalExceptionMiddleware", "");
+
+ ei.Properties["status"] = 0;
+ ei.Properties["jsonResult"] = !HttpMethods.IsGet(method) ? jsonResult : "";
+ ei.Properties["requestParam"] = sysOperLog.operParam;
+ ei.Properties["user"] = context.HttpContext.User.Identity.Name;
+
+ logger.Log(ei);
+ }
+ 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 (LogAttribute)attribute;
+ }
+
+ ///
+ /// 设置请求参数
+ ///
+ ///
+ ///
+ public static void GetRequestValue(SysOperLog operLog, HttpContext context)
+ {
+ 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;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/ZR.Admin.WebApi/Filters/VerifyAttribute.cs b/ZR.Admin.WebApi/Filters/VerifyAttribute.cs
new file mode 100644
index 0000000..cbfaff1
--- /dev/null
+++ b/ZR.Admin.WebApi/Filters/VerifyAttribute.cs
@@ -0,0 +1,67 @@
+using Infrastructure;
+using Infrastructure.Model;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Controllers;
+using Microsoft.AspNetCore.Mvc.Filters;
+using NLog;
+using System;
+using System.Linq;
+using ZR.Admin.WebApi.Extensions;
+using ZR.Model.System;
+
+namespace ZR.Admin.WebApi.Filters
+{
+ ///
+ /// 授权校验访问
+ /// 如果跳过授权登录在Action 或controller加上 AllowAnonymousAttribute
+ ///
+ public class VerifyAttribute : Attribute, IAuthorizationFilter
+ {
+ static readonly Logger logger = LogManager.GetCurrentClassLogger();
+ IWebHostEnvironment webHostEnvironment = (IWebHostEnvironment)App.ServiceProvider.GetService(typeof(IWebHostEnvironment));
+
+ //public VerifyAttribute() { }
+
+ ///
+ /// 只判断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;
+ // 检查登陆 - 在SignIn中判断用户合法性,将登陆信息保存在Cookie中,在SignOut中移除登陆信息
+ var userName = context.HttpContext.User.Identity.Name;
+
+ //使用jwt token校验2020-11-21
+ //string token = context.HttpContext.Request.Headers["Token"];
+ LoginUser info = Framework.JwtUtil.GetLoginUser(context.HttpContext);
+
+ if (info != null && info.UserId > 0)
+ {
+ logger.Info($"[{info.UserId}-{userName}-{ip}]用户登录校验成功");
+ }
+ else
+ {
+ string msg = $"请求访问:{url}授权认证失败,无法访问系统资源";
+ logger.Info(msg);
+
+ context.Result = new JsonResult(new ApiResult((int)ResultCode.DENY, msg));
+ }
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/Framework/AsyncFactory.cs b/ZR.Admin.WebApi/Framework/AsyncFactory.cs
new file mode 100644
index 0000000..07c10c1
--- /dev/null
+++ b/ZR.Admin.WebApi/Framework/AsyncFactory.cs
@@ -0,0 +1,35 @@
+using IPTools.Core;
+using Microsoft.AspNetCore.Http;
+using UAParser;
+using ZR.Admin.WebApi.Extensions;
+using ZR.Model.System;
+
+namespace ZR.Admin.WebApi.Framework
+{
+ public class AsyncFactory
+ {
+ ///
+ /// 记录用户登陆信息
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static SysLogininfor RecordLogInfo(HttpContext context, string status, string message)
+ {
+ ClientInfo clientInfo = context.GetClientInfo();
+ SysLogininfor sysLogininfor = new SysLogininfor();
+ sysLogininfor.browser = clientInfo.Device.Family;
+ sysLogininfor.os = clientInfo.OS.ToString();
+ sysLogininfor.ipaddr = context.GetClientUserIp();
+ sysLogininfor.msg = message;
+ sysLogininfor.userName = context.GetName();
+ sysLogininfor.status = status;
+ var ip_info = IpTool.Search(sysLogininfor.ipaddr);
+ sysLogininfor.loginLocation = ip_info.Province + "-" + ip_info.City;
+
+ return sysLogininfor;
+ }
+
+ }
+}
diff --git a/ZR.Admin.WebApi/Framework/CookieUtil.cs b/ZR.Admin.WebApi/Framework/CookieUtil.cs
new file mode 100644
index 0000000..eeb7e26
--- /dev/null
+++ b/ZR.Admin.WebApi/Framework/CookieUtil.cs
@@ -0,0 +1,17 @@
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.Cookies;
+using Microsoft.AspNetCore.Http;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Claims;
+using System.Threading.Tasks;
+
+namespace ZR.Admin.WebApi.Framework
+{
+ public class CookieUtil
+ {
+
+
+ }
+}
diff --git a/ZR.Admin.WebApi/Framework/JwtUtil.cs b/ZR.Admin.WebApi/Framework/JwtUtil.cs
new file mode 100644
index 0000000..e75abff
--- /dev/null
+++ b/ZR.Admin.WebApi/Framework/JwtUtil.cs
@@ -0,0 +1,114 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.IdentityModel.Tokens;
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.IdentityModel.Tokens.Jwt;
+using System.Linq;
+using System.Security.Claims;
+using System.Text;
+using ZR.Admin.WebApi.Extensions;
+using ZR.Model.System;
+
+namespace ZR.Admin.WebApi.Framework
+{
+ ///
+ /// 2020-11-20
+ ///
+ public class JwtUtil
+ {
+ public static readonly string KEY = "asdfghjklzxcvbnm";
+
+ ///
+ /// 获取用户身份信息
+ ///
+ ///
+ ///
+ public static LoginUser GetLoginUser(HttpContext httpContext)
+ {
+ string token = HttpContextExtension.GetToken(httpContext);
+ if (!string.IsNullOrEmpty(token))
+ {
+ return ValidateJwtToken(ParseToken(token));
+ }
+ return null;
+ }
+
+ ///
+ /// 生成token
+ ///
+ ///
+ ///
+ public static string GenerateJwtToken(List claims)
+ {
+ var tokenHandler = new JwtSecurityTokenHandler();
+ var key = Encoding.ASCII.GetBytes(KEY);
+ var tokenDescriptor = new SecurityTokenDescriptor
+ {
+ Subject = new ClaimsIdentity(claims),
+ //Issuer = "",
+ //Audience = "",
+ Expires = DateTime.Now.AddDays(7),
+ SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
+ };
+ var token = tokenHandler.CreateToken(tokenDescriptor);
+ return tokenHandler.WriteToken(token);
+ }
+
+ ///
+ /// 从令牌中获取数据声明
+ ///
+ /// 令牌
+ ///
+ public static IEnumerable ParseToken(string token)
+ {
+ var tokenHandler = new JwtSecurityTokenHandler();
+ var key = Encoding.ASCII.GetBytes(KEY);
+ try
+ {
+ tokenHandler.ValidateToken(token, new TokenValidationParameters
+ {
+ ValidateIssuerSigningKey = true,
+ IssuerSigningKey = new SymmetricSecurityKey(key),
+ ValidateIssuer = false,
+ ValidateAudience = false,
+ // set clockskew to zero so tokens expire exactly at token expiration time (instead of 5 minutes later)
+ ClockSkew = TimeSpan.Zero
+ }, out SecurityToken validatedToken);
+
+ //{{"alg":"HS256","typ":"JWT"}.{"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/sid":"2","unique_name":"ry","nameid":"2","given_name":"若依","nbf":1606654010,"exp":1606740410,"iat":1606654010}}
+ var jwtToken = (JwtSecurityToken)validatedToken;
+ return jwtToken.Claims;
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.Message);
+ // return null if validation fails
+ return null;
+ }
+ }
+
+ ///
+ /// jwt token校验
+ ///
+ ///
+ ///
+ private static LoginUser ValidateJwtToken(IEnumerable jwtToken)
+ {
+ try
+ {
+ var userId = jwtToken.FirstOrDefault(x => x.Type == "primarysid").Value;
+ var userName = jwtToken.FirstOrDefault(x => x.Type == "unique_name").Value;
+ var userData = jwtToken.FirstOrDefault(x => x.Type == ClaimTypes.UserData).Value;
+
+ LoginUser loginUser = JsonConvert.DeserializeObject(userData);
+ return loginUser;
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.Message);
+ return null;
+ }
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/Middleware/GlobalExceptionMiddleware.cs b/ZR.Admin.WebApi/Middleware/GlobalExceptionMiddleware.cs
new file mode 100644
index 0000000..4bbe298
--- /dev/null
+++ b/ZR.Admin.WebApi/Middleware/GlobalExceptionMiddleware.cs
@@ -0,0 +1,103 @@
+using Infrastructure;
+using Infrastructure.Model;
+using IPTools.Core;
+using Microsoft.AspNetCore.Http;
+using Newtonsoft.Json;
+using NLog;
+using System;
+using System.Threading.Tasks;
+using ZR.Admin.WebApi.Extensions;
+using ZR.Admin.WebApi.Filters;
+using ZR.Model.System;
+using ZR.Service.IService;
+
+namespace ZR.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)
+ {
+ LogLevel logLevel = 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 = LogLevel.Error;
+ context.Response.StatusCode = 500;
+ }
+
+ string responseResult = System.Text.Json.JsonSerializer.Serialize(new ApiResult(code, msg)).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 = context.User.Identity.Name,
+ operLocation = ip_info.Province + " " + ip_info.City,
+ operTime = DateTime.Now
+ };
+ LogActionFilter.GetRequestValue(sysOperLog, context);
+ LogEventInfo ei = new(logLevel, "GlobalExceptionMiddleware", error);
+
+ ei.Exception = ex;
+ ei.Message = error;
+ ei.Properties["status"] = 1;//走正常返回都是通过走GlobalExceptionFilter不通过
+ ei.Properties["jsonResult"] = responseResult;
+ ei.Properties["requestParam"] = sysOperLog.operParam;
+ ei.Properties["user"] = context.User.Identity.Name;
+
+ Logger.Log(ei);
+ await context.Response.WriteAsync(responseResult);
+
+ SysOperLogService.InsertOperlog(sysOperLog);
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/Middleware/RequestIPMiddleware.cs b/ZR.Admin.WebApi/Middleware/RequestIPMiddleware.cs
new file mode 100644
index 0000000..0baa7b8
--- /dev/null
+++ b/ZR.Admin.WebApi/Middleware/RequestIPMiddleware.cs
@@ -0,0 +1,70 @@
+using Common;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Logging;
+using NLog;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+
+namespace ZRAdmin.Middleware
+{
+ public class RequestIPMiddleware
+ {
+ private readonly RequestDelegate _next;
+
+ static readonly Logger Logger = LogManager.GetCurrentClassLogger();//声明NLog变量
+
+ public RequestIPMiddleware(RequestDelegate next)
+ {
+ _next = next;
+ }
+
+ public async Task Invoke(HttpContext context)
+ {
+ var url = context.Request.Path.ToString().ToLower();
+ string userip = Tools.GetRealIP();
+ //string agent = HttpContextExtension.GetUserAgent(context);
+
+ string[] urls = new string[] { "/css", "/js", "/images", "/lib", "/home/error", "/api" };
+
+ var strRegex = "(.jpg|.png|.gif|.php|.cfg|.ico)$"; //用于验证图片扩展名的正则表达式
+ var re = new Regex(strRegex);
+
+ //阻止.php访问往下请求
+ if (new Regex("(.php)$").IsMatch(url))
+ {
+ await context.Response.WriteAsync("hello");
+ return;
+ }
+
+ //var ip_info = IpTool.Search(userip);
+
+ ////bool flag = ((IList)urls).Contains(url);
+ //if (!re.IsMatch(url) )
+ //{
+ Logger.Debug($"IP中间件请求访问,IP[{userip}]");
+ //}
+
+ //两种方式传递下去 一是invoke 一个直接next
+ //await _next.Invoke(context);
+
+ await _next(context);
+ }
+ }
+
+ public static class RequestIPMiddlewareExtensions
+ {
+ ///
+ /// 用于引用请求IP中间件
+ ///
+ /// 扩展类型
+ /// IApplicationBuilder
+ public static IApplicationBuilder UseRequestIPMiddleware(this IApplicationBuilder builder)
+ {
+ return builder.UseMiddleware();
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/NLog.config b/ZR.Admin.WebApi/NLog.config
new file mode 100644
index 0000000..a9d6783
--- /dev/null
+++ b/ZR.Admin.WebApi/NLog.config
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ZR.Admin.WebApi/Program.cs b/ZR.Admin.WebApi/Program.cs
new file mode 100644
index 0000000..07633fb
--- /dev/null
+++ b/ZR.Admin.WebApi/Program.cs
@@ -0,0 +1,29 @@
+using Infrastructure.Startups;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Hosting;
+using NLog.Web;
+
+namespace ZR.Admin.WebApi
+{
+ public class Program
+ {
+ public static void Main(string[] args)
+ {
+ CreateHostBuilder(args).Build().Run();
+ }
+
+ public static IHostBuilder CreateHostBuilder(string[] args)
+ {
+ var builder = Host.CreateDefaultBuilder(args)
+ .ConfigureWebHostDefaults(webBuilder =>
+ {
+ webBuilder
+ .Init("Infrastructure")
+ .UseNLog()
+ .UseStartup();
+ });
+
+ return builder;
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/Properties/PublishProfiles/FolderProfile.pubxml b/ZR.Admin.WebApi/Properties/PublishProfiles/FolderProfile.pubxml
new file mode 100644
index 0000000..48bf8f3
--- /dev/null
+++ b/ZR.Admin.WebApi/Properties/PublishProfiles/FolderProfile.pubxml
@@ -0,0 +1,20 @@
+
+
+
+
+ True
+ False
+ True
+ Release
+ Any CPU
+ FileSystem
+ bin\Release\net5.0\publish\
+ FileSystem
+
+ net5.0
+ ba176987-aabb-406a-b4a8-6b63b422b703
+ false
+
+
\ No newline at end of file
diff --git a/ZR.Admin.WebApi/Properties/launchSettings.json b/ZR.Admin.WebApi/Properties/launchSettings.json
new file mode 100644
index 0000000..c5c2293
--- /dev/null
+++ b/ZR.Admin.WebApi/Properties/launchSettings.json
@@ -0,0 +1,27 @@
+{
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:50509/",
+ "sslPort": 44365
+ }
+ },
+ "profiles": {
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "ZRAdmin": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Stage"
+ },
+ "applicationUrl": "https://localhost:5001;http://localhost:5000"
+ }
+ }
+}
\ No newline at end of file
diff --git a/ZR.Admin.WebApi/Startup.cs b/ZR.Admin.WebApi/Startup.cs
new file mode 100644
index 0000000..360469a
--- /dev/null
+++ b/ZR.Admin.WebApi/Startup.cs
@@ -0,0 +1,127 @@
+using Hei.Captcha;
+using Infrastructure;
+using Infrastructure.Extensions;
+using Microsoft.AspNetCore.Authentication.Cookies;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.DataProtection;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc.Razor;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.OpenApi.Models;
+using System.IO;
+using ZR.Admin.WebApi.Extensions;
+using ZR.Admin.WebApi.Filters;
+using ZR.Admin.WebApi.Middleware;
+
+namespace ZR.Admin.WebApi
+{
+ public class Startup
+ {
+ public Startup(IConfiguration configuration)
+ {
+ Configuration = configuration;
+ }
+
+ public IConfiguration Configuration { get; }
+ public void ConfigureServices(IServiceCollection services)
+ {
+ string corsUrls = Configuration["sysConfig:cors"];
+
+ //ÅäÖÿçÓò
+ services.AddCors(c =>
+ {
+ c.AddPolicy("Policy", policy =>
+ {
+ policy.WithOrigins(corsUrls.Split(',', System.StringSplitOptions.RemoveEmptyEntries))
+ .AllowAnyHeader()//ÔÊÐíÈÎÒâͷ
+ .AllowCredentials()//ÔÊÐícookie
+ .AllowAnyMethod();//ÔÊÐíÈÎÒⷽ·¨
+ });
+ });
+ //Ïû³ýError unprotecting the session cookie¾¯¸æ
+ services.AddDataProtection().PersistKeysToFileSystem(new DirectoryInfo(Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + "DataProtection"));
+ //ÆÕͨÑé֤Âë
+ services.AddHeiCaptcha();
+ services.AddSession();
+ services.AddHttpContextAccessor();
+
+ //Cookie ÈÏ֤
+ services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie();
+
+ //°ó¶¨Õû¸ö¶ÔÏóµ½ModelÉÏ
+ services.Configure(Configuration);
+
+ InjectRepositories(services);
+
+ services.AddMvc(options =>
+ {
+ options.Filters.Add(typeof(GlobalActionMonitor));//ȫ¾Öע²áÒ쳣
+ })
+ .AddMvcLocalization()
+ .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix);
+
+ services.AddSwaggerGen(c =>
+ {
+ c.SwaggerDoc("v1", new OpenApiInfo { Title = "ZrAdmin", Version = "v1" });
+ });
+ }
+
+ // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+ {
+ if (env.IsDevelopment())
+ {
+ app.UseDeveloperExceptionPage();
+ }
+ app.UseSwagger();
+ app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "ZrAdmin v1"));
+
+ //ʹ¿ÉÒԶà´ζàȥbodyÄÚÈÝ
+ app.Use((context, next) =>
+ {
+ context.Request.EnableBuffering();
+ return next();
+ });
+ //¿ªÆô·ÃÎʾ²̬Îļþ/wwwrootĿ¼Îļþ£¬Ҫ·ÅÔÚUseRoutingǰÃæ
+ app.UseStaticFiles();
+
+ app.UseRouting();
+ app.UseCors("Policy");//Ҫ·ÅÔÚapp.UseEndpointsǰ¡£
+
+ //app.UseAuthentication»áÆôÓÃAuthenticationÖмä¼þ£¬¸ÃÖмä¼þ»á¸ù¾ݵ±ǰHttpÇëÇóÖеÄCookieÐÅϢÀ´ÉèÖÃHttpContext.UserÊôÐԣ¨ºóÃæ»áÓõ½£©£¬
+ //ËùÒÔֻÓÐÔÚapp.UseAuthentication·½·¨֮ºóע²áµÄÖмä¼þ²ÅÄܹ»´ÓHttpContext.UserÖжÁȡµ½ֵ£¬
+ //ÕâҲÊÇΪʲôÉÏÃæǿµ÷app.UseAuthentication·½·¨һ¶¨Ҫ·ÅÔÚÏÂÃæµÄapp.UseMvc·½·¨ǰÃ棬ÒòΪֻÓÐÕâÑùASP.NET CoreµÄMVCÖмä¼þÖвÅÄܶÁȡµ½HttpContext.UserµÄֵ¡£
+ app.UseAuthentication();
+ app.UseAuthorization();
+ app.UseSession();
+ app.UseResponseCaching();
+
+ // »ָ´/Æô¶¯ÈÎÎñ
+ app.UseAddTaskSchedulers();
+
+ app.UseMiddleware();
+
+ app.UseEndpoints(endpoints =>
+ {
+ endpoints.MapControllerRoute(
+ name: "default",
+ pattern: "{controller=Home}/{action=Index}/{id?}");
+ });
+ }
+
+ ///
+ /// ע²áServices·þÎñ
+ ///
+ ///
+ private static void InjectRepositories(IServiceCollection services)
+ {
+ services.AddAppService();
+
+ //¿ªÆô¼ƻ®ÈÎÎñ
+ services.AddTaskSchedulers();
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/Template/Controller.cs b/ZR.Admin.WebApi/Template/Controller.cs
new file mode 100644
index 0000000..6b343ed
--- /dev/null
+++ b/ZR.Admin.WebApi/Template/Controller.cs
@@ -0,0 +1,130 @@
+
+//------------------------------------------------------------------------------
+//
+// 此代码已从模板生成。
+//
+// 手动更改此文件可能导致应用程序出现意外的行为。
+// 如果重新生成代码,将覆盖对此文件的手动更改。
+//
+//------------------------------------------------------------------------------
+using Infrastructure.Attribute;
+using Microsoft.AspNetCore.Mvc;
+using ZR.Admin.WebApi.Filters;
+using ZR.Model.System;
+using ZR.Service.IService;
+using Infrastructure.Model;
+using SqlSugar;
+using Mapster;
+using ZR.Model.Dto.System;
+using Infrastructure.Enums;
+using Infrastructure;
+using ZR.Admin.WebApi.Extensions;
+
+namespace ZR.Admin.WebApi.Controllers
+{
+ ///
+ /// T4代码自动生成
+ ///
+
+ [Verify]
+ [Route("system/SysFile")]
+ public class SysFile1Controller: BaseController
+ {
+ ///
+ /// 文件管理接口
+ ///
+ private readonly ISysFileService _SysFileService;
+
+ public SysFile1Controller(ISysFileService SysFileService)
+ {
+ _SysFileService = SysFileService;
+ }
+
+ ///
+ /// 查询文件管理列表
+ ///
+ ///
+ [HttpGet("list")]
+ //[ActionPermissionFilter(Permission = "system:SysFile:list")]
+ public IActionResult Query([FromQuery] SysFileQueryDto parm)
+ {
+ //开始拼装查询条件
+ var predicate = Expressionable.Create();
+
+ //TODO 搜索条件
+ //predicate = predicate.And(m => m.Name.Contains(parm.Name));
+
+ var response = _SysFileService.GetPages(predicate.ToExpression(), parm);
+
+ return SUCCESS(response);
+ }
+
+ ///
+ /// 查询文件管理详情
+ ///
+ ///
+ ///
+ [HttpGet("{id}")]
+ public IActionResult Get(string id)
+ {
+ var response = _SysFileService.GetId(id);
+
+ return SUCCESS(response);
+ }
+
+ ///
+ /// 添加文件管理
+ ///
+ ///
+ [HttpPost]
+ //[ActionPermissionFilter(Permission = "system:SysFile:add")]
+ [Log(Title = "文件管理添加", BusinessType = BusinessType.INSERT)]
+ public IActionResult Create([FromBody] SysFile parm)
+ {
+ if (parm == null)
+ {
+ throw new CustomException("请求参数错误");
+ }
+ //从 Dto 映射到 实体
+ var addModel = parm.Adapt().ToCreate();
+ //addModel.CreateID = User.Identity.Name;
+
+ return SUCCESS(_SysFileService.Add(addModel));
+ }
+
+ ///
+ /// 更新文件管理
+ ///
+ ///
+ [HttpPut("edit")]
+ //[ActionPermissionFilter(Permission = "system:SysFile:update")]
+ [Log(Title = "文件管理修改", BusinessType = BusinessType.UPDATE)]
+ public IActionResult Update([FromBody] SysFile parm)
+ {
+ //从 Dto 映射到 实体
+ var addModel = parm.Adapt().ToCreate();
+ //addModel.CreateID = User.Identity.Name;
+ //TODO 字段映射
+ var response = _SysFileService.Update(addModel);
+
+ return SUCCESS(response);
+ }
+
+ ///
+ /// 删除文件管理
+ ///
+ ///
+ [HttpDelete("{id}")]
+ //[ActionPermissionFilter(Permission = "system:SysFile:delete")]
+ [Log(Title = "文件管理删除", BusinessType = BusinessType.DELETE)]
+ public IActionResult Delete(int id = 0)
+ {
+ if (id <= 0) { return OutputJson(ApiResult.Error($"删除失败Id 不能为空")); }
+
+ // 删除文件管理
+ var response = _SysFileService.Delete(id);
+
+ return SUCCESS(response);
+ }
+ }
+}
\ No newline at end of file
diff --git a/ZR.Admin.WebApi/Template/Controller.tt b/ZR.Admin.WebApi/Template/Controller.tt
new file mode 100644
index 0000000..3646cc6
--- /dev/null
+++ b/ZR.Admin.WebApi/Template/Controller.tt
@@ -0,0 +1,145 @@
+<#@ template debug="false" hostspecific="false" language="C#" #>
+<#@ assembly name="System.Core" #>
+<#@ import namespace="System.Linq" #>
+<#@ import namespace="System.Text" #>
+<#@ import namespace="System.Collections.Generic" #>
+<#@ output extension=".cs" #>
+
+<#
+string ModelName="SysFile";
+string ControllerName="SysFile";
+string ServiceName="SysFileService";
+string FileName="文件管理";
+string ModelNameSpace="ZRAdmin.Controllers";
+#>
+//------------------------------------------------------------------------------
+//
+// 此代码已从模板生成。
+//
+// 手动更改此文件可能导致应用程序出现意外的行为。
+// 如果重新生成代码,将覆盖对此文件的手动更改。
+//
+//------------------------------------------------------------------------------
+using Infrastructure.Attribute;
+using Microsoft.AspNetCore.Mvc;
+using ZRAdmin.Filters;
+using ZR.Model;
+using ZR.Model.System;
+using ZR.Model.Vo;
+using ZR.Service.IService;
+using Infrastructure.Model;
+using SqlSugar;
+using Mapster;
+using ZR.Model.Dto.System;
+using Infrastructure.Enums;
+using Infrastructure;
+using ZRAdmin.Extensions;
+
+namespace <#=ModelNameSpace#>
+{
+ ///
+ /// T4代码自动生成
+ ///
+
+ [Verify]
+ [Route("system/<#=ModelName#>")]
+ public class <#=ControllerName#>1Controller: BaseController
+ {
+ ///
+ /// <#=FileName#>接口
+ ///
+ private readonly I<#=ServiceName#> _<#=ServiceName#>;
+
+ public <#=ControllerName#>1Controller(I<#=ServiceName#> <#=ServiceName#>)
+ {
+ _<#=ServiceName#> = <#=ServiceName#>;
+ }
+
+ ///
+ /// 查询<#=FileName#>列表
+ ///
+ ///
+ [HttpGet("list")]
+ //[ActionPermissionFilter(Permission = "system:<#=ModelName#>:list")]
+ public IActionResult Query([FromQuery] <#=ModelName#>QueryDto parm)
+ {
+ //开始拼装查询条件
+ var predicate = Expressionable.Create<<#=ModelName#>>();
+
+ //TODO 搜索条件
+ //predicate = predicate.And(m => m.Name.Contains(parm.Name));
+
+ var response = _<#=ServiceName#>.GetPages(predicate.ToExpression(), parm);
+
+ return SUCCESS(response);
+ }
+
+ ///
+ /// 查询<#=FileName#>详情
+ ///
+ ///
+ ///
+ [HttpGet("{id}")]
+ public IActionResult Get(string id)
+ {
+ var response = _<#=ServiceName#>.GetId(id);
+
+ return SUCCESS(response);
+ }
+
+ ///
+ /// 添加<#=FileName#>
+ ///
+ ///
+ [HttpPost]
+ //[ActionPermissionFilter(Permission = "system:<#=ModelName#>:add")]
+ [Log(Title = "<#=FileName#>添加", BusinessType = BusinessType.INSERT)]
+ public IActionResult Create([FromBody] <#=ModelName#> parm)
+ {
+ if (parm == null)
+ {
+ throw new CustomException("请求参数错误");
+ }
+ //从 Dto 映射到 实体
+ var addModel = parm.Adapt<<#=ModelName#>>().ToCreate();
+ //addModel.CreateID = User.Identity.Name;
+
+ return SUCCESS(_<#=ServiceName#>.Add(addModel));
+ }
+
+ ///
+ /// 更新<#=FileName#>
+ ///
+ ///
+ [HttpPut("edit")]
+ //[ActionPermissionFilter(Permission = "system:<#=ModelName#>:update")]
+ [Log(Title = "<#=FileName#>修改", BusinessType = BusinessType.UPDATE)]
+ public IActionResult Update([FromBody] <#=ModelName#> parm)
+ {
+ //从 Dto 映射到 实体
+ var addModel = parm.Adapt<<#=ModelName#>>().ToCreate();
+ //addModel.CreateID = User.Identity.Name;
+ //TODO 字段映射
+ var response = _<#=ServiceName#>.Update(addModel);
+
+ return SUCCESS(response);
+ }
+
+ ///
+ /// 删除<#=FileName#>
+ ///
+ ///
+ [HttpDelete("{id}")]
+ //[ActionPermissionFilter(Permission = "system:<#=ModelName#>:delete")]
+ [Log(Title = "<#=FileName#>删除", BusinessType = BusinessType.DELETE)]
+ public IActionResult Delete(int id = 0)
+ {
+ if (id <= 0) { return OutputJson(ApiResult.Error($"删除失败Id 不能为空")); }
+
+ // 删除<#=FileName#>
+ var response = _<#=ServiceName#>.Delete(id);
+
+ return SUCCESS(response);
+ }
+ }
+}
\ No newline at end of file
diff --git a/ZR.Admin.WebApi/ZR.Admin.WebApi.csproj b/ZR.Admin.WebApi/ZR.Admin.WebApi.csproj
new file mode 100644
index 0000000..9f82d37
--- /dev/null
+++ b/ZR.Admin.WebApi/ZR.Admin.WebApi.csproj
@@ -0,0 +1,78 @@
+
+
+
+ net5.0
+ bc51af00-60b6-4e2a-935e-267c368c890a
+ false
+ zh-Hans
+
+
+
+ ..\ZRAdmin.xml
+ 1701;1702;1591;1570
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Always
+
+
+
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ TextTemplatingFileGenerator
+ Controller.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ Controller.tt
+
+
+
+
diff --git a/ZR.Admin.WebApi/appsettings.Development.json b/ZR.Admin.WebApi/appsettings.Development.json
new file mode 100644
index 0000000..8d64c6d
--- /dev/null
+++ b/ZR.Admin.WebApi/appsettings.Development.json
@@ -0,0 +1,30 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ },
+ "appName": "ZR Admin System",
+ "ConnectionStrings": {
+ "Conn_Admin": "server=127.0.0.1;database=admin;user=zr;pwd=abc"
+ },
+ "urls": "http://localhost:8888", //Æô¶¯url
+ "sysConfig": {
+ "DBCommandTimeout": 10,
+ "cors": "http://localhost:8887" //ÅäÖÿçÓòµØַ
+ },
+ "DemoMode": false, //ÊǷñÑÝʾģʽ
+ "DbKey": "",
+ "DbType": 0, //MySql = 0, SqlServer = 1, Sqlite = 2, Oracle = 3, PostgreSQL = 4,
+ "Upload": {
+ "UploadDirectory": "/",
+ "UploadUrl": "http://localhost:8888"
+ },
+ "ALYUN_OCS": {
+ "REGIONID": "cn-hangzhou",
+ "KEY": "XX",
+ "SECRET": "XX"
+ }
+}
diff --git a/ZR.Admin.WebApi/appsettings.Production.json b/ZR.Admin.WebApi/appsettings.Production.json
new file mode 100644
index 0000000..68ffe8e
--- /dev/null
+++ b/ZR.Admin.WebApi/appsettings.Production.json
@@ -0,0 +1,30 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ },
+ "appName": "ZR Admin system",
+ "ConnectionStrings": {
+ "Conn_Admin": "server=127.0.0.1;database=admin;user=zr;pwd=abc"
+ },
+ "urls": "http://localhost:8888",
+ "sysConfig": {
+ "DBCommandTimeout": 10,
+ "cors": "http://localhost:8887"
+ },
+ "DemoMode": false, //ÊǷñÑÝʾģʽ
+ "DbKey": "",
+ "DbType": 0, //MySql = 0, SqlServer = 1, Sqlite = 2, Oracle = 3, PostgreSQL = 4,
+ "Upload": {
+ "UploadDirectory": "/",
+ "UploadUrl": "http://localhost:8888"
+ },
+ "ALYUN_OCS": {
+ "REGIONID": "cn-hangzhou",
+ "KEY": "XX",
+ "SECRET": "XX"
+ }
+}
diff --git a/ZR.Admin.WebApi/appsettings.json b/ZR.Admin.WebApi/appsettings.json
new file mode 100644
index 0000000..8983e0f
--- /dev/null
+++ b/ZR.Admin.WebApi/appsettings.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ }
+}
diff --git a/ZR.Admin.WebApi/build.bat b/ZR.Admin.WebApi/build.bat
new file mode 100644
index 0000000..f3d0008
--- /dev/null
+++ b/ZR.Admin.WebApi/build.bat
@@ -0,0 +1,8 @@
+@echo off
+
+docker build -t ZRAdmin:latest -f ./Dockerfile .
+
+echo "==============²鿴¾µÏñ==========="
+docker images
+
+pause
\ No newline at end of file
diff --git a/ZR.Admin.WebApi/ip2region.db b/ZR.Admin.WebApi/ip2region.db
new file mode 100644
index 0000000..0fc60e6
Binary files /dev/null and b/ZR.Admin.WebApi/ip2region.db differ
diff --git a/ZR.CodeGenerator/TableMappingHelper.cs b/ZR.CodeGenerator/TableMappingHelper.cs
new file mode 100644
index 0000000..e0c9daa
--- /dev/null
+++ b/ZR.CodeGenerator/TableMappingHelper.cs
@@ -0,0 +1,110 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Infrastructure.Extensions;
+using ZR.Common.Extension;
+
+namespace ZR.CodeGenerator.CodeGenerator
+{
+ public class TableMappingHelper
+ {
+ ///
+ /// UserService转成userService
+ ///
+ ///
+ ///
+ public static string FirstLetterLowercase(string instanceName)
+ {
+ instanceName = instanceName.ParseToString();
+ if (!instanceName.IsEmpty())
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append(instanceName[0].ToString().ToLower() + instanceName.Substring(1));
+ return sb.ToString();
+ }
+ else
+ {
+ return instanceName;
+ }
+ }
+
+ ///
+ /// sys_menu_authorize变成MenuAuthorize
+ ///
+ public static string GetClassNamePrefix(string tableName)
+ {
+ string[] arr = tableName.Split('_');
+ StringBuilder sb = new StringBuilder();
+ for (int i = 1; i < arr.Length; i++)
+ {
+ sb.Append(arr[i][0].ToString().ToUpper() + arr[i].Substring(1));
+ }
+ return sb.ToString();
+ }
+
+ public static string GetPropertyDatatype(string sDatatype)
+ {
+ string sTempDatatype = string.Empty;
+ sDatatype = sDatatype.ToLower();
+ switch (sDatatype)
+ {
+ case "int":
+ case "number":
+ case "integer":
+ case "smallint":
+ sTempDatatype = "int?";
+ break;
+
+ case "bigint":
+ sTempDatatype = "long?";
+ break;
+
+ case "tinyint":
+ sTempDatatype = "byte?";
+ break;
+
+ case "numeric":
+ case "real":
+ sTempDatatype = "Single?";
+ break;
+
+ case "float":
+ sTempDatatype = "float?";
+ break;
+
+ case "decimal":
+ case "numer(8,2)":
+ sTempDatatype = "decimal?";
+ break;
+
+ case "bit":
+ sTempDatatype = "bool?";
+ break;
+
+ case "date":
+ case "datetime":
+ case "datetime2":
+ case "smalldatetime":
+ sTempDatatype = "DateTime?";
+ break;
+
+ case "money":
+ case "smallmoney":
+ sTempDatatype = "double?";
+ break;
+
+ case "char":
+ case "varchar":
+ case "nvarchar2":
+ case "text":
+ case "nchar":
+ case "nvarchar":
+ case "ntext":
+ default:
+ sTempDatatype = "string";
+ break;
+ }
+ return sTempDatatype;
+ }
+ }
+}
diff --git a/ZR.CodeGenerator/ZR.CodeGenerator.csproj b/ZR.CodeGenerator/ZR.CodeGenerator.csproj
new file mode 100644
index 0000000..948f805
--- /dev/null
+++ b/ZR.CodeGenerator/ZR.CodeGenerator.csproj
@@ -0,0 +1,18 @@
+
+
+
+ net5.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ZR.Common/Cache/CacheHelper.cs b/ZR.Common/Cache/CacheHelper.cs
new file mode 100644
index 0000000..9a4c8dc
--- /dev/null
+++ b/ZR.Common/Cache/CacheHelper.cs
@@ -0,0 +1,122 @@
+
+using Microsoft.Extensions.Caching.Memory;
+using System;
+using System.Web;
+
+///
+/// 数据缓存操作类 author by zhaorui 2021-3-6
+///
+namespace ZR.Common
+{
+ public class CacheHelper
+ {
+ public static MemoryCache Cache { get; set; }
+ static CacheHelper()
+ {
+ Cache = new MemoryCache(new MemoryCacheOptions
+ {
+ //SizeLimit = 1024
+ });
+ }
+
+ ///
+ /// 全局缓存时间
+ ///
+ public static int CacheTime = 5; //ConfigHelper.GetConfigInt("CacheTime");
+
+ ///
+ /// 获取缓存
+ ///
+ ///
+ ///
+ ///
+ 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);
+ //return HttpRuntime.Cache[CacheKey];
+ }
+
+ public static object Get(string CacheKey)
+ {
+ return Cache.Get(CacheKey);
+ }
+
+ ///
+ /// 设置缓存,永久缓存
+ ///
+ /// key
+ /// 值
+ public static void SetCache(string CacheKey, object objObject)
+ {
+ Cache.Set(CacheKey, objObject);
+ }
+
+ ///
+ /// 设置缓存
+ ///
+ /// key
+ /// 值
+ /// 过期时间(分钟)
+ public static void SetCache(string CacheKey, object objObject, int Timeout)
+ {
+ 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 void SetCache(string CacheKey, object objObject, DateTime absoluteExpiration, TimeSpan slidingExpiration)
+ {
+ 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/ZR.Common/ComputerHelper.cs b/ZR.Common/ComputerHelper.cs
new file mode 100644
index 0000000..041022f
--- /dev/null
+++ b/ZR.Common/ComputerHelper.cs
@@ -0,0 +1,150 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Text;
+using ZR.Common.Extension;
+
+namespace ZR.Common
+{
+ public class ComputerHelper
+ {
+ public static ComputerInfo GetComputerInfo()
+ {
+ ComputerInfo computerInfo = new ComputerInfo();
+ try
+ {
+ MemoryMetricsClient client = new MemoryMetricsClient();
+ MemoryMetrics memoryMetrics = client.GetMetrics();
+ computerInfo.TotalRAM = Math.Ceiling(memoryMetrics.Total / 1024).ToString() + " GB";
+ computerInfo.RAMRate = Math.Ceiling(100 * memoryMetrics.Used / memoryMetrics.Total).ToString() + " %";
+ computerInfo.CPURate = Math.Ceiling(GetCPURate().ParseToDouble()) + " %";
+ computerInfo.RunTime = GetRunTime();
+ }
+ catch (Exception ex)
+ {
+ //LogHelper.Error(ex);
+ }
+ return computerInfo;
+ }
+
+ public static bool IsUnix()
+ {
+ var isUnix = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
+ return isUnix;
+ }
+
+ public static string GetCPURate()
+ {
+ string cpuRate = string.Empty;
+ 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");
+ output = output.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)
+ {
+ //LogHelper.Error(ex);
+ }
+ return runTime;
+ }
+ }
+
+ public class MemoryMetrics
+ {
+ public double Total { get; set; }
+ public double Used { get; set; }
+ public double Free { get; set; }
+ }
+
+ public class MemoryMetricsClient
+ {
+ public MemoryMetrics GetMetrics()
+ {
+ if (ComputerHelper.IsUnix())
+ {
+ return GetUnixMetrics();
+ }
+ return GetWindowsMetrics();
+ }
+
+ private MemoryMetrics GetWindowsMetrics()
+ {
+ string output = ShellHelper.Cmd("wmic", "OS get FreePhysicalMemory,TotalVisibleMemorySize /Value");
+
+ var lines = output.Trim().Split('\n');
+ var freeMemoryParts = lines[0].Split('=', (char)StringSplitOptions.RemoveEmptyEntries);
+ var totalMemoryParts = lines[1].Split('=', (char)StringSplitOptions.RemoveEmptyEntries);
+
+ var metrics = new MemoryMetrics();
+ metrics.Total = Math.Round(double.Parse(totalMemoryParts[1]) / 1024, 0);
+ metrics.Free = Math.Round(double.Parse(freeMemoryParts[1]) / 1024, 0);
+ metrics.Used = metrics.Total - metrics.Free;
+
+ return metrics;
+ }
+
+ private MemoryMetrics GetUnixMetrics()
+ {
+ string output = ShellHelper.Bash("free -m");
+
+ var lines = output.Split('\n');
+ var memory = lines[1].Split(' ', (char)StringSplitOptions.RemoveEmptyEntries);
+
+ var metrics = new MemoryMetrics();
+ metrics.Total = double.Parse(memory[1]);
+ metrics.Used = double.Parse(memory[2]);
+ metrics.Free = double.Parse(memory[3]);
+
+ return metrics;
+ }
+ }
+
+ public class ComputerInfo
+ {
+ ///
+ /// CPU使用率
+ ///
+ public string CPURate { get; set; }
+ ///
+ /// 总内存
+ ///
+ public string TotalRAM { get; set; }
+ ///
+ /// 内存使用率
+ ///
+ public string RAMRate { get; set; }
+ ///
+ /// 系统运行时间
+ ///
+ public string RunTime { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/ZR.Common/DateTimeHelper.cs b/ZR.Common/DateTimeHelper.cs
new file mode 100644
index 0000000..2fb05d7
--- /dev/null
+++ b/ZR.Common/DateTimeHelper.cs
@@ -0,0 +1,100 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ZR.Common
+{
+ 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 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/ZR.Common/Extension/Extension.Convert.cs b/ZR.Common/Extension/Extension.Convert.cs
new file mode 100644
index 0000000..febe6bb
--- /dev/null
+++ b/ZR.Common/Extension/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 ZR.Common.Extension
+{
+ 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/ZR.Common/Extension/Extension.Enum.cs b/ZR.Common/Extension/Extension.Enum.cs
new file mode 100644
index 0000000..d5be020
--- /dev/null
+++ b/ZR.Common/Extension/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 ZR.Common.Extension
+{
+ 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/ZR.Common/Extension/Extension.Exception.cs b/ZR.Common/Extension/Extension.Exception.cs
new file mode 100644
index 0000000..f021439
--- /dev/null
+++ b/ZR.Common/Extension/Extension.Exception.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ZR.Common.Extension
+{
+ 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/ZR.Common/Extension/Extension.Linq.cs b/ZR.Common/Extension/Extension.Linq.cs
new file mode 100644
index 0000000..45425ec
--- /dev/null
+++ b/ZR.Common/Extension/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 ZR.Common.Extension
+{
+ 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/ZR.Common/Extension/Extension.Validate.cs b/ZR.Common/Extension/Extension.Validate.cs
new file mode 100644
index 0000000..379972b
--- /dev/null
+++ b/ZR.Common/Extension/Extension.Validate.cs
@@ -0,0 +1,46 @@
+//using Microsoft.AspNetCore.Http;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ZR.Common.Extension
+{
+ 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 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/ZR.Common/FileUtil.cs b/ZR.Common/FileUtil.cs
new file mode 100644
index 0000000..ae0a079
--- /dev/null
+++ b/ZR.Common/FileUtil.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace ZR.Common
+{
+ public class FileUtil
+ {
+ ///
+ /// 按时间来创建文件夹
+ ///
+ ///
+ /// eg: /{yourPath}/2020/11/3
+ public static string GetdirPath(string path = "")
+ {
+ DateTime date = DateTime.Now;
+ int year = date.Year;
+ int month = date.Month;
+ int day = date.Day;
+ int hour = date.Hour;
+
+ string timeDir = $"{year}/{month}/{day}/{hour}";// date.ToString("yyyyMM/dd/HH/");
+
+ if (!string.IsNullOrEmpty(path))
+ {
+ timeDir = $"{path}/{timeDir}";
+ }
+ return timeDir;
+ }
+
+ ///
+ /// 取文件名的MD5值(16位)
+ ///
+ /// 文件名,不包括扩展名
+ ///
+ public static string HashFileName(string str = null)
+ {
+ if (string.IsNullOrEmpty(str))
+ {
+ str = Guid.NewGuid().ToString();
+ }
+ MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
+ return BitConverter.ToString(md5.ComputeHash(Encoding.Default.GetBytes(str)), 4, 8).Replace("-", "");
+ }
+ }
+}
diff --git a/ZR.Common/HttpHelper.cs b/ZR.Common/HttpHelper.cs
new file mode 100644
index 0000000..403a916
--- /dev/null
+++ b/ZR.Common/HttpHelper.cs
@@ -0,0 +1,128 @@
+using System;
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ZR.Common
+{
+ 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/ZR.Common/ShellHelper.cs b/ZR.Common/ShellHelper.cs
new file mode 100644
index 0000000..c5f7ce3
--- /dev/null
+++ b/ZR.Common/ShellHelper.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Text;
+
+namespace ZR.Common
+{
+ public class ShellHelper
+ {
+ 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;
+ }
+
+ 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/ZR.Common/Tools.cs b/ZR.Common/Tools.cs
new file mode 100644
index 0000000..998f390
--- /dev/null
+++ b/ZR.Common/Tools.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ZR.Common
+{
+ public class Tools
+ {
+ ///
+ /// 要分割的字符串 eg: 1,3,10,00
+ ///
+ ///
+ ///
+ public static long[] SpitLongArrary(string str)
+ {
+ string[] strIds = str.Split(',', (char)StringSplitOptions.RemoveEmptyEntries);
+ long[] infoIdss = Array.ConvertAll(strIds, s => long.Parse(s));
+ return infoIdss;
+ }
+
+ public static int[] SpitIntArrary(string str)
+ {
+ string[] strIds = str.Split(',', (char)StringSplitOptions.RemoveEmptyEntries);
+ int[] infoIdss = Array.ConvertAll(strIds, s => int.Parse(s));
+ return infoIdss;
+ }
+
+ ///
+ /// 根据日期获取星期几
+ ///
+ 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;
+ }
+ }
+}
diff --git a/ZR.Common/ZR.Common.csproj b/ZR.Common/ZR.Common.csproj
new file mode 100644
index 0000000..bb64769
--- /dev/null
+++ b/ZR.Common/ZR.Common.csproj
@@ -0,0 +1,11 @@
+
+
+
+ net5.0
+
+
+
+
+
+
+
diff --git a/ZR.Model/ApiResult.cs b/ZR.Model/ApiResult.cs
new file mode 100644
index 0000000..462f8e0
--- /dev/null
+++ b/ZR.Model/ApiResult.cs
@@ -0,0 +1,103 @@
+using Newtonsoft.Json;
+using System.ComponentModel;
+
+namespace ZRModel
+{
+ ///
+ /// 通用json格式实体返回类
+ /// Author by zhaorui
+ ///
+ 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; }
+
+ public ApiResult()
+ {
+ Code = 0;
+ Msg = "fail";
+ }
+
+ public ApiResult OnSuccess()
+ {
+ Code = 100;
+ Msg = "success";
+ return this;
+ }
+ public ApiResult(int code, string msg, object data = null)
+ {
+ Code = code;
+ Msg = msg;
+ Data = data;
+ }
+
+ public ApiResult OnSuccess(object data = null)
+ {
+ Code = (int)ResultCode.SUCCESS;
+ Msg = "SUCCESS";
+ Data = data;
+ return this;
+ }
+
+ ///
+ /// 返回成功消息
+ ///
+ /// 数据对象
+ /// 成功消息
+ public static ApiResult Success(object data) { return new ApiResult(100, "success", data); }
+
+ ///
+ /// 返回成功消息
+ ///
+ /// 返回内容
+ /// 成功消息
+ public static ApiResult Success(string msg) { return new ApiResult(100, msg, null); }
+
+ ///
+ /// 返回成功消息
+ ///
+ /// 返回内容
+ /// 数据对象
+ /// 成功消息
+ public static ApiResult Success(string msg, object data) { return new ApiResult(100, msg, data); }
+
+ ///
+ /// 返回失败消息
+ ///
+ ///
+ ///
+ ///
+ public static ApiResult Error(int code, string msg) { return new ApiResult(code, msg); }
+
+ ///
+ /// 返回失败消息
+ ///
+ ///
+ ///
+ public static ApiResult Error(string msg) { return new ApiResult(200, msg); }
+
+ }
+ public enum ResultCode
+ {
+ [Description("success")]
+ SUCCESS = 100,
+ [Description("参数错误")]
+ PARAM_ERROR = 101,
+ [Description("自定义错误")]
+ CUSTOM_ERROR = 200,
+ FAIL = 0,
+ [Description("程序出错啦")]
+ GLOBAL_ERROR = 104,
+ [Description("请先绑定手机号")]
+ NOBIND_PHONENUM = 102,
+ [Description("授权失败")]
+ OAUTH_FAIL = 201,
+ [Description("未授权")]
+ DENY = 401
+ }
+}
diff --git a/ZR.Model/Dto/System/ArticleDto.cs b/ZR.Model/Dto/System/ArticleDto.cs
new file mode 100644
index 0000000..ff5a3c0
--- /dev/null
+++ b/ZR.Model/Dto/System/ArticleDto.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ZR.Model.Dto.System
+{
+ public class ArticleQueryDto: PagerInfo
+ {
+ public string Status { get; set; }
+ public string Title { get; set; }
+ public DateTime BeginTime { get; set; }
+ public DateTime EndTime { get; set; }
+
+ }
+}
diff --git a/ZR.Model/Dto/System/LoginBodyDto.cs b/ZR.Model/Dto/System/LoginBodyDto.cs
new file mode 100644
index 0000000..cf0fa0b
--- /dev/null
+++ b/ZR.Model/Dto/System/LoginBodyDto.cs
@@ -0,0 +1,30 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace ZR.Model.Dto.System
+{
+ 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; }
+ }
+}
diff --git a/ZR.Model/Dto/System/MenuDto.cs b/ZR.Model/Dto/System/MenuDto.cs
new file mode 100644
index 0000000..ac241f7
--- /dev/null
+++ b/ZR.Model/Dto/System/MenuDto.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ZR.Model.Dto.System
+{
+ public class MenuDto
+ {
+ //{"parentId":0,"menuName":"aaa","icon":"documentation","menuType":"M","orderNum":999,"visible":0,"status":0,"path":"aaa"}
+ public int parentId { get; set; }
+ public string menuName { get; set; }
+ public string icon { get; set; } = "";
+ public string menuType { get; set; }
+ public int orderNum { get; set; }
+ public int visible { get; set; }
+ public int status { get; set; }
+ public string path { get; set; } = "#";
+ public int MenuId { get; set; }
+ public string component { get; set; }
+ public int isCache { get; set; }
+ public int isFrame { get; set; }
+ public string perms { get; set; } = "";
+ }
+}
diff --git a/ZR.Model/Dto/System/RoleUsersCreateDto.cs b/ZR.Model/Dto/System/RoleUsersCreateDto.cs
new file mode 100644
index 0000000..2ba0cfb
--- /dev/null
+++ b/ZR.Model/Dto/System/RoleUsersCreateDto.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Text;
+
+namespace ZR.Model.Dto.System
+{
+ 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/ZR.Model/Dto/System/SysFileQueryDto.cs b/ZR.Model/Dto/System/SysFileQueryDto.cs
new file mode 100644
index 0000000..5c3d018
--- /dev/null
+++ b/ZR.Model/Dto/System/SysFileQueryDto.cs
@@ -0,0 +1,10 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ZR.Model.Dto.System
+{
+ public class SysFileQueryDto : PagerInfo
+ {
+ }
+}
diff --git a/ZR.Model/Dto/System/SysLogininfoDto.cs b/ZR.Model/Dto/System/SysLogininfoDto.cs
new file mode 100644
index 0000000..7d5bc43
--- /dev/null
+++ b/ZR.Model/Dto/System/SysLogininfoDto.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using ZR.Model.System;
+
+namespace ZR.Model.Dto.System
+{
+ 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/ZR.Model/Dto/System/SysOperLogDto.cs b/ZR.Model/Dto/System/SysOperLogDto.cs
new file mode 100644
index 0000000..e686da1
--- /dev/null
+++ b/ZR.Model/Dto/System/SysOperLogDto.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using ZR.Model.System;
+
+namespace ZR.Model.Dto.System
+{
+ public class SysOperLogDto : SysBase
+ {
+ ///
+ /// 页码
+ ///
+ public int pageNum { 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/ZR.Model/Dto/System/SysRoleDto.cs b/ZR.Model/Dto/System/SysRoleDto.cs
new file mode 100644
index 0000000..7ba3d47
--- /dev/null
+++ b/ZR.Model/Dto/System/SysRoleDto.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using ZR.Model.System;
+
+namespace ZR.Model.Dto.System
+{
+ 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/ZR.Model/Dto/System/SysUserDto.cs b/ZR.Model/Dto/System/SysUserDto.cs
new file mode 100644
index 0000000..ef7df57
--- /dev/null
+++ b/ZR.Model/Dto/System/SysUserDto.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using ZR.Model.System;
+
+namespace ZR.Model.Dto.System
+{
+ 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/ZR.Model/Dto/System/TasksDto.cs b/ZR.Model/Dto/System/TasksDto.cs
new file mode 100644
index 0000000..bc190bc
--- /dev/null
+++ b/ZR.Model/Dto/System/TasksDto.cs
@@ -0,0 +1,224 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Text;
+
+namespace ZR.Model.Dto.System
+{
+ 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 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 string BeginTime { get; set; }
+
+ ///
+ /// 描述 : 结束时间
+ /// 空值 : True
+ /// 默认 :
+ ///
+ [Display(Name = "结束时间")]
+ public string 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; }
+ }
+
+}
diff --git a/ZR.Model/Dto/System/TasksLogDto.cs b/ZR.Model/Dto/System/TasksLogDto.cs
new file mode 100644
index 0000000..7c573e4
--- /dev/null
+++ b/ZR.Model/Dto/System/TasksLogDto.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ZR.Model.Dto.System
+{
+ 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/ZR.Model/JsonDateConverter.cs b/ZR.Model/JsonDateConverter.cs
new file mode 100644
index 0000000..70ca6c8
--- /dev/null
+++ b/ZR.Model/JsonDateConverter.cs
@@ -0,0 +1,15 @@
+using Newtonsoft.Json.Converters;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ZR.Model
+{
+ public class JsonDateConverter: IsoDateTimeConverter
+ {
+ public JsonDateConverter()
+ {
+ DateTimeFormat = "yyyy-MM-dd HH:mm:ss";
+ }
+ }
+}
diff --git a/ZR.Model/OptionsSetting.cs b/ZR.Model/OptionsSetting.cs
new file mode 100644
index 0000000..8c723fc
--- /dev/null
+++ b/ZR.Model/OptionsSetting.cs
@@ -0,0 +1,50 @@
+
+namespace ZRModel
+{
+ ///
+ /// 获取配置文件POCO实体类
+ ///
+ public class OptionsSetting
+ {
+ ///
+ /// 1、喵播 2、fireStar
+ ///
+ public int Platform { get; set; }
+ public string AppName { get; set; }
+ public string Redis { get; set; }
+ public string Conn_Live { get; set; }
+ public string Conn_Admin { get; set; }
+ ///
+ /// mongodb连接字符串
+ ///
+ public string Mongo_Conn { get; set; }
+ public string Database { get; set; }
+
+ public LoggingOptions Logging { get; set; }
+ public MailOptions MailOptions { get; set; }
+ }
+ ///
+ /// 发送邮件数据配置
+ ///
+ public class MailOptions
+ {
+ public string From { get; set; }
+ public string Password { get; set; }
+ public string Host { get; set; }
+ public int Port { get; set; }
+ }
+ ///
+ /// 日志
+ ///
+ public class LoggingOptions
+ {
+ public LogLevelOptions LogLevel { get; set; }
+ }
+ public class LogLevelOptions
+ {
+ public string Default { get; set; }
+ public string Ssytem { get; set; }
+ public string Microsoft { get; set; }
+ }
+
+}
diff --git a/ZR.Model/PagerInfo.cs b/ZR.Model/PagerInfo.cs
new file mode 100644
index 0000000..f3921ef
--- /dev/null
+++ b/ZR.Model/PagerInfo.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ZR.Model
+{
+ public class PagerInfo
+ {
+ ///
+ /// 当前页码
+ ///
+ public int PageNum { get; set; }
+ private int pageSize;
+ ///
+ /// 总记录数
+ ///
+ public int TotalNum { get; set; }
+ ///
+ /// 总页码
+ ///
+ public int TotalPageNum { get; set; }
+ public int PageSize { get => pageSize; set => pageSize = value; }
+
+ public PagerInfo()
+ {
+ PageNum = 1;
+ PageSize = 20;
+ }
+
+ public PagerInfo(int page = 1, int pageSize = 20)
+ {
+ PageNum = page;
+ PageSize = pageSize;
+ }
+ }
+}
diff --git a/ZR.Model/System/Article.cs b/ZR.Model/System/Article.cs
new file mode 100644
index 0000000..cffa116
--- /dev/null
+++ b/ZR.Model/System/Article.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ZR.Model.System
+{
+ ///
+ /// 文章表
+ ///
+ [SqlSugar.SugarTable("article")]
+ public class Article
+ {
+ [SqlSugar.SugarColumn(IsIdentity = true, IsPrimaryKey = true)]
+ public int Cid { get; set; }
+ public string Title { get; set; }
+ public DateTime? CreateTime { get; set; }
+ [SqlSugar.SugarColumn(IsOnlyIgnoreInsert = true)]
+ public DateTime UpdateTime { get; set; }
+ ///
+ /// 文章内容
+ ///
+ public string Content { get; set; }
+ ///
+ /// 作者名
+ ///
+ public string AuthorName { get; set; }
+ public long UserId { get; set; }
+ ///
+ ///
+ ///
+ //public string Type { get; set; }
+ ///
+ /// 文章状态 1、发布 2、草稿
+ ///
+ public string Status { get; set; }
+ ///
+ /// 编辑器类型 markdown,html
+ ///
+ public string Fmt_type { get; set; }
+ ///
+ /// 文章标签eg:Net5,java
+ ///
+ public string Tags { get; set; }
+ public int Hits { get; set; }
+ public int Category_id { get; set; }
+ }
+}
diff --git a/ZR.Model/System/ArticleCategory.cs b/ZR.Model/System/ArticleCategory.cs
new file mode 100644
index 0000000..bd395d0
--- /dev/null
+++ b/ZR.Model/System/ArticleCategory.cs
@@ -0,0 +1,22 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ZR.Model.System
+{
+ ///
+ /// 文章目录
+ ///
+ [SqlSugar.SugarTable("articleCategory")]
+ public class ArticleCategory
+ {
+ public int Category_Id { get; set; }
+ public string Name { get; set; }
+ public int ParentId { get; set; }
+
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ [SqlSugar.SugarColumn(IsIgnore = true)]
+ public List Children { get; set; }
+ }
+}
diff --git a/ZR.Model/System/LoginUser.cs b/ZR.Model/System/LoginUser.cs
new file mode 100644
index 0000000..2bb2ab8
--- /dev/null
+++ b/ZR.Model/System/LoginUser.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ZR.Model.System
+{
+ ///
+ /// 登录用户信息存储
+ ///
+ public class LoginUser
+ {
+ public long UserId { get; set; }
+ public string UserName { get; set; }
+ public string NickName { get; set; }
+ ///
+ /// 角色集合
+ ///
+ public List RoleIds { get; set; }
+ ///
+ /// 权限集合
+ ///
+ public List Permissions{ get; set; }
+ public LoginUser()
+ {
+ }
+
+ public LoginUser(long userId, string userName)
+ {
+ UserId = userId;
+ UserName = userName;
+ }
+ public LoginUser(long userId, string userName, List roleIds, List permissions)
+ {
+ UserId = userId;
+ UserName = userName;
+ RoleIds = roleIds;
+ Permissions = permissions;
+ }
+ }
+}
diff --git a/ZR.Model/System/SysBase.cs b/ZR.Model/System/SysBase.cs
new file mode 100644
index 0000000..07d07f7
--- /dev/null
+++ b/ZR.Model/System/SysBase.cs
@@ -0,0 +1,54 @@
+//using Dapper.Contrib.Extensions;
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using SqlSugar;
+
+namespace ZR.Model.System
+{
+ public class SysBase
+ {
+ [SugarColumn(IsOnlyIgnoreUpdate = true)]//设置后修改不会有此字段
+ [JsonProperty(propertyName: "CreateBy")]
+ public string Create_by { get; set; }
+
+ [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)]//设置后插入数据不会有此字段
+ [JsonIgnore]
+ [JsonProperty(propertyName: "UpdateTime")]
+ public DateTime Update_time { get; set; } = DateTime.Now;
+
+ public string Remark { get; set; }
+
+ ///
+ /// 搜素时间起始时间
+ ///
+ ///
+ /// Write:需穿一个bool值,false时insert,update等操作会忽略此列(和Computed的作用差不多,看了源码也没发现与Computed有什么不一样的地方,有了解的朋友可以赐教下哈)
+ /// ExplicitKey:指定此列为主键(不自动增长类型例如guid,ExplicitKey与Key地区别下面会详细讲)
+ /// Key:指定此列为主键(自动增长主键),可忽略,忽略后默认查找
+ /// [Computed]计算属性,打上此标签,对象地insert,update等操作会忽略此列
+ ///
+ [SugarColumn(IsIgnore = true)]
+ //[Computed]
+ [JsonIgnore]
+ public DateTime? BeginTime { get; set; }
+
+ ///
+ /// 用于搜索使用
+ ///
+ [SugarColumn(IsIgnore = true)]
+ //[Computed]
+ [JsonIgnore]
+ public DateTime? EndTime { get; set; }
+ }
+}
diff --git a/ZR.Model/System/SysDept.cs b/ZR.Model/System/SysDept.cs
new file mode 100644
index 0000000..95ee177
--- /dev/null
+++ b/ZR.Model/System/SysDept.cs
@@ -0,0 +1,57 @@
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ZR.Model.System
+{
+ ///
+ /// 部门表
+ ///
+ [SqlSugar.SugarTable("sys_dept")]
+ 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/ZR.Model/System/SysDictData.cs b/ZR.Model/System/SysDictData.cs
new file mode 100644
index 0000000..fe8d30d
--- /dev/null
+++ b/ZR.Model/System/SysDictData.cs
@@ -0,0 +1,31 @@
+//using Dapper.Contrib.Extensions;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using SqlSugar;
+
+namespace ZR.Model.System
+{
+ ///
+ /// 字典数据表
+ ///
+ //[Table("sys_dict_data")]
+ [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; }
+ public string ListClass { get; set; }
+ public string IsDefault { get; set; }
+ public string Status { get; set; }
+ }
+}
diff --git a/ZR.Model/System/SysDictType.cs b/ZR.Model/System/SysDictType.cs
new file mode 100644
index 0000000..f46aad8
--- /dev/null
+++ b/ZR.Model/System/SysDictType.cs
@@ -0,0 +1,35 @@
+//using Dapper.Contrib.Extensions;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ZR.Model.System
+{
+ ///
+ /// 字典类型表
+ ///
+ [SugarTable("sys_dict_type")]//当和数据库名称不一样可以设置别名
+ //[Table("sys_dict_type")]
+ public class SysDictType : SysBase
+ {
+ ///
+ /// 字典主键
+ ///
+ [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]//主键并且自增 (string不能设置自增)
+ //[Key]
+ public long DictId { get; set; }
+ ///
+ /// 字典名称
+ ///
+ public string DictName { get; set; }
+ ///
+ /// 字典类型
+ ///
+ public string DictType { get; set; }
+ ///
+ /// 状态 0、正常 1、停用
+ ///
+ public string Status { get; set; }
+ }
+}
diff --git a/ZR.Model/System/SysFile.cs b/ZR.Model/System/SysFile.cs
new file mode 100644
index 0000000..5d17f40
--- /dev/null
+++ b/ZR.Model/System/SysFile.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ZR.Model.System
+{
+ [SqlSugar.SugarTable("sys_file")]
+ public class SysFile
+ {
+ public int Id { get; set; }
+ public string FilePath { get; set; }
+ public string FileName { get; set; }
+ public string StorePath { get; set; }
+ public string AccessPat { get; set; }
+ public int FileSize { get; set; }
+ public string FileExt { get; set; }
+ public DateTime? AddTime { get; set; }
+
+ }
+}
diff --git a/ZR.Model/System/SysLogininfor.cs b/ZR.Model/System/SysLogininfor.cs
new file mode 100644
index 0000000..e1ea472
--- /dev/null
+++ b/ZR.Model/System/SysLogininfor.cs
@@ -0,0 +1,56 @@
+//using Dapper.Contrib.Extensions;
+using SqlSugar;
+using System;
+
+namespace ZR.Model.System
+{
+ ///
+ /// sys_logininfor 表
+ ///
+ [SugarTable("sys_logininfor")]
+ public class SysLogininfor: SysBase
+ {
+ //[Key]
+ [SugarColumn(IsPrimaryKey = true)]
+ public long infoId { get; set; }
+
+ ///
+ /// 用户账号
+ ///
+ public string userName { get; set; }
+
+ ///
+ /// 登录状态 0成功 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; }
+
+ ///
+ /// 访问时间
+ ///
+ public DateTime loginTime { get; set; } = DateTime.Now;
+ }
+}
diff --git a/ZR.Model/System/SysMenu.cs b/ZR.Model/System/SysMenu.cs
new file mode 100644
index 0000000..1af655c
--- /dev/null
+++ b/ZR.Model/System/SysMenu.cs
@@ -0,0 +1,88 @@
+using System.Collections.Generic;
+
+namespace ZR.Model.System
+{
+ ///
+ /// Sys_menu表
+ ///
+ //[Table("sys_menu")]
+ [SqlSugar.SugarTable("sys_menu")]
+ public class SysMenu: SysBase
+ {
+ ///
+ /// 菜单ID
+ ///
+ //[Key]//非自动增长主键时使用ExplicitKey
+ [SqlSugar.SugarColumn(IsPrimaryKey = true)]
+ public long menuId { get; set; }
+ ///
+ /// 菜单名称
+ ///
+ public string menuName { get; set; }
+
+ ///
+ /// 父菜单名称
+ ///
+ [SqlSugar.SugarColumn(IsIgnore = true)]
+ public string parentName { 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不缓存)
+ ///
+ 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; }
+
+ ///
+ /// 权限字符串
+ ///
+ public string perms { get; set; }
+
+ ///
+ /// 菜单图标
+ ///
+ public string icon { get; set; } = string.Empty;
+
+ ///
+ /// 子菜单
+ ///
+ public List children = new List();
+ }
+}
diff --git a/ZR.Model/System/SysOperLog.cs b/ZR.Model/System/SysOperLog.cs
new file mode 100644
index 0000000..3a04de5
--- /dev/null
+++ b/ZR.Model/System/SysOperLog.cs
@@ -0,0 +1,84 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ZR.Model.System
+{
+ [SqlSugar.SugarTable("sys_oper_log")]
+ public class SysOperLog
+ {
+ [SqlSugar.SugarColumn(IsPrimaryKey = true)]
+ public long OperId { get; set; }
+ /** 操作模块 */
+ //@Excel(name = "操作模块")
+ 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; }
+
+ /** 业务类型数组 */
+ [SqlSugar.SugarColumn(IsIgnore = true)]
+ public int[] businessTypes { get; set; }
+
+ /** 请求方法 */
+ //@Excel(name = "请求方法")
+ 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 = "操作人员")
+ public String operName { get; set; }
+
+ /** 部门名称 */
+ //@Excel(name = "部门名称")
+ 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; }
+
+ /** 错误消息 */
+ //@Excel(name = "错误消息")
+ public String errorMsg { get; set; }
+
+ /** 操作时间 */
+ //@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ //@Excel(name = "操作时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+ //[DataType]
+ [JsonConverter(typeof(JsonDateConverter))]
+ public DateTime? operTime { get; set; }
+ ///
+ /// 操作用时
+ ///
+ public long Elapsed { get; set; }
+ }
+}
diff --git a/ZR.Model/System/SysPost.cs b/ZR.Model/System/SysPost.cs
new file mode 100644
index 0000000..600cc07
--- /dev/null
+++ b/ZR.Model/System/SysPost.cs
@@ -0,0 +1,16 @@
+namespace ZR.Model.System
+{
+ [SqlSugar.SugarTable("sys_post")]
+ public class SysPost: SysBase
+ {
+ ///
+ /// 岗位Id
+ ///
+ [SqlSugar.SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
+ public long PostId { get; set; }
+ public string PostCode { get; set; }
+ public string PostName { get; set; }
+ public int PostSort { get; set; }
+ public string Status { get; set; }
+ }
+}
diff --git a/ZR.Model/System/SysRole.cs b/ZR.Model/System/SysRole.cs
new file mode 100644
index 0000000..5026247
--- /dev/null
+++ b/ZR.Model/System/SysRole.cs
@@ -0,0 +1,74 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ZR.Model.System
+{
+ ///
+ /// 角色表 sys_role
+ ///
+ [SqlSugar.SugarTable("sys_role")]
+ public class SysRole : SysBase
+ {
+ ///
+ /// 角色ID
+ ///
+ [SqlSugar.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代表删除)
+ ///
+ [SqlSugar.SugarColumn(IsOnlyIgnoreInsert = true, IsOnlyIgnoreUpdate = true)]
+ public string DelFlag { get; set; }
+
+ ///
+ /// 菜单组
+ ///
+ [SqlSugar.SugarColumn(IsIgnore = true)]
+ public long[] MenuIds { get; set; }
+ ///
+ /// 部门组(数据权限)
+ ///
+ [SqlSugar.SugarColumn(IsIgnore = true)]
+ public long[] DeptIds { 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/ZR.Model/System/SysRoleMenu.cs b/ZR.Model/System/SysRoleMenu.cs
new file mode 100644
index 0000000..601c2ee
--- /dev/null
+++ b/ZR.Model/System/SysRoleMenu.cs
@@ -0,0 +1,23 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ZR.Model.System
+{
+ ///
+ /// 角色菜单
+ ///
+ [SqlSugar.SugarTable("sys_role_menu")]
+ public class SysRoleMenu
+ {
+ [JsonProperty("roleId")]
+ [SqlSugar.SugarColumn(IsPrimaryKey = true)]
+ public long Role_id { get; set; }
+ [JsonProperty("menuId")]
+ [SqlSugar.SugarColumn(IsPrimaryKey = true)]
+ public long Menu_id { get; set; }
+ public DateTime Create_time { get; set; }
+ public string Create_by { get; set; }
+ }
+}
diff --git a/ZR.Model/System/SysRolePost.cs b/ZR.Model/System/SysRolePost.cs
new file mode 100644
index 0000000..705b139
--- /dev/null
+++ b/ZR.Model/System/SysRolePost.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using SqlSugar;
+
+namespace ZR.Model.System
+{
+ ///
+ /// 角色部门
+ ///
+ [SugarTable("sys_role_post")]
+ public class SysRolePost
+ {
+ public long RoleId { get; set; }
+ public long DeptId { get; set; }
+ }
+}
diff --git a/ZR.Model/System/SysTasksLog.cs b/ZR.Model/System/SysTasksLog.cs
new file mode 100644
index 0000000..e339226
--- /dev/null
+++ b/ZR.Model/System/SysTasksLog.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ZR.Model.System
+{
+ ///
+ /// 任务日志
+ ///
+ [SqlSugar.SugarTable("sys_Tasks_log")]
+ public class SysTasksLog
+ {
+ ///
+ /// 日志Id
+ ///
+ [SqlSugar.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; }
+ public DateTime CreateTime { get; set; }
+ ///
+ /// 执行用时,毫秒
+ ///
+ //[SqlSugar.SugarColumn(IsIgnore = true)]
+ public double Elapsed { get; set; }
+ }
+}
diff --git a/ZR.Model/System/SysTasksQz.cs b/ZR.Model/System/SysTasksQz.cs
new file mode 100644
index 0000000..ac02bf8
--- /dev/null
+++ b/ZR.Model/System/SysTasksQz.cs
@@ -0,0 +1,156 @@
+using Newtonsoft.Json;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Text;
+
+namespace ZR.Model.System
+{
+ ///
+ ///计划任务
+ ///
+ [SugarTable("Sys_TasksQz")]
+ public class SysTasksQz
+ {
+ public SysTasksQz()
+ {
+ }
+
+ ///
+ /// 描述 : UID
+ /// 空值 : False
+ /// 默认 :
+ ///
+ [Display(Name = "UID")]
+ [SugarColumn(IsPrimaryKey = true)]
+ public string 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;
+ }
+}
diff --git a/ZR.Model/System/SysUser.cs b/ZR.Model/System/SysUser.cs
new file mode 100644
index 0000000..af36710
--- /dev/null
+++ b/ZR.Model/System/SysUser.cs
@@ -0,0 +1,113 @@
+using Newtonsoft.Json;
+using Npoi.Mapper.Attributes;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ZR.Model.System
+{
+ ///
+ /// 用户表
+ ///
+ [SugarTable("sys_user")]
+ public class SysUser : SysBase
+ {
+ ///
+ /// 用户id
+ ///
+ [SugarColumn(IsIdentity = true, IsPrimaryKey = true)]
+ public long UserId { get; set; }
+ [Column("用户名")]//对应Excel列名
+ //[Required]//校验必填
+ //[Duplication]//校验模板类该列数据是否重复
+ public string UserName { get; set; }
+
+ [Column("用户昵称")]
+ //[Required]
+ public string NickName { get; set; }
+
+ ///
+ /// '用户类型(00系统用户)',
+ ///
+ //[JsonProperty(propertyName: "userType")]
+ //public string User_type { get; set; } = "";
+ [SugarColumn(IsOnlyIgnoreInsert = true)]
+ public string Avatar { get; set; }
+
+ public string Email { get; set; }
+
+ [JsonIgnore]
+ //[ColName("用户密码")]
+ public string Password { get; set; }
+
+ //[ColName("手机号")]
+ public string Phonenumber { get; set; }
+
+ ///
+ /// 用户性别(0男 1女 2未知)
+ ///
+ public string Sex { get; set; }
+
+ ///
+ /// 帐号状态(0正常 1停用)
+ ///
+ 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)]
+ 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)]
+ public int[] RoleIds { get; set; }
+ ///
+ /// 岗位集合
+ ///
+ [SugarColumn(IsIgnore = true)]
+ public int[] PostIds { get; set; }
+
+ [SugarColumn(IsIgnore = true)]
+ public List Roles { get; set; }
+
+ #endregion
+ }
+}
diff --git a/ZR.Model/System/SysUserPost.cs b/ZR.Model/System/SysUserPost.cs
new file mode 100644
index 0000000..7804cca
--- /dev/null
+++ b/ZR.Model/System/SysUserPost.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using SqlSugar;
+
+namespace ZR.Model.System
+{
+
+ ///
+ /// 用户岗位
+ ///
+ [SugarTable("sys_user_post")]
+ public class SysUserPost
+ {
+ public long UserId { get; set; }
+ public long PostId { get; set; }
+ }
+}
diff --git a/ZR.Model/System/SysUserRole.cs b/ZR.Model/System/SysUserRole.cs
new file mode 100644
index 0000000..1495195
--- /dev/null
+++ b/ZR.Model/System/SysUserRole.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ZR.Model.System
+{
+ ///
+ /// 用户角色关联表 用户N-1 角色
+ ///
+ [SqlSugar.SugarTable("sys_user_role")]
+ 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/ZR.Model/System/UserConstants.cs b/ZR.Model/System/UserConstants.cs
new file mode 100644
index 0000000..bc68af6
--- /dev/null
+++ b/ZR.Model/System/UserConstants.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ZR.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_LINK = "L";
+
+ /** Layout组件标识 */
+ public static string LAYOUT = "Layout";
+ /** ParentView组件标识 */
+ public static string PARENT_VIEW = "ParentView";
+
+ /** 校验返回结果码 */
+ public static string UNIQUE = "0";
+ public static string NOT_UNIQUE = "1";
+ }
+}
diff --git a/ZR.Model/Vo/System/RouterVo.cs b/ZR.Model/Vo/System/RouterVo.cs
new file mode 100644
index 0000000..73b7399
--- /dev/null
+++ b/ZR.Model/Vo/System/RouterVo.cs
@@ -0,0 +1,50 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ZR.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; }
+ //[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ 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 Meta(string title, string icon, bool noCache)
+ {
+ Title = title;
+ Icon = icon;
+ NoCache = noCache;
+ }
+ }
+}
diff --git a/ZR.Model/Vo/System/TreeSelectVo.cs b/ZR.Model/Vo/System/TreeSelectVo.cs
new file mode 100644
index 0000000..46ed195
--- /dev/null
+++ b/ZR.Model/Vo/System/TreeSelectVo.cs
@@ -0,0 +1,58 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using ZR.Model.System;
+
+namespace ZR.Model.Vo.System
+{
+ ///
+ /// 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/ZR.Model/Vo/VMPageResult.cs b/ZR.Model/Vo/VMPageResult.cs
new file mode 100644
index 0000000..a6af85b
--- /dev/null
+++ b/ZR.Model/Vo/VMPageResult.cs
@@ -0,0 +1,53 @@
+using Newtonsoft.Json;
+using System.Collections.Generic;
+using System.Data;
+
+namespace ZR.Model.Vo
+{
+ public class VMPageResult where T : new()
+ {
+ public int Page { get; set; }
+ public int PageSize { get; set; }
+ public long TotalNum { get; set; }
+ //public int TotalPages { get; set; }
+ public IList Result { get; set; }
+ public long EndPage { get; set; }
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public DataTable Data { get; set; }
+
+ public VMPageResult()
+ {
+ }
+
+ ///
+ /// 集合使用
+ ///
+ ///
+ ///
+ public VMPageResult(IList result, PagerInfo pagerInfo)
+ {
+ this.Result = result;
+ this.TotalNum = pagerInfo.TotalNum;
+ this.PageSize = pagerInfo.PageSize;
+ this.Page = pagerInfo.PageNum;
+ //计算
+ this.EndPage = pagerInfo.TotalNum % PageSize == 0 ? pagerInfo.TotalNum / PageSize : pagerInfo.TotalNum / PageSize + 1;
+ }
+
+ ///
+ /// datable使用
+ ///
+ ///
+ ///
+ public VMPageResult(DataTable result, PagerInfo pagerInfo)
+ {
+ this.Data = result;
+ this.TotalNum = pagerInfo.TotalNum;
+ this.PageSize = pagerInfo.PageSize;
+ this.Page = pagerInfo.PageNum;
+ //计算
+ this.EndPage = pagerInfo.TotalNum % PageSize == 0 ? pagerInfo.TotalNum / PageSize : pagerInfo.TotalNum / PageSize + 1;
+ }
+ }
+
+}
diff --git a/ZR.Model/ZR.Model.csproj b/ZR.Model/ZR.Model.csproj
new file mode 100644
index 0000000..975d730
--- /dev/null
+++ b/ZR.Model/ZR.Model.csproj
@@ -0,0 +1,23 @@
+
+
+
+ netstandard2.1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ZR.Repository/DbProvider/SugarDbContext.cs b/ZR.Repository/DbProvider/SugarDbContext.cs
new file mode 100644
index 0000000..67ec657
--- /dev/null
+++ b/ZR.Repository/DbProvider/SugarDbContext.cs
@@ -0,0 +1,54 @@
+using Infrastructure;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace ZR.Repository.DbProvider
+{
+ ///
+ /// SqlSugar ORM
+ ///
+ public class SugarDbContext
+ {
+ public SqlSugarClient Db; //用来处理事务多表查询和复杂的操作
+
+ ///
+ /// 使用SugarSql获取连接对象
+ /// 构造方法有问题
+ ///
+ ///
+ public SugarDbContext()
+ {
+ string connStr = ConfigUtils.Instance.GetConnectionStrings(OptionsSetting.ConnAdmin);
+ string dbKey = ConfigUtils.Instance.GetAppConfig(OptionsSetting.DbKey);
+ int dbType = ConfigUtils.Instance.GetAppConfig(OptionsSetting.DbType, 0);
+ if (!string.IsNullOrEmpty(dbKey))
+ {
+ connStr = NETCore.Encrypt.EncryptProvider.DESDecrypt(connStr, dbKey);
+ }
+ Db = new SqlSugarClient(new List()
+ {
+ new ConnectionConfig(){
+ ConnectionString = connStr,
+ DbType = (DbType)dbType,
+ IsAutoCloseConnection = true,//开启自动释放模式和EF原理一样
+ InitKeyType = InitKeyType.Attribute,//从特性读取主键和自增列信息
+ ConfigId = 0
+ },
+ });
+
+ //调式代码 用来打印SQL
+ Db.Aop.OnLogExecuting = (sql, pars) =>
+ {
+ Console.WriteLine("【SQL语句】" + sql.ToLower() + "\r\n" + Db.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value)));
+ };
+ //出错打印日志
+ Db.Aop.OnError = (e) =>
+ {
+ Console.WriteLine($"[执行Sql出错]{e.Message},SQL={e.Sql}");
+ Console.WriteLine();
+ };
+ }
+ }
+}
diff --git a/ZR.Repository/Interceptor/SqlLogInterceptorAttribute.cs b/ZR.Repository/Interceptor/SqlLogInterceptorAttribute.cs
new file mode 100644
index 0000000..fe569de
--- /dev/null
+++ b/ZR.Repository/Interceptor/SqlLogInterceptorAttribute.cs
@@ -0,0 +1,16 @@
+using AspectCore.DynamicProxy;
+using System.Threading.Tasks;
+using ZR.Repository.DbProvider;
+
+namespace ZR.Repository.Interceptor
+{
+
+ public class SqlLogInterceptorAttribute : AbstractInterceptorAttribute
+ {
+ public override Task Invoke(AspectContext context, AspectDelegate next)
+ {
+ global::System.Console.WriteLine("");
+ return next(context);
+ }
+ }
+}
diff --git a/ZR.Repository/System/ArticleRepository.cs b/ZR.Repository/System/ArticleRepository.cs
new file mode 100644
index 0000000..5b0cd75
--- /dev/null
+++ b/ZR.Repository/System/ArticleRepository.cs
@@ -0,0 +1,20 @@
+using Infrastructure.Attribute;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using ZR.Model.Dto.System;
+using ZR.Model.System;
+
+namespace ZR.Repository.System
+{
+ ///
+ /// 文章管理
+ ///
+ [AppService(ServiceLifetime = LifeTime.Transient)]
+ public class ArticleRepository
+ {
+
+ }
+}
diff --git a/ZR.Repository/System/BaseRepository.cs b/ZR.Repository/System/BaseRepository.cs
new file mode 100644
index 0000000..cd7a790
--- /dev/null
+++ b/ZR.Repository/System/BaseRepository.cs
@@ -0,0 +1,21 @@
+using Infrastructure.Attribute;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using ZR.Repository.DbProvider;
+
+namespace ZR.Repository.System
+{
+ public class BaseRepository : SugarDbContext
+ {
+ protected void PrintLog()
+ {
+ //调式代码 用来打印SQL
+ Db.Aop.OnLogExecuting = (sql, pars) =>
+ {
+ Console.WriteLine("【SQL语句】" + sql.ToLower() + "\r\n" + Db.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value)));
+ };
+ }
+ }
+}
diff --git a/ZR.Repository/System/SysDeptRepository.cs b/ZR.Repository/System/SysDeptRepository.cs
new file mode 100644
index 0000000..4935ec2
--- /dev/null
+++ b/ZR.Repository/System/SysDeptRepository.cs
@@ -0,0 +1,30 @@
+using Infrastructure.Attribute;
+using System.Collections.Generic;
+using ZR.Model.System;
+
+namespace ZR.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 Db.SqlQueryable(sql).AddParameters(new { @deptId = deptId }).ToList();
+ }
+
+ public int UdateDeptChildren(SysDept dept)
+ {
+ return Db.Updateable(dept).UpdateColumns(it => new { it.Ancestors }).ExecuteCommand();
+ }
+ }
+}
diff --git a/ZR.Repository/System/SysDictDataRepository.cs b/ZR.Repository/System/SysDictDataRepository.cs
new file mode 100644
index 0000000..43b24b6
--- /dev/null
+++ b/ZR.Repository/System/SysDictDataRepository.cs
@@ -0,0 +1,117 @@
+using Infrastructure.Attribute;
+using System;
+using System.Collections.Generic;
+using ZR.Model.System;
+
+namespace ZR.Repository.System
+{
+ ///
+ /// 字典数据
+ ///
+ [AppService(ServiceLifetime = LifeTime.Transient)]
+ public class SysDictDataRepository : BaseRepository
+ {
+ ///
+ /// 字典类型数据搜索
+ ///
+ ///
+ ///
+ public List SelectDictDataList(SysDictData dictData)
+ {
+ return Db.Queryable()
+ .WhereIF(!string.IsNullOrEmpty(dictData.DictLabel), it => it.DictLabel.Contains(dictData.DictLabel))
+ .WhereIF(!string.IsNullOrEmpty(dictData.Status), it => it.Status == dictData.Status)
+ .WhereIF(!string.IsNullOrEmpty(dictData.DictType), it => it.DictType == dictData.DictType)
+ .ToList();
+ }
+
+ ///
+ /// 根据字典类型查询
+ ///
+ ///
+ ///
+ public List SelectDictDataByType(string dictType)
+ {
+ return Db.Queryable().Where(f => f.Status == "0" && f.DictType == dictType)
+ .OrderBy(it => it.DictSort)
+ .ToList();
+ }
+
+ ///
+ /// 根据DictCode查询
+ ///
+ ///
+ ///
+ public SysDictData SelectDictDataById(long dictCode)
+ {
+ return Db.Queryable().Where(f => f.DictCode == dictCode).First();
+ }
+
+ ///
+ /// 新增保存字典数据信息
+ ///
+ ///
+ ///
+ public long InsertDictData(SysDictData dict)
+ {
+ var result = Db.Insertable(dict).IgnoreColumns(it => new { dict.Update_by })
+ .ExecuteReturnIdentity();
+ return result;
+ }
+
+ ///
+ /// 修改数据
+ ///
+ ///
+ ///
+ public long UpdateDictData(SysDictData dict)
+ {
+ return Db.Updateable()
+ .SetColumns(t => new SysDictData()
+ {
+ Remark = dict.Remark,
+ Update_time = DateTime.Now,
+ DictSort = dict.DictSort,
+ DictLabel = dict.DictLabel,
+ DictValue = dict.DictValue,
+ Status = dict.Status
+ })
+ .Where(f => f.DictCode == dict.DictCode).ExecuteCommand();
+ }
+
+ ///
+ /// 批量删除字典数据信息
+ ///
+ ///
+ ///
+ public int DeleteDictDataByIds(long[] dictCodes)
+ {
+ return Db.Deleteable().In(dictCodes).ExecuteCommand();
+ }
+
+ ///
+ /// 查询字典数据
+ ///
+ ///
+ ///
+ public int CountDictDataByType(string dictType)
+ {
+ return Db.Queryable().Count(f => f.DictType == dictType);
+ }
+
+ ///
+ /// 同步修改字典类型
+ ///
+ /// 旧字典类型
+ /// 新字典类型
+ ///
+ public int UpdateDictDataType(string old_dictType, string new_dictType)
+ {
+ //只更新DictType字段根据where条件
+ return Db.Updateable()
+ .SetColumns(t => new SysDictData() { DictType = new_dictType })
+ .Where(f => f.DictType == old_dictType)
+ .ExecuteCommand();
+ }
+ }
+}
diff --git a/ZR.Repository/System/SysDictRepository.cs b/ZR.Repository/System/SysDictRepository.cs
new file mode 100644
index 0000000..f30a142
--- /dev/null
+++ b/ZR.Repository/System/SysDictRepository.cs
@@ -0,0 +1,91 @@
+using Infrastructure.Attribute;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using ZR.Model.System;
+
+namespace ZR.Repository.System
+{
+ ///
+ /// 字典
+ ///
+ [AppService(ServiceLifetime = LifeTime.Transient)]
+ public class SysDictRepository : BaseRepository
+ {
+ ///
+ /// 查询字段类型列表
+ ///
+ /// 实体模型
+ ///
+ public List SelectDictTypeList(SysDictType dictType)
+ {
+ return Db
+ .Queryable()
+ .WhereIF(!string.IsNullOrEmpty(dictType.DictName), it => it.DictName.Contains(dictType.DictName))
+ .WhereIF(!string.IsNullOrEmpty(dictType.Status), it => it.Status == dictType.Status)
+ .WhereIF(!string.IsNullOrEmpty(dictType.DictType), it => it.DictType == dictType.DictType).ToList();
+ }
+
+ ///
+ /// 根据Id查询
+ ///
+ ///
+ ///
+ public SysDictType SelectDictTypeById(long id)
+ {
+ return Db.Queryable().First(it => it.DictId == id);
+ }
+
+ ///
+ /// 检查字典类型唯一值
+ ///
+ ///
+ ///
+ public SysDictType CheckDictTypeUnique(string dictType)
+ {
+ return Db.Queryable().First(it => it.DictType == dictType);
+ }
+
+ ///
+ /// 删除一个
+ ///
+ ///
+ ///
+ public int DeleteDictTypeById(long id)
+ {
+ return Db.Deleteable().In(id).ExecuteCommand();
+ }
+
+ ///
+ /// 批量删除
+ ///
+ ///
+ ///
+ public int DeleteDictTypeByIds(long[] id)
+ {
+ return Db.Deleteable().In(id).ExecuteCommand();
+ }
+
+ ///
+ /// 插入
+ ///
+ ///
+ ///
+ public long InsertDictType(SysDictType sysDictType)
+ {
+ var result = Db.Insertable(sysDictType).IgnoreColumns(it => new { sysDictType.Update_by })
+ .ExecuteReturnIdentity();
+ return result;
+ }
+
+ ///
+ /// 修改
+ ///
+ ///
+ ///
+ public int UpdateDictType(SysDictType dictType)
+ {
+ return Db.Updateable(dictType).IgnoreColumns(it => new { dictType.Create_by }).ExecuteCommand();
+ }
+ }
+}
diff --git a/ZR.Repository/System/SysLogininfoRepository.cs b/ZR.Repository/System/SysLogininfoRepository.cs
new file mode 100644
index 0000000..1bdb962
--- /dev/null
+++ b/ZR.Repository/System/SysLogininfoRepository.cs
@@ -0,0 +1,89 @@
+using Infrastructure.Attribute;
+using Infrastructure.Extensions;
+using System.Collections.Generic;
+using ZR.Model;
+using ZR.Model.Dto.System;
+using ZR.Model.System;
+
+namespace ZR.Repository.System
+{
+ [AppService(ServiceLifetime = LifeTime.Transient)]
+ public class SysLogininfoRepository : BaseRepository
+ {
+ ///
+ /// 查询登录日志
+ ///
+ ///
+ ///
+ ///
+ public List GetLoginLog(SysLogininfor logininfoDto, PagerInfo pager)
+ {
+ int totalCount = 0;
+ var list = Db.Queryable()
+ .Where(it => it.loginTime >= logininfoDto.BeginTime && it.loginTime <= logininfoDto.EndTime)
+ .WhereIF(logininfoDto.ipaddr.IfNotEmpty(), f => f.ipaddr == logininfoDto.ipaddr)
+ .WhereIF(logininfoDto.userName.IfNotEmpty(), f => f.userName.Contains(logininfoDto.userName))
+ .WhereIF(logininfoDto.status.IfNotEmpty(), f => f.status == logininfoDto.status)
+ .OrderBy(it => it.infoId, SqlSugar.OrderByType.Desc)
+ .IgnoreColumns(it => new { it.Create_by, it.Create_time, it.Update_by, it.Update_time, it.Remark })
+ .ToPageList(pager.PageNum, pager.PageSize, ref totalCount);
+ pager.TotalNum = totalCount;
+ return list;
+ }
+
+ ///
+ /// 登录日志记录
+ ///
+ ///
+ ///
+ public void AddLoginInfo(SysLogininfor sysLogininfor)
+ {
+ int result = Db.Insertable(sysLogininfor)
+ .IgnoreColumns(it => new { it.Create_by, it.Create_time, it.Remark })
+ .ExecuteReturnIdentity();
+ }
+
+ ///
+ /// 清空登录日志
+ ///
+ public void TruncateLogininfo()
+ {
+ string sql = "truncate table sys_logininfor";
+
+ Db.Ado.ExecuteCommand(sql);
+ }
+
+ ///
+ /// 删除登录日志
+ ///
+ ///
+ ///
+ public int DeleteLogininforByIds(long[] ids)
+ {
+ return Db.Deleteable().In(ids).ExecuteCommand();
+ }
+
+ ///
+ /// 登录
+ ///
+ /// 登录实体
+ ///
+ public SysUser Login(LoginBodyDto user)
+ {
+ return Db.Queryable().First(it => it.UserName == user.Username && it.Password == user.Password);
+ }
+
+ ///
+ /// 修改登录信息
+ ///
+ ///
+ ///
+ ///
+ public void UpdateLoginInfo(LoginBodyDto user, long userId)
+ {
+ Db.Updateable(new SysUser() { LoginIP = user.LoginIP, LoginDate = Db.GetDate(), UserId = userId })
+ .UpdateColumns(it => new { it.LoginIP, it.LoginDate })
+ .ExecuteCommand();
+ }
+ }
+}
diff --git a/ZR.Repository/System/SysMenuRepository.cs b/ZR.Repository/System/SysMenuRepository.cs
new file mode 100644
index 0000000..0332b87
--- /dev/null
+++ b/ZR.Repository/System/SysMenuRepository.cs
@@ -0,0 +1,192 @@
+using Infrastructure.Attribute;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using ZR.Model.Dto.System;
+using ZR.Model.System;
+
+namespace ZR.Repository.System
+{
+ ///
+ /// 系统菜单
+ ///
+ [AppService(ServiceLifetime = LifeTime.Transient)]
+ public class SysMenuRepository : BaseRepository
+ {
+ ///
+ /// 获取所有菜单(菜单管理)
+ ///
+ ///
+ public List SelectMenuList(SysMenu menu)
+ {
+ return Db.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)
+ .OrderBy(it => new { it.parentId, it.orderNum })
+ .ToList();
+ }
+
+ ///
+ /// 根据用户查询系统菜单列表
+ ///
+ ///
+ /// 用户id
+ ///
+ public List SelectMenuListByUserId(SysMenu sysMenu, long userId)
+ {
+ return Db.Queryable((menu, roleMenu, userRole, role) => new JoinQueryInfos(
+ JoinType.Left, menu.menuId == roleMenu.Menu_id,
+ JoinType.Left, roleMenu.Role_id == userRole.RoleId,
+ JoinType.Left, userRole.RoleId == role.RoleId
+ ))
+ .Where((menu, roleMenu, userRole, role) => userRole.UserId == userId)
+ .WhereIF(!string.IsNullOrEmpty(sysMenu.menuName), (menu, roleMenu, userRole, role) => menu.menuName.Contains(sysMenu.menuName))
+ .WhereIF(!string.IsNullOrEmpty(sysMenu.visible), (menu, roleMenu, userRole, role) => menu.visible == sysMenu.visible)
+ .WhereIF(!string.IsNullOrEmpty(sysMenu.status), (menu, roleMenu, userRole, role) => menu.status == sysMenu.status)
+ .OrderBy((menu, roleMenu, userRole, role) => new { menu.parentId, menu.orderNum })
+ //.Distinct()
+ .Select((menu, roleMenu, userRole, role) => menu).ToList();
+ }
+
+ #region 左侧菜单树
+
+ ///
+ /// 管理员获取左侧菜单树
+ ///
+ ///
+ public List SelectMenuTreeAll()
+ {
+ var menuTypes = new string[] { "M", "C" };
+
+ return Db.Queryable()
+ .Where(f => f.status == "0" && menuTypes.Contains(f.menuType))
+ .OrderBy(it => new { it.parentId, it.orderNum }).ToList();
+ }
+
+ ///
+ /// 根据用户角色获取左侧菜单树
+ ///
+ ///
+ ///
+ public List SelectMenuTreeByRoleIds(List roleIds)
+ {
+ var menuTypes = new string[] { "M", "C"};
+ return Db.Queryable((menu, roleMenu) => new JoinQueryInfos(
+ JoinType.Left, menu.menuId == roleMenu.Menu_id
+ ))
+ .Where((menu, roleMenu) => roleIds.Contains(roleMenu.Role_id) && menuTypes.Contains(menu.menuType) && menu.status == "0")
+ .OrderBy((menu, roleMenu) => new { menu.parentId, menu.orderNum })
+ .Select((menu, roleMenu) => menu).ToList();
+ }
+
+ #endregion
+
+ ///
+ /// 获取菜单详情
+ ///
+ ///
+ ///
+ public SysMenu SelectMenuById(int menuId)
+ {
+ return Db.Queryable().Where(it => it.menuId == menuId).Single();
+ }
+
+ ///
+ /// 添加菜单
+ ///
+ ///
+ ///
+ public int AddMenu(SysMenu menu)
+ {
+ menu.Create_time = Db.GetDate();
+ menu.menuId = Db.Insertable(menu).ExecuteReturnIdentity();
+ return 1;
+ }
+
+ ///
+ /// 编辑菜单
+ ///
+ ///
+ ///
+ public int EditMenu(SysMenu menu)
+ {
+ return Db.Updateable(menu).ExecuteCommand();
+ }
+
+ ///
+ /// 删除菜单
+ ///
+ ///
+ ///
+ public int DeleteMenuById(int menuId)
+ {
+ return Db.Deleteable().Where(it => it.menuId == menuId).ExecuteCommand();
+ }
+
+ ///
+ /// 菜单排序
+ ///
+ /// 菜单Dto
+ ///
+ public int ChangeSortMenu(MenuDto menuDto)
+ {
+ var result = Db.Updateable(new SysMenu() { menuId = menuDto.MenuId, orderNum = menuDto.orderNum })
+ .UpdateColumns(it => new { it.orderNum }).ExecuteCommand();
+ return result;
+ }
+
+ ///
+ /// 查询菜单权限
+ ///
+ ///
+ ///
+ public List SelectMenuPermsByUserId(long userId)
+ {
+ return Db.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 Db.Queryable()
+ .Where(it => it.menuName == menu.menuName && it.parentId == menu.parentId).Single();
+ }
+
+ ///
+ /// 是否存在菜单子节点
+ ///
+ ///
+ ///
+ public int HasChildByMenuId(long menuId)
+ {
+ return Db.Queryable().Where(it => it.parentId == menuId).Count();
+ }
+
+ #region RoleMenu
+
+ ///
+ /// 查询菜单使用数量
+ ///
+ ///
+ ///
+ public int CheckMenuExistRole(long menuId)
+ {
+ return Db.Queryable().Where(it => it.Menu_id == menuId).Count();
+ }
+
+ #endregion
+ }
+}
diff --git a/ZR.Repository/System/SysOperLogRepository.cs b/ZR.Repository/System/SysOperLogRepository.cs
new file mode 100644
index 0000000..840de43
--- /dev/null
+++ b/ZR.Repository/System/SysOperLogRepository.cs
@@ -0,0 +1,73 @@
+using Infrastructure.Attribute;
+using Infrastructure.Extensions;
+using System.Collections.Generic;
+using ZR.Model;
+using ZR.Model.Dto.System;
+using ZR.Model.System;
+
+namespace ZR.Repository.System
+{
+ [AppService(ServiceLifetime = LifeTime.Transient)]
+ public class SysOperLogRepository : BaseRepository
+ {
+ ///
+ /// 查询操作日志
+ ///
+ ///
+ /// 分页数据
+ ///
+ public List GetSysOperLog(SysOperLogDto sysOper, PagerInfo pagerInfo)
+ {
+ int totalCount = 0;
+ var list = Db.Queryable()
+ .Where(it => it.operTime >= sysOper.BeginTime && it.operTime <= sysOper.EndTime)
+ .WhereIF(sysOper.Title.IfNotEmpty(), it => it.title.Contains(sysOper.Title))
+ .WhereIF(sysOper.operName.IfNotEmpty(), it => it.operName.Contains(sysOper.operName))
+ .WhereIF(sysOper.BusinessType != -1, it =>it.businessType == sysOper.BusinessType)
+ .WhereIF(sysOper.Status != -1, it => it.status == sysOper.Status)
+ .OrderBy(it => it.OperId, SqlSugar.OrderByType.Desc)
+ .ToPageList(pagerInfo.PageNum, pagerInfo.PageSize, ref totalCount);
+ pagerInfo.TotalNum = totalCount;
+ return list;
+ }
+
+ ///
+ /// 添加操作日志
+ ///
+ ///
+ ///
+ public void AddSysOperLog(SysOperLog sysOperLog)
+ {
+ Db.Insertable(sysOperLog).ExecuteCommandAsync();
+ }
+
+ ///
+ /// 清空日志
+ ///
+ public void ClearOperLog()
+ {
+ string sql = "truncate table sys_oper_log";
+ Db.Ado.ExecuteCommand(sql);
+ }
+
+ ///
+ /// 删除操作日志
+ ///
+ ///
+ ///
+ public int DeleteOperLogByIds(long[] operIds)
+ {
+ return Db.Deleteable().In(operIds).ExecuteCommand();
+ }
+
+ ///
+ /// 查询操作日志
+ ///
+ ///
+ ///
+ public SysOperLog SelectOperLogById(long operId)
+ {
+ return Db.Queryable().InSingle(operId);
+ }
+ }
+}
diff --git a/ZR.Repository/System/SysRoleRepository.cs b/ZR.Repository/System/SysRoleRepository.cs
new file mode 100644
index 0000000..fc2480d
--- /dev/null
+++ b/ZR.Repository/System/SysRoleRepository.cs
@@ -0,0 +1,182 @@
+using Infrastructure.Attribute;
+using SqlSugar;
+using System.Collections.Generic;
+using ZR.Model.System;
+
+namespace ZR.Repository.System
+{
+ ///
+ /// 角色操作类
+ ///
+ [AppService(ServiceLifetime = LifeTime.Transient)]
+ public class SysRoleRepository : BaseRepository
+ {
+ ///
+ /// 根据条件分页查询角色数据
+ ///
+ ///
+ public List SelectRoleList(SysRole sysRole)
+ {
+ return Db.Queryable()
+ .Where(role => role.DelFlag == "0")
+ .WhereIF(!string.IsNullOrEmpty(sysRole.RoleName), role => role.RoleName.Contains(sysRole.RoleName))
+ .WhereIF(!string.IsNullOrEmpty(sysRole.Status), role => role.Status == sysRole.Status)
+ .WhereIF(!string.IsNullOrEmpty(sysRole.RoleKey), role => role.RoleKey == sysRole.RoleKey)
+ .OrderBy(role => role.RoleSort)
+ .ToList();
+ }
+
+ ///
+ /// 根据用户查询
+ ///
+ ///
+ ///
+ public List SelectRolePermissionByUserId(long userId)
+ {
+ return Db.Queryable()
+ .Where(role => role.DelFlag == "0")
+ .Where(it => SqlFunc.Subqueryable().Where(s => s.UserId == userId).Any())
+ .OrderBy(role => role.RoleSort)
+ .ToList();
+ }
+
+ ///
+ /// 查询所有角色
+ ///
+ ///
+ public List SelectRoleAll()
+ {
+ return Db.Queryable().OrderBy(it => it.RoleSort).ToList();
+ }
+
+ ///
+ /// 通过角色ID查询角色
+ ///
+ /// 角色编号
+ ///
+ public SysRole SelectRoleById(long roleId)
+ {
+ return Db.Queryable().InSingle(roleId);
+ }
+
+ ///
+ /// 通过角色ID删除角色
+ ///
+ ///
+ ///
+ public int DeleteRoleByRoleIds(long[] roleId)
+ {
+ return Db.Deleteable().In(roleId).ExecuteCommand();
+ }
+
+ ///
+ /// 获取用户所有角色信息
+ ///
+ ///
+ ///
+ public List SelectUserRoleListByUserId(long userId)
+ {
+ return Db.Queryable((ur, r) => new SqlSugar.JoinQueryInfos(
+ SqlSugar.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 Db.Queryable().Where(it => it.Role_id == roleId).ToList();
+ }
+
+ ///
+ /// 批量插入用户菜单
+ ///
+ ///
+ ///
+ public int AddRoleMenu(List sysRoleMenus)
+ {
+ return Db.Insertable(sysRoleMenus).ExecuteCommand();
+ }
+
+ ///
+ /// 删除角色与菜单关联
+ ///
+ ///
+ ///
+ public int DeleteRoleMenuByRoleId(long roleId)
+ {
+ return Db.Deleteable().Where(it => it.Role_id == roleId).ExecuteCommand();
+ }
+
+ #endregion
+
+ ///
+ /// 添加角色
+ ///
+ ///
+ ///
+ public long InsertRole(SysRole sysRole)
+ {
+ sysRole.Create_time = Db.GetDate();
+ return Db.Insertable(sysRole).ExecuteReturnBigIdentity();
+ }
+
+ ///
+ /// 修改用户角色
+ ///
+ ///
+ ///
+ public int UpdateSysRole(SysRole sysRole)
+ {
+ var db = Db;
+ sysRole.Update_time = db.GetDate();
+
+ return db.Updateable()
+ .SetColumns(it => it.Update_time == sysRole.Update_time)
+ .SetColumns(it => it.Remark == sysRole.Remark)
+ .SetColumns(it => it.Update_by == sysRole.Update_by)
+ .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 Db.Updateable(role).UpdateColumns(t => new { t.Status }).ExecuteCommand();
+ }
+
+ ///
+ /// 检查角色权限是否存在
+ ///
+ /// 角色权限
+ ///
+ public SysRole CheckRoleKeyUnique(string roleKey)
+ {
+ return Db.Queryable().Where(it => it.RoleKey == roleKey).Single();
+ }
+
+ ///
+ /// 校验角色名称是否唯一
+ ///
+ /// 角色名称
+ ///
+ public SysRole CheckRoleNameUnique(string roleName)
+ {
+ return Db.Queryable().Where(it => it.RoleName == roleName).Single();
+ }
+ }
+}
diff --git a/ZR.Repository/System/SysUserPostRepository.cs b/ZR.Repository/System/SysUserPostRepository.cs
new file mode 100644
index 0000000..73ffb91
--- /dev/null
+++ b/ZR.Repository/System/SysUserPostRepository.cs
@@ -0,0 +1,27 @@
+using Infrastructure.Attribute;
+using SqlSugar;
+using System.Collections.Generic;
+using ZR.Model.System;
+
+namespace ZR.Repository.System
+{
+ ///
+ /// 用户岗位
+ ///
+ [AppService(ServiceLifetime = LifeTime.Transient)]
+ public class SysUserPostRepository : BaseRepository
+ {
+ ///
+ /// 获取用户岗位
+ ///
+ ///
+ ///
+ public List SelectPostsByUserId(long userId)
+ {
+ return Db.Queryable((p, up) => new JoinQueryInfos(
+ JoinType.Left, up.PostId == p.PostId
+ )).Where((p, up) => up.UserId == userId)
+ .Select().ToList();
+ }
+ }
+}
diff --git a/ZR.Repository/System/SysUserRepository.cs b/ZR.Repository/System/SysUserRepository.cs
new file mode 100644
index 0000000..03ab81c
--- /dev/null
+++ b/ZR.Repository/System/SysUserRepository.cs
@@ -0,0 +1,147 @@
+using Infrastructure.Attribute;
+using System;
+using System.Collections.Generic;
+using ZR.Model;
+using ZR.Model.System;
+
+namespace ZR.Repository.System
+{
+ ///
+ /// 用户管理
+ ///
+ [AppService(ServiceLifetime = LifeTime.Transient)]
+ public class SysUserRepository : BaseRepository
+ {
+ ///
+ /// 根据条件分页查询用户列表
+ ///
+ ///
+ ///
+ ///
+ public List SelectUserList(SysUser user, PagerInfo pager)
+ {
+ string sql = @"SELECT u.*,d.deptName, d.leader
+ FROM sys_user u
+ left join sys_dept d on u.deptId = d.deptId
+ WHERE u.delFlag = '0' ";
+ int totalCount = 0;
+ var list = Db.SqlQueryable(sql)
+ .WhereIF(!string.IsNullOrEmpty(user.UserName), it => it.UserName.Contains(user.UserName))
+ .WhereIF(!string.IsNullOrEmpty(user.Status), it => it.Status == user.Status)
+ .WhereIF(user.BeginTime != DateTime.MinValue && user.BeginTime != null, it => it.Create_time >= user.BeginTime)
+ .WhereIF(user.EndTime != DateTime.MinValue && user.BeginTime != null, it => it.EndTime <= user.EndTime)
+ .WhereIF(user.DeptId != 0, it => it.DeptId == user.DeptId)
+ .OrderBy(it => it.UserId)
+ .ToPageList(pager.PageNum, pager.PageSize, ref totalCount);
+ pager.TotalNum = totalCount;
+ return list;
+ }
+
+ ///
+ /// 通过用户ID查询用户
+ ///
+ ///
+ ///
+ public SysUser SelectUserById(long userId)
+ {
+ return Db.Queryable().Where(f => f.UserId == userId).First();
+ }
+
+ ///
+ /// 校验用户名是否存在
+ ///
+ ///
+ ///
+ public int CheckUserNameUnique(string userName)
+ {
+ return Db.Queryable().Where(it => it.UserName == userName).Count();
+ }
+
+ ///
+ /// 添加用户
+ ///
+ ///
+ ///
+ public int AddUser(SysUser sysUser)
+ {
+ sysUser.Create_time = DateTime.Now;
+ return Db.Insertable(sysUser).ExecuteReturnIdentity();
+ }
+
+ ///
+ /// 重置密码
+ ///
+ ///
+ ///
+ ///
+ public int ResetPwd(long userid, string password)
+ {
+ return Db.Updateable(new SysUser() { UserId = userid, Password = password })
+ .UpdateColumns(it => new { it.Password }).ExecuteCommand();
+ }
+
+ ///
+ /// 改变用户状态
+ ///
+ ///
+ ///
+ public int ChangeUserStatus(SysUser user)
+ {
+ return Db.Updateable(user).UpdateColumns(t => new { t.Status })
+ .ExecuteCommand();
+ }
+
+ ///
+ /// 删除用户
+ ///
+ /// 用户id
+ ///
+ public int DeleteUser(long userid)
+ {
+ return Db.Updateable(new SysUser() { UserId = userid, DelFlag = "2" })
+ .UpdateColumns(t => t.DelFlag)
+ .ExecuteCommand();
+ }
+
+ ///
+ /// 修改用户信息
+ ///
+ ///
+ ///
+ public int UpdateUser(SysUser user)
+ {
+ return Db.Updateable(user)
+ //.SetColumns(t => new SysUser()
+ //{
+ // UserName = user.UserName,
+ // Status = user.Status,
+ // NickName = user.NickName,
+ // Remark = user.Remark,
+ // Email = user.Email,
+ // Update_by = user.Update_by,
+ // Phonenumber = user.Phonenumber,
+ // Update_time = DateTime.Now,
+ // Sex = user.Sex,
+ // DeptId = user.DeptId
+ //})
+ .IgnoreColumns(ignoreAllNullColumns: true)//忽略所有为null
+ .IgnoreColumns(it => new { it.Password, it.Avatar })
+ .Where(f => f.UserId == user.UserId).ExecuteCommand();
+ }
+
+ ///
+ /// 修改用户头像
+ ///
+ ///
+ ///
+ public int UpdatePhoto(SysUser user)
+ {
+ return Db.Updateable()
+ .SetColumns(t => new SysUser()
+ {
+ Avatar = user.Avatar
+ })
+ .Where(f => f.UserId == user.UserId).ExecuteCommand();
+ }
+ }
+}
diff --git a/ZR.Repository/System/SysUserRoleRepository.cs b/ZR.Repository/System/SysUserRoleRepository.cs
new file mode 100644
index 0000000..d64bb93
--- /dev/null
+++ b/ZR.Repository/System/SysUserRoleRepository.cs
@@ -0,0 +1,77 @@
+using Infrastructure.Attribute;
+using SqlSugar;
+using System.Collections.Generic;
+using ZR.Model.System;
+
+namespace ZR.Repository.System
+{
+ [AppService(ServiceLifetime = LifeTime.Transient)]
+ public class SysUserRoleRepository : BaseRepository
+ {
+ ///
+ /// 删除用户角色
+ ///
+ ///
+ ///
+ public int DeleteUserRoleByUserId(int userId)
+ {
+ return Db.Deleteable().Where(it => it.UserId == userId).ExecuteCommand();
+ }
+
+ ///
+ /// 批量删除角色对应用户
+ ///
+ /// 角色id
+ /// 用户id集合
+ ///
+ public int DeleteRoleUserByUserIds(long roleId, List userIds)
+ {
+ return Db.Deleteable().Where(it => it.RoleId == roleId && userIds.Contains(it.UserId))
+ .ExecuteCommand();
+ }
+
+ ///
+ /// 添加用户角色
+ ///
+ ///
+ ///
+ public int AddUserRole(List sysUsers)
+ {
+ return Db.Insertable(sysUsers).ExecuteCommand();
+ }
+
+ ///
+ /// 删除角色关联的用户
+ ///
+ ///
+ ///
+ public int DeleteUserRoleByRoleId(int roleId)
+ {
+ return Db.Deleteable().In(roleId).ExecuteCommand();
+ }
+
+ ///
+ /// 获取角色分配个数
+ ///
+ ///
+ ///
+ public int CountUserRoleByRoleId(long roleId)
+ {
+ return Db.Queryable().Where(it => it.RoleId == roleId).Count();
+ }
+
+ ///
+ /// 获取用户数据根据角色id
+ ///
+ ///
+ ///
+ public List GetSysUsersByRoleId(long roleId)
+ {
+ return Db.Queryable((t1, user) => new JoinQueryInfos(
+ JoinType.Left, t1.UserId == user.UserId))
+ .Where((t1, user) => t1.RoleId == roleId && user.DelFlag == "0")
+ .Select((t1, user) => user)
+ .ToList();
+ }
+ }
+}
diff --git a/ZR.Repository/ZR.Repository.csproj b/ZR.Repository/ZR.Repository.csproj
new file mode 100644
index 0000000..c4175f5
--- /dev/null
+++ b/ZR.Repository/ZR.Repository.csproj
@@ -0,0 +1,18 @@
+
+
+
+ net5.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ZR.Service/BaseService.cs b/ZR.Service/BaseService.cs
new file mode 100644
index 0000000..f2d3830
--- /dev/null
+++ b/ZR.Service/BaseService.cs
@@ -0,0 +1,313 @@
+using Infrastructure.Attribute;
+using Infrastructure.Model;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+using ZR.Model;
+using ZR.Repository.DbProvider;
+
+namespace ZR.Service
+{
+ ///
+ /// 基础服务定义
+ ///
+ ///
+ public class BaseService : SugarDbContext, IBaseService where T : class, new()
+ {
+ #region 事务
+
+ ///
+ /// 启用事务
+ ///
+ public void BeginTran()
+ {
+ Db.Ado.BeginTran();
+ }
+
+ ///
+ /// 提交事务
+ ///
+ public void CommitTran()
+ {
+ Db.Ado.CommitTran();
+ }
+
+ ///
+ /// 回滚事务
+ ///
+ public void RollbackTran()
+ {
+ Db.Ado.RollbackTran();
+ }
+
+ #endregion
+
+ #region 添加操作
+ ///
+ /// 添加一条数据
+ ///
+ /// T
+ ///
+ public int Add(T parm)
+ {
+ return Db.Insertable(parm).RemoveDataCache().ExecuteCommand();
+ }
+
+ ///
+ /// 批量添加数据
+ ///
+ /// List
+ ///
+ public int Add(List parm)
+ {
+ return Db.Insertable(parm).RemoveDataCache().ExecuteCommand();
+ }
+
+ ///
+ /// 添加或更新数据
+ ///
+ /// List
+ ///
+ public T Saveable(T parm, Expression> uClumns = null, Expression> iColumns = null)
+ {
+ var command = Db.Saveable(parm);
+
+ if (uClumns != null)
+ {
+ command = command.UpdateIgnoreColumns(uClumns);
+ }
+
+ if (iColumns != null)
+ {
+ command = command.InsertIgnoreColumns(iColumns);
+ }
+
+ return command.ExecuteReturnEntity();
+ }
+
+ ///
+ /// 批量添加或更新数据
+ ///
+ /// List
+ ///
+ public List Saveable(List parm, Expression> uClumns = null, Expression> iColumns = null)
+ {
+ var command = Db.Saveable(parm);
+
+ if (uClumns != null)
+ {
+ command = command.UpdateIgnoreColumns(uClumns);
+ }
+
+ if (iColumns != null)
+ {
+ command = command.InsertIgnoreColumns(iColumns);
+ }
+
+ return command.ExecuteReturnList();
+ }
+ #endregion
+
+ #region 查询操作
+
+ ///
+ /// 根据条件查询数据是否存在
+ ///
+ /// 条件表达式树
+ ///
+ public bool Any(Expression> where)
+ {
+ return Db.Queryable().Any(where);
+ }
+
+ ///
+ /// 根据条件合计字段
+ ///
+ /// 条件表达式树
+ ///
+ public TResult Sum(Expression> where, Expression> field)
+ {
+ return Db.Queryable().Where(where).Sum(field);
+ }
+
+ ///
+ /// 根据主值查询单条数据
+ ///
+ /// 主键值
+ /// 泛型实体
+ public T GetId(object pkValue)
+ {
+ return Db.Queryable().InSingle(pkValue);
+ }
+
+ ///
+ /// 根据主键查询多条数据
+ ///
+ ///
+ ///
+ public List GetIn(object[] ids)
+ {
+ return Db.Queryable().In(ids).ToList();
+ }
+
+ ///
+ /// 根据条件取条数
+ ///
+ /// 条件表达式树
+ ///
+ public int GetCount(Expression> where)
+ {
+ return Db.Queryable().Count(where);
+
+ }
+
+ ///
+ /// 查询所有数据(无分页,请慎用)
+ ///
+ ///
+ public List GetAll(bool useCache = false, int cacheSecond = 3600)
+ {
+ return Db.Queryable().WithCacheIF(useCache, cacheSecond).ToList();
+ }
+
+ ///
+ /// 获得一条数据
+ ///
+ /// Expression>
+ ///
+ public T GetFirst(Expression> where)
+ {
+ return Db.Queryable().Where(where).First();
+ }
+
+ ///
+ /// 获得一条数据
+ ///
+ /// string
+ ///
+ public T GetFirst(string parm)
+ {
+ return Db.Queryable().Where(parm).First();
+ }
+
+
+ ///
+ /// 根据条件查询分页数据
+ ///
+ ///
+ ///
+ ///
+ public PagedInfo GetPages(Expression> where, PagerInfo parm)
+ {
+ var source = Db.Queryable().Where(where);
+
+ return source.ToPage(parm);
+ }
+
+ public PagedInfo GetPages(Expression> where, PagerInfo parm, Expression> order, string orderEnum = "Asc")
+ {
+ var source = Db.Queryable().Where(where).OrderByIF(orderEnum == "Asc", order, OrderByType.Asc).OrderByIF(orderEnum == "Desc", order, OrderByType.Desc);
+
+ return source.ToPage(parm);
+ }
+
+ ///
+ /// 根据条件查询数据
+ ///
+ /// 条件表达式树
+ ///
+ public List GetWhere(Expression> where, bool useCache = false, int cacheSecond = 3600)
+ {
+ var query = Db.Queryable().Where(where).WithCacheIF(useCache, cacheSecond);
+ return query.ToList();
+ }
+
+ ///