diff --git a/src/.dockerignore b/src/.dockerignore new file mode 100644 index 0000000..3729ff0 --- /dev/null +++ b/src/.dockerignore @@ -0,0 +1,25 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md \ No newline at end of file diff --git a/src/.vscode/launch.json b/src/.vscode/launch.json new file mode 100644 index 0000000..38ca105 --- /dev/null +++ b/src/.vscode/launch.json @@ -0,0 +1,51 @@ +{ + // 使用 IntelliSense 了解相关属性。 + // 悬停以查看现有属性的描述。 + // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + "program": "${workspaceFolder}/bin/Debug//", + "args": [], + "cwd": "${workspaceFolder}", + "stopAtEntry": false, + "console": "internalConsole" + }, + + { + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md + "name": ".NET Core Launch (web)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + // If you have changed target frameworks, make sure to update the program path. + "program": "${workspaceFolder}/ZNYC.Recruitment.Api/bin/Debug/net5.0/ZNYC.Recruitment.Api.dll", + "args": [], + "cwd": "${workspaceFolder}/ZNYC.Recruitment.Api", + "stopAtEntry": false, + // Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser + "serverReadyAction": { + "action": "openExternally", + "pattern": "\\\\bNow listening on:\\\\s+(https?://\\\\S+)" + }, + "env": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "sourceFileMap": { + "/Views": "${workspaceFolder}/Views" + } + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach", + "processId": "${command:pickProcess}" + } + ] +} \ No newline at end of file diff --git a/src/.vscode/solution-explorer/class.cs-template b/src/.vscode/solution-explorer/class.cs-template new file mode 100644 index 0000000..015da46 --- /dev/null +++ b/src/.vscode/solution-explorer/class.cs-template @@ -0,0 +1,8 @@ +using System; + +namespace {{namespace}} +{ + public class {{name}} + { + } +} diff --git a/src/.vscode/solution-explorer/class.ts-template b/src/.vscode/solution-explorer/class.ts-template new file mode 100644 index 0000000..ff2edef --- /dev/null +++ b/src/.vscode/solution-explorer/class.ts-template @@ -0,0 +1,3 @@ +export class {{name}} { + +} \ No newline at end of file diff --git a/src/.vscode/solution-explorer/class.vb-template b/src/.vscode/solution-explorer/class.vb-template new file mode 100644 index 0000000..38ef67f --- /dev/null +++ b/src/.vscode/solution-explorer/class.vb-template @@ -0,0 +1,9 @@ +Imports System + +Namespace {{namespace}} + + Public Class {{name}} + + End Class + +End Namespace diff --git a/src/.vscode/solution-explorer/default.ts-template b/src/.vscode/solution-explorer/default.ts-template new file mode 100644 index 0000000..04af870 --- /dev/null +++ b/src/.vscode/solution-explorer/default.ts-template @@ -0,0 +1,3 @@ +export default {{name}} { + +} \ No newline at end of file diff --git a/src/.vscode/solution-explorer/enum.cs-template b/src/.vscode/solution-explorer/enum.cs-template new file mode 100644 index 0000000..7d4cdee --- /dev/null +++ b/src/.vscode/solution-explorer/enum.cs-template @@ -0,0 +1,8 @@ +using System; + +namespace {{namespace}} +{ + public enum {{name}} + { + } +} diff --git a/src/.vscode/solution-explorer/interface.cs-template b/src/.vscode/solution-explorer/interface.cs-template new file mode 100644 index 0000000..6b5dec1 --- /dev/null +++ b/src/.vscode/solution-explorer/interface.cs-template @@ -0,0 +1,8 @@ +using System; + +namespace {{namespace}} +{ + public interface {{name}} + { + } +} diff --git a/src/.vscode/solution-explorer/interface.ts-template b/src/.vscode/solution-explorer/interface.ts-template new file mode 100644 index 0000000..3ea404b --- /dev/null +++ b/src/.vscode/solution-explorer/interface.ts-template @@ -0,0 +1,3 @@ +export interface {{name}} { + +} \ No newline at end of file diff --git a/src/.vscode/solution-explorer/template-list.json b/src/.vscode/solution-explorer/template-list.json new file mode 100644 index 0000000..2849622 --- /dev/null +++ b/src/.vscode/solution-explorer/template-list.json @@ -0,0 +1,46 @@ +{ + "templates": [ + { + "name": "Class", + "extension": "cs", + "file": "./class.cs-template", + "parameters": "./template-parameters.js" + }, + { + "name": "Interface", + "extension": "cs", + "file": "./interface.cs-template", + "parameters": "./template-parameters.js" + }, + { + "name": "Enum", + "extension": "cs", + "file": "./enum.cs-template", + "parameters": "./template-parameters.js" + }, + { + "name": "Class", + "extension": "ts", + "file": "./class.ts-template", + "parameters": "./template-parameters.js" + }, + { + "name": "Interface", + "extension": "ts", + "file": "./interface.ts-template", + "parameters": "./template-parameters.js" + }, + { + "name": "Default", + "extension": "ts", + "file": "./default.ts-template", + "parameters": "./template-parameters.js" + }, + { + "name": "Class", + "extension": "vb", + "file": "./class.vb-template", + "parameters": "./template-parameters.js" + } + ] +} \ No newline at end of file diff --git a/src/.vscode/solution-explorer/template-parameters.js b/src/.vscode/solution-explorer/template-parameters.js new file mode 100644 index 0000000..daba8b2 --- /dev/null +++ b/src/.vscode/solution-explorer/template-parameters.js @@ -0,0 +1,17 @@ +var path = require("path"); + +module.exports = function(filename, projectPath, folderPath) { + var namespace = "Unknown"; + if (projectPath) { + namespace = path.basename(projectPath, path.extname(projectPath)); + if (folderPath) { + namespace += "." + folderPath.replace(path.dirname(projectPath), "").substring(1).replace(/[\\\/]/g, "."); + } + namespace = namespace.replace(/[\\\-]/g, "_"); + } + + return { + namespace: namespace, + name: path.basename(filename, path.extname(filename)) + } +}; \ No newline at end of file diff --git a/src/.vscode/tasks.json b/src/.vscode/tasks.json new file mode 100644 index 0000000..a330b40 --- /dev/null +++ b/src/.vscode/tasks.json @@ -0,0 +1,42 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/ZNYC.Recruitment.Api/ZNYC.Recruitment.Api.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "publish", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "${workspaceFolder}/ZNYC.Recruitment.Api/ZNYC.Recruitment.Api.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "watch", + "command": "dotnet", + "type": "process", + "args": [ + "watch", + "run", + "${workspaceFolder}/ZNYC.Recruitment.Api/ZNYC.Recruitment.Api.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/src/Dockerfile b/src/Dockerfile new file mode 100644 index 0000000..8a9a44b --- /dev/null +++ b/src/Dockerfile @@ -0,0 +1,29 @@ +#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base +WORKDIR /app +EXPOSE 80 +EXPOSE 443 + +ENV TZ=Asia/Shanghai +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build +WORKDIR /src +COPY ["Znyc.Recruitment.Api/Znyc.Recruitment.Api.csproj", "Znyc.Recruitment.Api/"] +COPY ["Znyc.Recruitment.Services/Znyc.Recruitment.Service.csproj", "Znyc.Recruitment.Services/"] +COPY ["Znyc.Recruitment.Repository/Znyc.Recruitment.Repository.csproj", "Znyc.Recruitment.Repository/"] +COPY ["Znyc.Recruitment.Model/Znyc.Recruitment.Model.csproj", "Znyc.Recruitment.Model/"] +COPY ["Znyc.Recruitment.Common/Znyc.Recruitment.Common.csproj", "Znyc.Recruitment.Common/"] +RUN dotnet restore "Znyc.Recruitment.Api/Znyc.Recruitment.Api.csproj" +COPY . . +WORKDIR "/src/Znyc.Recruitment.Api" +RUN dotnet build "Znyc.Recruitment.Api.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "Znyc.Recruitment.Api.csproj" -c Release -o /app/publish + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "Znyc.Recruitment.Api.dll"] \ No newline at end of file diff --git a/src/LICENSE b/src/LICENSE new file mode 100644 index 0000000..4e3c578 --- /dev/null +++ b/src/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 zhontai + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/src/README.md b/src/README.md new file mode 100644 index 0000000..9cebec8 --- /dev/null +++ b/src/README.md @@ -0,0 +1 @@ +众能云车人才招聘后端API \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/.config/dotnet-tools.json b/src/Znyc.Recruitment.Api/.config/dotnet-tools.json new file mode 100644 index 0000000..aaaa036 --- /dev/null +++ b/src/Znyc.Recruitment.Api/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-ef": { + "version": "5.0.3", + "commands": [ + "dotnet-ef" + ] + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Aop/AopHelper.cs b/src/Znyc.Recruitment.Api/Aop/AopHelper.cs new file mode 100644 index 0000000..b13bda0 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Aop/AopHelper.cs @@ -0,0 +1,39 @@ +using Castle.DynamicProxy; +using System; +using System.Reflection; +using System.Threading.Tasks; + +namespace Znyc.Recruitment.Aop +{ + public class AopHelper + { + public static async Task ExecuteGenericMethod(Task returnValue, Action callBackAction, + Action exceptionAction, Action finallyAction) + { + try + { + T result = await returnValue; + callBackAction?.Invoke(result); + return result; + } + catch (Exception ex) + { + exceptionAction?.Invoke(ex); + return default; + } + finally + { + finallyAction?.Invoke(); + } + } + + public static object CallGenericMethod(IInvocation invocation, Action callBackAction, + Action exceptionAction, Action finallyAction) + { + return typeof(AopHelper) + .GetMethod("ExecuteGenericMethod", BindingFlags.Public | BindingFlags.Static) + .MakeGenericMethod(invocation.Method.ReturnType.GenericTypeArguments[0]) + .Invoke(null, new[] { invocation.ReturnValue, callBackAction, exceptionAction, finallyAction }); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Aop/TransactionInterceptor.cs b/src/Znyc.Recruitment.Api/Aop/TransactionInterceptor.cs new file mode 100644 index 0000000..df82ac7 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Aop/TransactionInterceptor.cs @@ -0,0 +1,67 @@ +using Castle.DynamicProxy; +using FreeSql; +using System.Reflection; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Attributes; +using Znyc.Recruitment.Common.Extensions; +using Znyc.Recruitment.Common.Output; + +namespace Znyc.Recruitment.Aop +{ + public class TransactionInterceptor : IInterceptor + { + private readonly UnitOfWorkManager _unitOfWorkManager; + private IUnitOfWork _unitOfWork; + + public TransactionInterceptor(UnitOfWorkManager unitOfWorkManager) + { + _unitOfWorkManager = unitOfWorkManager; + } + + public void Intercept(IInvocation invocation) + { + MethodInfo method = invocation.MethodInvocationTarget ?? invocation.Method; + if (method.HasAttribute()) + { + InterceptTransaction(invocation, method); + } + else + { + invocation.Proceed(); + } + } + + private async void InterceptTransaction(IInvocation invocation, MethodInfo method) + { + try + { + TransactionAttribute transaction = method.GetAttribute(); + _unitOfWork = _unitOfWorkManager.Begin(transaction.Propagation, transaction.IsolationLevel); + invocation.Proceed(); + + dynamic returnValue = invocation.ReturnValue; + if (returnValue is Task) + { + returnValue = await returnValue; + } + + if (returnValue is IResponseOutput res && !res.Successed) + { + _unitOfWork.Rollback(); + } + else + { + _unitOfWork.Commit(); + } + } + catch + { + _unitOfWork.Rollback(); + } + finally + { + _unitOfWork.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Attributes/HiddenApiAttribute .cs b/src/Znyc.Recruitment.Api/Attributes/HiddenApiAttribute .cs new file mode 100644 index 0000000..97f6cee --- /dev/null +++ b/src/Znyc.Recruitment.Api/Attributes/HiddenApiAttribute .cs @@ -0,0 +1,44 @@ +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; +using System; + +namespace Znyc.Recruitment.Attributes +{ + /// + /// 隐藏接口,不生成到swagger文档展示(Swashbuckle.AspNetCore 5.0.0) + /// + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] + public class HiddenApiAttribute : Attribute + { + } + + public class HiddenApiFilter : IDocumentFilter + { + /// + /// 重写Apply方法,移除隐藏接口的生成 + /// + /// swagger文档文件 + /// + public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) + { + foreach (Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescription apiDescription in context.ApiDescriptions) + { + ControllerActionDescriptor api = + apiDescription.ActionDescriptor as + ControllerActionDescriptor; //这里强转来获取到控制器的名称 + if (api?.ControllerName == "CommonBase") //过滤的核心逻辑 + { + string key = "/" + apiDescription.RelativePath; + if (key.Contains("?")) + { + int idx = key.IndexOf("?", StringComparison.Ordinal); + key = key.Substring(0, idx); + } + + swaggerDoc.Paths.Remove(key); + } + } + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Attributes/LoginAttribute.cs b/src/Znyc.Recruitment.Api/Attributes/LoginAttribute.cs new file mode 100644 index 0000000..694f379 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Attributes/LoginAttribute.cs @@ -0,0 +1,12 @@ +using System; + +namespace Znyc.Recruitment.Attributes +{ + /// + /// 启用登录 + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] + public class LoginAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Attributes/NoOprationLogAttribute.cs b/src/Znyc.Recruitment.Api/Attributes/NoOprationLogAttribute.cs new file mode 100644 index 0000000..6dd7f72 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Attributes/NoOprationLogAttribute.cs @@ -0,0 +1,12 @@ +using System; + +namespace Znyc.Recruitment.Attributes +{ + /// + /// 禁用操作日志 + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] + public class NoOprationLogAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Attributes/PermissionAttribute.cs b/src/Znyc.Recruitment.Api/Attributes/PermissionAttribute.cs new file mode 100644 index 0000000..6d1442a --- /dev/null +++ b/src/Znyc.Recruitment.Api/Attributes/PermissionAttribute.cs @@ -0,0 +1,55 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Linq; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Auth; + +namespace Znyc.Recruitment.Attributes +{ + /// + /// 启用权限 + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] + public class PermissionAttribute : AuthorizeAttribute, IAuthorizationFilter, IAsyncAuthorizationFilter + { + public Task OnAuthorizationAsync(AuthorizationFilterContext context) + { + OnAuthorization(context); + return Task.CompletedTask; + } + + public void OnAuthorization(AuthorizationFilterContext context) + { + //排除匿名访问 + if (context.ActionDescriptor.EndpointMetadata.Any(m => m.GetType() == typeof(AllowAnonymousAttribute))) + { + return; + } + + //登录验证 + IUser user = context.HttpContext.RequestServices.GetService(); + ; + if (user == null || !(user?.Id > 0)) + { + context.Result = new ChallengeResult(); + return; + } + + //排除登录接口 + if (context.ActionDescriptor.EndpointMetadata.Any(m => m.GetType() == typeof(LoginAttribute))) + { + return; + } + + //权限验证 v1.1.0增加权限 + //var httpMethod = context.HttpContext.Request.Method; + //var api = context.ActionDescriptor.AttributeRouteInfo.Template; + //var permissionHandler = context.HttpContext.RequestServices.GetService(); + //var isValid = await permissionHandler.ValidateAsync(api, httpMethod); + //if (!isValid) context.Result = new ForbidResult(); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Attributes/QuartzAttribute.cs b/src/Znyc.Recruitment.Api/Attributes/QuartzAttribute.cs new file mode 100644 index 0000000..6b58698 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Attributes/QuartzAttribute.cs @@ -0,0 +1,67 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Linq; +using System.Threading.Tasks; +using Znyc.Recruitment.Api.Auth; + +namespace Znyc.Recruitment.Attributes +{ + /// + /// 定时任务启动密钥 + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] + public class QuartzAttribute : AuthorizeAttribute, IAuthorizationFilter, IAsyncAuthorizationFilter + { + private IApiHandler _apiHandler; + + public Task OnAuthorizationAsync(AuthorizationFilterContext context) + { + OnAuthorization(context); + return Task.CompletedTask; + } + + public async void OnAuthorization(AuthorizationFilterContext context) + { + //排除匿名访问 + if (context.ActionDescriptor.EndpointMetadata.Any(m => m.GetType() == typeof(AllowAnonymousAttribute))) + { + return; + } + + string apiUrl = context.HttpContext.Request.Path.Value; + _apiHandler = context.HttpContext.RequestServices.GetService(); + Model.ApiEntity entity = await _apiHandler.ValidateAsync(apiUrl); + //key/value 存入数据库去查询,不同的api对应不同的key/value + string authHeader = context.HttpContext.Request.Headers[entity.AuthKey]; + if (authHeader != null && authHeader.Equals(entity.AuthValue)) + { + return; + } + + context.Result = new StatusCodeResult(StatusCodes.Status401Unauthorized); + } + + public void OnAuthorizationTest(AuthorizationFilterContext context) + { + //key/value 存入数据库去查询,不同的api对应不同的key/value + string authHeader = context.HttpContext.Request.Headers["Authorization"]; + if (authHeader != null && authHeader.StartsWith("Quartz")) + { + if (authHeader.Equals("Quartz 5r59#ioFJLQ@Pye6")) + { + return; + } + + context.Result = new StatusCodeResult(StatusCodes.Status401Unauthorized); + } + else + { + context.Result = new StatusCodeResult(StatusCodes.Status401Unauthorized); + } + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Attributes/ValidateInputAttribute.cs b/src/Znyc.Recruitment.Api/Attributes/ValidateInputAttribute.cs new file mode 100644 index 0000000..e0f3d42 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Attributes/ValidateInputAttribute.cs @@ -0,0 +1,32 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using System; +using System.Linq; +using Znyc.Recruitment.Common.Output; + +namespace Znyc.Recruitment.Attributes +{ + /// + /// 输入模型验证 + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] + public class ValidateInputAttribute : ActionFilterAttribute + { + public override void OnResultExecuting(ResultExecutingContext context) + { + if (!context.ModelState.IsValid) + { + try + { + context.Result = + new JsonResult(ResponseOutput.Fail(context.ModelState.Values.First().Errors[0].ErrorMessage)); + } + catch + { + context.Result = new StatusCodeResult(StatusCodes.Status500InternalServerError); + } + } + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Attributes/VersionRouteAttribute.cs b/src/Znyc.Recruitment.Api/Attributes/VersionRouteAttribute.cs new file mode 100644 index 0000000..1b0913e --- /dev/null +++ b/src/Znyc.Recruitment.Api/Attributes/VersionRouteAttribute.cs @@ -0,0 +1,22 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using System; +using Znyc.Recruitment.Enums; + +namespace Znyc.Recruitment.Attributes +{ + /// + /// 自定义路由 /api/{version}/[controler]/[action] + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] + public class VersionRouteAttribute : RouteAttribute, IApiDescriptionGroupNameProvider + { + public VersionRouteAttribute(ApiVersion version = ApiVersion.v1, string action = "[action]") + : base($"/api/{version}/[controller]/{action}") + { + GroupName = version.ToString(); + } + + public string GroupName { get; set; } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Auth/ApiHandler.cs b/src/Znyc.Recruitment.Api/Auth/ApiHandler.cs new file mode 100644 index 0000000..9a7b7a5 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Auth/ApiHandler.cs @@ -0,0 +1,25 @@ +using System.Threading.Tasks; +using Znyc.Recruitment.Model; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Auth +{ + /// + /// 定时任务 + /// + public class ApiHandler : IApiHandler + { + private readonly IApiService _apiService; + + public ApiHandler(IApiService apiService) + { + _apiService = apiService; + } + + public async Task ValidateAsync(string apiUrl) + { + ApiEntity result = await _apiService.GetApiAsync(apiUrl); + return result; + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Auth/IApiHandler.cs b/src/Znyc.Recruitment.Api/Auth/IApiHandler.cs new file mode 100644 index 0000000..ee7bf19 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Auth/IApiHandler.cs @@ -0,0 +1,13 @@ +using System.Threading.Tasks; +using Znyc.Recruitment.Model; + +namespace Znyc.Recruitment.Api.Auth +{ + /// + /// 定时任务 + /// + public interface IApiHandler + { + public Task ValidateAsync(string apiUrl); + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Auth/IPermissionHandler.cs b/src/Znyc.Recruitment.Api/Auth/IPermissionHandler.cs new file mode 100644 index 0000000..b10eb2b --- /dev/null +++ b/src/Znyc.Recruitment.Api/Auth/IPermissionHandler.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; + +namespace Znyc.Recruitment.Auth +{ + /// + /// 权限处理接口 + /// + public interface IPermissionHandler + { + /// + /// 权限验证 + /// + /// + /// + /// + Task ValidateAsync(string api, string httpMethod); + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Auth/PermissionHandler.cs b/src/Znyc.Recruitment.Api/Auth/PermissionHandler.cs new file mode 100644 index 0000000..04f0c34 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Auth/PermissionHandler.cs @@ -0,0 +1,35 @@ +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Attributes; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Auth +{ + /// + /// 权限处理 + /// + [SingleInstance] + public class PermissionHandler : IPermissionHandler + { + private readonly IUserService _userService; + + public PermissionHandler(IUserService userService) + { + _userService = userService; + } + + /// + /// 权限验证 v1.1.0后增加权限验证 + /// + /// 接口路径 + /// http请求方法 + /// + public async Task ValidateAsync(string api, string httpMethod) + { + //var permissions = await _userService.GetPermissionsAsync(); + + ////var isValid = permissions.Any(m => m.EqualsIgnoreCase($"{httpMethod}/{api}")); + //var isValid = permissions.Any(m => m != null && m.EqualsIgnoreCase($"/{api}")); + return await Task.FromResult(true); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Auth/ResponseAuthenticationHandler.cs b/src/Znyc.Recruitment.Api/Auth/ResponseAuthenticationHandler.cs new file mode 100644 index 0000000..93d5f46 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Auth/ResponseAuthenticationHandler.cs @@ -0,0 +1,74 @@ +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using System; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Extensions; +using StatusCodes = Znyc.Recruitment.Enums.StatusCodes; + +namespace Znyc.Recruitment.Auth +{ + /// + /// 响应认证处理器 + /// + public class ResponseAuthenticationHandler : AuthenticationHandler + { + public ResponseAuthenticationHandler( + IOptionsMonitor options, + ILoggerFactory logger, + UrlEncoder encoder, + ISystemClock clock + ) : base(options, logger, encoder, clock) + { + } + + protected override Task HandleAuthenticateAsync() + { + throw new NotImplementedException(); + } + + protected override async Task HandleChallengeAsync(AuthenticationProperties properties) + { + Response.ContentType = "application/json"; + Response.StatusCode = Microsoft.AspNetCore.Http.StatusCodes.Status401Unauthorized; + await Response.WriteAsync(JsonConvert.SerializeObject( + new ResponseStatusData + { + Code = StatusCodes.Status401Unauthorized, + Msg = StatusCodes.Status401Unauthorized.ToDescription() + }, + new JsonSerializerSettings + { + ContractResolver = new CamelCasePropertyNamesContractResolver() + } + )); + } + + protected override async Task HandleForbiddenAsync(AuthenticationProperties properties) + { + Response.ContentType = "application/json"; + Response.StatusCode = Microsoft.AspNetCore.Http.StatusCodes.Status403Forbidden; + await Response.WriteAsync(JsonConvert.SerializeObject( + new ResponseStatusData + { + Code = StatusCodes.Status403Forbidden, + Msg = StatusCodes.Status403Forbidden.ToDescription() + }, + new JsonSerializerSettings + { + ContractResolver = new CamelCasePropertyNamesContractResolver() + } + )); + } + } + + public class ResponseStatusData + { + public StatusCodes Code { get; set; } = StatusCodes.Status1Ok; + public string Msg { get; set; } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/ActivityController.cs b/src/Znyc.Recruitment.Api/Controllers/ActivityController.cs new file mode 100644 index 0000000..52d5dc0 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/ActivityController.cs @@ -0,0 +1,121 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Controllers +{ + /// + /// 活动页 + /// + [ApiExplorerSettings(IgnoreApi = false)] + public class ActivityController : BaseController + { + private readonly IActivityService _activityService; + + public ActivityController(IActivityService activityService) + { + _activityService = activityService; + } + + /// + /// 查询活动列表 + /// + /// + [HttpGet] + [AllowAnonymous] + [Route("api/v1/activitys")] + + public async Task>> GetListAsync() + { + return await _activityService.GetListAsync(); + } + + /// + /// 根据Id查询活动详情 + /// + /// + /// + [HttpGet] + [AllowAnonymous] + [Route("api/v1/activity/{id}")] + + public async Task> GetAsync(long id) + { + return await _activityService.GetAsync(id); + } + + /// + /// 邀请排行榜 + /// + /// + /// + /// + [HttpGet] + [AllowAnonymous] + [Route("api/v1/invitation/activitys/search")] + public async Task>> GetInviteTopAsync(int currentPage = 1, int pageSize = 10) + { + return await _activityService.GetInviteTopAsync(currentPage, pageSize); + } + + /// + /// 累计签到排行榜 + /// + /// + /// + /// + [HttpGet] + [Route("api/v1/sign/activitys/search")] + [AllowAnonymous] + public async Task>> GetTotalSeriesDaysAsync(int currentPage = 1, int pageSize = 10) + { + return await _activityService.GetTotalSeriesDaysAsync(currentPage, pageSize); + } + + /// + /// 积分排行榜 + /// + /// + /// + /// + [HttpGet] + [AllowAnonymous] + [Route("api/v1/currency/activitys/search")] + public async Task>> GetAvailableCreditsAsync(int currentPage = 1, int pageSize = 10) + { + return await _activityService.GetAvailableCreditsAsync(currentPage, pageSize); + } + + /// + /// 求职浏览量排行榜 + /// + /// + /// + /// + [HttpGet] + [Route("api/v1/applyjob/activitys/search")] + [AllowAnonymous] + public async Task>> GetApplyJobPageViewAsync(int currentPage = 1, int pageSize = 10) + { + return await _activityService.GetApplyJobPageViewAsync(currentPage, pageSize); + } + + /// + /// 招聘浏览量排行榜 + /// + /// + /// + /// + [HttpGet] + [Route("api/v1/recruitment/activitys/search")] + [AllowAnonymous] + public async Task>> GetRecruitmentPageViewAsync(int currentPage = 1, int pageSize = 10) + { + return await _activityService.GetRecruitmentPageViewAsync(currentPage, pageSize); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/ApplyJobController.cs b/src/Znyc.Recruitment.Api/Controllers/ApplyJobController.cs new file mode 100644 index 0000000..7573edb --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/ApplyJobController.cs @@ -0,0 +1,156 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.ComponentModel.DataAnnotations; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; + +namespace Znyc.apply.Api.Controllers +{ + /// + /// 求职信息管理 + /// + public class ApplyJobController : BaseController + { + private readonly IApplyJobService _applyJobService; + + public ApplyJobController( + IApplyJobService applyJobService + ) + { + _applyJobService = applyJobService; + } + + /// + /// 单条查询 + /// + /// + /// + [HttpGet] + [AllowAnonymous] + [Route("api/v1/apply/{id}")] + public async Task> GetAsync([Required] long id) + { + return await _applyJobService.GetAsync(id); + } + + /// + /// 我的求职简历 + /// + /// + [HttpGet] + [Route("api/v1/my/apply")] + public async Task> GetMyApplyAsync() + { + return await _applyJobService.GetMyApplyAsync(); + } + + /// + /// 分页查询 + /// + /// 内容 + /// 省 + /// 市 + /// 行业id + /// 岗位类型 + /// 排序 + /// 当前页 + /// 页数 + /// + [HttpGet] + [AllowAnonymous] + [Route("api/v1/applys/search")] + public async Task PageAsync(string key, string provinceId, string cityId, + long industryId, long jobId, long areaid, string sort, int currentPage = 1, int pageSize = 20) + { + return await _applyJobService.PageAsync(key, provinceId, cityId, industryId, jobId, areaid, sort, currentPage, + pageSize); + } + + /// + /// 获取手机号码 + /// + /// + /// + [HttpGet] + [Route("api/v1/apply/phone/{id}")] + public async Task GetPhoneAsync([Required] long id) + { + return await _applyJobService.GetPhoneAsync(id); + } + + /// + /// 添加求职信息 + /// + /// + /// + [HttpPost] + [Route("api/v1/apply")] + public async Task AddAsync([Required] ApplyJobAddInput input) + { + return await _applyJobService.AddAsync(input); + } + + /// + /// 修改求职信息 + /// + /// + /// + [HttpPut] + [Route("api/v1/apply")] + public async Task UpdateAsync([Required] ApplyJobUpdateInput input) + { + return await _applyJobService.UpdateAsync(input); + } + + /// + /// 一键刷新 + /// + /// + [HttpPut] + [Route("api/v1/apply/refresh/{id}")] + public async Task RefreshAsync([Required] long id) + { + return await _applyJobService.RefreshAsync(id); + } + + /// + /// 置顶求职信息 + /// + /// + /// + [HttpPut] + [Route("api/v1/apply/top/{id}")] + public async Task UpdateTopAsync([Required] long id) + { + return await _applyJobService.UpdateTopAsync(id); + } + + /// + /// 更改求职信息状态 + /// + /// + /// 求职状态1-正在找/2-已找到 + /// + [HttpPut] + [Route("api/v1/apply/status/{status}/{id}")] + public async Task UpdateStateAsync([Required] int status, [Required] long id) + { + return await _applyJobService.UpdateStateAsync(status, id); + } + + /// + /// 是否公开求职信息 + /// + /// + /// + /// + [HttpPut] + [Route("api/v1/apply/public/{isPublic}/{id}")] + public async Task IsPublicAsync([Required] bool isPublic, [Required] long id) + { + return await _applyJobService.IsPublicAsync(isPublic, id); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/AuditController.cs b/src/Znyc.Recruitment.Api/Controllers/AuditController.cs new file mode 100644 index 0000000..fe31493 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/AuditController.cs @@ -0,0 +1,35 @@ +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Controllers +{ + /// + /// 审核记录管理 + /// + [ApiExplorerSettings(IgnoreApi = false)] + public class AuditController : BaseController + { + private readonly IAuditService _auditService; + + public AuditController(IAuditService auditService) + { + _auditService = auditService; + } + + /// + /// 审核记录 + /// + /// + /// + /// + [HttpGet] + [Route("api/v1/audits/search")] + public async Task>> PageAsync(int currentPage = 1, int pageSize = 10) + { + return await _auditService.PageAsync(currentPage, pageSize); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/AuthController.cs b/src/Znyc.Recruitment.Api/Controllers/AuthController.cs new file mode 100644 index 0000000..4103896 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/AuthController.cs @@ -0,0 +1,63 @@ +using Microsoft.AspNetCore.Mvc; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Controllers +{ + /// + /// 授权管理 + /// + public class AuthController : BaseController + { + private readonly IAuthService _authService; + + public AuthController( + IAuthService authService + ) + { + _authService = authService; + } + + /// + /// 百度地图获取AccessToken + /// + /// + [HttpGet] + [Route("api/v1/auth/baidu/accesstoken")] + public IResponseOutput GetAccessTokenAsync() + { + return _authService.GetAccessTokenAsync(); + } + + /// + /// 微信获取AccessToken + /// + /// + [HttpGet] + [Route("api/v1/auth/weixin/accesstoken")] + public IResponseOutput GetWxAccessTokenAsync() + { + return _authService.GetWxAccessTokenAsync(); + } + + /// + /// 获取小程序码 + /// + /// + [HttpGet] + [Route("api/v1/auth/weixin/unlimited")] + public IResponseOutput GetUnlimitedAsync(string? id) + { + if(id is not null) + { + return _authService.GetUnlimitedAsync(id); + } + else + { + return _authService.GetUnlimitedAsync(); + } + + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/BannerController.cs b/src/Znyc.Recruitment.Api/Controllers/BannerController.cs new file mode 100644 index 0000000..a4b9bc7 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/BannerController.cs @@ -0,0 +1,36 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Controllers +{ + /// + /// 广告页 + /// + [ApiExplorerSettings(IgnoreApi = false)] + public class BannerController : BaseController + { + private readonly IBannerService _bannerService; + + public BannerController(IBannerService bannerService) + { + _bannerService = bannerService; + } + + /// + /// 查询广告列表 + /// + /// + [HttpGet] + [Route("api/v1/banners")] + [AllowAnonymous] + public async Task>> GetBannerListAsync(int tag) + { + return await _bannerService.GetBannerListAsync(tag); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/BaseController.cs b/src/Znyc.Recruitment.Api/Controllers/BaseController.cs new file mode 100644 index 0000000..9c99353 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/BaseController.cs @@ -0,0 +1,15 @@ +using Microsoft.AspNetCore.Mvc; +using Znyc.Recruitment.Attributes; + +namespace Znyc.Recruitment.Controllers +{ + /// + /// 基础控制器 + /// + [ApiController] + [Permission] + [ValidateInput] + public abstract class BaseController : ControllerBase + { + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/BrowseController.cs b/src/Znyc.Recruitment.Api/Controllers/BrowseController.cs new file mode 100644 index 0000000..5a2e907 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/BrowseController.cs @@ -0,0 +1,51 @@ +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Controllers +{ + /// + /// 用户浏览信息管理 + /// + + public class BrowseController : BaseController + { + private readonly IBrowseService _browseService; + + public BrowseController(IBrowseService browseService) + { + _browseService = browseService; + } + + /// + /// 用户浏览求职信息 + /// + /// + /// + /// + [HttpGet] + [Route("api/v1/apply/browses/search")] + public async Task>> ApplyJobPageAsync( + int currentPage = 1, int pageSize = 10) + { + return await _browseService.ApplyJobPageAsync(currentPage, pageSize); + } + + /// + /// 用户浏览招聘信息 + /// + /// + /// + /// + [HttpGet] + [Route("api/v1/recruitment/browses/search")] + public async Task>> RecruitmentPageAsync( + int currentPage = 1, int pageSize = 10) + { + return await _browseService.RecruitmentPageAsync(currentPage, pageSize); + } + + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/CallFeedbackController.cs b/src/Znyc.Recruitment.Api/Controllers/CallFeedbackController.cs new file mode 100644 index 0000000..19462e7 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/CallFeedbackController.cs @@ -0,0 +1,37 @@ +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Controllers +{ + /// + /// 通话评价 + /// + [ApiExplorerSettings(IgnoreApi = false)] + public class CallFeedbackController : BaseController + { + private readonly ICallFeedbackService _callFeedbackService; + + public CallFeedbackController(ICallFeedbackService callFeedbackService) + { + _callFeedbackService = callFeedbackService; + } + + + + + /// + /// 新增通话评价 + /// + /// + /// + [HttpPost] + [Route("api/v1/callfeedback")] + public async Task AddCallFeedbackAsync(CallFeedbackAddInput input) + { + return await _callFeedbackService.AddCallFeedbackAsync(input); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/CertificationController.cs b/src/Znyc.Recruitment.Api/Controllers/CertificationController.cs new file mode 100644 index 0000000..aa362cf --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/CertificationController.cs @@ -0,0 +1,58 @@ +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Controllers +{ + /// + /// 实名认证管理 + /// + public class CertificationController : BaseController + { + private readonly ICertificationService _certificationService; + + public CertificationController( + ICertificationService certificationService + ) + { + _certificationService = certificationService; + } + + /// + /// 查询实名认证信息 + /// + /// + [HttpGet] + [Route("api/v1/certification")] + public async Task> GetAsync() + { + return await _certificationService.GetAsync(); + } + + /// + /// 新增实名认证信息 + /// + /// + /// + [HttpPost] + [Route("api/v1/certification")] + public async Task AddAsync(CertificationAddInput certificationAddInput) + { + return await _certificationService.AddAsync(certificationAddInput); + } + + /// + /// 更新实名认证信息 + /// + /// + /// + [HttpPut] + [Route("api/v1/certification")] + public async Task UpdateAsync(CertificationUpdateInput certificationUpdateInput) + { + return await _certificationService.UpdateAsync(certificationUpdateInput); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/CityEncyclopediaController.cs b/src/Znyc.Recruitment.Api/Controllers/CityEncyclopediaController.cs new file mode 100644 index 0000000..c3abc6b --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/CityEncyclopediaController.cs @@ -0,0 +1,42 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Controllers +{ + public class CityEncyclopediaController : BaseController + { + private readonly ICityEncyclopediaService encyclopediaService; + + public CityEncyclopediaController(ICityEncyclopediaService encyclopediaService) + { + this.encyclopediaService = encyclopediaService; + + } + + /// + /// 查询行业岗位 + /// + /// + /// + [HttpGet] + [Route("api/v1/CityEncyclopedia")] + [AllowAnonymous] + public async Task>> GetListByIdAsync() + { + return await this.encyclopediaService.GetListByIdAsync(); + } + + + + + + + + + } +} diff --git a/src/Znyc.Recruitment.Api/Controllers/CollectionController.cs b/src/Znyc.Recruitment.Api/Controllers/CollectionController.cs new file mode 100644 index 0000000..3a4f477 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/CollectionController.cs @@ -0,0 +1,79 @@ +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Controllers +{ + /// + /// 用户收藏信息管理 + /// + public class CollectionController : BaseController + { + private readonly ICollectionService _collectionService; + + public CollectionController(ICollectionService collectionService) + { + _collectionService = collectionService; + } + + /// + /// 用户收藏求职信息 + /// + /// + /// + /// + [HttpGet] + + [Route("api/v1/apply/collections/search")] + public async Task>> ApplyJobPageAsync( + int currentPage = 1, int pageSize = 10) + { + return await _collectionService.ApplyJobPageAsync(currentPage, pageSize); + } + + /// + /// 用户收藏招聘信息 + /// + /// + /// + /// + [HttpGet] + [Route("api/v1/recruitment/collections/search")] + public async Task>> RecruitmentPageAsync( + int currentPage = 1, int pageSize = 10) + { + return await _collectionService.RecruitmentPageAsync(currentPage, pageSize); + } + + /// + /// + /// + /// + /// + /// + [HttpGet] + [Route("api/v1/collection/{productType}/{productId}")] + public async Task AddAsync(int productType, long productId) + { + return await _collectionService.AddAsync(productType, productId); + } + + + + + /// + /// 取消收藏 + /// + /// + /// + /// + [HttpPut] + [Route("api/v1/collection/cancel/{productType}/{productId}")] + public async Task CancelAsync(int productType, long productId) + { + return await _collectionService.CancelAsync(productType, productId); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/CurrencyController.cs b/src/Znyc.Recruitment.Api/Controllers/CurrencyController.cs new file mode 100644 index 0000000..87760d3 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/CurrencyController.cs @@ -0,0 +1,49 @@ +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Controllers +{ + /// + /// 用户云币管理 + /// + public class CurrencyController : BaseController + { + private readonly ICurrencyService _currencyService; + + public CurrencyController( + ICurrencyService currencyService + ) + { + _currencyService = currencyService; + } + + /// + /// 获取用户云币信息 + /// + /// + [HttpGet] + [Route("api/v1/currency")] + public async Task> GetAsync() + { + return await _currencyService.GetAsync(); + } + + /// + /// 云币账单 + /// + /// 0-全部/1-增加/2-减少 + /// + /// + /// + [HttpGet] + [Route("api/v1/currencys/search")] + public async Task>> PageAsync( + int currencyType, int currentPage = 1, int pageSize = 10) + { + return await _currencyService.PageAsync(currencyType, currentPage, pageSize); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/CurrencyIntroController.cs b/src/Znyc.Recruitment.Api/Controllers/CurrencyIntroController.cs new file mode 100644 index 0000000..0416605 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/CurrencyIntroController.cs @@ -0,0 +1,36 @@ +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Controllers +{ + /// + /// 用户云币管理 + /// + + public class CurrencyIntroController : BaseController + { + private readonly ICurrencyIntroService _currencyIntroService; + + public CurrencyIntroController( + ICurrencyIntroService currencyIntroService + ) + { + _currencyIntroService = currencyIntroService; + } + + /// + /// 获取云币来源列表 + /// + /// + [HttpGet] + [Route("api/v1/currencyintros")] + public async Task>> ListAsync() + { + return await _currencyIntroService.GetListAsync(); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/DeliveryResumeController.cs b/src/Znyc.Recruitment.Api/Controllers/DeliveryResumeController.cs new file mode 100644 index 0000000..674cc4a --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/DeliveryResumeController.cs @@ -0,0 +1,76 @@ +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Enums; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Controllers +{ + /// + /// 用户投递简历信息管理 + /// + public class DeliveryResumeController : BaseController + { + private readonly IDeliveryResumeService _deliveryResumeService; + + public DeliveryResumeController(IDeliveryResumeService deliveryResumeService) + { + _deliveryResumeService = deliveryResumeService; + } + + /// + /// 我的求职--我的投递/对我感兴趣 + /// + /// 1-我的投递/2-对我感兴趣 + /// + /// + /// + [HttpGet] + [Route("api/v1/apply/deliverys/search")] + public async Task>> ApplyJobPageAsync( + DeliveryType deliveryType, int currentPage = 1, int pageSize = 20) + { + return await _deliveryResumeService.ApplyJobPageAsync(deliveryType, currentPage, pageSize); + } + + /// + /// 我的招聘——我感兴趣的/收到的求职 + /// + /// 1-收到的求职/2-我感兴趣的 + /// + /// + /// + [HttpGet] + [Route("api/v1/recruitment/deliverys/search")] + public async Task>> RecruitmentPageAsync( + DeliveryType deliveryType, int currentPage = 1, int pageSize = 20) + { + return await _deliveryResumeService.RecruitmentPageAsync(deliveryType, currentPage, pageSize); + } + + /// + /// 新增用户投递简历信息 + /// + /// + /// + [HttpPost] + [Route("api/v1/delivery")] + public async Task AddAsync(DeliveryResumeAddInput input) + { + return await _deliveryResumeService.AddAsync(input); + } + + /// + /// 已查看用户投递简历信息 + /// + /// 1--求职/2--招聘 + /// + [HttpPut] + [Route("api/v1/deliverys/{productType}")] + public async Task UpdateAsync(int productType) + { + return await _deliveryResumeService.UpdateAsync(productType); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/DictionaryController.cs b/src/Znyc.Recruitment.Api/Controllers/DictionaryController.cs new file mode 100644 index 0000000..4fea068 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/DictionaryController.cs @@ -0,0 +1,61 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Controllers +{ + /// + /// 数据字典 + /// + public class DictionaryController : BaseController + { + private readonly IDictionaryService _dictionaryServices; + public DictionaryController(IDictionaryService dictionaryServices) + { + _dictionaryServices = dictionaryServices; + } + + /// + /// 根据Id获取字典 + /// + /// + /// + [HttpGet] + [AllowAnonymous] + [Route("api/v1/dict/{id}")] + public async Task> GetByIdAsync([Required] int id) + { + return await _dictionaryServices.GetByIdAsync(id); + } + + ///// + ///// 根据pid查询字典列表 + ///// + ///// + ///// + //[HttpGet] + //[AllowAnonymous] + //[Route("api/v1/dict/{pid}")] + //public async Task>> GetListByParentIdAsync([Required] long pid) + //{ + // return await _dictionaryServices.GetListByParentIdAsync(pid); + //} + + /// + /// + /// + /// + /// + [HttpGet] + [AllowAnonymous] + [Route("api/v1/dict/code/{code}")] + public async Task>> GetListByCodeAsync(string code) + { + return await _dictionaryServices.GetListByCodeAsync(code); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/DocumentController.cs b/src/Znyc.Recruitment.Api/Controllers/DocumentController.cs new file mode 100644 index 0000000..5ba7eab --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/DocumentController.cs @@ -0,0 +1,36 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; +using Znyc.Recruitment.Service.Document.Output; + +namespace Znyc.Recruitment.Api.Controllers +{ + /// + /// 文档管理 + /// + + public class DocumentController : BaseController + { + private readonly IDocumentService _documentService; + + public DocumentController( + IDocumentService documentService + ) + { + _documentService = documentService; + } + + /// + /// 上传文档图片 + /// + /// + [HttpGet] + [AllowAnonymous] + [Route("api/document")] + public ImageOutput UploadImageAsync() + { + return _documentService.UploadImageAsync(); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/FeedbackController.cs b/src/Znyc.Recruitment.Api/Controllers/FeedbackController.cs new file mode 100644 index 0000000..315442b --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/FeedbackController.cs @@ -0,0 +1,34 @@ +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Controllers +{ + /// + /// 意见反馈 + /// + [ApiExplorerSettings(IgnoreApi = false)] + public class FeedbackController : BaseController + { + private readonly IFeedbackService _feedbackService; + + public FeedbackController(IFeedbackService feedbackService) + { + _feedbackService = feedbackService; + } + + /// + /// 新增意见反馈 + /// + /// + /// + [HttpPost] + [Route("api/v1/feedback")] + public async Task AddFeedbackAsync(FeedbackAddInput input) + { + return await _feedbackService.AddFeedbackAsync(input); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/IndustryJobsController.cs b/src/Znyc.Recruitment.Api/Controllers/IndustryJobsController.cs new file mode 100644 index 0000000..c2ebbfb --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/IndustryJobsController.cs @@ -0,0 +1,37 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Controllers +{ + /// + /// 行业岗位管理 + /// + + public class IndustryJobsController : BaseController + { + private readonly IIndustryJobsService _industryJobsService; + + public IndustryJobsController(IIndustryJobsService industryJobsService) + { + _industryJobsService = industryJobsService; + } + + /// + /// 查询行业岗位 + /// + /// + /// + [HttpGet] + [Route("api/v1/industryjob/{id}")] + [AllowAnonymous] + public async Task>> GetListByIdAsync(long id = 0) + { + return await _industryJobsService.GetListByIdAsync(id); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/LoginController.cs b/src/Znyc.Recruitment.Api/Controllers/LoginController.cs new file mode 100644 index 0000000..7f76276 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/LoginController.cs @@ -0,0 +1,41 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; +using Znyc.Recruitment.Service.Login.OutPut; + +namespace Znyc.Recruitment.Api.Controllers +{ + /// + /// 登录管理 + /// + + public class LoginController : BaseController + { + private readonly ILoginService _loginService; + + public LoginController( + ILoginService loginService + ) + { + _loginService = loginService; + } + + /// + /// Wx登录授权 + /// + /// + /// + [HttpPost] + [AllowAnonymous] + [Route("api/v1/login")] + public async Task> Login(LoginInput loginInput) + { + + return await _loginService.Login(loginInput); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/MessageController.cs b/src/Znyc.Recruitment.Api/Controllers/MessageController.cs new file mode 100644 index 0000000..4f1412c --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/MessageController.cs @@ -0,0 +1,80 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Controllers +{ + /// + /// 信息通知管理 + /// + public class MessageController : BaseController + { + private readonly IMessageLogsService _messageLogsService; + private readonly IMessageService _messageService; + + public MessageController( + IMessageService messageService, + IMessageLogsService messageLogsService + ) + { + _messageService = messageService; + _messageLogsService = messageLogsService; + } + + /// + /// 查询消息通知列表 + /// + /// + /// + /// + /// + [HttpGet] + [Route("api/v1/notifications/search")] + public async Task>> MessageLogsPageAsync(int productType, + int currentPage, int pageSize) + { + return await _messageLogsService.MessageLogsPageAsync(productType, currentPage, pageSize); + } + + /// + /// 已读消息记录 + /// + /// 1--求职/2--招聘/3--实名 + /// + [HttpPut] + [Route("api/v1/notification/{productType}")] + public async Task UpdateAsync(int productType) + { + return await _messageLogsService.UpdateAsync(productType); + } + + /// + /// 获取新用户滚动播放列表 + /// + /// + [HttpGet] + [AllowAnonymous] + [Route("api/v1/register/newusers")] + public async Task> GetRegistUserListAsync() + { + return await _messageLogsService.GetRegistUserListAsync(); + } + + + /// + /// 邀请新用户信息滚动播放列表 + /// + /// + [HttpGet] + [AllowAnonymous] + [Route("api/v1/invitation/newusers")] + public async Task>> GetInviteNewUserAsync() + { + return await _messageLogsService.GetInviteNewUserAsync(); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/ProductCategoryController.cs b/src/Znyc.Recruitment.Api/Controllers/ProductCategoryController.cs new file mode 100644 index 0000000..1dc8bad --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/ProductCategoryController.cs @@ -0,0 +1,39 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Controllers +{ + /// + /// 商品品牌表 + /// + + [ApiExplorerSettings(IgnoreApi = true)] + [Obsolete] + public class ProductCategoryController : BaseController + { + private readonly IProductCategoryService _productCategoryService; + + public ProductCategoryController(IProductCategoryService productCategoryService) + { + _productCategoryService = productCategoryService; + } + + /// + /// 产品图片 + /// + /// + [HttpGet] + [AllowAnonymous] + [Route("api/v1/product/categorys")] + public async Task>> ListAsync() + { + return await _productCategoryService.ListAsync(); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/ProductInfoController.cs b/src/Znyc.Recruitment.Api/Controllers/ProductInfoController.cs new file mode 100644 index 0000000..9069e44 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/ProductInfoController.cs @@ -0,0 +1,40 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Controllers +{ + /// + /// 商品服务 + /// + + public class ProductInfoController : BaseController + { + private readonly IProductInfoService _productInfoService; + + public ProductInfoController(IProductInfoService productInfoService) + { + _productInfoService = productInfoService; + } + + /// + /// 分页获取商品信息 + /// + /// + /// 品牌 + /// 分类 + /// + /// + /// + [HttpGet] + [AllowAnonymous] + [Route("api/v1/products/search")] + public async Task>> PageAsync(long brandId, long categoryId, string key, int currentPage = 1, int pageSize = 10) + { + return await _productInfoService.PageAsync(brandId, categoryId, key, currentPage, pageSize); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/ProductPicController.cs b/src/Znyc.Recruitment.Api/Controllers/ProductPicController.cs new file mode 100644 index 0000000..3fecf8f --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/ProductPicController.cs @@ -0,0 +1,37 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Controllers +{ + /// + /// 产品图片 + /// + [Route("api/product/pic")] + [ApiExplorerSettings(IgnoreApi = true)] + public class ProductPicController : BaseController + { + private readonly IProductPicService _productPicService; + + public ProductPicController(IProductPicService productPicService) + { + _productPicService = productPicService; + } + /// + /// 产品图片 + /// + /// + [HttpGet] + + [AllowAnonymous] + [Route("api/product/pictures")] + public async Task>> ListAsync() + { + return await _productPicService.ListAsync(); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/ProudctWarehouseController.cs b/src/Znyc.Recruitment.Api/Controllers/ProudctWarehouseController.cs new file mode 100644 index 0000000..66ef351 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/ProudctWarehouseController.cs @@ -0,0 +1,37 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Controllers +{ + /// + /// Banner + /// + [ApiExplorerSettings(IgnoreApi = true)] + public class ProudctWarehouseController : BaseController + { + private readonly IProudctWarehouseService _proudctWarehouseService; + + public ProudctWarehouseController(IProudctWarehouseService proudctWarehouseService) + { + _proudctWarehouseService = proudctWarehouseService; + } + + /// + /// 产品图片 + /// + /// + [HttpGet] + [AllowAnonymous] + [Route("api/v1/proudct/warehouse")] + + public async Task>> ListAsync() + { + return await _proudctWarehouseService.ListAsync(); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/QuartzController.cs b/src/Znyc.Recruitment.Api/Controllers/QuartzController.cs new file mode 100644 index 0000000..9a903fa --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/QuartzController.cs @@ -0,0 +1,100 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Znyc.Recruitment.Attributes; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Controllers +{ + /// + /// 定时调度 + /// + [Quartz] + [AllowAnonymous] + public class QuartzController : BaseController + { + private readonly IApplyJobService _applyJobService; + private readonly ICacheService _cacheService; + private readonly ICurrencyService _currencyService; + private readonly IRecruitmentService _recruitmentService; + private readonly ISignService _signService; + + public QuartzController( + ISignService signService, + IApplyJobService applyJobService, + IRecruitmentService recruitmentService, + ICurrencyService currencyService, + ICacheService cacheService + ) + { + _signService = signService; + _applyJobService = applyJobService; + _recruitmentService = recruitmentService; + _currencyService = currencyService; + _cacheService = cacheService; + } + + /// + /// 置顶到期取消 + /// + /// + [HttpGet] + [Route("api/v1/sync/top")] + public async Task CancelTopAsync() + { + await _applyJobService.CancelTopAsync(); + await _recruitmentService.CancelTopAsync(); + return ResponseOutput.Success(); + } + + /// + /// 月重置签到次数 + /// + /// + [HttpGet] + [Route("api/v1/sync/sign")] + public async Task ResetSignAsync() + { + return await _signService.ResetSignAsync(); + } + + /// + /// 每日清空临时积分 + /// + /// + [HttpGet] + [Route("api/v1/sync/emptytemporarycurrency")] + public async Task ResetTemporaryCurrencyAsync() + { + return await _currencyService.ResetTemporaryCurrencyAsync(); + } + + /// + /// 每日清空云币来源缓存 + /// + /// + [HttpGet] + [Route("api/v1/sync/emptycurrencyintro")] + public async Task ResetCurrencyIntroAsync() + { + return await _cacheService.RemoveAllCurrencyIntroAsync(); + } + + /// + /// 同步浏览量 + /// + /// + [HttpGet] + [Route("api/v1/sync/pageview")] + public async Task PageViewAsync() + { + await _recruitmentService.PageViewAsync(); + await _applyJobService.PageViewAsync(); + return ResponseOutput.Success(); + } + + + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/RechargeController.cs b/src/Znyc.Recruitment.Api/Controllers/RechargeController.cs new file mode 100644 index 0000000..9ee74d7 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/RechargeController.cs @@ -0,0 +1,34 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Controllers +{ + /// + /// 充值活动服务 + /// + public class RechargeController : BaseController + { + private readonly IRechargeService _rechargeService; + + public RechargeController(IRechargeService rechargeService) + { + _rechargeService = rechargeService; + } + + /// + /// 获取充值活动 + /// + /// + [HttpGet] + [AllowAnonymous] + [Route("api/v1/recharge")] + public async Task> GetAsync() + { + return await _rechargeService.GetAsync(); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/RecruitmentController.cs b/src/Znyc.Recruitment.Api/Controllers/RecruitmentController.cs new file mode 100644 index 0000000..4853060 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/RecruitmentController.cs @@ -0,0 +1,201 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.ComponentModel.DataAnnotations; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Enums; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Controllers +{ + /// + /// 招聘信息管理 + /// + public class RecruitmentController : BaseController + { + private readonly IRecruitmentService _recruitmentService; + + + public RecruitmentController(IRecruitmentService recruitmentService) + { + _recruitmentService = recruitmentService; + } + + /// + /// 单条查询 + /// + /// + /// + [HttpGet] + [AllowAnonymous] + [Route("api/v1/recruitment/{id}")] + + public async Task> GetByIdAsync([Required] long id) + { + return await _recruitmentService.GetByIdAsync(id); + } + + /// + /// 我的招聘信息 + /// + /// 招聘状态 + /// 当前页码 + /// 页数 + /// + [HttpGet] + [Route("api/v1/my/recruitments/search")] + public async Task>> MyRecruitmentPageAsync( + ProductStatusEnum productStatus, + int currentPage = 1, int pageSize = 10) + { + return await _recruitmentService.MyRecruitmentPageAsync(productStatus, currentPage, pageSize); + } + + /// + /// 分页查询招聘信息 + /// + /// 标题 + /// 省 + /// 市 + /// 行业Id + /// 岗位Id + /// 排序 + /// 当前页码 + /// 页数 + /// + [HttpGet] + [Route("api/v1/recruitments/search")] + [AllowAnonymous] + public async Task>> PageAsync(string key, long provinceId, + long cityId, + long industryId, + long areaid, + long jobId, string sort, + int currentPage = 1, int pageSize = 20) + { + return await _recruitmentService.PageAsync(key, provinceId, cityId, areaid, industryId, jobId, sort, + currentPage, pageSize); + } + + + /// + /// 获取上一次发布信息的手机号码和发布人 + /// + /// + /// + [HttpGet] + [Route("api/v1/recruitment/GetPhoneAndReleaseAsync/{id}")] + [AllowAnonymous] + public async Task GetPhoneAndReleaseAsync([Required] long id) + { + return await _recruitmentService.GetOldAsync(id); + } + + + /// + /// 获取手机号码 + /// + /// + /// + [HttpGet] + [Route("api/v1/recruitment/phone/{id}")] + public async Task GetPhoneAsync([Required] long id) + { + return await _recruitmentService.GetPhoneAsync(id); + } + + /// + /// 新增招聘信息 + /// + /// + /// + [HttpPost] + [Route("api/v1/recruitment")] + public async Task AddAsync(RecruitmentAddInput input) + { + + var matc = this._recruitmentService.Matching(input); + + return await _recruitmentService.AddAsync(matc); + } + + ///// + ///// 查询行业岗位 + ///// + ///// + ///// + //[HttpPost] + //[Route("api/v1/Matching")] + //public async Task Matching(RecruitmentAddInput MatchingInput) + //{ + // return await this._recruitmentService.Matching(MatchingInput); + //} + + + + + /// + /// 编辑招聘信息 + /// + /// + /// + [HttpPut] + [Route("api/v1/recruitment")] + public async Task UpdateAsync(RecruitmentUpdateInput input) + { + return await _recruitmentService.UpdateAsync(input); + } + + /// + /// 刷新招聘信息 + /// + /// + /// + [HttpPut] + [Route("api/v1/recruitment/refresh/{id}")] + [Route("refresh")] + public async Task RefreshAsync([Required] long id) + { + return await _recruitmentService.RefreshAsync(id); + } + + /// + /// 置顶招聘信息 + /// + /// + /// + [HttpPut] + [Route("api/v1/recruitment/top/{id}")] + public async Task TopAsync([Required] long id) + { + return await _recruitmentService.TopAsync(id); + } + + /// + /// 更改招聘信息状态 + /// + /// + /// 招聘状态 + /// + [HttpPut] + [Route("api/v1/recruitment/{status}/{id}")] + public async Task UpdateStateAsync([Required] long id, [Required] int status) + { + return await _recruitmentService.UpdateStateAsync(id, status); + } + + /// + /// 是否公开招聘信息 + /// + /// + /// + /// + [HttpPut] + [Route("api/v1/recruitment/public/{id}")] + public async Task IsPublicAsync([Required] long id, [Required] bool isPublic) + { + return await _recruitmentService.IsPublicAsync(id, isPublic); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/ShareController.cs b/src/Znyc.Recruitment.Api/Controllers/ShareController.cs new file mode 100644 index 0000000..070170a --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/ShareController.cs @@ -0,0 +1,36 @@ +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Controllers +{ + /// + /// 分享管理 + /// + public class ShareController : BaseController + { + private readonly ICurrencyService _currencyService; + + public ShareController( + ICurrencyService currencyService + ) + { + _currencyService = currencyService; + } + + /// + /// 分享 + /// + /// + /// newusers(邀请新用户)/dailyshare(每日分享)/personalposter(生成海报) + /// + [HttpGet] + [Route("api/v1/share/{shareType}/{userId}")] + public async Task ShareAsync(string shareType, long userId) + { + return await _currencyService.ShareAsync(shareType, userId); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/SignController.cs b/src/Znyc.Recruitment.Api/Controllers/SignController.cs new file mode 100644 index 0000000..c6df674 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/SignController.cs @@ -0,0 +1,46 @@ +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Controllers +{ + /// + /// 用户签到管理 + /// + public class SignController : BaseController + { + private readonly ISignService _signService; + + public SignController( + ISignService signService + ) + { + _signService = signService; + } + + /// + /// 月签到记录 + /// + /// + /// + [HttpGet] + [Route("api/v1/sign/{date}")] + public async Task> GetAsync(string date) + { + return await _signService.GetAsync(date); + } + + /// + /// 今日签到 + /// + /// + [HttpGet] + [Route("api/v1/sign/info")] + public async Task SignAsync() + { + return await _signService.SignAsync(); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/UserController.cs b/src/Znyc.Recruitment.Api/Controllers/UserController.cs new file mode 100644 index 0000000..8b1271e --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/UserController.cs @@ -0,0 +1,72 @@ +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Controllers +{ + /// + /// 用户管理 + /// + public class UserController : BaseController + { + private readonly IUserService _userService; + + public UserController( + IUserService userService + ) + { + _userService = userService; + } + + ///// + ///// 用户信息 + ///// + ///// + //[HttpGet] + //[Route("")] + //public async Task> GetUserAsync() + //{ + // return await _userService.GetUserAsync(); + //} + + /// + /// 修改用户信息 + /// + /// + /// + [HttpPut] + [Route("api/v1/user")] + public async Task> UpdateAsync(UserUpdateInput userUpdateInput) + { + return await _userService.UpdateAsync(userUpdateInput); + } + + /// + /// 未读提示 + /// + /// + [HttpGet] + [Route("api/v1/user/unreadinformation")] + public async Task>> UnreadMessage() + { + return await _userService.UnreadMessage(); + } + + /// + /// 我的邀请记录 + /// + /// + /// + /// + [HttpGet] + [Route("api/v1/user/invitationrecords/search")] + public async Task>> InvitePageAsync( + int currentPage = 1, int pageSize = 20) + { + return await _userService.InvitePageAsync(currentPage, pageSize); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Controllers/WxPayController.cs b/src/Znyc.Recruitment.Api/Controllers/WxPayController.cs new file mode 100644 index 0000000..827b901 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Controllers/WxPayController.cs @@ -0,0 +1,48 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Controllers; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Controllers +{ + /// + /// 支付服务 + /// + public class WxPayController : BaseController + { + private readonly IAuthService _authService; + + public WxPayController(IAuthService authService) + { + _authService = authService; + } + + /// + /// 微信小程序支付 + /// + /// 商品Id + /// + [HttpGet] + [AllowAnonymous] + [Route("api/v1/wxpay/{productId}")] + public Task WxPay(long productId) + { + return _authService.WxPay(productId); + } + + /// + /// 微信小程序支付回调 + /// + /// + [HttpPost] + [AllowAnonymous] + [Route("api/v1/wxpay/notify")] + + public Task NotifyUrl() + { + return _authService.NotifyUrl(); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Db/Data.cs b/src/Znyc.Recruitment.Api/Db/Data.cs new file mode 100644 index 0000000..cb3fc6b --- /dev/null +++ b/src/Znyc.Recruitment.Api/Db/Data.cs @@ -0,0 +1,18 @@ +using Znyc.Recruitment.Model; + +namespace Znyc.Recruitment.Db +{ + /// + /// 数据 + /// + public class Data + { + public DictionaryEntity[] Dictionaries { get; set; } + + public PermissionEntity[] Permissions { get; set; } + public UserEntity[] Users { get; set; } + public RoleEntity[] Roles { get; set; } + public UserRoleEntity[] UserRoles { get; set; } + public RolePermissionEntity[] RolePermissions { get; set; } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Db/Data/data.json b/src/Znyc.Recruitment.Api/Db/Data/data.json new file mode 100644 index 0000000..c46da3a --- /dev/null +++ b/src/Znyc.Recruitment.Api/Db/Data/data.json @@ -0,0 +1,2777 @@ +{ + "dictionaries": [ + ], + "apis": [ + { + "id": 1, + "label": "接口管理", + "path": "api", + "description": "" + }, + { + "id": 2, + "label": "授权管理", + "path": "auth", + "description": "" + }, + { + "id": 3, + "label": "数据字典", + "path": "dictionary", + "description": "" + }, + { + "id": 5, + "label": "权限管理", + "path": "permission", + "description": "" + }, + { + "id": 6, + "label": "角色管理", + "path": "role", + "description": "" + }, + { + "id": 7, + "label": "用户管理", + "path": "user", + "description": "" + }, + { + "id": 8, + "label": "视图管理", + "path": "view", + "description": "" + }, + { + "id": 10, + "parentId": 1, + "label": "查询单条接口", + "path": "/api/admin/api/get", + "httpMethods": "get", + "description": "" + }, + { + "id": 11, + "parentId": 1, + "label": "查询全部接口", + "path": "/api/admin/api/getlist", + "httpMethods": "get", + "description": "" + }, + { + "id": 12, + "parentId": 1, + "label": "查询分页接口", + "path": "/api/admin/api/getpage", + "httpMethods": "post", + "description": "" + }, + { + "id": 13, + "parentId": 1, + "label": "新增接口", + "path": "/api/admin/api/add", + "httpMethods": "post", + "description": "" + }, + { + "id": 14, + "parentId": 1, + "label": "修改接口", + "path": "/api/admin/api/update", + "httpMethods": "put", + "description": "" + }, + { + "id": 15, + "parentId": 1, + "label": "删除接口", + "path": "/api/admin/api/softdelete", + "httpMethods": "delete", + "description": "" + }, + { + "id": 16, + "parentId": 1, + "label": "批量删除接口", + "path": "/api/admin/api/batchsoftdelete", + "httpMethods": "put", + "description": "" + }, + { + "id": 17, + "parentId": 1, + "label": "同步接口", + "path": "/api/admin/api/sync", + "httpMethods": "post", + "description": "支持新增和修改接口\r\n根据接口是否存在自动禁用和启用api" + }, + { + "id": 18, + "parentId": 2, + "label": "获取验证码", + "path": "/api/admin/auth/getverifycode", + "httpMethods": "get", + "description": "" + }, + { + "id": 19, + "parentId": 2, + "label": "获取密钥", + "path": "/api/admin/auth/getpasswordencryptkey", + "httpMethods": "get", + "description": "" + }, + { + "id": 20, + "parentId": 2, + "label": "查询用户信息", + "path": "/api/admin/auth/getuserinfo", + "httpMethods": "get", + "description": "" + }, + { + "id": 21, + "parentId": 2, + "label": "用户登录", + "path": "/api/admin/auth/login", + "httpMethods": "post", + "description": "根据登录信息生成Token" + }, + { + "id": 22, + "parentId": 3, + "label": "查询单条数据字典", + "path": "/api/admin/dictionary/get", + "httpMethods": "get", + "description": "" + }, + { + "id": 23, + "parentId": 3, + "label": "查询分页数据字典", + "path": "/api/admin/dictionary/getpage", + "httpMethods": "post", + "description": "" + }, + { + "id": 24, + "parentId": 3, + "label": "新增数据字典", + "path": "/api/admin/dictionary/add", + "httpMethods": "post", + "description": "" + }, + { + "id": 25, + "parentId": 3, + "label": "修改数据字典", + "path": "/api/admin/dictionary/update", + "httpMethods": "put", + "description": "" + }, + { + "id": 26, + "parentId": 3, + "label": "删除数据字典", + "path": "/api/admin/dictionary/softdelete", + "httpMethods": "delete", + "description": "" + }, + { + "id": 31, + "parentId": 5, + "label": "查询权限列表", + "path": "/api/admin/permission/getlist", + "httpMethods": "get", + "description": "" + }, + { + "id": 32, + "parentId": 5, + "label": "查询单条分组", + "path": "/api/admin/permission/getgroup", + "httpMethods": "get", + "description": "" + }, + { + "id": 33, + "parentId": 5, + "label": "查询单条菜单", + "path": "/api/admin/permission/getmenu", + "httpMethods": "get", + "description": "" + }, + { + "id": 34, + "parentId": 5, + "label": "查询单条接口", + "path": "/api/admin/permission/getapi", + "httpMethods": "get", + "description": "" + }, + { + "id": 35, + "parentId": 5, + "label": "查询角色权限-权限列表", + "path": "/api/admin/permission/getpermissionlist", + "httpMethods": "get", + "description": "" + }, + { + "id": 36, + "parentId": 5, + "label": "查询角色权限", + "path": "/api/admin/permission/getrolepermissionlist", + "httpMethods": "get", + "description": "" + }, + { + "id": 37, + "parentId": 5, + "label": "新增分组", + "path": "/api/admin/permission/addgroup", + "httpMethods": "post", + "description": "" + }, + { + "id": 38, + "parentId": 5, + "label": "新增菜单", + "path": "/api/admin/permission/addmenu", + "httpMethods": "post", + "description": "" + }, + { + "id": 39, + "parentId": 5, + "label": "新增接口", + "path": "/api/admin/permission/addapi", + "httpMethods": "post", + "description": "" + }, + { + "id": 40, + "parentId": 5, + "label": "修改分组", + "path": "/api/admin/permission/updategroup", + "httpMethods": "put", + "description": "" + }, + { + "id": 41, + "parentId": 5, + "label": "修改菜单", + "path": "/api/admin/permission/updatemenu", + "httpMethods": "put", + "description": "" + }, + { + "id": 42, + "parentId": 5, + "label": "修改接口", + "path": "/api/admin/permission/updateapi", + "httpMethods": "put", + "description": "" + }, + { + "id": 43, + "parentId": 5, + "label": "删除权限", + "path": "/api/admin/permission/softdelete", + "httpMethods": "delete", + "description": "" + }, + { + "id": 44, + "parentId": 5, + "label": "保存角色权限", + "path": "/api/admin/permission/assign", + "httpMethods": "post", + "description": "" + }, + { + "id": 45, + "parentId": 6, + "label": "查询单条角色", + "path": "/api/admin/role/get", + "httpMethods": "get", + "description": "" + }, + { + "id": 46, + "parentId": 6, + "label": "查询分页角色", + "path": "/api/admin/role/getpage", + "httpMethods": "post", + "description": "" + }, + { + "id": 47, + "parentId": 6, + "label": "新增角色", + "path": "/api/admin/role/add", + "httpMethods": "post", + "description": "" + }, + { + "id": 48, + "parentId": 6, + "label": "修改角色", + "path": "/api/admin/role/update", + "httpMethods": "put", + "description": "" + }, + { + "id": 49, + "parentId": 6, + "label": "删除角色", + "path": "/api/admin/role/softdelete", + "httpMethods": "delete", + "description": "" + }, + { + "id": 50, + "parentId": 6, + "label": "批量删除角色", + "path": "/api/admin/role/batchsoftdelete", + "httpMethods": "put", + "description": "" + }, + { + "id": 51, + "parentId": 7, + "label": "查询用户基本信息", + "path": "/api/admin/user/getbasic", + "httpMethods": "get", + "description": "" + }, + { + "id": 52, + "parentId": 7, + "label": "查询单条用户", + "path": "/api/admin/user/get", + "httpMethods": "get", + "description": "" + }, + { + "id": 53, + "parentId": 7, + "label": "查询分页用户", + "path": "/api/admin/user/getpage", + "httpMethods": "post", + "description": "" + }, + { + "id": 54, + "parentId": 7, + "label": "新增用户", + "path": "/api/admin/user/add", + "httpMethods": "post", + "description": "" + }, + { + "id": 55, + "parentId": 7, + "label": "修改用户", + "path": "/api/admin/user/update", + "httpMethods": "put", + "description": "" + }, + { + "id": 56, + "parentId": 7, + "label": "删除用户", + "path": "/api/admin/user/softdelete", + "httpMethods": "delete", + "description": "" + }, + { + "id": 57, + "parentId": 7, + "label": "批量删除用户", + "path": "/api/admin/user/batchsoftdelete", + "httpMethods": "put", + "description": "" + }, + { + "id": 58, + "parentId": 7, + "label": "更新用户密码", + "path": "/api/admin/user/changepassword", + "httpMethods": "put", + "description": "" + }, + { + "id": 59, + "parentId": 7, + "label": "更新用户基本信息", + "path": "/api/admin/user/updatebasic", + "httpMethods": "put", + "description": "" + }, + { + "id": 60, + "parentId": 8, + "label": "查询单条视图", + "path": "/api/admin/view/get", + "httpMethods": "get", + "description": "" + }, + { + "id": 61, + "parentId": 8, + "label": "查询全部视图", + "path": "/api/admin/view/getlist", + "httpMethods": "get", + "description": "" + }, + { + "id": 62, + "parentId": 8, + "label": "查询分页视图", + "path": "/api/admin/view/getpage", + "httpMethods": "post", + "description": "" + }, + { + "id": 63, + "parentId": 8, + "label": "新增视图", + "path": "/api/admin/view/add", + "httpMethods": "post", + "description": "" + }, + { + "id": 64, + "parentId": 8, + "label": "修改视图", + "path": "/api/admin/view/update", + "httpMethods": "put", + "description": "" + }, + { + "id": 65, + "parentId": 8, + "label": "删除视图", + "path": "/api/admin/view/softdelete", + "httpMethods": "delete", + "description": "" + }, + { + "id": 66, + "parentId": 8, + "label": "批量删除视图", + "path": "/api/admin/view/batchsoftdelete", + "httpMethods": "put", + "description": "" + }, + { + "id": 67, + "parentId": 8, + "label": "同步视图", + "path": "/api/admin/view/sync", + "httpMethods": "post", + "description": "支持新增和修改视图\r\n根据视图是否存在自动禁用和启用视图" + }, + { + "id": 70, + "label": "缓存管理", + "path": "cache", + "description": "" + }, + { + "id": 71, + "parentId": 70, + "label": "获取缓存列表", + "path": "/api/admin/cache/list", + "httpMethods": "get", + "description": "" + }, + { + "id": 72, + "parentId": 70, + "label": "清除缓存", + "path": "/api/admin/cache/clear", + "httpMethods": "delete", + "description": "" + }, + { + "id": 73, + "label": "登录日志管理", + "path": "loginlog", + "description": "" + }, + { + "id": 74, + "label": "操作日志管理", + "path": "oprationlog", + "description": "" + }, + { + "id": 75, + "parentId": 73, + "label": "查询分页登录日志", + "path": "/api/admin/loginlog/getpage", + "httpMethods": "post", + "description": "" + }, + { + "id": 76, + "parentId": 74, + "label": "查询分页操作日志", + "path": "/api/admin/oprationlog/getpage", + "httpMethods": "post", + "description": "" + }, + { + "id": 78, + "label": "文档管理", + "path": "document", + "description": "" + }, + { + "id": 79, + "parentId": 78, + "label": "查询文档列表", + "path": "/api/admin/document/getlist", + "httpMethods": "get", + "description": "" + }, + { + "id": 80, + "parentId": 78, + "label": "查询单条分组", + "path": "/api/admin/document/getgroup", + "httpMethods": "get", + "description": "" + }, + { + "id": 81, + "parentId": 78, + "label": "查询单条菜单", + "path": "/api/admin/document/getmenu", + "httpMethods": "get", + "description": "" + }, + { + "id": 82, + "parentId": 78, + "label": "查询精简文档列表", + "path": "/api/admin/document/getplainlist", + "httpMethods": "get", + "description": "" + }, + { + "id": 83, + "parentId": 78, + "label": "新增分组", + "path": "/api/admin/document/addgroup", + "httpMethods": "post", + "description": "" + }, + { + "id": 84, + "parentId": 78, + "label": "新增菜单", + "path": "/api/admin/document/addmenu", + "httpMethods": "post", + "description": "" + }, + { + "id": 85, + "parentId": 78, + "label": "修改分组", + "path": "/api/admin/document/updategroup", + "httpMethods": "put", + "description": "" + }, + { + "id": 86, + "parentId": 78, + "label": "修改菜单", + "path": "/api/admin/document/updatemenu", + "httpMethods": "put", + "description": "" + }, + { + "id": 87, + "parentId": 78, + "label": "删除文档", + "path": "/api/admin/document/softdelete", + "httpMethods": "delete", + "description": "" + }, + { + "id": 88, + "parentId": 78, + "label": "查询单条文档内容", + "path": "/api/admin/document/getcontent", + "httpMethods": "get", + "description": "" + }, + { + "id": 89, + "parentId": 78, + "label": "修改文档内容", + "path": "/api/admin/document/updatecontent", + "httpMethods": "put", + "description": "" + }, + { + "id": 90, + "parentId": 78, + "label": "上传文档图片", + "path": "/api/admin/document/uploadimage", + "httpMethods": "post", + "description": "" + }, + { + "id": 91, + "parentId": 78, + "label": "查询文档图片列表", + "path": "/api/admin/document/getimagelist", + "httpMethods": "get", + "description": "" + }, + { + "id": 92, + "parentId": 78, + "label": "删除图片", + "path": "/api/admin/document/deleteimage", + "httpMethods": "delete", + "description": "" + }, + { + "id": 93, + "parentId": 7, + "label": "上传头像", + "path": "/api/admin/user/avatarupload", + "httpMethods": "post", + "description": "" + }, + { + "id": 94, + "parentId": 5, + "label": "查询单条权限点", + "path": "/api/admin/permission/getdot", + "httpMethods": "get", + "description": "" + }, + { + "id": 95, + "parentId": 5, + "label": "新增权限点", + "path": "/api/admin/permission/adddot", + "httpMethods": "post", + "description": "" + }, + { + "id": 96, + "parentId": 5, + "label": "修改权限点", + "path": "/api/admin/permission/updatedot", + "httpMethods": "put", + "description": "" + }, + { + "id": 97, + "parentId": 2, + "label": "刷新Token", + "path": "/api/admin/auth/refresh", + "httpMethods": "get", + "description": "以旧换新" + } + ], + "views": [ + { + "id": 1, + "parentId": 2, + "label": "首页", + "path": "/admin/home", + "sort": 1 + }, + { + "id": 2, + "label": "平台管理", + "path": "admin", + "sort": 1 + }, + { + "id": 3, + "parentId": 14, + "name": "user", + "label": "用户管理", + "path": "/admin/user", + "sort": 1 + }, + { + "id": 4, + "parentId": 14, + "name": "role", + "label": "角色管理", + "path": "/admin/role", + "sort": 2 + }, + { + "id": 5, + "parentId": 14, + "name": "api", + "label": "接口管理", + "path": "/admin/api", + "sort": 3 + }, + { + "id": 6, + "parentId": 14, + "name": "v", + "label": "视图管理", + "path": "/admin/view", + "sort": 4 + }, + { + "id": 7, + "parentId": 14, + "name": "permission", + "label": "权限管理", + "path": "/admin/permission", + "sort": 5 + }, + { + "id": 8, + "parentId": 14, + "name": "assign", + "label": "角色权限", + "path": "/admin/role-permission", + "sort": 6 + }, + { + "id": 9, + "parentId": 2, + "label": "系统配置", + "path": "config", + "sort": 3 + }, + { + "id": 10, + "parentId": 9, + "name": "dictonary", + "label": "数据字典", + "path": "/admin/dictionary", + "sort": 1 + }, + { + "id": 11, + "parentId": 15, + "name": "log", + "label": "操作日志", + "path": "/admin/opration-log", + "description": "", + "sort": 2 + }, + { + "id": 12, + "parentId": 2, + "label": "个人管理", + "path": "account", + "sort": 5 + }, + { + "id": 13, + "parentId": 12, + "name": "settings", + "label": "个人设置", + "path": "/account/settings", + "sort": 1 + }, + { + "id": 14, + "parentId": 2, + "label": "权限管理", + "path": "auth", + "description": "", + "sort": 2 + }, + { + "id": 15, + "parentId": 2, + "label": "日志管理", + "path": "logs", + "description": "", + "sort": 4 + }, + { + "id": 16, + "parentId": 14, + "label": "缓存管理", + "path": "/admin/cache", + "description": "", + "sort": 7 + }, + { + "id": 17, + "parentId": 15, + "label": "登录日志", + "path": "/admin/login-log", + "description": "", + "sort": 1 + }, + { + "id": 18, + "parentId": 2, + "label": "文档管理", + "path": "/admin/document", + "description": "" + } + ], + "permissions": [ + { + "id": 1, + "parentId": 65, + "label": "更新日志", + "type": 2, + "viewId": 1, + "path": "/", + "icon": "el-icon-notebook-2", + "closable": false, + "opened": false, + "newWindow": false, + "external": false, + "sort": 1, + "description": "" + }, + { + "id": 2, + "parentId": 65, + "label": "权限管理", + "type": 1, + "path": "", + "icon": "fa fa-sitemap", + "closable": false, + "opened": false, + "sort": 2, + "description": "" + }, + { + "id": 3, + "parentId": 65, + "label": "系统配置", + "type": 1, + "path": "", + "icon": "el-icon-s-platform", + "closable": false, + "opened": false, + "sort": 3, + "description": "" + }, + { + "id": 4, + "label": "个人管理", + "type": 1, + "path": "", + "icon": "el-icon-s-custom", + "closable": false, + "opened": false, + "sort": 2, + "description": "" + }, + { + "id": 5, + "parentId": 66, + "label": "Admin", + "type": 2, + "path": "https://zhontai.net", + "icon": "el-icon-s-promotion", + "closable": false, + "newWindow": false, + "external": false, + "sort": 5, + "description": "" + }, + { + "id": 6, + "parentId": 66, + "label": "FreeSql", + "type": 2, + "path": "https://github.com/dotnetcore/FreeSql/wiki", + "icon": "el-icon-s-promotion", + "closable": false, + "newWindow": false, + "external": false, + "sort": 6, + "description": "" + }, + { + "id": 7, + "parentId": 2, + "label": "用户管理", + "type": 2, + "viewId": 3, + "path": "/admin/user", + "closable": true, + "opened": false, + "newWindow": false, + "external": true, + "sort": 1, + "description": "" + }, + { + "id": 8, + "parentId": 2, + "label": "角色管理", + "type": 2, + "viewId": 4, + "path": "/admin/role", + "icon": "", + "closable": true, + "opened": false, + "sort": 2, + "description": "" + }, + { + "id": 9, + "parentId": 2, + "label": "接口管理", + "type": 2, + "viewId": 5, + "path": "/admin/api", + "closable": true, + "opened": false, + "sort": 3, + "description": "" + }, + { + "id": 10, + "parentId": 2, + "label": "视图管理", + "type": 2, + "viewId": 6, + "path": "/admin/view", + "icon": "", + "closable": true, + "sort": 4, + "description": "" + }, + { + "id": 11, + "parentId": 2, + "label": "权限管理", + "type": 2, + "viewId": 7, + "path": "/admin/permission", + "closable": true, + "opened": false, + "sort": 5, + "description": "" + }, + { + "id": 12, + "parentId": 2, + "label": "角色权限", + "type": 2, + "viewId": 8, + "path": "/admin/role-permisson", + "closable": true, + "opened": false, + "newWindow": false, + "external": false, + "sort": 6, + "description": "" + }, + { + "id": 13, + "parentId": 8, + "label": "查询", + "code": "api:admin:role:getpage", + "type": 3, + "apiId": 46, + "path": " ", + "closable": false, + "opened": false, + "sort": 1, + "description": "" + }, + { + "id": 14, + "parentId": 8, + "label": "新增", + "code": "api:admin:role:add", + "type": 3, + "apiId": 47, + "path": " ", + "closable": false, + "opened": false, + "sort": 2, + "description": "" + }, + { + "id": 15, + "parentId": 8, + "label": "修改", + "code": "api:admin:role:update", + "type": 3, + "apiId": 48, + "path": " ", + "closable": false, + "opened": false, + "sort": 3, + "description": "" + }, + { + "id": 16, + "parentId": 8, + "label": "删除", + "code": "api:admin:role:softdelete", + "type": 3, + "apiId": 49, + "path": " ", + "closable": true, + "opened": false, + "sort": 4, + "description": "" + }, + { + "id": 17, + "parentId": 8, + "label": "批量删除", + "code": "api:admin:role:batchsoftdelete", + "type": 3, + "apiId": 50, + "path": " ", + "icon": "", + "closable": false, + "opened": false, + "sort": 5, + "description": "" + }, + { + "id": 18, + "parentId": 8, + "label": "查询单条角色", + "code": "api:admin:role:get", + "type": 3, + "apiId": 45, + "sort": 6, + "description": "" + }, + { + "id": 19, + "parentId": 7, + "label": "查询", + "code": "api:admin:user:getpage", + "type": 3, + "apiId": 53, + "path": "", + "closable": true, + "opened": false, + "sort": 1, + "description": "" + }, + { + "id": 20, + "parentId": 7, + "label": "新增", + "code": "api:admin:user:add", + "type": 3, + "apiId": 54, + "path": "", + "closable": false, + "opened": false, + "sort": 2, + "description": "" + }, + { + "id": 21, + "parentId": 7, + "label": "修改", + "code": "api:admin:user:update", + "type": 3, + "apiId": 55, + "path": "", + "closable": true, + "opened": false, + "sort": 3, + "description": "" + }, + { + "id": 22, + "parentId": 7, + "label": "删除", + "code": "api:admin:user:softdelete", + "type": 3, + "apiId": 56, + "path": "", + "closable": true, + "opened": false, + "sort": 4, + "description": "" + }, + { + "id": 23, + "parentId": 7, + "label": "批量删除", + "code": "api:admin:user:batchsoftdelete", + "type": 3, + "apiId": 57, + "path": "", + "icon": "", + "sort": 5, + "description": "" + }, + { + "id": 24, + "parentId": 7, + "label": "查询单条用户", + "code": "api:admin:user:get", + "type": 3, + "apiId": 52, + "sort": 6, + "description": "" + }, + { + "id": 25, + "parentId": 9, + "label": "查询", + "code": "api:admin:api:getlist", + "type": 3, + "apiId": 11, + "path": "", + "icon": "", + "sort": 1, + "description": "" + }, + { + "id": 26, + "parentId": 9, + "label": "新增", + "code": "api:admin:api:add", + "type": 3, + "apiId": 13, + "path": " ", + "closable": false, + "opened": false, + "sort": 2, + "description": "" + }, + { + "id": 27, + "parentId": 9, + "label": "修改", + "code": "api:admin:api:update", + "type": 3, + "apiId": 14, + "path": " ", + "closable": false, + "opened": false, + "sort": 3, + "description": "" + }, + { + "id": 28, + "parentId": 9, + "label": "删除", + "code": "api:admin:api:softdelete", + "type": 3, + "apiId": 15, + "path": " ", + "closable": false, + "opened": false, + "sort": 4, + "description": "" + }, + { + "id": 29, + "parentId": 9, + "label": "批量删除", + "code": "api:admin:api:batchsoftdelete", + "type": 3, + "apiId": 16, + "path": "", + "icon": "", + "sort": 5, + "description": "" + }, + { + "id": 30, + "parentId": 9, + "label": "同步", + "code": "api:admin:api:sync", + "type": 3, + "apiId": 17, + "path": "", + "icon": "", + "sort": 6, + "description": "" + }, + { + "id": 31, + "parentId": 9, + "label": "查询单条接口", + "code": "api:admin:api:get", + "type": 3, + "apiId": 10, + "sort": 7, + "description": "" + }, + { + "id": 32, + "parentId": 11, + "label": "查询", + "code": "api:admin:permission:getlist", + "type": 3, + "apiId": 31, + "path": "", + "icon": "", + "sort": 1, + "description": "" + }, + { + "id": 33, + "parentId": 11, + "label": "新增分组", + "code": "api:admin:permission:addgroup", + "type": 3, + "apiId": 37, + "sort": 2, + "description": "" + }, + { + "id": 34, + "parentId": 11, + "label": "新增菜单", + "code": "api:admin:permission:addmenu", + "type": 3, + "apiId": 38, + "sort": 3, + "description": "" + }, + { + "id": 35, + "parentId": 11, + "label": "新增接口", + "code": "api:admin:permission:addapi", + "type": 3, + "apiId": 39, + "sort": 4, + "description": "" + }, + { + "id": 36, + "parentId": 11, + "label": "修改分组", + "code": "api:admin:permission:updategroup", + "type": 3, + "apiId": 40, + "sort": 5, + "description": "" + }, + { + "id": 37, + "parentId": 11, + "label": "修改菜单", + "code": "api:admin:permission:updatemenu", + "type": 3, + "apiId": 41, + "sort": 6, + "description": "" + }, + { + "id": 38, + "parentId": 11, + "label": "修改接口", + "code": "api:admin:permission:updateapi", + "type": 3, + "apiId": 42, + "sort": 7, + "description": "" + }, + { + "id": 39, + "parentId": 11, + "label": "删除", + "code": "api:admin:permission:softdelete", + "type": 3, + "apiId": 43, + "path": " ", + "closable": false, + "opened": false, + "sort": 8, + "description": "" + }, + { + "id": 40, + "parentId": 11, + "label": "查询单条分组", + "code": "api:admin:permission:getgroup", + "type": 3, + "apiId": 32, + "sort": 9, + "description": "" + }, + { + "id": 41, + "parentId": 11, + "label": "查询单条菜单", + "code": "api:admin:permission:getmenu", + "type": 3, + "apiId": 33, + "sort": 10, + "description": "" + }, + { + "id": 42, + "parentId": 11, + "label": "查询单条接口", + "code": "api:admin:permission:getapi", + "type": 3, + "apiId": 34, + "sort": 11, + "description": "" + }, + { + "id": 43, + "parentId": 12, + "label": "查询角色", + "code": "api:admin:role:getpage", + "type": 3, + "apiId": 46, + "path": "", + "icon": "", + "sort": 1, + "description": "" + }, + { + "id": 44, + "parentId": 12, + "label": "查询权限", + "code": "api:admin:permission:getpermissionlist", + "type": 3, + "apiId": 35, + "path": "", + "icon": "", + "sort": 2, + "description": "" + }, + { + "id": 45, + "parentId": 12, + "label": "查询角色权限", + "code": "api:admin:permission:getrolepermissionlist", + "type": 3, + "apiId": 36, + "path": "", + "icon": "", + "sort": 3, + "description": "" + }, + { + "id": 46, + "parentId": 12, + "label": "保存角色权限", + "code": "api:admin:permission:assign", + "type": 3, + "apiId": 44, + "path": " ", + "closable": false, + "opened": false, + "sort": 4, + "description": "" + }, + { + "id": 47, + "parentId": 4, + "label": "个人设置", + "type": 2, + "viewId": 13, + "path": "/account/settings", + "icon": "el-icon-setting", + "closable": true, + "opened": false, + "newWindow": false, + "external": false, + "sort": 1, + "description": "" + }, + { + "id": 48, + "parentId": 47, + "label": "查询基本信息", + "code": "api:admin:user:getbasic", + "type": 3, + "apiId": 51, + "path": "", + "icon": "", + "closable": false, + "opened": false, + "sort": 1, + "description": "" + }, + { + "id": 49, + "parentId": 47, + "label": "更新基本信息", + "code": "api:admin:user:updatebasic", + "type": 3, + "apiId": 59, + "sort": 2, + "description": "" + }, + { + "id": 50, + "parentId": 47, + "label": "更新密码", + "code": "api:admin:user:changepassword", + "type": 3, + "apiId": 58, + "path": " ", + "icon": "", + "closable": false, + "opened": false, + "sort": 3, + "description": "" + }, + { + "id": 51, + "parentId": 3, + "label": "基础数据", + "type": 1, + "icon": "fa fa-database", + "opened": false, + "sort": 1 + }, + { + "id": 52, + "parentId": 64, + "label": "查询", + "code": "api:admin:dictionary:getpage", + "type": 3, + "apiId": 23, + "path": " ", + "icon": "", + "closable": false, + "opened": false, + "sort": 1, + "description": "" + }, + { + "id": 53, + "parentId": 64, + "label": "新增", + "code": "api:admin:dictionary:add", + "type": 3, + "apiId": 24, + "path": " ", + "icon": "", + "closable": false, + "opened": false, + "sort": 2, + "description": "" + }, + { + "id": 54, + "parentId": 64, + "label": "修改", + "code": "api:admin:dictionary:update", + "type": 3, + "apiId": 25, + "path": " ", + "icon": "", + "closable": false, + "opened": false, + "sort": 3, + "description": "" + }, + { + "id": 55, + "parentId": 64, + "label": "删除", + "code": "api:admin:dictionary:softdelete", + "type": 3, + "apiId": 26, + "path": " ", + "icon": "", + "closable": false, + "opened": false, + "sort": 4, + "description": "" + }, + { + "id": 56, + "parentId": 64, + "label": "查询单条数据字典", + "code": "api:admin:dictionary:get", + "type": 3, + "apiId": 22, + "sort": 5, + "description": "" + }, + { + "id": 57, + "parentId": 10, + "label": "查询", + "code": "api:admin:view:getlist", + "type": 3, + "apiId": 61, + "sort": 1, + "description": "" + }, + { + "id": 58, + "parentId": 10, + "label": "新增", + "code": "api:admin:view:add", + "type": 3, + "apiId": 63, + "sort": 2, + "description": "" + }, + { + "id": 59, + "parentId": 10, + "label": "修改", + "code": "api:admin:view:update", + "type": 3, + "apiId": 64, + "sort": 3, + "description": "" + }, + { + "id": 60, + "parentId": 10, + "label": "删除", + "code": "api:admin:view:softdelete", + "type": 3, + "apiId": 65, + "sort": 4, + "description": "" + }, + { + "id": 61, + "parentId": 10, + "label": "批量删除", + "code": "api:admin:view:batchsoftdelete", + "type": 3, + "apiId": 66, + "sort": 5, + "description": "" + }, + { + "id": 62, + "parentId": 10, + "label": "同步", + "code": "api:admin:view:sync", + "type": 3, + "apiId": 67, + "sort": 6, + "description": "" + }, + { + "id": 63, + "parentId": 10, + "label": "查询单条视图", + "code": "api:admin:view:get", + "type": 3, + "apiId": 60, + "sort": 7, + "description": "" + }, + { + "id": 64, + "parentId": 3, + "label": "树形字典", + "type": 2, + "viewId": 10, + "path": "/admin/dictionary", + "icon": "fa fa-database", + "closable": true, + "opened": false, + "newWindow": false, + "external": false, + "sort": 1, + "description": "" + }, + { + "id": 65, + "label": "平台管理", + "type": 1, + "icon": "el-icon-s-platform", + "opened": true, + "sort": 1 + }, + { + "id": 66, + "label": "帮助文档", + "type": 1, + "icon": "el-icon-question", + "opened": true, + "sort": 3 + }, + { + "id": 67, + "parentId": 2, + "label": "缓存管理", + "type": 2, + "viewId": 16, + "path": "/admin/cache", + "icon": "", + "closable": true, + "newWindow": false, + "external": false, + "sort": 7, + "description": "" + }, + { + "id": 68, + "parentId": 67, + "label": "获取缓存列表", + "code": "api:admin:cache:list", + "type": 3, + "apiId": 71, + "sort": 1, + "description": "" + }, + { + "id": 69, + "parentId": 67, + "label": "清除缓存", + "code": "api:admin:cache:clear", + "type": 3, + "apiId": 72, + "sort": 2, + "description": "" + }, + { + "id": 70, + "parentId": 65, + "label": "日志管理", + "type": 1, + "icon": "el-icon-notebook-2", + "opened": true, + "sort": 4 + }, + { + "id": 71, + "parentId": 70, + "label": "登录日志", + "type": 2, + "viewId": 17, + "path": "/admin/login-log", + "icon": "", + "closable": true, + "newWindow": false, + "external": false, + "sort": 1, + "description": "" + }, + { + "id": 72, + "parentId": 70, + "label": "操作日志", + "type": 2, + "viewId": 11, + "path": "/admin/opration-log", + "icon": "", + "closable": true, + "newWindow": false, + "external": false, + "sort": 2, + "description": "" + }, + { + "id": 73, + "parentId": 72, + "label": "查询分页操作日志", + "code": "api:admin:oprationlog:getpage", + "type": 3, + "apiId": 76, + "sort": 1, + "description": "" + }, + { + "id": 74, + "parentId": 71, + "label": "查询分页登录日志", + "code": "api:admin:loginlog:getpage", + "type": 3, + "apiId": 75, + "sort": 1, + "description": "" + }, + { + "id": 75, + "parentId": 66, + "label": "文档管理", + "type": 2, + "viewId": 18, + "path": "/admin/document", + "icon": "el-icon-notebook-2", + "closable": true, + "newWindow": false, + "external": true, + "sort": 0, + "description": "" + }, + { + "id": 76, + "parentId": 75, + "label": "查询精简文档列表", + "code": "api:admin:document:getplainlist", + "type": 3, + "apiId": 82, + "sort": 2, + "description": "" + }, + { + "id": 77, + "parentId": 75, + "label": "新增分组", + "code": "api:admin:document:addgroup", + "type": 3, + "apiId": 83, + "sort": 5, + "description": "" + }, + { + "id": 78, + "parentId": 75, + "label": "新增菜单", + "code": "api:admin:document:addmenu", + "type": 3, + "apiId": 84, + "sort": 6, + "description": "" + }, + { + "id": 79, + "parentId": 75, + "label": "修改分组", + "code": "api:admin:document:updategroup", + "type": 3, + "apiId": 85, + "sort": 7, + "description": "" + }, + { + "id": 80, + "parentId": 75, + "label": "修改菜单", + "code": "api:admin:document:updatemenu", + "type": 3, + "apiId": 86, + "sort": 8, + "description": "" + }, + { + "id": 81, + "parentId": 75, + "label": "删除文档", + "code": "api:admin:document:softdelete", + "type": 3, + "apiId": 87, + "sort": 9, + "description": "" + }, + { + "id": 82, + "parentId": 75, + "label": "查询单条分组", + "code": "api:admin:document:getgroup", + "type": 3, + "apiId": 80, + "sort": 3, + "description": "" + }, + { + "id": 83, + "parentId": 75, + "label": "查询单条菜单", + "code": "api:admin:document:getmenu", + "type": 3, + "apiId": 81, + "sort": 4, + "description": "" + }, + { + "id": 90, + "parentId": 75, + "label": "查询文档列表", + "code": "api:admin:document:getlist", + "type": 3, + "apiId": 79, + "sort": 1, + "description": "" + }, + { + "id": 91, + "parentId": 75, + "label": "查询单条文档内容", + "code": "api:admin:document:getcontent", + "type": 3, + "apiId": 88, + "sort": 10, + "description": "" + }, + { + "id": 92, + "parentId": 75, + "label": "修改文档内容", + "code": "api:admin:document:updatecontent", + "type": 3, + "apiId": 89, + "sort": 11, + "description": "" + }, + { + "id": 93, + "parentId": 75, + "label": "上传文档图片", + "code": "api:admin:document:uploadimage", + "type": 3, + "apiId": 90, + "sort": 0, + "description": "" + }, + { + "id": 94, + "parentId": 75, + "label": "查询文档图片列表", + "code": "api:admin:document:getimagelist", + "type": 3, + "apiId": 91, + "sort": 0, + "description": "" + }, + { + "id": 95, + "parentId": 75, + "label": "删除图片", + "code": "api:admin:document:deleteimage", + "type": 3, + "apiId": 92, + "sort": 0, + "description": "" + }, + { + "id": 96, + "parentId": 11, + "label": "查询单条权限点", + "code": "api:admin:permission:getdot", + "type": 3, + "apiId": 94, + "sort": 0, + "description": "" + }, + { + "id": 97, + "parentId": 11, + "label": "新增权限点", + "code": "api:admin:permission:adddot", + "type": 3, + "apiId": 95, + "sort": 0, + "description": "" + }, + { + "id": 98, + "parentId": 11, + "label": "修改权限点", + "code": "api:admin:permission:updatedot", + "type": 3, + "apiId": 96, + "sort": 0, + "description": "" + } + ], + "users": [ + { + "id": 1, + "userName": "user", + "password": "96E79218965EB72C92A549DD5A33112", + "nickName": "平台用户", + "avatar": "", + "remark": "" + }, + { + "id": 2, + "userName": "admin", + "password": "96E79218965EB72C92A549DD5A33112", + "nickName": "管理员", + "avatar": "", + "remark": "" + }, + { + "id": 3, + "userName": "jack", + "password": "96E79218965EB72C92A549DD5A33112", + "nickName": "杰克" + } + ], + "roles": [ + { + "id": 1, + "name": "平台用户", + "description": "演示" + }, + { + "id": 2, + "name": "系统管理员", + "description": "" + }, + { + "id": 3, + "name": "文档管理员", + "description": "" + } + ], + "userRoles": [ + { + "id": 10, + "userId": 1, + "roleId": 1 + }, + { + "id": 3, + "userId": 2, + "roleId": 2 + }, + { + "id": 9, + "userId": 3, + "roleId": 3 + } + ], + "rolePermissions": [ + { + "id": 104, + "roleId": 1, + "permissionId": 1 + }, + { + "id": 66, + "roleId": 1, + "permissionId": 2 + }, + { + "id": 67, + "roleId": 1, + "permissionId": 3 + }, + { + "id": 68, + "roleId": 1, + "permissionId": 4 + }, + { + "id": 69, + "roleId": 1, + "permissionId": 5 + }, + { + "id": 70, + "roleId": 1, + "permissionId": 6 + }, + { + "id": 71, + "roleId": 1, + "permissionId": 7 + }, + { + "id": 72, + "roleId": 1, + "permissionId": 8 + }, + { + "id": 73, + "roleId": 1, + "permissionId": 9 + }, + { + "id": 74, + "roleId": 1, + "permissionId": 10 + }, + { + "id": 75, + "roleId": 1, + "permissionId": 11 + }, + { + "id": 76, + "roleId": 1, + "permissionId": 12 + }, + { + "id": 77, + "roleId": 1, + "permissionId": 13 + }, + { + "id": 78, + "roleId": 1, + "permissionId": 18 + }, + { + "id": 79, + "roleId": 1, + "permissionId": 19 + }, + { + "id": 80, + "roleId": 1, + "permissionId": 24 + }, + { + "id": 81, + "roleId": 1, + "permissionId": 25 + }, + { + "id": 82, + "roleId": 1, + "permissionId": 31 + }, + { + "id": 83, + "roleId": 1, + "permissionId": 32 + }, + { + "id": 84, + "roleId": 1, + "permissionId": 40 + }, + { + "id": 85, + "roleId": 1, + "permissionId": 41 + }, + { + "id": 86, + "roleId": 1, + "permissionId": 42 + }, + { + "id": 87, + "roleId": 1, + "permissionId": 43 + }, + { + "id": 88, + "roleId": 1, + "permissionId": 44 + }, + { + "id": 89, + "roleId": 1, + "permissionId": 45 + }, + { + "id": 90, + "roleId": 1, + "permissionId": 47 + }, + { + "id": 91, + "roleId": 1, + "permissionId": 48 + }, + { + "id": 92, + "roleId": 1, + "permissionId": 51 + }, + { + "id": 93, + "roleId": 1, + "permissionId": 52 + }, + { + "id": 98, + "roleId": 1, + "permissionId": 53 + }, + { + "id": 99, + "roleId": 1, + "permissionId": 54 + }, + { + "id": 100, + "roleId": 1, + "permissionId": 55 + }, + { + "id": 94, + "roleId": 1, + "permissionId": 56 + }, + { + "id": 95, + "roleId": 1, + "permissionId": 57 + }, + { + "id": 96, + "roleId": 1, + "permissionId": 63 + }, + { + "id": 97, + "roleId": 1, + "permissionId": 64 + }, + { + "id": 103, + "roleId": 1, + "permissionId": 65 + }, + { + "id": 131, + "roleId": 1, + "permissionId": 66 + }, + { + "id": 136, + "roleId": 1, + "permissionId": 67 + }, + { + "id": 137, + "roleId": 1, + "permissionId": 68 + }, + { + "id": 143, + "roleId": 1, + "permissionId": 70 + }, + { + "id": 144, + "roleId": 1, + "permissionId": 71 + }, + { + "id": 145, + "roleId": 1, + "permissionId": 72 + }, + { + "id": 147, + "roleId": 1, + "permissionId": 73 + }, + { + "id": 146, + "roleId": 1, + "permissionId": 74 + }, + { + "id": 156, + "roleId": 1, + "permissionId": 75 + }, + { + "id": 157, + "roleId": 1, + "permissionId": 76 + }, + { + "id": 160, + "roleId": 1, + "permissionId": 82 + }, + { + "id": 161, + "roleId": 1, + "permissionId": 83 + }, + { + "id": 163, + "roleId": 1, + "permissionId": 90 + }, + { + "id": 166, + "roleId": 1, + "permissionId": 91 + }, + { + "id": 168, + "roleId": 1, + "permissionId": 94 + }, + { + "id": 192, + "roleId": 1, + "permissionId": 96 + }, + { + "id": 102, + "roleId": 2, + "permissionId": 1 + }, + { + "id": 2, + "roleId": 2, + "permissionId": 2 + }, + { + "id": 3, + "roleId": 2, + "permissionId": 3 + }, + { + "id": 4, + "roleId": 2, + "permissionId": 4 + }, + { + "id": 5, + "roleId": 2, + "permissionId": 5 + }, + { + "id": 6, + "roleId": 2, + "permissionId": 6 + }, + { + "id": 7, + "roleId": 2, + "permissionId": 7 + }, + { + "id": 8, + "roleId": 2, + "permissionId": 8 + }, + { + "id": 9, + "roleId": 2, + "permissionId": 9 + }, + { + "id": 10, + "roleId": 2, + "permissionId": 10 + }, + { + "id": 11, + "roleId": 2, + "permissionId": 11 + }, + { + "id": 12, + "roleId": 2, + "permissionId": 12 + }, + { + "id": 13, + "roleId": 2, + "permissionId": 13 + }, + { + "id": 14, + "roleId": 2, + "permissionId": 14 + }, + { + "id": 15, + "roleId": 2, + "permissionId": 15 + }, + { + "id": 16, + "roleId": 2, + "permissionId": 16 + }, + { + "id": 17, + "roleId": 2, + "permissionId": 17 + }, + { + "id": 18, + "roleId": 2, + "permissionId": 18 + }, + { + "id": 19, + "roleId": 2, + "permissionId": 19 + }, + { + "id": 20, + "roleId": 2, + "permissionId": 20 + }, + { + "id": 21, + "roleId": 2, + "permissionId": 21 + }, + { + "id": 22, + "roleId": 2, + "permissionId": 22 + }, + { + "id": 23, + "roleId": 2, + "permissionId": 23 + }, + { + "id": 24, + "roleId": 2, + "permissionId": 24 + }, + { + "id": 25, + "roleId": 2, + "permissionId": 25 + }, + { + "id": 26, + "roleId": 2, + "permissionId": 26 + }, + { + "id": 27, + "roleId": 2, + "permissionId": 27 + }, + { + "id": 28, + "roleId": 2, + "permissionId": 28 + }, + { + "id": 29, + "roleId": 2, + "permissionId": 29 + }, + { + "id": 30, + "roleId": 2, + "permissionId": 30 + }, + { + "id": 31, + "roleId": 2, + "permissionId": 31 + }, + { + "id": 32, + "roleId": 2, + "permissionId": 32 + }, + { + "id": 33, + "roleId": 2, + "permissionId": 33 + }, + { + "id": 34, + "roleId": 2, + "permissionId": 34 + }, + { + "id": 35, + "roleId": 2, + "permissionId": 35 + }, + { + "id": 36, + "roleId": 2, + "permissionId": 36 + }, + { + "id": 37, + "roleId": 2, + "permissionId": 37 + }, + { + "id": 38, + "roleId": 2, + "permissionId": 38 + }, + { + "id": 39, + "roleId": 2, + "permissionId": 39 + }, + { + "id": 40, + "roleId": 2, + "permissionId": 40 + }, + { + "id": 41, + "roleId": 2, + "permissionId": 41 + }, + { + "id": 42, + "roleId": 2, + "permissionId": 42 + }, + { + "id": 43, + "roleId": 2, + "permissionId": 43 + }, + { + "id": 44, + "roleId": 2, + "permissionId": 44 + }, + { + "id": 45, + "roleId": 2, + "permissionId": 45 + }, + { + "id": 46, + "roleId": 2, + "permissionId": 46 + }, + { + "id": 47, + "roleId": 2, + "permissionId": 47 + }, + { + "id": 48, + "roleId": 2, + "permissionId": 48 + }, + { + "id": 49, + "roleId": 2, + "permissionId": 49 + }, + { + "id": 50, + "roleId": 2, + "permissionId": 50 + }, + { + "id": 51, + "roleId": 2, + "permissionId": 51 + }, + { + "id": 52, + "roleId": 2, + "permissionId": 52 + }, + { + "id": 53, + "roleId": 2, + "permissionId": 53 + }, + { + "id": 54, + "roleId": 2, + "permissionId": 54 + }, + { + "id": 55, + "roleId": 2, + "permissionId": 55 + }, + { + "id": 56, + "roleId": 2, + "permissionId": 56 + }, + { + "id": 57, + "roleId": 2, + "permissionId": 57 + }, + { + "id": 58, + "roleId": 2, + "permissionId": 58 + }, + { + "id": 59, + "roleId": 2, + "permissionId": 59 + }, + { + "id": 60, + "roleId": 2, + "permissionId": 60 + }, + { + "id": 61, + "roleId": 2, + "permissionId": 61 + }, + { + "id": 62, + "roleId": 2, + "permissionId": 62 + }, + { + "id": 63, + "roleId": 2, + "permissionId": 63 + }, + { + "id": 64, + "roleId": 2, + "permissionId": 64 + }, + { + "id": 101, + "roleId": 2, + "permissionId": 65 + }, + { + "id": 132, + "roleId": 2, + "permissionId": 66 + }, + { + "id": 133, + "roleId": 2, + "permissionId": 67 + }, + { + "id": 134, + "roleId": 2, + "permissionId": 68 + }, + { + "id": 135, + "roleId": 2, + "permissionId": 69 + }, + { + "id": 138, + "roleId": 2, + "permissionId": 70 + }, + { + "id": 139, + "roleId": 2, + "permissionId": 71 + }, + { + "id": 140, + "roleId": 2, + "permissionId": 72 + }, + { + "id": 142, + "roleId": 2, + "permissionId": 73 + }, + { + "id": 141, + "roleId": 2, + "permissionId": 74 + }, + { + "id": 148, + "roleId": 2, + "permissionId": 75 + }, + { + "id": 150, + "roleId": 2, + "permissionId": 76 + }, + { + "id": 151, + "roleId": 2, + "permissionId": 77 + }, + { + "id": 152, + "roleId": 2, + "permissionId": 78 + }, + { + "id": 153, + "roleId": 2, + "permissionId": 79 + }, + { + "id": 154, + "roleId": 2, + "permissionId": 80 + }, + { + "id": 155, + "roleId": 2, + "permissionId": 81 + }, + { + "id": 158, + "roleId": 2, + "permissionId": 82 + }, + { + "id": 159, + "roleId": 2, + "permissionId": 83 + }, + { + "id": 162, + "roleId": 2, + "permissionId": 90 + }, + { + "id": 165, + "roleId": 2, + "permissionId": 91 + }, + { + "id": 164, + "roleId": 2, + "permissionId": 92 + }, + { + "id": 167, + "roleId": 2, + "permissionId": 93 + }, + { + "id": 169, + "roleId": 2, + "permissionId": 94 + }, + { + "id": 170, + "roleId": 2, + "permissionId": 95 + }, + { + "id": 194, + "roleId": 2, + "permissionId": 96 + }, + { + "id": 193, + "roleId": 2, + "permissionId": 97 + }, + { + "id": 195, + "roleId": 2, + "permissionId": 98 + }, + { + "id": 173, + "roleId": 3, + "permissionId": 4 + }, + { + "id": 174, + "roleId": 3, + "permissionId": 47 + }, + { + "id": 189, + "roleId": 3, + "permissionId": 48 + }, + { + "id": 190, + "roleId": 3, + "permissionId": 49 + }, + { + "id": 191, + "roleId": 3, + "permissionId": 50 + }, + { + "id": 171, + "roleId": 3, + "permissionId": 66 + }, + { + "id": 172, + "roleId": 3, + "permissionId": 75 + }, + { + "id": 179, + "roleId": 3, + "permissionId": 76 + }, + { + "id": 182, + "roleId": 3, + "permissionId": 77 + }, + { + "id": 183, + "roleId": 3, + "permissionId": 78 + }, + { + "id": 184, + "roleId": 3, + "permissionId": 79 + }, + { + "id": 185, + "roleId": 3, + "permissionId": 80 + }, + { + "id": 186, + "roleId": 3, + "permissionId": 81 + }, + { + "id": 180, + "roleId": 3, + "permissionId": 82 + }, + { + "id": 181, + "roleId": 3, + "permissionId": 83 + }, + { + "id": 178, + "roleId": 3, + "permissionId": 90 + }, + { + "id": 187, + "roleId": 3, + "permissionId": 91 + }, + { + "id": 188, + "roleId": 3, + "permissionId": 92 + }, + { + "id": 176, + "roleId": 3, + "permissionId": 93 + }, + { + "id": 177, + "roleId": 3, + "permissionId": 94 + }, + { + "id": 175, + "roleId": 3, + "permissionId": 95 + } + ] +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Db/DbHelper.cs b/src/Znyc.Recruitment.Api/Db/DbHelper.cs new file mode 100644 index 0000000..955208a --- /dev/null +++ b/src/Znyc.Recruitment.Api/Db/DbHelper.cs @@ -0,0 +1,62 @@ +using FreeSql.Aop; +using System; +using System.Reflection; +using Yitter.IdGenerator; +using Znyc.Recruitment.Common.Attributes; +using Znyc.Recruitment.Common.Auth; +using Znyc.Recruitment.Common.Extensions; + +namespace Znyc.Recruitment.Db +{ + public class DbHelper + { + /// + /// 审计数据 + /// + /// + /// + public static void AuditValue(AuditValueEventArgs e, IUser user) + { + if (e.Column.CsType == typeof(long) + && e.Property.GetCustomAttribute(false) != null + && (e.Value.IsNull() || (long)e.Value == default || (long?)e.Value == default)) + { + e.Value = YitIdHelper.NextId(); + } + + if (user.IsNull() || user.Id <= 0) + { + return; + } + + if (e.AuditValueType == AuditValueType.Insert) + { + switch (e.Property.Name) + { + case "CreatedUserId": + if (e.Value.IsNull() || (long)e.Value == default || (long?)e.Value == default) + { + e.Value = user.Id; + } + + break; + case "CreatedTime": + e.Value = DateTime.Now; + break; + } + } + else if (e.AuditValueType == AuditValueType.Update) + { + switch (e.Property.Name) + { + case "ModifiedUserId": + e.Value = user.Id; + break; + case "ModifiedTime": + e.Value = DateTime.Now; + break; + } + } + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Db/ServiceCollectionExtensions.cs b/src/Znyc.Recruitment.Api/Db/ServiceCollectionExtensions.cs new file mode 100644 index 0000000..2acc44a --- /dev/null +++ b/src/Znyc.Recruitment.Api/Db/ServiceCollectionExtensions.cs @@ -0,0 +1,67 @@ +using FreeSql; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using System; +using System.Linq; +using Znyc.Recruitment.Common.Attributes; +using Znyc.Recruitment.Common.Auth; +using Znyc.Recruitment.Common.Configs; +using Znyc.Recruitment.Common.Helpers; + +namespace Znyc.Recruitment.Db +{ + public static class ServiceCollectionExtensions + { + /// + /// 添加数据库 + /// + /// + /// + public static void AddDb(this IServiceCollection services, IHostEnvironment env) + { + + DbConfig dbConfig = new ConfigHelper().Get("appconfig", env.EnvironmentName).DbConfig; + FreeSqlBuilder freeSqlBuilder = new FreeSqlBuilder() + .UseConnectionString(dbConfig.Type, dbConfig.ConnectionString) + .UseLazyLoading(false) + .UseNoneCommandParameter(true); + + // 监听所有命令 + if (dbConfig.MonitorCommand) + { + freeSqlBuilder.UseMonitorCommand(cmd => { }, + (cmd, traceLog) => { Console.WriteLine($"{cmd.CommandText}\r\n"); }); + } + + IFreeSql fsql = freeSqlBuilder.Build(); + services.AddSingleton(fsql); + services.AddScoped(); + + //重定义统一平台用户表名 + fsql.Aop.ConfigEntity += (s, e) => + { + if (e.EntityType.GetCustomAttributes(typeof(MasterTableAttribute), false).FirstOrDefault() is + MasterTableAttribute attr) + { + e.ModifyResult.Name = attr.Name; //表名 + } + }; + + + // 监听所有sql语句 + if (dbConfig.Curd) + { + fsql.Aop.CurdAfter += (s, e) => + { + Console.WriteLine($"{e.Sql}\r\n"); + Console.WriteLine($"耗时:{e.ElapsedMilliseconds}ms\r\n"); + }; + } + + //审计数据 + IUser user = services.BuildServiceProvider().GetService(); + fsql.Aop.AuditValue += (s, e) => { DbHelper.AuditValue(e, user); }; + + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Dockerfile b/src/Znyc.Recruitment.Api/Dockerfile new file mode 100644 index 0000000..8a9a44b --- /dev/null +++ b/src/Znyc.Recruitment.Api/Dockerfile @@ -0,0 +1,29 @@ +#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base +WORKDIR /app +EXPOSE 80 +EXPOSE 443 + +ENV TZ=Asia/Shanghai +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build +WORKDIR /src +COPY ["Znyc.Recruitment.Api/Znyc.Recruitment.Api.csproj", "Znyc.Recruitment.Api/"] +COPY ["Znyc.Recruitment.Services/Znyc.Recruitment.Service.csproj", "Znyc.Recruitment.Services/"] +COPY ["Znyc.Recruitment.Repository/Znyc.Recruitment.Repository.csproj", "Znyc.Recruitment.Repository/"] +COPY ["Znyc.Recruitment.Model/Znyc.Recruitment.Model.csproj", "Znyc.Recruitment.Model/"] +COPY ["Znyc.Recruitment.Common/Znyc.Recruitment.Common.csproj", "Znyc.Recruitment.Common/"] +RUN dotnet restore "Znyc.Recruitment.Api/Znyc.Recruitment.Api.csproj" +COPY . . +WORKDIR "/src/Znyc.Recruitment.Api" +RUN dotnet build "Znyc.Recruitment.Api.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "Znyc.Recruitment.Api.csproj" -c Release -o /app/publish + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "Znyc.Recruitment.Api.dll"] \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Enums/ApiVersion.cs b/src/Znyc.Recruitment.Api/Enums/ApiVersion.cs new file mode 100644 index 0000000..fb46edf --- /dev/null +++ b/src/Znyc.Recruitment.Api/Enums/ApiVersion.cs @@ -0,0 +1,18 @@ +namespace Znyc.Recruitment.Enums +{ + /// + /// 接口版本 + /// + public enum ApiVersion + { + /// + /// V1 版本 + /// + v1 = 1, + + /// + /// V2 版本 + /// + v2 = 2 + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Enums/StatusCodes.cs b/src/Znyc.Recruitment.Api/Enums/StatusCodes.cs new file mode 100644 index 0000000..84afae2 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Enums/StatusCodes.cs @@ -0,0 +1,40 @@ +using System.ComponentModel; + +namespace Znyc.Recruitment.Enums +{ + /// + /// 状态码枚举 + /// + public enum StatusCodes + { + /// + /// 操作失败 + /// + [Description("操作失败")] Status0NotOk = 0, + + /// + /// 操作成功 + /// + [Description("操作成功")] Status1Ok = 1, + + /// + /// 未登录(需要重新登录) + /// + [Description("未登录")] Status401Unauthorized = 401, + + /// + /// 权限不足 + /// + [Description("权限不足")] Status403Forbidden = 403, + + /// + /// 资源不存在 + /// + [Description("资源不存在")] Status404NotFound = 404, + + /// + /// 系统内部错误(非业务代码里显式抛出的异常,例如由于数据不正确导致空指针异常、数据库异常等等) + /// + [Description("系统内部错误")] Status500InternalServerError = 500 + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Extensions/EventBusExtension.cs b/src/Znyc.Recruitment.Api/Extensions/EventBusExtension.cs new file mode 100644 index 0000000..f814543 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Extensions/EventBusExtension.cs @@ -0,0 +1,55 @@ +using Autofac; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using System; +using Znyc.Recruitment.Common.Configs; +using Znyc.Recruitment.Common.Helpers; +using Znyc.Recruitment.Evenbus; +using Znyc.Recruitment.Service; + +namespace Znyc.Recruitment.Api.Extensions +{ + /// + /// EventBus 事件总线服务 + /// + public static class EventBusExtension + { + public static void AddEventBusSetup(this IServiceCollection services, IHostEnvironment env) + { + + RabbitMQConfig rabbitMQConfig = new ConfigHelper().Get("appconfig", env.EnvironmentName).RabbitMQConfig; + + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + + string subscriptionClientName = rabbitMQConfig.Connection; + + services.AddSingleton(); + services.AddTransient(); + services.AddTransient(); + + services.AddSingleton(sp => + { + IRabbitMQPersistentConnection rabbitMQPersistentConnection = sp.GetRequiredService(); + ILifetimeScope iLifetimeScope = sp.GetRequiredService(); + ILogger logger = sp.GetRequiredService>(); + IEventBusSubscriptionsManager eventBusSubcriptionsManager = sp.GetRequiredService(); + int retryCount = rabbitMQConfig.RetryCount; + return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount); + }); + } + + + public static void ConfigureEventBus(this IApplicationBuilder app) + { + IEventBus eventBus = app.ApplicationServices.GetRequiredService(); + eventBus.Subscribe(); + eventBus.Subscribe(); + + } + } +} diff --git a/src/Znyc.Recruitment.Api/Extensions/HangFireExtension.cs b/src/Znyc.Recruitment.Api/Extensions/HangFireExtension.cs new file mode 100644 index 0000000..c243f55 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Extensions/HangFireExtension.cs @@ -0,0 +1,75 @@ +using Hangfire; +using Hangfire.Dashboard.BasicAuthorization; +using Hangfire.Redis; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using System; +using Znyc.Recruitment.Common.Configs; +using Znyc.Recruitment.Common.Helpers; +using Znyc.Recruitment.HangFire; + +namespace Znyc.Recruitment.Api.Extensions +{ + /// + /// HangFire启动服务 + /// + public static class HangFireExtension + { + public static void AddHangFireSetup(this IServiceCollection services, IHostEnvironment env) + { + RedisConfig redisConfig = new ConfigHelper().Get("appconfig", env.EnvironmentName).RedisConfig; + services.AddHangfire(x => x.UseRedisStorage(redisConfig.ConnectionString)); + services.AddHangfireServer(options => + { + options.Queues = new[] { HangFireQueuesConfig.@default.ToString(), HangFireQueuesConfig.apis.ToString(), HangFireQueuesConfig.web.ToString(), HangFireQueuesConfig.recurring.ToString() }; + options.ServerTimeout = TimeSpan.FromMinutes(4); + options.SchedulePollingInterval = TimeSpan.FromSeconds(15);//秒级任务需要配置短点,一般任务可以配置默认时间,默认15秒 + options.ShutdownTimeout = TimeSpan.FromMinutes(30); //超时时间 + options.WorkerCount = Math.Max(Environment.ProcessorCount, 20); //工作线程数,当前允许的最大线程,默认20 + }); + } + + + public static void ConfigureHangFire(this IApplicationBuilder app, IHostEnvironment env) + { + HangFireConfig hangFireConfig = new ConfigHelper().Get("appconfig", env.EnvironmentName).HangfireConfig; + //授权 + var filter = new BasicAuthAuthorizationFilter( + new BasicAuthAuthorizationFilterOptions + { + SslRedirect = false, + // Require secure connection for dashboard + RequireSsl = false, + // Case sensitive login checking + LoginCaseSensitive = false, + // Users + Users = new[] + { + new BasicAuthAuthorizationUser + { + Login =hangFireConfig.Login ,//App.Configuration["Hangfire:Login"], + PasswordClear =hangFireConfig.Password //App.Configuration["Hangfire:Password"] + } + } + }); + + var options = new DashboardOptions + { + AppPath = "/",//返回时跳转的地址 + DisplayStorageConnectionString = false,//是否显示数据库连接信息 + Authorization = new[] + { + filter + }, + IsReadOnlyFunc = Context => + { + return false;//是否只读面板 + } + }; + + app.UseHangfireDashboard("/rm_job", options); + HangfireDispose.HangfireService(); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Extensions/RabbitMQExtension.cs b/src/Znyc.Recruitment.Api/Extensions/RabbitMQExtension.cs new file mode 100644 index 0000000..765382c --- /dev/null +++ b/src/Znyc.Recruitment.Api/Extensions/RabbitMQExtension.cs @@ -0,0 +1,41 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using RabbitMQ.Client; +using System; +using Znyc.Recruitment.Common.Configs; +using Znyc.Recruitment.Common.Helpers; +using Znyc.Recruitment.Evenbus; + +namespace Znyc.Recruitment.Api.Extensions +{ + /// + /// RabbitMQ启动服务 + /// + public static class RabbitMQExtension + { + public static void AddRabbitMQSetup(this IServiceCollection services, IHostEnvironment env) + { + RabbitMQConfig rabbitMQConfig = new ConfigHelper().Get("appconfig", env.EnvironmentName).RabbitMQConfig; + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + + services.AddSingleton(sp => + { + ILogger logger = sp.GetRequiredService>(); + + ConnectionFactory factory = new ConnectionFactory() + { + HostName = rabbitMQConfig.Connection, + DispatchConsumersAsync = true + }; + factory.UserName = rabbitMQConfig.UserName; + factory.Password = rabbitMQConfig.Password; + int retryCount = rabbitMQConfig.RetryCount; + return new RabbitMQPersistentConnection(factory, logger, retryCount); + }); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Extensions/UploadConfigApplicationBuilderExtensions.cs b/src/Znyc.Recruitment.Api/Extensions/UploadConfigApplicationBuilderExtensions.cs new file mode 100644 index 0000000..8ced039 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Extensions/UploadConfigApplicationBuilderExtensions.cs @@ -0,0 +1,36 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.FileProviders; +using System; +using System.IO; +using Znyc.Recruitment.Common.Configs; +using Znyc.Recruitment.Common.Const; +using Znyc.Recruitment.Common.Helpers; + +namespace Znyc.Recruitment.Extensions +{ + public static class UploadConfigApplicationBuilderExtensions + { + private static void UseFileUploadConfig(IApplicationBuilder app, FileUploadConfig config) + { + if (!Directory.Exists(config.UploadPath)) + { + Directory.CreateDirectory(config.UploadPath); + } + + app.UseStaticFiles(new StaticFileOptions + { + RequestPath = config.RequestPath, + FileProvider = new PhysicalFileProvider(config.UploadPath) + }); + } + + public static IApplicationBuilder UseUploadConfig(this IApplicationBuilder app) + { + UploadConfig uploadConfig = new ConfigHelper().Get("appconfig", Environment.GetEnvironmentVariable(CommonConst.ASPNETCORE_ENVIRONMENT)).UploadConfig; + UseFileUploadConfig(app, uploadConfig.Avatar); + UseFileUploadConfig(app, uploadConfig.Document); + + return app; + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Filters/ExceptionFilter.cs b/src/Znyc.Recruitment.Api/Filters/ExceptionFilter.cs new file mode 100644 index 0000000..0ff69d4 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Filters/ExceptionFilter.cs @@ -0,0 +1,59 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Extensions; +using Znyc.Recruitment.Common.Output; +using Znyc.Recruitment.Enums; + +namespace Znyc.Recruitment.Filters +{ + /// + /// 异常错误过滤 + /// + public class ExceptionFilter : IExceptionFilter, IAsyncExceptionFilter + { + private readonly IWebHostEnvironment _env; + private readonly ILogger _logger; + + public ExceptionFilter(IWebHostEnvironment env, ILogger logger) + { + _env = env; + _logger = logger; + } + + public Task OnExceptionAsync(ExceptionContext context) + { + OnException(context); + return Task.CompletedTask; + } + + public void OnException(ExceptionContext context) + + { + string message; + if (_env.IsProduction()) + { + message = StatusCodes.Status500InternalServerError.ToDescription(); + } + else + { + message = context.Exception.Message; + } + + //_logger.LogError(context.Exception, message); + IResponseOutput data = ResponseOutput.Fail(message); + context.Result = new InternalServerErrorResult(data); + } + } + + public class InternalServerErrorResult : ObjectResult + { + public InternalServerErrorResult(object value) : base(value) + { + StatusCode = Microsoft.AspNetCore.Http.StatusCodes.Status500InternalServerError; + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Program.cs b/src/Znyc.Recruitment.Api/Program.cs new file mode 100644 index 0000000..2d24887 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Program.cs @@ -0,0 +1,69 @@ +using Autofac.Extensions.DependencyInjection; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using NLog; +using NLog.Web; +using System; +using System.Threading.Tasks; +using Znyc.Recruitment.Common.Configs; +using Znyc.Recruitment.Common.Const; +using Znyc.Recruitment.Common.Helpers; + +namespace Znyc.Recruitment.Api +{ + public class Program + { + private static readonly AppConfig AppConfig = + new ConfigHelper().Get("appconfig", + Environment.GetEnvironmentVariable(CommonConst.ASPNETCORE_ENVIRONMENT)) ?? new AppConfig(); + + public static async Task Main(string[] args) + { + Logger logger = LogManager.GetCurrentClassLogger(); + try + { + Console.WriteLine("project initialization...."); + Console.WriteLine(Environment.GetEnvironmentVariable(CommonConst.ASPNETCORE_ENVIRONMENT)); + + IHost host = CreateHostBuilder(args).Build(); + await host.RunAsync(); + return 0; + } + catch (Exception ex) + { + Console.WriteLine(ex); + logger.Error(ex, "Stopped program because of exception"); + return 1; + } + finally + { + LogManager.Shutdown(); + } + } + + public static IHostBuilder CreateHostBuilder(string[] args) + { + return Host.CreateDefaultBuilder(args) + .UseServiceProviderFactory(new AutofacServiceProviderFactory()) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder + // .UseEnvironment(Environments.Production) + .UseStartup() + .ConfigureAppConfiguration((host, config) => + { + }) + .UseUrls(AppConfig.Urls); + }) + .ConfigureLogging(logging => + { + // LogManager.LoadConfiguration("Config/nlog.config"); logging.ConfigureNLog($"nlog.{Environment.GetEnvironmentVariable(CommonConst.ASPNETCORE_ENVIRONMENT)}.config"); + logging.ClearProviders(); + logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Warning); + }) + .UseNLog(); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Properties/launchSettings.json b/src/Znyc.Recruitment.Api/Properties/launchSettings.json new file mode 100644 index 0000000..0d14318 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Properties/launchSettings.json @@ -0,0 +1,34 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:5001", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Znyc.Recruitment.Api": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": "true", + "applicationUrl": "http://localhost" + }, + "Docker": { + "commandName": "Docker", + "launchBrowser": true, + "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}", + "publishAllPorts": true + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Startup.cs b/src/Znyc.Recruitment.Api/Startup.cs new file mode 100644 index 0000000..315758b --- /dev/null +++ b/src/Znyc.Recruitment.Api/Startup.cs @@ -0,0 +1,398 @@ +using Autofac; +using Autofac.Extras.DynamicProxy; +using CSRedis; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; +using Microsoft.IdentityModel.Tokens; +using Microsoft.OpenApi.Models; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using Senparc.CO2NET; +using Senparc.CO2NET.AspNet; +using Senparc.Weixin; +using Senparc.Weixin.Entities; +using Senparc.Weixin.RegisterServices; +using Senparc.Weixin.TenPay; +using Swashbuckle.AspNetCore.SwaggerUI; +using System; +using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using Yitter.IdGenerator; +using Znyc.Recruitment.Aop; +using Znyc.Recruitment.Api.Auth; +using Znyc.Recruitment.Api.Extensions; +using Znyc.Recruitment.Auth; +using Znyc.Recruitment.Common.Attributes; +using Znyc.Recruitment.Common.Auth; +using Znyc.Recruitment.Common.Cache; +using Znyc.Recruitment.Common.Configs; +using Znyc.Recruitment.Common.Helpers; +using Znyc.Recruitment.Db; +using Znyc.Recruitment.Enums; +using Znyc.Recruitment.Extensions; +using Znyc.Recruitment.Filters; +using NLog; +using Senparc.Weixin.MP.Containers; + +namespace Znyc.Recruitment +{ + public class Startup + { + private const string DefaultCorsPolicyName = "Allow"; + private readonly AppConfig _appConfig; + private readonly ConfigHelper _configHelper; + private readonly IConfiguration _configuration; + private readonly IHostEnvironment _env; + + public Startup(IConfiguration configuration, IWebHostEnvironment env) + { + _configuration = configuration; + _env = env; + _configHelper = new ConfigHelper(); + _appConfig = _configHelper.Get("appconfig", env.EnvironmentName) ?? new AppConfig(); + } + + private static string BasePath => AppContext.BaseDirectory; + + public void ConfigureServices(IServiceCollection services) + { + //雪花漂移算法 + YitIdHelper.SetIdGenerator(new IdGeneratorOptions(1) { WorkerIdBitLength = 6 }); + + // ClaimType不被更改 + JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); + + //用户信息 + services.AddSingleton(); + services.TryAddSingleton(); + + //数据库 + services.AddDb(_env); + + //应用配置 + services.AddSingleton(_appConfig); + + #region AutoMapper 自动映射 + + var serviceAssembly = Assembly.Load("Znyc.Recruitment.Service"); + services.AddAutoMapper(serviceAssembly); + + #endregion AutoMapper 自动映射 + + #region Cors 跨域 + + if (_appConfig.CorUrls?.Length > 0) + { + services.AddCors(options => + { + options.AddPolicy(DefaultCorsPolicyName, policy => + { + policy + .WithOrigins(_appConfig.CorUrls) + .AllowAnyHeader() + .AllowAnyMethod() + .AllowCredentials(); + }); + }); + } + + #endregion Cors 跨域 + + #region Jwt身份认证授权 + var jwtConfig = _appConfig.JwtConfig; + + services.AddAuthentication(options => + { + options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = nameof(ResponseAuthenticationHandler); //401 + options.DefaultForbidScheme = nameof(ResponseAuthenticationHandler); //403 + }) + .AddJwtBearer(options => + { + options.TokenValidationParameters = new TokenValidationParameters + { + ValidateIssuer = true, + ValidateAudience = true, + ValidateLifetime = true, + ValidateIssuerSigningKey = true, + ValidIssuer = jwtConfig.Issuer, + ValidAudience = jwtConfig.Audience, + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtConfig.SecurityKey)), + ClockSkew = TimeSpan.Zero + }; + }) + .AddScheme( + nameof(ResponseAuthenticationHandler), o => { }); + + #endregion Jwt身份认证授权 + + #region Swagger Api文档 + + if (_appConfig.Swagger) + { + services.AddSwaggerGen(options => + { + typeof(ApiVersion).GetEnumNames().ToList().ForEach(version => + { + options.SwaggerDoc(version, new OpenApiInfo + { + Version = version, + Title = "Znyc.Recruitment" + }); + options.OrderActionsBy(o => o.RelativePath); + }); + //生成api文档 + var basePath = AppContext.BaseDirectory; + var xmlPath = Path.Combine(basePath, "Znyc.Recruitment.Api.xml"); + options.IncludeXmlComments(xmlPath); + + #region 添加设置Token的按钮 + + //添加Jwt验证设置 + options.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Id = "Bearer", + Type = ReferenceType.SecurityScheme + } + }, + new List() + } + }); + + options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme + { + Description = "Value: Bearer {token}", + Name = "Authorization", + In = ParameterLocation.Header, + Type = SecuritySchemeType.ApiKey + }); + + #endregion 添加设置Token的按钮 + }); + } + + #endregion Swagger Api文档 + + #region 操作日志 + + //if (_appConfig.Log.Operation) + //{ + // services.AddSingleton(); + //} + + #endregion 操作日志 + + #region 控制器 + + services.AddControllers(options => + { + options.Filters.Add(); + //禁止去除ActionAsync后缀 + options.SuppressAsyncSuffixInActionNames = false; + }) + .AddNewtonsoftJson(options => + { + //忽略循环引用 + options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; + //使用驼峰 首字母小写 + options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); + //设置时间格式 + options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; + //设置时区 + options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local; + }); + + #endregion 控制器 + + #region 缓存 + + var cacheConfig = _appConfig.RedisConfig; + var csredis = new CSRedisClient(cacheConfig.ConnectionString); + RedisHelper.Initialization(csredis); + services.AddSingleton(); + + #endregion 缓存 + + #region Senparc.Weixin 注册 + services.AddSenparcWeixinServices(_configuration).AddMemoryCache(); + services.TryAddSingleton(); + Senparc.Weixin.WxOpen.Containers.AccessTokenContainer.RegisterAsync("wx71f2b227f8eaf00a", "bf868056d4e58f4b2831ff74308120ac"); + AccessTokenContainer.RegisterAsync("wx71f2b227f8eaf00a", "bf868056d4e58f4b2831ff74308120ac"); + AccessTokenContainer.RegisterAsync("wx78474b2ab9ac3e6c", "a2349cf1dc0871e799109f0f824d38a3"); + #endregion + + #region RabbitMQ + services.AddRabbitMQSetup(_env); + services.AddEventBusSetup(_env); + + #endregion + + #region HangFire + services.AddHangFireSetup(_env); + #endregion + + #region Nlog + services.Configure(opts => opts.SuppressStatusMessages = true); + if(_env.IsProduction()) + LogManager.LoadConfiguration($"nlog.Production.config"); + + #endregion + + + } + + public void ConfigureContainer(ContainerBuilder builder) + { + #region AutoFac IOC容器 + + try + { + #region SingleInstance + + //无接口注入单例 + var assemblyCore = Assembly.Load("Znyc.Recruitment.Api"); + var assemblyCommon = Assembly.Load("Znyc.Recruitment.Common"); + builder.RegisterAssemblyTypes(assemblyCore, assemblyCommon) + .Where(t => t.GetCustomAttribute() != null) + .SingleInstance(); + //有接口注入单例 + builder.RegisterAssemblyTypes(assemblyCore, assemblyCommon) + .Where(t => t.GetCustomAttribute() != null) + .AsImplementedInterfaces() + .SingleInstance(); + + #endregion SingleInstance + + #region Aop + + var interceptorServiceTypes = new List(); + if (_appConfig.Aop.Transaction) + { + builder.RegisterType(); + interceptorServiceTypes.Add(typeof(TransactionInterceptor)); + } + + #endregion Aop + + #region Repository + + var assemblyRepository = Assembly.Load("Znyc.Recruitment.Repository"); + builder.RegisterAssemblyTypes(assemblyRepository) + .AsImplementedInterfaces() + .InstancePerDependency(); + + #endregion Repository + + #region Service + + var assemblyServices = Assembly.Load("Znyc.Recruitment.Service"); + builder.RegisterAssemblyTypes(assemblyServices) + .AsImplementedInterfaces() + .InstancePerDependency() + .EnableInterfaceInterceptors() + .InterceptedBy(interceptorServiceTypes.ToArray()); + + #endregion Service + } + catch (Exception ex) + { + throw new Exception(ex.Message + "\n" + ex.InnerException); + } + + #endregion AutoFac IOC容器 + } + + public void Configure(IApplicationBuilder app, IOptions senparcSetting, + IOptions senparcWeixinSetting) + { + #region app配置 + + //IP限流 + //if (_appConfig.RateLimit) + //{ + // app.UseIpRateLimiting(); + //} + + //异常 + app.UseExceptionHandler("/Error"); + + //静态文件 + app.UseUploadConfig(); + + //注册 Senparc.Weixin 及基础库 + var registerService = app.UseSenparcGlobal(_env, senparcSetting.Value, _ => { }, true) + .UseSenparcWeixin(senparcWeixinSetting.Value, weixinRegister => weixinRegister + // .RegisterMpAccount(senparcWeixinSetting.Value)) + .RegisterTenpayV3(senparcWeixinSetting.Value, "云车招聘")); + + //路由 + app.UseRouting(); + + //跨域 + if (_appConfig.CorUrls?.Length > 0) + { + app.UseCors(DefaultCorsPolicyName); + } + + //认证 + app.UseAuthentication(); + + //授权 + app.UseAuthorization(); + + //Https + // app.UseHsts(); + + //配置端点 + app.UseEndpoints(endpoints => { endpoints.MapDefaultControllerRoute(); }); + + #endregion app配置 + + #region Swagger Api文档 + + if (_appConfig.Swagger) + { + app.UseSwagger(); + app.UseSwaggerUI(c => + { + typeof(ApiVersion).GetEnumNames().OrderBy(e => e).ToList().ForEach(version => + { + c.SwaggerEndpoint($"/swagger/{version}/swagger.json", $"api {version}"); + }); + c.RoutePrefix = ""; //直接根目录访问,如果是IIS发布可以注释该语句,并打开launchSettings.launchUrl + c.DocExpansion(DocExpansion.None); + c.DefaultModelsExpandDepth(-1); //不显示Models + }); + } + + + #endregion Swagger Api文档 + + // 事件总线,订阅服务 + app.ConfigureEventBus(); + + #region HangFire + app.ConfigureHangFire(_env); + #endregion + + + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Znyc.Recruitment.Api.csproj b/src/Znyc.Recruitment.Api/Znyc.Recruitment.Api.csproj new file mode 100644 index 0000000..e77b014 --- /dev/null +++ b/src/Znyc.Recruitment.Api/Znyc.Recruitment.Api.csproj @@ -0,0 +1,116 @@ + + + + net6.0 + + OutOfProcess + false + 1.0.0 + MIT + jiaoqi + jiaoqi + git + WebApi + https://gitee.com/guangzhou-zhongneng-cloud-car_1/Znyc.-recruitment.git + https://gitee.com/guangzhou-zhongneng-cloud-car_1/Znyc.-recruitment.git + ;WebApi + Znyc.Recruitment + Znyc.Recruitment + Linux + ..\.. + 717d3417-b18a-454d-aa5f-870d08b412a9 + + + + + 1701;1702;1591 + + false + D:\Code\广州众能云车科技有限公司\znyc.recruitment.api\src\Znyc.Recruitment.Api\Znyc.Recruitment.Api.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + + + + Always + + + PreserveNewest + + + PreserveNewest + + + + + + + \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/Znyc.Recruitment.Api.xml b/src/Znyc.Recruitment.Api/Znyc.Recruitment.Api.xml new file mode 100644 index 0000000..06c8bbd --- /dev/null +++ b/src/Znyc.Recruitment.Api/Znyc.Recruitment.Api.xml @@ -0,0 +1,904 @@ + + + + Znyc.Recruitment.Api + + + + + 隐藏接口,不生成到swagger文档展示(Swashbuckle.AspNetCore 5.0.0) + + + + + 重写Apply方法,移除隐藏接口的生成 + + swagger文档文件 + + + + + 启用登录 + + + + + 禁用操作日志 + + + + + 启用权限 + + + + + 定时任务启动密钥 + + + + + 输入模型验证 + + + + + 自定义路由 /api/{version}/[controler]/[action] + + + + + 定时任务 + + + + + 定时任务 + + + + + 活动页 + + + + + 查询活动列表 + + + + + + 根据Id查询活动详情 + + + + + + + 邀请排行榜 + + + + + + + + 累计签到排行榜 + + + + + + + + 积分排行榜 + + + + + + + + 求职浏览量排行榜 + + + + + + + + 招聘浏览量排行榜 + + + + + + + + 审核记录管理 + + + + + 审核记录 + + + + + + + + 授权管理 + + + + + 百度地图获取AccessToken + + + + + + 微信获取AccessToken + + + + + + 获取小程序码 + + + + + + 广告页 + + + + + 查询广告列表 + + + + + + 用户浏览信息管理 + + + + + 用户浏览求职信息 + + + + + + + + 用户浏览招聘信息 + + + + + + + + 通话评价 + + + + + 新增通话评价 + + + + + + + 实名认证管理 + + + + + 查询实名认证信息 + + + + + + 新增实名认证信息 + + + + + + + 更新实名认证信息 + + + + + + + 查询行业岗位 + + + + + + + 用户收藏信息管理 + + + + + 用户收藏求职信息 + + + + + + + + 用户收藏招聘信息 + + + + + + + + + + + + + + + + 取消收藏 + + + + + + + + 用户云币管理 + + + + + 获取用户云币信息 + + + + + + 云币账单 + + 0-全部/1-增加/2-减少 + + + + + + + 用户云币管理 + + + + + 获取云币来源列表 + + + + + + 用户投递简历信息管理 + + + + + 我的求职--我的投递/对我感兴趣 + + 1-我的投递/2-对我感兴趣 + + + + + + + 我的招聘——我感兴趣的/收到的求职 + + 1-收到的求职/2-我感兴趣的 + + + + + + + 新增用户投递简历信息 + + + + + + + 已查看用户投递简历信息 + + 1--求职/2--招聘 + + + + + 文档管理 + + + + + 上传文档图片 + + + + + + 意见反馈 + + + + + 新增意见反馈 + + + + + + + 行业岗位管理 + + + + + 查询行业岗位 + + + + + + + 登录管理 + + + + + Wx登录授权 + + + + + + + 信息通知管理 + + + + + 查询消息通知列表 + + + + + + + + + 已读消息记录 + + 1--求职/2--招聘/3--实名 + + + + + 获取新用户滚动播放列表 + + + + + + 邀请新用户信息滚动播放列表 + + + + + + 商品品牌表 + + + + + 产品图片 + + + + + + 商品服务 + + + + + 分页获取商品信息 + + + 品牌 + 分类 + + + + + + + 产品图片 + + + + + 产品图片 + + + + + + Banner + + + + + 产品图片 + + + + + + 定时调度 + + + + + 置顶到期取消 + + + + + + 月重置签到次数 + + + + + + 每日清空临时积分 + + + + + + 每日清空云币来源缓存 + + + + + + 同步浏览量 + + + + + + 充值活动服务 + + + + + 获取充值活动 + + + + + + 招聘信息管理 + + + + + 单条查询 + + + + + + + 我的招聘信息 + + 招聘状态 + 当前页码 + 页数 + + + + + 分页查询招聘信息 + + 标题 + 省 + 市 + 行业Id + 岗位Id + 排序 + 当前页码 + 页数 + + + + + 获取上一次发布信息的手机号码和发布人 + + + + + + + 获取手机号码 + + + + + + + 新增招聘信息 + + + + + + + 编辑招聘信息 + + + + + + + 刷新招聘信息 + + + + + + + 置顶招聘信息 + + + + + + + 更改招聘信息状态 + + + 招聘状态 + + + + + 是否公开招聘信息 + + + + + + + + 分享管理 + + + + + 分享 + + + newusers(邀请新用户)/dailyshare(每日分享)/personalposter(生成海报) + + + + + 用户签到管理 + + + + + 月签到记录 + + + + + + + 今日签到 + + + + + + 用户管理 + + + + + 修改用户信息 + + + + + + + 未读提示 + + + + + + 我的邀请记录 + + + + + + + + 支付服务 + + + + + 微信小程序支付 + + 商品Id + + + + + 微信小程序支付回调 + + + + + + EventBus 事件总线服务 + + + + + HangFire启动服务 + + + + + RabbitMQ启动服务 + + + + + 权限处理接口 + + + + + 权限验证 + + + + + + + + 权限处理 + + + + + 权限验证 v1.1.0后增加权限验证 + + 接口路径 + http请求方法 + + + + + 响应认证处理器 + + + + + 基础控制器 + + + + + 数据字典 + + + + + 根据Id获取字典 + + + + + + + + + + + + + + 数据 + + + + + 审计数据 + + + + + + + 添加数据库 + + + + + + + 接口版本 + + + + + V1 版本 + + + + + V2 版本 + + + + + 状态码枚举 + + + + + 操作失败 + + + + + 操作成功 + + + + + 未登录(需要重新登录) + + + + + 权限不足 + + + + + 资源不存在 + + + + + 系统内部错误(非业务代码里显式抛出的异常,例如由于数据不正确导致空指针异常、数据库异常等等) + + + + + 异常错误过滤 + + + + + 求职信息管理 + + + + + 单条查询 + + + + + + + 我的求职简历 + + + + + + 分页查询 + + 内容 + 省 + 市 + 行业id + 岗位类型 + 排序 + 当前页 + 页数 + + + + + 获取手机号码 + + + + + + + 添加求职信息 + + + + + + + 修改求职信息 + + + + + + + 一键刷新 + + + + + + 置顶求职信息 + + + + + + + 更改求职信息状态 + + + 求职状态1-正在找/2-已找到 + + + + + 是否公开求职信息 + + + + + + + diff --git a/src/Znyc.Recruitment.Api/appsettings.Development.json b/src/Znyc.Recruitment.Api/appsettings.Development.json new file mode 100644 index 0000000..ea251df --- /dev/null +++ b/src/Znyc.Recruitment.Api/appsettings.Development.json @@ -0,0 +1,38 @@ +{ + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Trace", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*", + //CO2NET + "SenparcSetting": { + "DefaultCacheNamespace": "DefaultCache", + "IsDebug": true, + "SenparcUnionAgentKey": "#{SenparcUnionAgentKey}#" + }, + //Senparc.Weixin SDK + "SenparcWeixinSetting": { + //΢ȫ + "IsDebug": true, + //׷С + "WxOpenAppId": "wx71f2b227f8eaf00a", + "WxOpenAppSecret": "8bf5367798b22856f4daf0d0fd4db6b0", + "WxOpenToken": "#{WxOpenToken}#", + "WxOpenEncodingAESKey": "#{WxOpenEncodingAESKey}#", + ////΢Źں + "WeixinAppId": "wx78474b2ab9ac3e6c", + "WeixinAppSecret": "a2349cf1dc0871e799109f0f824d38a3", + //΢֧V3°棩 + "TenPayV3_AppId": "wx71f2b227f8eaf00a", + "TenPayV3_AppSecret": "8bf5367798b22856f4daf0d0fd4db6b0", + "TenPayV3_MchId": "1610262173", + "TenPayV3_Key": "KlRZJKvAstv4SJapStuyHhCOzqrrjSUD", + "TenPayV3_TenpayNotify": "https://znyc.natapp4.cc/api/v1/wxpay/notify", + "TenPayV3_WxOpenTenpayNotify": "https://znyc.natapp4.cc/api/v1/wxpay/notify" + + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/appsettings.Production.json b/src/Znyc.Recruitment.Api/appsettings.Production.json new file mode 100644 index 0000000..28506e2 --- /dev/null +++ b/src/Znyc.Recruitment.Api/appsettings.Production.json @@ -0,0 +1,40 @@ +{ + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Trace", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*", + //CO2NET + "SenparcSetting": { + "DefaultCacheNamespace": "DefaultCache", + "IsDebug": true, + "SenparcUnionAgentKey": "#{SenparcUnionAgentKey}#" + }, + //Senparc.Weixin SDK + "SenparcWeixinSetting": { + //΢ȫ + "IsDebug": true, + //׷С + "WxOpenAppId": "wx71f2b227f8eaf00a", + "WxOpenAppSecret": "8bf5367798b22856f4daf0d0fd4db6b0", + "WxOpenToken": "#{WxOpenToken}#", + "WxOpenEncodingAESKey": "#{WxOpenEncodingAESKey}#", + ////΢Źں + //"WeixinAppId": "wx78474b2ab9ac3e6c", + //"WeixinAppSecret": "a2349cf1dc0871e799109f0f824d38a3", + //΢֧V3°棩 + "TenPayV3_AppId": "wx71f2b227f8eaf00a", + "TenPayV3_AppSecret": "8bf5367798b22856f4daf0d0fd4db6b0", + "TenPayV3_MchId": "1610262173", + "TenPayV3_Key": "KlRZJKvAstv4SJapStuyHhCOzqrrjSUD", + "TenPayV3_TenpayNotify": "https://znyunche.com/api/v1/wxpay/notify", + "TenPayV3_WxOpenTenpayNotify": "https://znyunche.com/api/v1/wxpay/notify" + + + + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/appsettings.Staging.json b/src/Znyc.Recruitment.Api/appsettings.Staging.json new file mode 100644 index 0000000..e369b97 --- /dev/null +++ b/src/Znyc.Recruitment.Api/appsettings.Staging.json @@ -0,0 +1,41 @@ +{ + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Trace", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*", + //CO2NET + "SenparcSetting": { + "DefaultCacheNamespace": "DefaultCache", + "IsDebug": true, + "SenparcUnionAgentKey": "#{SenparcUnionAgentKey}#" + }, + //Senparc.Weixin SDK + "SenparcWeixinSetting": { + //΢ȫ + "IsDebug": true, + //׷С + "WxOpenAppId": "wx71f2b227f8eaf00a", + "WxOpenAppSecret": "8bf5367798b22856f4daf0d0fd4db6b0", + "WxOpenToken": "#{WxOpenToken}#", + "WxOpenEncodingAESKey": "#{WxOpenEncodingAESKey}#", + ////΢Źں + //"WeixinAppId": "wx78474b2ab9ac3e6c", + //"WeixinAppSecret": "a2349cf1dc0871e799109f0f824d38a3", + + //΢֧V3°棩 + "TenPayV3_AppId": "wx71f2b227f8eaf00a", + "TenPayV3_AppSecret": "8bf5367798b22856f4daf0d0fd4db6b0", + "TenPayV3_MchId": "1610262173", + "TenPayV3_Key": "KlRZJKvAstv4SJapStuyHhCOzqrrjSUD", + "TenPayV3_TenpayNotify": "https://znyunche.com/api/v1/wxpay/notify", + "TenPayV3_WxOpenTenpayNotify": "https://znyunche.com/api/v1/wxpay/notify" + + + + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/configs/appconfig.Development.json b/src/Znyc.Recruitment.Api/configs/appconfig.Development.json new file mode 100644 index 0000000..c59967d --- /dev/null +++ b/src/Znyc.Recruitment.Api/configs/appconfig.Development.json @@ -0,0 +1,289 @@ +{ + //Apiַ + "urls": [ "http://*:80" ], + //ַ + "corUrls": [ "http://*:9000" ], + //Swaggerĵ + "swagger": true, + //ͳһ֤Ȩ + "IdentityServer": { + // + "enable": false, + "url": "" + }, + // + "aop": { + // + "transaction": true + }, + // + "rateLimit": false, + "BaiduConfig": { + "AppID": "23954973", + "ApiKey": "zCU8ZvomVm3upmIlI9kY8svK", + "SecretKey": "H4m3G8adKbRpIICyKtX8rqjHmjCugld9" + }, + "RedisConfig": { + //ַ + "connectionString": "81.71.148.57:46379,password=dfeFEgeGH/,defaultdatabase=0" + //ַ + //"connectionStringRateLimit": "81.71.148.57:46379,password=dfeFEgeGH/,defaultdatabase=0" + + }, + "DbConfig": { + //в + "monitorCommand": true, + //Curd + "curd": true, + //ݿ MySql = 0, + "type": 0, + //ַ + // + "connectionString": "Server=81.71.148.57; Port=43306; Database=znyc_recruitment; Uid=znyc; Pwd=bIQISVSO; Charset=utf8mb4", + //ӿ + "slaveConnectionStringList": [ + //"Server=81.71.148.57; Port=43306; Database=znyc_recruitment; Uid=znyc; Pwd=bIQISVSO; Charset=utf8mb4", + ] + }, + "JwtConfig": { + // + "issuer": "Znyc", + // + "audience": "Znyc", + //Կ + "securityKey": "ertJKl#521*a@790asD&1#", + //Ч() 2880 = 2 + "expires": 2880, + //ˢЧ() 4320 = 3 + "refreshExpires": 4320 + }, + "RateLimiting": { + /* + https://github.com/stefanprodan/AspNetCoreRateLimit/wiki/IpRateLimitMiddleware + https://github.com/stefanprodan/AspNetCoreRateLimit/wiki/Using-Redis-as-a-distributed-counter-store + */ + "IpRateLimiting": { + "EnableEndpointRateLimiting": true, + "StackBlockedRequests": false, + "RealIpHeader": "X-Real-IP", + "ClientIdHeader": "X-ClientId", + "IpWhitelist": [], // "127.0.0.1" + "EndpointWhitelist": [ "get:/api/auth/refresh" ], // "get:/api/a", "*:/api/b" + "ClientWhitelist": [], + "HttpStatusCode": 429, + "QuotaExceededResponse": { + "Content": "{{\"code\":429,\"msg\":\"ʹƵ\"}}", + "ContentType": "application/json", + "StatusCode": 429 + }, + "GeneralRules": [ + { + "Endpoint": "*", + "Period": "1s", + "Limit": 3 + }, + { + "Endpoint": "*", + "Period": "10m", + "Limit": 200 + } + ] + } + }, + + "SMSConfig": { + "SecretId": "AKIDGSN2VjJkZ7pIYzcdo0zjDCKCnQpEhXbW", + "SecretKey": "rQDI7fuoUyIEvLT5RWKqkUyGQJwBiU2P", + "SmsSdkAppid": "1400497500", + //ǩ + "Sign": "Ƴ", + "Region": "ap-guangzhou", + //ģ + "TemplateList": [ + { + //Ʊұ䶯֪ͨ + "ChangePhoneTemplateId": "900754", + //ʵ֤ + "CertificationTemplateId": "925734" + } + ] + }, + "UploadConfig": { + //ͷ + "avatar": { + //ϴ· D:/upload/admin/avatar + "uploadPath": "../upload/avatar", + //· + "requestPath": "/upload/avatar", + //ȡ· + "readPath": "https://znyc-rm-1306377152.cos.ap-guangzhou.myqcloud.com/", + + + //·ڸʽ yyyy/MM/dd + "dateTimeFormat": "", + //{û} + "format": "", + //ͼƬС 1M = 1 * 1024 * 1024 + "maxSize": 1048576, + //ϴ-1 + "limit": 1, + //ͼƬʽ + "contentType": [ "image/jpg", "image/png", "image/jpeg", "image/gif" ] + }, + //ĵͼƬ + "document": { + //ϴ· D:/upload/admin/document + "uploadPath": "../upload/document", + //· + "requestPath": "/images", + //·ڸʽ yyyy/MM/dd + "dateTimeFormat": "", + //{ĵ} + "format": "", + //ͼƬС 1M = 1 * 1024 * 1024 + "maxSize": 1048576, + //ϴ-1 + "limit": -1, + //ͼƬʽ + "contentType": [ "image/jpg", "image/png", "image/jpeg", "image/gif" ] + } + }, + "CosConfig": { + "secretId": "AKIDGMBk7D3cuvf8KFtGMBj00iALFsEJ7dsq", + "secretKey": "i9IBn8Bzav0pMcbJkunPjmY3HsCF2Zom", + "bucket": "Znyc-images-1306377152", + "region": "ap-guangzhou", + "allowPrefix": "a.jpg", + "durationSeconds": 1800, + "allowActions": [ + "name/cos:PutObject", + // ϴСϴ + "name/cos:PostObject", + // Ƭϴ + "name/cos:InitiateMultipartUpload", + "name/cos:ListMultipartUploads", + "name/cos:ListParts", + "name/cos:UploadPart", + "name/cos:CompleteMultipartUpload" + ] + }, + "WxConfig": { + //AppID(СID) + "AppId": "wx71f2b227f8eaf00a", + //AppSecret(СԿ) + "AppSecret": "bf868056d4e58f4b2831ff74308120ac", + "EnvVersion": "trial", + //΢Ŷ֪ͨģ + "WxTemplateList": [ + { + //Ʊұ䶯֪ͨ + "CurrencyChangeTemplate": "6YXRyjN8An9fcxqsZeyEJLn_fp9fA-ic1eksWqnSu-s", + //֪ͨ + "ApprovalResultsTemplate": "dm1yuO5nVqiRQyMWcS4VZOjOZY5rDCjhiqiUcueyMJc", + "CallFeedbackTemplate": "4-TN3LtOf5cUq_xhHg4Aymq3_t2ywbt4nljwxGEqhBk" + } + ], + //ں + ////΢Źں + "WeixinAppId": "wx78474b2ab9ac3e6c", + "WxOpenAppSecret": "a2349cf1dc0871e799109f0f824d38a3", + "WxOpenToken": "rzC0pRTuBznwd3", + "WxOpenEncodingAESKey": "Z9ifQKA8kvQjybOXuXl8I0r9cFHWJGwW2q5iE5e37AM", + //΢֧V3°棩 + "TenPayV3_MchId": "#{TenPayV3_MchId}#", + "TenPayV3_SubMchId": "#{TenPayV3_SubMchId}#", //̻ûп + "TenPayV3_Key": "#{TenPayV3_Key}#", + "TenPayV3_AppId": "#{TenPayV3_AppId}#", + "TenPayV3_AppSecret": "#{TenPayV3_AppSecret}#", + "TenPayV3_TenpayNotify": "#{TenPayV3_TenpayNotify}#", //http://YourDomainName/TenpayV3/PayNotifyUrl + //TenPayV3_WxOpenTenpayNotifyĬ TenPayV3_TenpayNotify ֵ "WxOpen" + "TenPayV3_WxOpenTenpayNotify": "#{TenPayV3_WxOpenTenpayNotify}#" //http://YourDomainName/TenpayV3/PayNotifyUrlWxOpen + }, + "LogConfig": { + /* + * https://nlog-project.org/config/ + * use + private readonly ILogger _logger; + constructor(ILogger logger) + { + _logger = logger; + } + _logger.LogDebug(1, ""); + + + + private readonly ILogger _logger; + constructor() + { + _logger = LogManager.GetLogger("loggerName"); + + _logger = LogManager.GetCurrentClassLogger(); + } + _logger.Error(""); + */ + "nLog": { + "extensions": { + "NLog.Web.AspNetCore": { + "assembly": "NLog.Web.AspNetCore" + } + }, + "targets": { + // + "debug": { + "type": "File", + "fileName": "../logs/debug-${shortdate}.log", + "layout": "${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}" + }, + // + "warn": { + "type": "File", + "fileName": "../logs/warn-${shortdate}.log", + "layout": "${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}" + }, + // + "error": { + "type": "File", + "fileName": "../logs/error-${shortdate}.log", + "layout": "${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}" + } + }, + "rules": [ + { + "logger": "*", + "minLevel": "Trace", + "maxlevel": "Debug", + "writeTo": "debug" + }, + { + "logger": "*", + "minLevel": "Info", + "maxlevel": "Warn", + "writeTo": "warn" + }, + { + "logger": "*", + "minLevel": "Error", + "maxlevel": "Fatal", + "writeTo": "error" + }, + //Ҫ΢־ + { + "logger": "Microsoft.*", + "maxLevel": "Info", + "final": "true" + } + ] + } + }, + "RabbitMQConfig": { + "Connection": "81.71.148.57", + "UserName": "znyc", + "Password": "znyc2021", + "RetryCount": 3 + }, + "HangfireConfig": { + "Login": "znyc", + "Password": "znyc2021" + } + +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/configs/appconfig.Production.json b/src/Znyc.Recruitment.Api/configs/appconfig.Production.json new file mode 100644 index 0000000..e3298f4 --- /dev/null +++ b/src/Znyc.Recruitment.Api/configs/appconfig.Production.json @@ -0,0 +1,291 @@ +{ + //Api地址 + "urls": [ "http://*:80" ], + //跨域地址 + "corUrls": [ "http://*:9000" ], + //Swagger文档 + "swagger": false, + //统一认证授权服务器 + "IdentityServer": { + //启用 + "enable": true, + + "url": "" + }, + //面向切面编程 + "aop": { + //事物 + "transaction": true + }, + //限流 + "rateLimit": false, + //百度ocr + "BaiduConfig": { + "AppID": "23954973", + "ApiKey": "zCU8ZvomVm3upmIlI9kY8svK", + "SecretKey": "H4m3G8adKbRpIICyKtX8rqjHmjCugld9" + }, + "RedisConfig": { + //连接字符串 + "connectionString": "172.16.0.17:6379" + //限流连接字符串 + //"connectionStringRateLimit": "172.16.0.17:6379" + }, + "DbConfig": { + //监听所有操作 + "monitorCommand": false, + //监听Curd操作 + "curd": false, + //数据库类型 MySql = 0, + "type": 0, + //连接字符串 + "connectionString": "Server=172.16.0.6; Port=3306; Database=znyc_recruitment; Uid=znyc; Pwd=UhcAoRR5A3hnt^%U; Charset=utf8mb4;", + //从库 + "slaveConnectionStringList": [ + //Server=172.16.0.6; Port=3306; Database=Znyc_recruitment; Uid=Znyc; Pwd=UhcAoRR5A3hnt^%U; Charset=utf8mb4 + ] + }, + "JwtConfig": { + //发行者 + "issuer": "Znyc", + //订阅者 + "audience": "Znyc", + //密钥 + "securityKey": "ertJKl#521*a@790asD&1#", + //有效期(分钟) 2880 = 2天 + "expires": 2880, + //刷新有效期(分钟) 4320 = 3天 + "refreshExpires": 4320 + }, + "RateLimiting": { + /* + https://github.com/stefanprodan/AspNetCoreRateLimit/wiki/IpRateLimitMiddleware + https://github.com/stefanprodan/AspNetCoreRateLimit/wiki/Using-Redis-as-a-distributed-counter-store + */ + "IpRateLimiting": { + "EnableEndpointRateLimiting": true, + "StackBlockedRequests": false, + "RealIpHeader": "X-Real-IP", + "ClientIdHeader": "X-ClientId", + "IpWhitelist": [], // "127.0.0.1" + "EndpointWhitelist": [ "get:/api/auth/refresh" ], // "get:/api/a", "*:/api/b" + "ClientWhitelist": [], + "HttpStatusCode": 429, + "QuotaExceededResponse": { + "Content": "{{\"code\":429,\"msg\":\"访问过于频繁!\"}}", + "ContentType": "application/json", + "StatusCode": 429 + }, + "GeneralRules": [ + { + "Endpoint": "*", + "Period": "1s", + "Limit": 3 + }, + { + "Endpoint": "*", + "Period": "10m", + "Limit": 200 + } + ] + } + }, + "SMSConfig": { + "SecretId": "AKIDGSN2VjJkZ7pIYzcdo0zjDCKCnQpEhXbW", + "SecretKey": "rQDI7fuoUyIEvLT5RWKqkUyGQJwBiU2P", + "SmsSdkAppid": "1400497500", + //短信签名 + "Sign": "众能云车", + "Region": "ap-guangzhou", + //短信模板 + "TemplateList": [ + { + //云币变动通知 + "ChangePhoneTemplateId": "900754", + //实名认证 + "CertificationTemplateId": "925734" + } + ] + }, + "UploadConfig": { + //头像 + "avatar": { + //上传路径 D:/upload/admin/avatar + "uploadPath": "../upload/avatar", + //请求路径 + "requestPath": "/upload/avatar", + //读取路径 + "readPath": "https://Znyc-rm-1306377152.cos.ap-guangzhou.myqcloud.com/", + + //路径日期格式 yyyy/MM/dd + "dateTimeFormat": "", + //{用户编号} + "format": "", + //图片大小不超过 1M = 1 * 1024 * 1024 + "maxSize": 1048576, + //最大允许上传张数,-1不限制 + "limit": 1, + //图片格式 + "contentType": [ "image/jpg", "image/png", "image/jpeg", "image/gif" ] + }, + //文档图片 + "document": { + //上传路径 D:/upload/admin/document + "uploadPath": "../upload/document", + //请求路径 + "requestPath": "/images", + //路径日期格式 yyyy/MM/dd + "dateTimeFormat": "", + //{文档编号} + "format": "", + //图片大小不超过 1M = 1 * 1024 * 1024 + "maxSize": 1048576, + //最大允许上传张数,-1不限制 + "limit": -1, + //图片格式 + "contentType": [ "image/jpg", "image/png", "image/jpeg", "image/gif" ] + }, + + "secretId": "AKIDGSN2VjJkZ7pIYzcdo0zjDCKCnQpEhXbW", + "secretKey": "rQDI7fuoUyIEvLT5RWKqkUyGQJwBiU2P", + "bucket": "Znyc-rm-1306377152", + "region": "ap-guangzhou" + }, + "CosConfig": { + "secretId": "AKIDGMBk7D3cuvf8KFtGMBj00iALFsEJ7dsq", + "secretKey": "i9IBn8Bzav0pMcbJkunPjmY3HsCF2Zom", + "bucket": "Znyc-images-1306377152", + "region": "ap-guangzhou", + "allowPrefix": "a.jpg", + "durationSeconds": 1800, + "allowActions": [ + "name/cos:PutObject", + // 表单上传、小程序上传 + "name/cos:PostObject", + // 分片上传 + "name/cos:InitiateMultipartUpload", + "name/cos:ListMultipartUploads", + "name/cos:ListParts", + "name/cos:UploadPart", + "name/cos:CompleteMultipartUpload" + ] + }, + + "WxConfig": { + //AppID(小程序ID) + "AppId": "wx71f2b227f8eaf00a", + //AppSecret(小程序密钥) + "AppSecret": "bf868056d4e58f4b2831ff74308120ac", + "EnvVersion": "release", + //微信订阅通知模板 + "WxTemplateList": [ + { + //云币变动通知 + "CurrencyChangeTemplate": "6YXRyjN8An9fcxqsZeyEJLn_fp9fA-ic1eksWqnSu-s", + //审批结果通知 + "ApprovalResultsTemplate": "dm1yuO5nVqiRQyMWcS4VZOjOZY5rDCjhiqiUcueyMJc", + "CallFeedbackTemplate": "4-TN3LtOf5cUq_xhHg4Aymq3_t2ywbt4nljwxGEqhBk" + } + ], + //公众号 + "WeixinAppId": "wx78474b2ab9ac3e6c", + "WxOpenAppSecret": "a2349cf1dc0871e799109f0f824d38a3", + "WxOpenToken": "rzC0pRTuBznwd3", + "WxOpenEncodingAESKey": "Z9ifQKA8kvQjybOXuXl8I0r9cFHWJGwW2q5iE5e37AM", + //微信支付V3(新版) + "TenPayV3_MchId": "#{TenPayV3_MchId}#", + "TenPayV3_SubMchId": "#{TenPayV3_SubMchId}#", //子商户,没有可留空 + "TenPayV3_Key": "#{TenPayV3_Key}#", + "TenPayV3_AppId": "#{TenPayV3_AppId}#", + "TenPayV3_AppSecret": "#{TenPayV3_AppSecret}#", + "TenPayV3_TenpayNotify": "#{TenPayV3_TenpayNotify}#", //http://YourDomainName/TenpayV3/PayNotifyUrl + //如果不设置TenPayV3_WxOpenTenpayNotify,默认在 TenPayV3_TenpayNotify 的值最后加上 "WxOpen" + "TenPayV3_WxOpenTenpayNotify": "#{TenPayV3_WxOpenTenpayNotify}#" //http://YourDomainName/TenpayV3/PayNotifyUrlWxOpen + }, + "LogConfig": { + /* + * https://nlog-project.org/config/ + * use + private readonly ILogger _logger; + constructor(ILogger logger) + { + _logger = logger; + } + _logger.LogDebug(1, "调试"); + + 或 + + private readonly ILogger _logger; + constructor() + { + _logger = LogManager.GetLogger("loggerName"); + 或 + _logger = LogManager.GetCurrentClassLogger(); + } + _logger.Error("错误"); + */ + "nLog": { + "extensions": { + "NLog.Web.AspNetCore": { + "assembly": "NLog.Web.AspNetCore" + } + }, + "targets": { + //调试 + "debug": { + "type": "File", + "fileName": "../logs/debug-${shortdate}.log", + "layout": "${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}" + }, + //警告 + "warn": { + "type": "File", + "fileName": "../logs/warn-${shortdate}.log", + "layout": "${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}" + }, + //错误 + "error": { + "type": "File", + "fileName": "../logs/error-${shortdate}.log", + "layout": "${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}" + } + }, + "rules": [ + { + "logger": "*", + "minLevel": "Trace", + "maxlevel": "Debug", + "writeTo": "debug" + }, + { + "logger": "*", + "minLevel": "Info", + "maxlevel": "Warn", + "writeTo": "warn" + }, + { + "logger": "*", + "minLevel": "Error", + "maxlevel": "Fatal", + "writeTo": "error" + }, + //跳过不重要的微软日志 + { + "logger": "Microsoft.*", + "maxLevel": "Info", + "final": "true" + } + ] + } + }, + "RabbitMQConfig": { + "Connection": "172.16.0.2", + "UserName": "root", + "Password": "znyc20219696", + "RetryCount": 3 + }, + "HangfireConfig": { + "Login": "root", + "Password": "5lh!#q6I" + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/configs/appconfig.Staging.json b/src/Znyc.Recruitment.Api/configs/appconfig.Staging.json new file mode 100644 index 0000000..4c8b6d3 --- /dev/null +++ b/src/Znyc.Recruitment.Api/configs/appconfig.Staging.json @@ -0,0 +1,295 @@ +{ + //Apiַ + "urls": [ "http://*:80" ], + //ַ + "corUrls": [ "http://*:9000" ], + //Swaggerĵ + "swagger": false, + //ͳһ֤Ȩ + "IdentityServer": { + // + "enable": false, + "url": "" + }, + // + "aop": { + // + "transaction": true + }, + // + "rateLimit": false, + "env": "p/s/d", //ٶocr + "BaiduConfig": { + "AppID": "23954973", + "ApiKey": "zCU8ZvomVm3upmIlI9kY8svK", + "SecretKey": "H4m3G8adKbRpIICyKtX8rqjHmjCugld9" + }, + "RedisConfig": { + //ַ + "connectionString": "10.0.8.16:46379,password=dfeFEgeGH/,defaultdatabase=0" + //"connectionString": "81.71.148.57:46379,password=dfeFEgeGH/,defaultdatabase=0" + //ַ + //"connectionStringRateLimit": "49.234.103.173:46379,password=123456789,defaultdatabase=0" + //"connectionStringRateLimit": "81.71.15.59:46379,password=kl7$#DKbs4Gd,defaultdatabase=0" + }, + "DbConfig": { + //в + "monitorCommand": false, + //Curd + "curd": true, + //ݿ MySql = 0, SqlServer = 1, PostgreSQL = 2, Oracle = 3, Sqlite = 4, OdbcOracle = 5, OdbcSqlServer = 6, OdbcMySql = 7, OdbcPostgreSQL = 8, Odbc = 9, OdbcDameng = 10, MsAccess = 11 + "type": 0, + //ַ + "connectionString": "Server=10.0.8.16; Port=43306; Database=znyc_recruitment; Uid=znyc; Pwd=bIQISVSO; Charset=utf8mb4;SslMode=none;Max pool size=10", + //"connectionString": "Server=81.71.148.57; Port=43306; Database=znyc_recruitment; Uid=znyc; Pwd=bIQISVSO; Charset=utf8mb4", + //ӿ + "slaveConnectionStringList": [ + //"Server=49.234.221.158; Port=43306; Database=znyc_test; Uid=znyc; Pwd=987654321;Charset=utf8mb4", + ] + }, + "JwtConfig": { + // + "issuer": "znyc", + // + "audience": "znyc", + //Կ + "securityKey": "ertJKl#521*a@790asD&1#", + //Ч() 2880 = 2 + "expires": 2880, + //ˢЧ() 4320 = 3 + "refreshExpires": 4320 + }, + "RateLimiting": { + /* + https://github.com/stefanprodan/AspNetCoreRateLimit/wiki/IpRateLimitMiddleware + https://github.com/stefanprodan/AspNetCoreRateLimit/wiki/Using-Redis-as-a-distributed-counter-store + */ + "IpRateLimiting": { + "EnableEndpointRateLimiting": true, + "StackBlockedRequests": false, + "RealIpHeader": "X-Real-IP", + "ClientIdHeader": "X-ClientId", + "IpWhitelist": [], // "127.0.0.1" + "EndpointWhitelist": [ "get:/api/auth/refresh" ], // "get:/api/a", "*:/api/b" + "ClientWhitelist": [], + "HttpStatusCode": 429, + "QuotaExceededResponse": { + "Content": "{{\"code\":429,\"msg\":\"ʹƵ\"}}", + "ContentType": "application/json", + "StatusCode": 429 + }, + "GeneralRules": [ + { + "Endpoint": "*", + "Period": "1s", + "Limit": 3 + }, + { + "Endpoint": "*", + "Period": "10m", + "Limit": 200 + } + ] + } + }, + "SMSConfig": { + "SecretId": "AKIDGSN2VjJkZ7pIYzcdo0zjDCKCnQpEhXbW", + "SecretKey": "rQDI7fuoUyIEvLT5RWKqkUyGQJwBiU2P", + "SmsSdkAppid": "1400497500", + //ǩ + "Sign": "Ƴ", + "Region": "ap-guangzhou", + //ģ + "TemplateList": [ + { + //Ʊұ䶯֪ͨ + "ChangePhoneTemplateId": "900754", + //ʵ֤ + "CertificationTemplateId": "925734" + } + ] + }, + "UploadConfig": { + //ͷ + "avatar": { + //ϴ· D:/upload/admin/avatar + "uploadPath": "../upload/avatar", + //· + "requestPath": "/upload/avatar", + //ȡ· + "readPath": "https://znyc-rm-1306377152.cos.ap-guangzhou.myqcloud.com/", + + //·ڸʽ yyyy/MM/dd + "dateTimeFormat": "", + //{û} + "format": "", + //ͼƬС 1M = 1 * 1024 * 1024 + "maxSize": 1048576, + //ϴ-1 + "limit": 1, + //ͼƬʽ + "contentType": [ "image/jpg", "image/png", "image/jpeg", "image/gif" ] + }, + //ĵͼƬ + "document": { + //ϴ· D:/upload/admin/document + "uploadPath": "../upload/document", + //· + "requestPath": "/images", + //·ڸʽ yyyy/MM/dd + "dateTimeFormat": "", + //{ĵ} + "format": "", + //ͼƬС 1M = 1 * 1024 * 1024 + "maxSize": 1048576, + //ϴ-1 + "limit": -1, + //ͼƬʽ + "contentType": [ "image/jpg", "image/png", "image/jpeg", "image/gif" ] + }, + + "secretId": "AKIDGSN2VjJkZ7pIYzcdo0zjDCKCnQpEhXbW", + "secretKey": "rQDI7fuoUyIEvLT5RWKqkUyGQJwBiU2P", + "bucket": "znyc-rm-1306377152", + "region": "ap-guangzhou" + }, + "CosConfig": { + "secretId": "AKIDGMBk7D3cuvf8KFtGMBj00iALFsEJ7dsq", + "secretKey": "i9IBn8Bzav0pMcbJkunPjmY3HsCF2Zom", + "bucket": "znyc-images-1306377152", + "region": "ap-guangzhou", + "allowPrefix": "a.jpg", + "durationSeconds": 1800, + "allowActions": [ + "name/cos:PutObject", + // ϴСϴ + "name/cos:PostObject", + // Ƭϴ + "name/cos:InitiateMultipartUpload", + "name/cos:ListMultipartUploads", + "name/cos:ListParts", + "name/cos:UploadPart", + "name/cos:CompleteMultipartUpload" + ] + }, + "WxConfig": { + //AppID(СID) + "AppId": "wx71f2b227f8eaf00a", + //AppSecret(СԿ) + "AppSecret": "bf868056d4e58f4b2831ff74308120ac", + "EnvVersion": "trial", + //΢Ŷ֪ͨģ + "WxTemplateList": [ + { + //Ʊұ䶯֪ͨ + "CurrencyChangeTemplate": "6YXRyjN8An9fcxqsZeyEJLn_fp9fA-ic1eksWqnSu-s", + //֪ͨ + "ApprovalResultsTemplate": "dm1yuO5nVqiRQyMWcS4VZOjOZY5rDCjhiqiUcueyMJc", + //Ƹ + "RecruitmentFoundTemplate": "KrAHbKwd4WOdVP8dj-qY4h7CpBgYZxDY7TLha5wSPBg", + //ְҵ + "CallFeedbackTemplate": "4-TN3LtOf5cUq_xhHg4Aymq3_t2ywbt4nljwxGEqhBk" + } + ], + //ں + "WeixinAppId": "wx78474b2ab9ac3e6c", + "WxOpenAppSecret": "a2349cf1dc0871e799109f0f824d38a3", + "WxOpenToken": "rzC0pRTuBznwd3", + "WxOpenEncodingAESKey": "Z9ifQKA8kvQjybOXuXl8I0r9cFHWJGwW2q5iE5e37AM", + //΢֧V3°棩 + "TenPayV3_MchId": "#{TenPayV3_MchId}#", + "TenPayV3_SubMchId": "#{TenPayV3_SubMchId}#", //̻ûп + "TenPayV3_Key": "#{TenPayV3_Key}#", + "TenPayV3_AppId": "#{TenPayV3_AppId}#", + "TenPayV3_AppSecret": "#{TenPayV3_AppSecret}#", + "TenPayV3_TenpayNotify": "#{TenPayV3_TenpayNotify}#", //http://YourDomainName/TenpayV3/PayNotifyUrl + //TenPayV3_WxOpenTenpayNotifyĬ TenPayV3_TenpayNotify ֵ "WxOpen" + "TenPayV3_WxOpenTenpayNotify": "#{TenPayV3_WxOpenTenpayNotify}#" //http://YourDomainName/TenpayV3/PayNotifyUrlWxOpen + }, + "LogConfig": { + /* + * https://nlog-project.org/config/ + * use + private readonly ILogger _logger; + constructor(ILogger logger) + { + _logger = logger; + } + _logger.LogDebug(1, ""); + + + + private readonly ILogger _logger; + constructor() + { + _logger = LogManager.GetLogger("loggerName"); + + _logger = LogManager.GetCurrentClassLogger(); + } + _logger.Error(""); + */ + "nLog": { + "extensions": { + "NLog.Web.AspNetCore": { + "assembly": "NLog.Web.AspNetCore" + } + }, + "targets": { + // + "debug": { + "type": "File", + "fileName": "../logs/debug-${shortdate}.log", + "layout": "${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}" + }, + // + "warn": { + "type": "File", + "fileName": "../logs/warn-${shortdate}.log", + "layout": "${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}" + }, + // + "error": { + "type": "File", + "fileName": "../logs/error-${shortdate}.log", + "layout": "${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}" + } + }, + "rules": [ + { + "logger": "*", + "minLevel": "Trace", + "maxlevel": "Debug", + "writeTo": "debug" + }, + { + "logger": "*", + "minLevel": "Info", + "maxlevel": "Warn", + "writeTo": "warn" + }, + { + "logger": "*", + "minLevel": "Error", + "maxlevel": "Fatal", + "writeTo": "error" + }, + //Ҫ΢־ + { + "logger": "Microsoft.*", + "maxLevel": "Info", + "final": "true" + } + ] + } + }, + "RabbitMQConfig": { + "Connection": "10.0.8.16", + "UserName": "znyc", + "Password": "znyc2021", + "RetryCount": 3 + }, + "HangfireConfig": { + "Login": "znyc", + "Password": "znyc2021" + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/nlog.Production.config b/src/Znyc.Recruitment.Api/nlog.Production.config new file mode 100644 index 0000000..e04c324 --- /dev/null +++ b/src/Znyc.Recruitment.Api/nlog.Production.config @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Znyc.Recruitment.Api/nlog.config b/src/Znyc.Recruitment.Api/nlog.config new file mode 100644 index 0000000..4b1e9cd --- /dev/null +++ b/src/Znyc.Recruitment.Api/nlog.config @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Znyc.Recruitment.Common/Attributes/MasterTableAttribute.cs b/src/Znyc.Recruitment.Common/Attributes/MasterTableAttribute.cs new file mode 100644 index 0000000..b47d665 --- /dev/null +++ b/src/Znyc.Recruitment.Common/Attributes/MasterTableAttribute.cs @@ -0,0 +1,19 @@ +using System; +using Znyc.Recruitment.Common.Const; + +namespace Znyc.Recruitment.Common.Attributes +{ + [AttributeUsage(AttributeTargets.Class)] + public class MasterTableAttribute : Attribute + { + public MasterTableAttribute(string name) + { + Name = DbConst.PrefixName + name; + } + + /// + /// 重定义统一平台用户表名 + /// + public string Name { get; } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Common/Attributes/SingleInstanceAttribute.cs b/src/Znyc.Recruitment.Common/Attributes/SingleInstanceAttribute.cs new file mode 100644 index 0000000..56836da --- /dev/null +++ b/src/Znyc.Recruitment.Common/Attributes/SingleInstanceAttribute.cs @@ -0,0 +1,12 @@ +using System; + +namespace Znyc.Recruitment.Common.Attributes +{ + /// + /// 单例注入 + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property)] + public class SingleInstanceAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Common/Attributes/SnowflakeAttribute.cs b/src/Znyc.Recruitment.Common/Attributes/SnowflakeAttribute.cs new file mode 100644 index 0000000..0312402 --- /dev/null +++ b/src/Znyc.Recruitment.Common/Attributes/SnowflakeAttribute.cs @@ -0,0 +1,9 @@ +using System; + +namespace Znyc.Recruitment.Common.Attributes +{ + [AttributeUsage(AttributeTargets.Property)] + public class SnowflakeAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Common/Attributes/TransactionAttribute.cs b/src/Znyc.Recruitment.Common/Attributes/TransactionAttribute.cs new file mode 100644 index 0000000..92203e9 --- /dev/null +++ b/src/Znyc.Recruitment.Common/Attributes/TransactionAttribute.cs @@ -0,0 +1,23 @@ +using FreeSql; +using System; +using System.Data; + +namespace Znyc.Recruitment.Common.Attributes +{ + /// + /// 启用事物 + /// + [AttributeUsage(AttributeTargets.Method)] + public class TransactionAttribute : Attribute + { + /// + /// 事务传播方式 REQUIRED + /// + public Propagation Propagation { get; set; } + + /// + /// 事务隔离级别 + /// + public IsolationLevel? IsolationLevel { get; set; } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Common/Auth/ClaimAttributes.cs b/src/Znyc.Recruitment.Common/Auth/ClaimAttributes.cs new file mode 100644 index 0000000..adc6366 --- /dev/null +++ b/src/Znyc.Recruitment.Common/Auth/ClaimAttributes.cs @@ -0,0 +1,48 @@ +namespace Znyc.Recruitment.Common.Auth +{ + /// + /// Claim属性 + /// + public static class ClaimAttributes + { + /// + /// 用户Id + /// + public const string UserId = "id"; + + /// + /// 姓名 + /// + public const string UserName = "nn"; + + /// + /// 刷新有效期 + /// + public const string RefreshExpires = "re"; + + /// + /// 微信认证Id + /// + public const string OpenId = "oid"; + + /// + /// 权限id + /// + public const string RoleId = "rid"; + + /// + /// 开放平台Id(区分用户唯一性) + /// + public const string UnionId = "uid"; + + /// + /// 头像url + /// + public const string AvatarUrl = "avatarurl"; + + /// + /// SessionKey + /// + public const string SessionKey = "sessionKey"; + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Common/Auth/IUser.cs b/src/Znyc.Recruitment.Common/Auth/IUser.cs new file mode 100644 index 0000000..58b00d0 --- /dev/null +++ b/src/Znyc.Recruitment.Common/Auth/IUser.cs @@ -0,0 +1,46 @@ +namespace Znyc.Recruitment.Common.Auth +{ + /// + /// 用户信息接口 + /// + public interface IUser + { + /// + /// 主键 + /// + long Id { get; } + + /// + /// 权限Id + /// + string RoleId { get; } + + /// + /// 昵称 + /// + string UserName { get; } + + /// + /// 微信唯一用户信息 + /// + string OpenId { get; } + + /// + /// 头像 + /// + string AvatarUrl { get; } + + /// + /// SessionKey + /// + string SessionKey { get; } + + /// + /// UnionId + /// + string UnionId { get; } + + + + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Common/Auth/IUserToken.cs b/src/Znyc.Recruitment.Common/Auth/IUserToken.cs new file mode 100644 index 0000000..fbddcd5 --- /dev/null +++ b/src/Znyc.Recruitment.Common/Auth/IUserToken.cs @@ -0,0 +1,11 @@ +using System.Security.Claims; + +namespace Znyc.Recruitment.Common.Auth +{ + public interface IUserToken + { + string Create(Claim[] claims); + + Claim[] Decode(string jwtToken); + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Common/Auth/User.cs b/src/Znyc.Recruitment.Common/Auth/User.cs new file mode 100644 index 0000000..aa625f7 --- /dev/null +++ b/src/Znyc.Recruitment.Common/Auth/User.cs @@ -0,0 +1,146 @@ +using Microsoft.AspNetCore.Http; +using Znyc.Recruitment.Common.Helpers; + +namespace Znyc.Recruitment.Common.Auth +{ + /// + /// 用户信息 + /// + public class User : IUser + { + private readonly IHttpContextAccessor _accessor; + + public User(IHttpContextAccessor accessor) + { + _accessor = accessor; + } + + /// + /// 用户Id + /// + public virtual long Id + { + get + { + System.Security.Claims.Claim id = _accessor?.HttpContext?.User?.FindFirst(ClaimAttributes.UserId); + if (id != null && id.Value.NotNull()) + { + return id.Value.ToLong(); + } + + return 0; + } + } + + /// + /// 权限Id + /// + public string RoleId + { + get + { + System.Security.Claims.Claim name = _accessor?.HttpContext?.User?.FindFirst(ClaimAttributes.RoleId); + + if (name != null && name.Value.NotNull()) + { + return name.Value; + } + + return ""; + } + } + + /// + /// 昵称 + /// + public string UserName + { + get + { + System.Security.Claims.Claim name = _accessor?.HttpContext?.User?.FindFirst(ClaimAttributes.UserName); + + if (name != null && name.Value.NotNull()) + { + return name.Value; + } + + return ""; + } + } + + /// + /// OpenId + /// + public string OpenId + { + get + { + System.Security.Claims.Claim name = _accessor?.HttpContext?.User?.FindFirst(ClaimAttributes.OpenId); + + if (name != null && name.Value.NotNull()) + { + return name.Value; + } + + return ""; + } + } + + /// + /// UnionId + /// + public string UnionId + { + get + { + System.Security.Claims.Claim name = _accessor?.HttpContext?.User?.FindFirst(ClaimAttributes.UnionId); + + if (name != null && name.Value.NotNull()) + { + return name.Value; + } + + return ""; + } + } + + /// + /// AvatarUrl + /// + public string AvatarUrl + { + get + { + System.Security.Claims.Claim name = _accessor?.HttpContext?.User?.FindFirst(ClaimAttributes.AvatarUrl); + + if (name != null && name.Value.NotNull()) + { + return name.Value; + } + + return ""; + } + } + + /// + /// SessionKey + /// + public string SessionKey + { + get + { + System.Security.Claims.Claim name = _accessor?.HttpContext?.User?.FindFirst(ClaimAttributes.SessionKey); + + if (name != null && name.Value.NotNull()) + { + return name.Value; + } + + return ""; + } + } + + + + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Common/Auth/UserToken.cs b/src/Znyc.Recruitment.Common/Auth/UserToken.cs new file mode 100644 index 0000000..b47ddb5 --- /dev/null +++ b/src/Znyc.Recruitment.Common/Auth/UserToken.cs @@ -0,0 +1,51 @@ +using Microsoft.IdentityModel.Tokens; +using System; +using System.IdentityModel.Tokens.Jwt; +using System.Linq; +using System.Security.Claims; +using System.Text; +using Znyc.Recruitment.Common.Attributes; +using Znyc.Recruitment.Common.Configs; +using Znyc.Recruitment.Common.Extensions; + +namespace Znyc.Recruitment.Common.Auth +{ + [SingleInstance] + public class UserToken : IUserToken + { + //private readonly JwtConfig _jwtConfig; + private readonly AppConfig _appConfig; + + public UserToken(AppConfig appConfig) + { + _appConfig = appConfig; + + } + + public string Create(Claim[] claims) + { + SymmetricSecurityKey key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_appConfig.JwtConfig.SecurityKey)); + SigningCredentials signingCredentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); + string timestamp = DateTime.Now.AddMinutes(_appConfig.JwtConfig.Expires + _appConfig.JwtConfig.RefreshExpires).ToTimestamp() + .ToString(); + claims = claims.Append(new Claim(ClaimAttributes.RefreshExpires, timestamp)).ToArray(); + + JwtSecurityToken token = new JwtSecurityToken( + _appConfig.JwtConfig.Issuer, + _appConfig.JwtConfig.Audience, + claims, + DateTime.Now, + DateTime.Now.AddMinutes(_appConfig.JwtConfig.Expires), + signingCredentials + ); + return new JwtSecurityTokenHandler().WriteToken(token); + } + + public Claim[] Decode(string jwtToken) + { + JwtSecurityTokenHandler jwtSecurityTokenHandler = new JwtSecurityTokenHandler(); + JwtSecurityToken jwtSecurityToken = jwtSecurityTokenHandler.ReadJwtToken(jwtToken); + return jwtSecurityToken?.Claims?.ToArray(); + } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Common/BaseModel/Entity.cs b/src/Znyc.Recruitment.Common/BaseModel/Entity.cs new file mode 100644 index 0000000..a770784 --- /dev/null +++ b/src/Znyc.Recruitment.Common/BaseModel/Entity.cs @@ -0,0 +1,25 @@ +using FreeSql.DataAnnotations; +using System.ComponentModel; +using Znyc.Recruitment.Common.Attributes; + +namespace Znyc.Recruitment.Common.BaseModel +{ + public interface IEntity + { + } + + public class Entity : IEntity + { + /// + /// 编号 + /// + [Description("主键Id")] + [Snowflake] + [Column(Position = 1, IsIdentity = false, IsPrimary = true)] + public virtual TKey Id { get; set; } + } + + public class Entity : Entity + { + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Common/BaseModel/EntityAdd.cs b/src/Znyc.Recruitment.Common/BaseModel/EntityAdd.cs new file mode 100644 index 0000000..13f93f4 --- /dev/null +++ b/src/Znyc.Recruitment.Common/BaseModel/EntityAdd.cs @@ -0,0 +1,39 @@ +using FreeSql.DataAnnotations; +using System; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; + +namespace Znyc.Recruitment.Common.BaseModel +{ + /// + /// 实体创建审计 + /// + public class EntityAdd : Entity, IEntityAdd where TKey : struct + { + /// + /// 创建者 + /// + [Description("创建者")] + [Column(Position = -2, CanUpdate = false)] + [MaxLength(50)] + public string CreatedUserName { get; set; } + + /// + /// 创建者Id + /// + [Description("创建者Id")] + [Column(Position = -3, CanUpdate = false)] + public TKey CreatedUserId { get; set; } + + /// + /// 创建时间 + /// + [Description("创建时间")] + [Column(Position = -1, CanUpdate = false, ServerTime = DateTimeKind.Local)] + public DateTime CreatedTime { get; set; } + } + + public class EntityAdd : EntityAdd + { + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Common/BaseModel/EntityBase.cs b/src/Znyc.Recruitment.Common/BaseModel/EntityBase.cs new file mode 100644 index 0000000..72989d3 --- /dev/null +++ b/src/Znyc.Recruitment.Common/BaseModel/EntityBase.cs @@ -0,0 +1,55 @@ +using FreeSql.DataAnnotations; +using System; +using System.ComponentModel; + +namespace Znyc.Recruitment.Common.BaseModel +{ + /// + /// 实体审计 + /// + public class EntityBase : Entity, IEntitySoftDelete, IEntityAdd, IEntityUpdate + where TKey : struct + { + /// + /// 创建者Id + /// + [Description("创建者Id")] + [Column(Position = -1, CanUpdate = false)] + public TKey CreatedUserId { get; set; } + + /// + /// 创建时间 + /// + [Description("创建时间")] + [Column(Position = -2, CanUpdate = false, ServerTime = DateTimeKind.Local)] + public DateTime CreatedTime { get; set; } + + + /// + /// 修改者Id + /// + [Description("修改者Id")] + [Column(Position = -3, CanInsert = false)] + public TKey ModifiedUserId { get; set; } + + /// + /// 修改时间 + /// + [Description("修改时间")] + [Column(Position = -4, CanInsert = false, ServerTime = DateTimeKind.Local)] + public DateTime ModifiedTime { get; set; } + + /// + /// 是否删除 + /// + [Description("是否删除")] + [Column(Position = -5)] + public bool IsDeleted { get; set; } = false; + + + } + + public class EntityBase : EntityBase + { + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Common/BaseModel/EntitySoftDelete.cs b/src/Znyc.Recruitment.Common/BaseModel/EntitySoftDelete.cs new file mode 100644 index 0000000..a385a6a --- /dev/null +++ b/src/Znyc.Recruitment.Common/BaseModel/EntitySoftDelete.cs @@ -0,0 +1,22 @@ +using FreeSql.DataAnnotations; +using System.ComponentModel; + +namespace Znyc.Recruitment.Common.BaseModel +{ + /// + /// 实体软删除 + /// + public class EntitySoftDelete : Entity, IEntitySoftDelete + { + /// + /// 是否删除 + /// + [Description("是否删除")] + [Column(Position = -1)] + public bool IsDeleted { get; set; } = false; + } + + public class EntitySoftDelete : EntitySoftDelete + { + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Common/BaseModel/EntityUpdate.cs b/src/Znyc.Recruitment.Common/BaseModel/EntityUpdate.cs new file mode 100644 index 0000000..4ef853d --- /dev/null +++ b/src/Znyc.Recruitment.Common/BaseModel/EntityUpdate.cs @@ -0,0 +1,39 @@ +using FreeSql.DataAnnotations; +using System; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; + +namespace Znyc.Recruitment.Common.BaseModel +{ + /// + /// 实体修改审计 + /// + public class EntityUpdate : Entity, IEntityUpdate where TKey : struct + { + /// + /// 修改者 + /// + [Description("修改者")] + [Column(Position = -2, CanInsert = false)] + [MaxLength(50)] + public string ModifiedUserName { get; set; } + + /// + /// 修改者Id + /// + [Description("修改者Id")] + [Column(Position = -3, CanInsert = false)] + public TKey ModifiedUserId { get; set; } + + /// + /// 修改时间 + /// + [Description("修改时间")] + [Column(Position = -1, CanInsert = false, ServerTime = DateTimeKind.Local)] + public DateTime ModifiedTime { get; set; } + } + + public class EntityUpdate : EntityUpdate + { + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Common/BaseModel/EntityVersion.cs b/src/Znyc.Recruitment.Common/BaseModel/EntityVersion.cs new file mode 100644 index 0000000..98948ba --- /dev/null +++ b/src/Znyc.Recruitment.Common/BaseModel/EntityVersion.cs @@ -0,0 +1,22 @@ +using FreeSql.DataAnnotations; +using System.ComponentModel; + +namespace Znyc.Recruitment.Common.BaseModel +{ + /// + /// 实体版本 + /// + public class EntityVersion : Entity, IEntityVersion + { + /// + /// 版本 + /// + [Description("版本")] + [Column(Position = -1, IsVersion = true)] + public int Version { get; set; } + } + + public class EntityVersion : EntityVersion + { + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Common/BaseModel/IEntityAdd.cs b/src/Znyc.Recruitment.Common/BaseModel/IEntityAdd.cs new file mode 100644 index 0000000..abe651c --- /dev/null +++ b/src/Znyc.Recruitment.Common/BaseModel/IEntityAdd.cs @@ -0,0 +1,10 @@ +using System; + +namespace Znyc.Recruitment.Common.BaseModel +{ + public interface IEntityAdd where TKey : struct + { + TKey CreatedUserId { get; set; } + DateTime CreatedTime { get; set; } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Common/BaseModel/IEntitySoftDelete.cs b/src/Znyc.Recruitment.Common/BaseModel/IEntitySoftDelete.cs new file mode 100644 index 0000000..8b09201 --- /dev/null +++ b/src/Znyc.Recruitment.Common/BaseModel/IEntitySoftDelete.cs @@ -0,0 +1,10 @@ +namespace Znyc.Recruitment.Common.BaseModel +{ + public interface IEntitySoftDelete + { + /// + /// 是否删除 + /// + bool IsDeleted { get; set; } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Common/BaseModel/IEntityUpdate.cs b/src/Znyc.Recruitment.Common/BaseModel/IEntityUpdate.cs new file mode 100644 index 0000000..e85b358 --- /dev/null +++ b/src/Znyc.Recruitment.Common/BaseModel/IEntityUpdate.cs @@ -0,0 +1,10 @@ +using System; + +namespace Znyc.Recruitment.Common.BaseModel +{ + public interface IEntityUpdate where TKey : struct + { + TKey ModifiedUserId { get; set; } + DateTime ModifiedTime { get; set; } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Common/BaseModel/IEntityVersion.cs b/src/Znyc.Recruitment.Common/BaseModel/IEntityVersion.cs new file mode 100644 index 0000000..fd3e91a --- /dev/null +++ b/src/Znyc.Recruitment.Common/BaseModel/IEntityVersion.cs @@ -0,0 +1,10 @@ +namespace Znyc.Recruitment.Common.BaseModel +{ + public interface IEntityVersion + { + /// + /// 版本 + /// + int Version { get; set; } + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Common/Cache/CacheKey.cs b/src/Znyc.Recruitment.Common/Cache/CacheKey.cs new file mode 100644 index 0000000..a61a575 --- /dev/null +++ b/src/Znyc.Recruitment.Common/Cache/CacheKey.cs @@ -0,0 +1,235 @@ +using System.ComponentModel; + +namespace Znyc.Recruitment.Common.Cache +{ + /// + /// 缓存键 + /// + public static class CacheKey + { + /// + /// 用户权限 admin:user:用户主键:permissions + /// + [Description("用户权限")] public const string UserPermissions = "user:{0}:permissions"; + + /// + /// 单条字典 + /// + [Description("字典")] public const string Dictionary = "dictionary:get:{0}"; + + /// + /// 字典列表 + /// + [Description("字典列表")] public const string DictionaryList = "dictionary:list"; + + /// + /// 行业岗位(树状) + /// + [Description("行业岗位(树状)")] public const string IndustryJobsList = "industryjobs:list"; + + + + /// + /// 省市区(树状) + /// + [Description("省市区(树状)")] public const string CityEncyclopedia = "CityEncyclopedia:list"; + + + /// + /// 行业岗位(全部) + /// + [Description("行业岗位")] public const string AllIndustryJobs = "allindustryjobs:list"; + + /// + /// 省市列表树状 + /// + [Description("省市县")] public const string RegionList = "region:list"; + + /// + /// 置顶求职信息列表 + /// + [Description("求职")] public const string ApplyJob = "applyjob:top:list"; + + /// + /// 置顶招聘信息列表 + /// + [Description("招聘")] public const string Recruitment = "recruitment:top:list"; + + /// + /// 云币列表 + /// + [Description("云币列表")] public const string CurrencyIntro = "currency:intro:{0}"; + + /// + /// 验证码 verify:code: + /// + [Description("验证码")] public const string VerifyCodeKey = "verify:code:{0}"; + + /// + /// 收藏求职列表 + /// + [Description("收藏求职列表")] public const string ApplyCollectionList = "collection:applylist:{0}"; + + /// + /// 收藏求职列表 + /// + [Description("收藏求职列表")] public const string RecruitmentCollectionList = "collection:recruitmentlist:{0}"; + + /// + /// 收藏求职列表 + /// + [Description("关注公众号unionId列表")] public const string FollowPublicUnionId = "followpublic:unionid"; + + /// + /// 百度token + /// + [Description("百度token")] public const string BaiduAccessToken = "token:baidu:{0}"; + + /// + /// 微信token + /// + [Description("微信token")] public const string WxAccessToken = "token:weixin:{0}"; + + /// + /// 实名认证信息 + /// + [Description("实名认证信息")] public const string Certification = "certification:{0}"; + + /// + /// 广告图片 + /// + [Description("广告图片")] public const string BannerList = "banner:list"; + + /// + /// 活动图片 + /// + [Description("活动图片")] public const string ActivityList = "activity:list"; + + /// + /// 物流公司 + /// + [Description("物流公司")] public const string ShippingList = "shipping:list"; + + /// + /// 商品品牌 + /// + [Description("商品品牌")] public const string ProductBrandList = "product:brand:list"; + + /// + /// 商品品牌 + /// + [Description("商品库存")] public const string ProudctWarehouseList = "product:warehouse:list"; + + /// + /// 商品分类 + /// + [Description("商品分类")] public const string ProductCategoryList = "product:category:list"; + + /// + /// 商品图片 + /// + [Description("商品图片")] public const string ProductPicList = "product:pic:list"; + + /// + /// 充值金额信息 + /// + [Description("充值金额信息")] public const string ProductInfoList = "productinfo:list"; + + /// + /// 充值活动信息 + /// + [Description("充值活动信息")] public const string RechargeList = "recharge:list"; + + /// + /// 用户信息 + /// + [Description("用户信息")] public const string User = "user:{0}"; + + /// + /// 用户签到信息 + /// + [Description("用户签到信息")] public const string UserSign = "usersign:{0}:{1}"; + + /// + /// 求职浏览量信息 + /// + [Description("求职浏览量信息")] public const string ApplyJobPageView = "pageviews:applyJob"; + + /// + /// 招聘浏览量信息 + /// + [Description("招聘浏览量信息")] public const string RecruitmentPageView = "pageviews:recruitment"; + + /// + /// 用户未读信息 + /// + [Description("用户未读信息")] public const string UnreadMessage = "unread:number:{0}"; + + + /// + /// 求职列表 + /// + [Description("求职列表")] public const string ApplyList = "applylist:{0}"; + + /// + /// 招聘列表 + /// + [Description("招聘列表")] public const string RecruitmentList = "recruitmentlist:{0}"; + + /// + /// 新用户昵称信息 + /// + [Description("新用户昵称信息")] public const string RegisteredUserlist = "registeredUserlist"; + + /// + /// 邀请新用户信息 + /// + [Description("邀请新用户信息")] public const string InviteNewUser = "invite:newuser"; + + /// + /// 浏览求职信息 + /// + [Description("浏览求职信息")] public const string BrowseApplyJobList = "browse:applyjob:{0}"; + + /// + /// 浏览招聘信息 + /// + [Description("浏览招聘信息")] public const string BrowseRecruitmentList = "browse:recruitment:{0}"; + + /// + /// 邀请排行榜 + /// + [Description("邀请排行榜")] public const string InviteTop = "toplist:invite"; + + /// + /// 累计签到排行榜 + /// + [Description("累计签到排行榜")] public const string TotalSeriesDaysTop = "toplist:totalseriesdays"; + + /// + /// 积分排行榜 + /// + [Description("积分排行榜")] public const string AvailableCredits = "toplist:availablecredits"; + + /// + /// 充值排行榜 + /// + [Description("充值排行榜")] public const string BuyCurrency = "toplist:buycurrency"; + + /// + /// 通话排行榜 + /// + [Description("通话排行榜")] public const string CallPhone = "toplist:callphone"; + + /// + /// 活跃用户 + /// + [Description("活跃用户")] public const string ActiveUser = "activeuser:{0}"; + + /// + /// 是否首次登陆 + /// + [Description("是否首次登陆")] public const string IsFristLogin = "fristlogin:{0}"; + + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Common/Cache/IRedisCache.cs b/src/Znyc.Recruitment.Common/Cache/IRedisCache.cs new file mode 100644 index 0000000..3360a16 --- /dev/null +++ b/src/Znyc.Recruitment.Common/Cache/IRedisCache.cs @@ -0,0 +1,380 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Znyc.Recruitment.Common.Cache +{ + /// + /// 缓存接口 + /// + public interface IRedisCache + { + /// + /// 用于在 key 存在时删除 key + /// + /// 键 + long Del(params string[] key); + + /// + /// 用于在 key 存在时删除 key + /// + /// 键 + /// + Task DelAsync(params string[] key); + + /// + /// 用于在 key 模板存在时删除 + /// + /// key模板 + /// + Task DelByPatternAsync(string pattern); + + /// + /// 检查给定 key 是否存在 + /// + /// 键 + /// + bool Exists(string key); + + /// + /// 检查给定 key 是否存在 + /// + /// 键 + /// + Task ExistsAsync(string key); + + /// + /// 获取指定 key 的值 + /// + /// 键 + /// + string Get(string key); + + /// + /// 获取指定 key 的值 + /// + /// byte[] 或其他类型 + /// 键 + /// + T Get(string key); + + /// + /// 获取指定 key 的值 + /// + /// 键 + /// + Task GetAsync(string key); + + /// + /// 获取指定 key 的值 + /// + /// byte[] 或其他类型 + /// 键 + /// + Task GetAsync(string key); + + /// + /// 设置指定 key 的值,所有写入参数object都支持string | byte[] | 数值 | 对象 + /// + /// 键 + /// 值 + bool Set(string key, object value); + + /// + /// 设置指定 key 的值,所有写入参数object都支持string | byte[] | 数值 | 对象 + /// + /// 键 + /// 值 + /// 有效期 + bool Set(string key, object value, TimeSpan expire); + + /// + /// 设置指定 key 的值,所有写入参数object都支持string | byte[] | 数值 | 对象 + /// + /// 键 + /// 值 + /// + Task SetAsync(string key, object value); + + /// + /// 设置指定 key 的值,所有写入参数object都支持string | byte[] | 数值 | 对象 + /// + /// 键 + /// 值 + /// 有效期 + /// + Task SetAsync(string key, object value, TimeSpan expire); + + /// + /// 追加 + /// + /// + /// + /// + Task AppendAsync(string key, object value); + + /// + /// 追加 + /// + /// + /// + /// + long Append(string key, object value); + + /// + /// 自增 + /// + /// + /// + Task IncrAsync(string key); + + /// + /// 自增 + /// + /// + /// + long Incr(string key); + + #region Hash + + /// + /// + /// + /// + /// + /// + bool HSet(string key, string filed, object value); + + /// + /// + /// + /// + /// + /// + Task HSetAsync(string key, string filed, object value); + + /// + /// + /// + /// + /// + Task HMSetAsync(string key, object[] value); + + /// + /// + /// + /// + /// + bool HMSet(string key, object[] value); + + /// + /// + /// + /// + /// + string[] HMGet(string key, string[] filed); + + /// + /// + /// + /// + /// + Task HMGetAsync(string key, string filed); + + /// + /// + /// + /// + /// + long Del(string key, string[] filed); + + /// + /// + /// + /// + /// + Task HDelAsync(string key, string filed); + + /// + /// + /// + /// + /// + bool HExists(string key, string filed); + + /// + /// + /// + /// + /// + Task HExistsAsync(string key, string filed); + + /// + /// 自增 + /// + /// + /// + /// + Task HIncrAsync(string key, string filed); + + /// + /// 自增 + /// + /// + /// + /// + long HIncr(string key, string filed); + + /// + /// 获取所有 + /// + /// + /// + Task> HGetAllAsync(string key); + + /// + /// 获取所有 + /// + /// + /// + Dictionary HGetAll(string key); + + /// + /// 设置一个键值对(不存在,则创建;否则,修改) + /// + /// + /// + /// + /// + Task HSetNxAsync(string key, string filed, object value); + + /// + /// 设置一个键值对(不存在,则创建;否则,修改) + /// + /// + /// + /// + /// + bool HSetNx(string key, string filed, object value); + + /// + /// 获取哈希表中的所有值 + /// + /// + /// + /// + Task HValsAsync(string key); + + #endregion Hash + + + /// + /// + /// + /// + /// + /// + Task SAddAsync(string key, params T[] members); + + /// + /// 获取集合成员数 + /// + /// + /// + Task SCardAsync(string key); + + + /// + /// + /// + /// + /// + /// + Task ZAddAsync(string key, params (decimal, object)[] scoreMembers); + + /// + /// 用于计算集合中元素的数量 + /// + /// + /// + Task ZCardAsync(string key); + + /// + /// 返回有序集中指定区间内的成员,通过索引,分数从高到底 + /// + /// + /// + /// + /// + Task ZRevRangeAsync(string key, long start, long stop); + + + /// + /// 通过索引区间返回有序集合成指定区间内的成员 + /// + /// + /// + /// + /// + Task ZRangeAsync(string key, long start, long stop); + + + /// + /// 通过索引区间返回有序集合成指定区间内的成员 + /// + /// + /// + /// + /// + Task ZRemRangeByRankAsync(string key, long start, long stop); + + /// + /// 有序集合中对指定成员的分数加上增量 increment + /// + /// + /// + /// + /// + Task ZIncrByAsync(string key, string member, decimal increment = 1); + + /// + /// 返回有序集中指定区间内的成员和分数,通过索引,分数从高到低 + /// + /// + /// + /// + /// + Task<(string, decimal)[]> ZRevRangeWithScoresAsync(string key, long start, long stop); + + #region BitMap + /// + /// 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit) + /// + /// + /// + /// + /// + Task SetBitAsync(string key, uint offset, bool value); + + /// + /// 计算给定位置被设置为 1 的比特位的数量 + /// + /// + /// + /// + /// + Task BitCountAsync(string key, long start, long end); + + #endregion + + + /// + /// Redis Setnx(SET if Not eXists) 命令在指定的 key 不存在时,为 key 设置指定的值。 + /// + /// + /// + /// + Task SetNxAsync(string key, object value); + + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Common/Cache/RedisCache.cs b/src/Znyc.Recruitment.Common/Cache/RedisCache.cs new file mode 100644 index 0000000..b1e96ec --- /dev/null +++ b/src/Znyc.Recruitment.Common/Cache/RedisCache.cs @@ -0,0 +1,325 @@ +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Znyc.Recruitment.Common.Cache +{ + /// + /// Redis缓存 + /// + public class RedisCache : IRedisCache + { + public long Del(params string[] key) + { + return RedisHelper.Del(key); + } + + public Task DelAsync(params string[] key) + { + return RedisHelper.DelAsync(key); + } + + public async Task DelByPatternAsync(string pattern) + { + if (pattern.IsNull()) + { + return default; + } + + pattern = Regex.Replace(pattern, @"\{.*\}", "*"); + + string[] keys = await RedisHelper.KeysAsync(pattern); + if (keys != null && keys.Length > 0) + { + return await RedisHelper.DelAsync(keys); + } + + return default; + } + + public bool Exists(string key) + { + return RedisHelper.Exists(key); + } + + public Task ExistsAsync(string key) + { + return RedisHelper.ExistsAsync(key); + } + + public string Get(string key) + { + return RedisHelper.Get(key); + } + + public T Get(string key) + { + return RedisHelper.Get(key); + } + + public Task GetAsync(string key) + { + return RedisHelper.GetAsync(key); + } + + public Task GetAsync(string key) + { + return RedisHelper.GetAsync(key); + } + + public bool Set(string key, object value) + { + return RedisHelper.Set(key, value); + } + + public bool Set(string key, object value, TimeSpan expire) + { + return RedisHelper.Set(key, value, expire); + } + + public Task SetAsync(string key, object value) + { + return RedisHelper.SetAsync(key, value); + } + + public Task SetAsync(string key, object value, TimeSpan expire) + { + return RedisHelper.SetAsync(key, value, expire); + } + + public Task AppendAsync(string key, object value) + { + return RedisHelper.AppendAsync(key, value); + } + + public long Append(string key, object value) + { + return RedisHelper.Append(key, value); + } + + public Task IncrAsync(string key) + { + return RedisHelper.IncrByAsync(key); + } + + public long Incr(string key) + { + return RedisHelper.IncrBy(key); + } + + #region Hash + + public bool HSet(string key, string filed, object value) + { + return RedisHelper.HSet(key, filed, value); + } + + public Task HSetAsync(string key, string filed, object value) + { + return RedisHelper.HSetAsync(key, filed, value); + } + + public Task HMSetAsync(string key, object[] value) + { + return RedisHelper.HMSetAsync(key, value); + } + + public bool HMSet(string key, object[] value) + { + return RedisHelper.HMSet(key, value); + } + + public string[] HMGet(string key, string[] filed) + { + return RedisHelper.HMGet(key, filed); + } + + public Task HMGetAsync(string key, string filed) + { + return RedisHelper.HMGetAsync(key, filed); + } + + public long Del(string key, string[] filed) + { + return RedisHelper.HDel(key, filed); + } + + public Task HDelAsync(string key, string filed) + { + return RedisHelper.HDelAsync(key, filed); + } + + public bool HExists(string key, string filed) + { + return RedisHelper.HExists(key, filed); + } + + public Task HExistsAsync(string key, string filed) + { + return RedisHelper.HExistsAsync(key, filed); + } + + public Task HIncrAsync(string key, string filed) + { + return RedisHelper.HIncrByAsync(key, filed); + } + + public long HIncr(string key, string filed) + { + return RedisHelper.HIncrBy(key, filed); + } + + public Task> HGetAllAsync(string key) + { + return RedisHelper.HGetAllAsync(key); + } + + public Dictionary HGetAll(string key) + { + return RedisHelper.HGetAll(key); + } + + public Task HSetNxAsync(string key, string filed, object value) + { + return RedisHelper.HSetNxAsync(key, filed, value); + } + + public bool HSetNx(string key, string filed, object value) + { + return RedisHelper.HSetNx(key, filed, value); + } + + public Task HValsAsync(string key) + { + return RedisHelper.HValsAsync(key); + } + + #endregion Hash + + #region Set + + public Task SAddAsync(string key, params T[] members) + { + return RedisHelper.SAddAsync(key, members); + } + + + public Task SCardAsync(string key) + { + return RedisHelper.SCardAsync(key); + } + #endregion + + + #region ZSet + + /// + /// + /// + /// + /// + /// + public Task ZAddAsync(string key, params (decimal, object)[] scoreMembers) + { + return RedisHelper.ZAddAsync(key, scoreMembers); + } + + /// + /// 用于计算集合中元素的数量 + /// + /// + /// + public Task ZCardAsync(string key) + { + return RedisHelper.ZCardAsync(key); + } + + /// + /// 返回有序集中指定区间内的成员,通过索引,分数从高到底 + /// + /// + /// + /// + /// + public Task ZRevRangeAsync(string key, long start, long stop) + { + return RedisHelper.ZRevRangeAsync(key, start, stop); + } + + /// + /// 通过索引区间返回有序集合成指定区间内的成员 + /// + /// + /// + /// + /// + public Task ZRangeAsync(string key, long start, long stop) + { + return RedisHelper.ZRangeAsync(key, start, stop); + + } + + /// + /// 通过索引区间返回有序集合成指定区间内的成员 + /// + /// + /// + /// + /// + public Task ZRemRangeByRankAsync(string key, long start, long stop) + { + return RedisHelper.ZRemRangeByRankAsync(key, start, stop); + } + + /// + /// 有序集合中对指定成员的分数加上增量 increment + /// + /// + /// + /// + /// + public Task ZIncrByAsync(string key, string member, decimal increment = 1) + { + return RedisHelper.ZIncrByAsync(key, member, increment); + } + + /// + /// 返回有序集中指定区间内的成员和分数,通过索引,分数从高到低 + /// + /// + /// + /// + /// + public Task<(string, decimal)[]> ZRevRangeWithScoresAsync(string key, long start, long stop) + { + return RedisHelper.ZRevRangeWithScoresAsync(key, start, stop); + } + #endregion + + #region BitMap + public Task SetBitAsync(string key, uint offset, bool value) + { + return RedisHelper.SetBitAsync(key, offset, value); + } + + public Task BitCountAsync(string key, long start, long end) + { + return RedisHelper.BitCountAsync(key, start, end); + } + #endregion + + + /// + /// Redis Setnx(SET if Not eXists) 命令在指定的 key 不存在时,为 key 设置指定的值。 + /// + /// + /// + /// + public async Task SetNxAsync(string key, object value) + { + return await RedisHelper.SetNxAsync(key, value); + } + + } +} \ No newline at end of file diff --git a/src/Znyc.Recruitment.Common/Configs/AppConfig.cs b/src/Znyc.Recruitment.Common/Configs/AppConfig.cs new file mode 100644 index 0000000..1c33bb4 --- /dev/null +++ b/src/Znyc.Recruitment.Common/Configs/AppConfig.cs @@ -0,0 +1,563 @@ +using FreeSql; +using System; +using System.Collections.Generic; +using System.IO; + +namespace Znyc.Recruitment.Common.Configs +{ + /// + /// 应用配置 + /// + public class AppConfig + { + /// + /// Api地址,默认 http://*:80 + /// + public string[] Urls { get; set; } // = new[]{ "http://*:80" }; + + /// + /// 跨域地址,默认 http://*:9000 + /// + public string[] CorUrls { get; set; } // = new[]{ "http://*:9000" }; + + /// + /// Swagger文档 + /// + public bool Swagger { get; set; } = true; + + /// + /// 统一认证授权服务器 + /// + public IdentityServer IdentityServer { get; set; } = new(); + + /// + /// Aop配置 + /// + public AopConfig Aop { get; set; } = new(); + + /// + /// 日志配置 + /// + public LogConfig Log { get; set; } = new(); + + /// + /// 限流 + /// + public bool RateLimit { get; set; } = false; + + /// + /// 百度ocr配置 + /// + public BaiduConfig BaiduConfig { get; set; } = new(); + + /// + /// jwt配置 + /// + public JwtConfig JwtConfig { get; set; } + + /// + /// 短信配置 + /// + public SmsConfig SmsConfig { get; set; } + + /// + /// COS配置 + /// + public CosConfig CosConfig { get; set; } + + /// + /// Wx配置 + /// + public WxConfig WxConfig { get; set; } + + /// + /// Redis配置 + /// + public RedisConfig RedisConfig { get; set; } + + /// + /// 数据库配置 + /// + public DbConfig DbConfig { get; set; } + + /// + /// 上传配置 + /// + public UploadConfig UploadConfig { get; set; } + + /// + /// RabbitMQConfig + /// + public RabbitMQConfig RabbitMQConfig { get; set; } + + /// + /// HangfireConfig + /// + public HangFireConfig HangfireConfig { get; set; } + + + + } + + /// + /// 统一认证授权服务器配置 + /// + public class IdentityServer + { + /// + /// 启用 + /// + public bool Enable { get; set; } = false; + + /// + /// 地址 + /// + public string Url { get; set; } = "https://localhost:5000"; + } + + /// + /// Aop配置 + /// + public class AopConfig + { + /// + /// 事物 + /// + public bool Transaction { get; set; } = true; + } + + /// + /// 日志配置 + /// + public class LogConfig + { + /// + /// 操作日志 + /// + public string ApiKey { get; set; } = "rrgtKI7LybZn8OZiSBP9ZzwsPKUBcG3i6TIZjmfV111111111"; + + /// + /// ServerUrl + /// + public string ServerUrl { get; set; } = "http://49.234.103.173:5001"; + } + + /// + /// 百度ocr配置 + /// + public class BaiduConfig + { + /// + /// AppID + /// + public string AppID { get; set; } + + /// + /// ApiKey + /// + public string ApiKey { get; set; } + + /// + /// SecretKey + /// + public string SecretKey { get; set; } + } + /// + /// Jwt配置 + /// + public class JwtConfig + { + /// + /// 发行者 + /// + public string Issuer { get; set; } = "http://127.0.0.1:8888"; + + /// + /// 订阅者 + /// + public string Audience { get; set; } = "http://127.0.0.1:8888"; + + /// + /// 密钥 + /// + public string SecurityKey { get; set; } = "ertJKl#521*a@790asD&1#"; + + /// + /// 有效期(分钟) + /// + public long Expires { get; set; } = 420; + + /// + /// 刷新有效期(分钟) + /// + public int RefreshExpires { get; set; } = 480; + } + + /// + /// 短信配置 + /// + public class SmsConfig + { + /// + /// SecretId + /// + public string SecretId { get; set; } + + /// + /// SecretKey + /// + public string SecretKey { get; set; } + + /// + /// 短信id + /// + public string SmsSdkAppid { get; set; } + + /// + /// 签名 + /// + public string Sign { get; set; } + + public string Region { get; set; } + + /// + /// 模板列表 + /// + public List