From 05ee79a04f9dbe6f7f42f6656ce00bb657daf170 Mon Sep 17 00:00:00 2001 From: tongfei <244188119@qq.com> Date: Wed, 18 Oct 2023 10:37:41 +0800 Subject: [PATCH] domian-build --- src/WMS.Web.Api/wwwroot/WMS.Web.Domain.xml | 968 ++++++++++++++++++ .../IService/Public/IHttpClientService.cs | 17 + .../IService/Public/ILoginService.cs | 73 ++ .../IService/Public/ISingleDataService.cs | 127 +++ src/WMS.Web.Domain/Mappers/AppMapper.cs | 17 + src/WMS.Web.Domain/Mappers/MapperList.cs | 56 + src/WMS.Web.Domain/Options/AppOptions.cs | 39 + src/WMS.Web.Domain/Options/SoaOptions.cs | 39 + .../Services/Public/HttpClientService.cs | 230 +++++ .../Services/Public/LoginService.cs | 387 +++++++ .../Services/Public/RedisClientService.cs | 93 ++ .../Services/Public/SingleDataService.cs | 473 +++++++++ src/WMS.Web.Domain/Values/ResultCodes.cs | 13 + .../Values/Single/SingleAction.cs | 105 ++ .../Values/Single/SingleControllerType.cs | 29 + .../Values/Single/SingleLoginAction.cs | 42 + .../Values/Single/SysConfigAction.cs | 186 ++++ src/WMS.Web.Domain/WMS.Web.Domain.csproj | 5 - 18 files changed, 2894 insertions(+), 5 deletions(-) create mode 100644 src/WMS.Web.Domain/IService/Public/IHttpClientService.cs create mode 100644 src/WMS.Web.Domain/IService/Public/ILoginService.cs create mode 100644 src/WMS.Web.Domain/IService/Public/ISingleDataService.cs create mode 100644 src/WMS.Web.Domain/Mappers/AppMapper.cs create mode 100644 src/WMS.Web.Domain/Mappers/MapperList.cs create mode 100644 src/WMS.Web.Domain/Options/AppOptions.cs create mode 100644 src/WMS.Web.Domain/Options/SoaOptions.cs create mode 100644 src/WMS.Web.Domain/Services/Public/HttpClientService.cs create mode 100644 src/WMS.Web.Domain/Services/Public/LoginService.cs create mode 100644 src/WMS.Web.Domain/Services/Public/RedisClientService.cs create mode 100644 src/WMS.Web.Domain/Services/Public/SingleDataService.cs create mode 100644 src/WMS.Web.Domain/Values/ResultCodes.cs create mode 100644 src/WMS.Web.Domain/Values/Single/SingleAction.cs create mode 100644 src/WMS.Web.Domain/Values/Single/SingleControllerType.cs create mode 100644 src/WMS.Web.Domain/Values/Single/SingleLoginAction.cs create mode 100644 src/WMS.Web.Domain/Values/Single/SysConfigAction.cs diff --git a/src/WMS.Web.Api/wwwroot/WMS.Web.Domain.xml b/src/WMS.Web.Api/wwwroot/WMS.Web.Domain.xml index 4edb2f1c..424ad6fc 100644 --- a/src/WMS.Web.Api/wwwroot/WMS.Web.Domain.xml +++ b/src/WMS.Web.Api/wwwroot/WMS.Web.Domain.xml @@ -4,5 +4,973 @@ WMS.Web.Domain + + + 登录服务接口 + + + + + 得到单点用户信息 + + + + + + + 登录退出 + + + + + + + 刷新token + + + + + + 单点退出通知token失效 + + + + + + + + + 单点退出通知token失效 + + + + + + + 获取登录后的信息 + + + + + + + 单点-在线接口 + + + + + + + 单点-下线接口 + + + + + + + 单点数据返回服务接口 + + + + + 获取单点数据:根据方法名和公司ID + + + + + + + + + 获取单点数据:根据方法名和公司ID + + + + + + + + + 获取单点数据:根据方法名和公司ID + + + + + + + + + 获取单点数据:根据方法名和公司ID + + + + + + + + + 根据名字模糊匹配 + + + + + + + + + 获取单点数据集合:泛型-同步 + + + + + + + + + 获取单点数据集合:泛型-异步 + + + + + + + + + 获取单点数据集合:泛型-异步-无缓存 + + + + + + + + + 单点数据:可对接全部接口 + + 返回对象 + 请求对象 + 方法名称 + 请求对象 + 方法名称 + 控制器名称 + + + + + 单点数据:可对接全部接口-无缓存 + + + + + + + + + + + + 获取单点数据:请求对象和接口方法名 + + + + + + + + + + 获取客户仓库 + + + + + + + + mapper映射 + + + + + 集合映射 + + + + + 映射实体里 集合属性 + + + + + + + + + + + 数据库 + + + + + redis + + + + + 单点数据请求地址-后端使用接口地址 + + + + + redis数据目录 + + + + + 数据库类型 + + + + + 是否允许缓存 + + + + + 单点系统地址 + + + + + 应用id + + + + + AppId + + + + + AppSecret + + + + + 公钥 + + + + + 私钥 + + + + + Get方法 + + + + + + + + + + Get方法 + + + + + + + + + + Post方法 + + + + + + + + + + + Post方法 + + + + + + + + + + 公共http请求 + + + + + + + + + + + + 设置HttpRequestMessage + + + + + + + + + + 设置请求内容 + + + + + + + + 设置请求头和超时时间:返回client + + + + + + + + 创建token + + + + + + + + + 得到单点用户信息 + + + + + + + 登录退出 + + + + + + 刷新token + + + + + + 单点退出通知token失效 + + + + + + + + + 单点退出通知token失效 + + 这个是单点传过来的SeesionId + + + + + 缓存退出的token + + + + + + + 获取登录后的信息 + + + + + + + 移除登录后的用户信息 + + + + + + 单点-在线接口 + + + + + + + 单点-下线接口 + + + + + + + 保存单个key value + + + + + + + + + 获取单个key的值 + + + + + 移除redis + + + + + + + 获取一个key的对象 + + + + + 保存一个对象 + + + + + + 单点数据返回服务 + + + + + 获取单点数据:根据接口方法名和公司ID + 后端列表查询统一使用 + + + + + + + + 获取单点数据:根据接口方法名和公司ID + 后端列表查询统一使用 + + + + + + + + 获取单点数据:根据接口方法名和公司ID + 后端列表查询统一使用 + + + + + + + + 根据名字模糊匹配 + + + + + + + + + 获取单点数据:根据接口方法名和公司ID + 后端列表查询统一使用 + + + + + + + + 获取单点数据集合:泛型-同步 + + + + + + + + + 获取单点数据集合:泛型-异步 + + + + + + + + + 获取单点数据集合:泛型-异步-无缓存 + + + + + + + + + 单点数据:可对接全部接口 + + 返回对象 + 请求对象 + 方法名称 + 请求对象 + 方法名称 + 控制器名称 + + + + + 单点数据:可对接全部接口 + + 返回对象 + 请求对象 + 方法名称 + 请求对象 + 方法名称 + 控制器名称 + + + + + 获取单点数据:配置项接口 + + + + + + + + + + 请求单点服务接口:同步 + + + + + + + + + 请求单点服务接口:异步 + + + + + + + + + 获取客户仓库 + + + + + + + + 错误提示信息 + + + + + 对接单点的接口方法-枚举 + + + + + 组织集合 + + + + + 用户集合 + + + + + 人员集合 + + + + + 供应商集合 + + + + + 客户集合 + + + + + 收款条件集合 + + + + + 付款条件集合 + + + + + 结算方式集合 + + + + + 结算币别集合 + + + + + 税率集合 + + + + + 汇率集合 + + + + + 仓库集合 + + + + + 单位集合 + + + + + 客户仓库集合 + + + + + 部门集合 + + + + + 仓库211集合 + + + + + 供应商默认联系人集合 + + + + + 菜单集合 + + + + + 单点-控制器枚举 + + + + + 单点OPS列表数据-控制器 + + + + + 单点配置项数据-控制器 + + + + + 单点登录项数据-控制器 + + + + + 单点公共接口数据-控制器 + + + + + 单点数据接口-登录要使用的数据接口-方法枚举 + + + + + 菜单 + + + + + 人员 + + + + + 公司 + + + + + 供应商 + + + + + 客户 + + + + + 全部信息 + + + + + 公司信息 + + + + + 单点数据:配置项和公共接口的方法枚举值 + + + + + 供应商-根据名称和公司 + + + + + 组织-根据公司 + + + + + 部门-根据组织和公司 + + + + + 人员-根据公司 + + + + + 人员-根据部门和公司 + + + + + 人员-根据组织和公司 + + + + + 客户-根据公司 + + + + + 客户-根据客户和组织和公司 + + + + + 客户信息-根据客户和组织和公司 + + + + + 收款条件-根据公司 + + + + + 付款条件-根据公司 + + + + + 结算方式-根据公司 + + + + + 结算币别-根据公司 + + + + + 单位-根据公司 + + + + + 单位(部分属性)-根据公司 + + + + + 税率-根据公司 + + + + + 仓库-根据名称和公司 + + + + + 仓库-根据组织和公司 + + + + + 仓库(不是调拨中转仓)-根据组织和公司 + + + + + 仓库(211)-根据组织和公司 + + + + + 仓库-根据客户和公司 + + + + + 仓位-根据仓库和名称 + + + + + 仓位-根据- + + + + + 汇率信息-根据原币、目标币和公司 + + + + + 客户仓库-根据客户和组织和公司 + + + + + 付款条件,结算币别,结算方式,采购员,采购部门-根据供应商和组织 + + + + + 获取仓库:根据仓库id + + + + + 获取库存:根据组织和公司 + + + + + 获取客户仓库:根据客户IDS和组织和公司 + + + + + 汇率(所有) + + + + + 供应商选择后获取:付款条件,结算币别,结算方式,采购员,采购部门,根据组织IDS + + + + + 获取客户仓库:根据code集合 + + + + + 供应商:根据ids + + + + + 根据公司搜索所有仓库(计算补货频次) + + + + + 获取仓库:根据codes + + + + + 获取客户仓库:根据codes + + + + + 获取调拨中转仓库:根据公司 + + + + + 获取供应商数据根据ids + + + + + 获取仓库:根据默认补货客户 + + + + + 获取用户(ID和Name):根据公司 + + + + + 全部部门-根据组织和公司:不处理子级 + + + + + 获取全部员工:根据公司和组织 + + diff --git a/src/WMS.Web.Domain/IService/Public/IHttpClientService.cs b/src/WMS.Web.Domain/IService/Public/IHttpClientService.cs new file mode 100644 index 00000000..6b35e31a --- /dev/null +++ b/src/WMS.Web.Domain/IService/Public/IHttpClientService.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +namespace WMS.Web.Domain.IService.Public +{ + public interface IHttpClientService + { + Task GetAsync(string url, int timeoutSecond = 180); + Task GetAsync(string url, Dictionary dicHeaders, int timeoutSecond = 180); + Task PostAsync(string url, string requestBody, int timeoutSecond = 180); + Task PostAsync(string url, string requestBody, Dictionary dicHeaders, int timeoutSecond = 180); + Task ExecuteAsync(string url, HttpMethod method, string requestBody, Dictionary dicHeaders, int timeoutSecond = 180); + } +} diff --git a/src/WMS.Web.Domain/IService/Public/ILoginService.cs b/src/WMS.Web.Domain/IService/Public/ILoginService.cs new file mode 100644 index 00000000..3fe2c687 --- /dev/null +++ b/src/WMS.Web.Domain/IService/Public/ILoginService.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using WMS.Web.Core.Dto.Login; +using WMS.Web.Core.Internal.Results; + +namespace WMS.Web.Domain.IService.Public +{ + /// + /// 登录服务接口 + /// + public interface ILoginService + { + /// + /// 得到单点用户信息 + /// + /// + /// + Task> GetUserInfoAsync(string code); + + /// + /// 登录退出 + /// + /// + /// + Task LoginOutAsync(LoginOutDto dto); + + + /// + /// 刷新token + /// + /// + Task> RefreshToken(string OldToken, string RefreshToken); + + /// + /// 单点退出通知token失效 + /// + /// + /// + /// + /// + Task LoginOutSingleAsync(int ucid, string token, int expires_in); + + /// + /// 单点退出通知token失效 + /// + /// + /// + Task LoginOutSingleAsync(string SeesionId); + + /// + /// 获取登录后的信息 + /// + /// + /// + LoginInDto GetLoginInfo(string authorization); + + /// + /// 单点-在线接口 + /// + /// + /// + Task Online(string sessionId); + + /// + /// 单点-下线接口 + /// + /// + /// + Task Offline(string sessionId); + } +} diff --git a/src/WMS.Web.Domain/IService/Public/ISingleDataService.cs b/src/WMS.Web.Domain/IService/Public/ISingleDataService.cs new file mode 100644 index 00000000..5cbaeec4 --- /dev/null +++ b/src/WMS.Web.Domain/IService/Public/ISingleDataService.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using WMS.Web.Domain.Values.Single; + +namespace WMS.Web.Domain.IService.Public +{ + /// + /// 单点数据返回服务接口 + /// + public interface ISingleDataService + { + /// + /// 获取单点数据:根据方法名和公司ID + /// + /// + /// + /// + /// + string GetSingleData(SingleAction action, int companyId, int id); + + /// + /// 获取单点数据:根据方法名和公司ID + /// + /// + /// + /// + /// + decimal GetSingleDataNumber(SingleAction action, int companyId, int id); + /// + /// 获取单点数据:根据方法名和公司ID + /// + /// + /// + /// + /// + string GetSingleDataCode(SingleAction action, int companyId, int id); + + /// + /// 获取单点数据:根据方法名和公司ID + /// + /// + /// + /// + /// + string GetSingleData(SingleAction action, int companyId, string code); + /// + /// 根据名字模糊匹配 + /// + /// + /// + /// + /// + List GetIdsBySingleName(SingleAction action, int companyId, string name); + + + /// + /// 获取单点数据集合:泛型-同步 + /// + /// + /// + /// + /// + List GetSingleData(SingleAction action, int companyId) where T : class; + + /// + /// 获取单点数据集合:泛型-异步 + /// + /// + /// + /// + /// + Task> GetSingleDataAsync(SingleAction action, int companyId) where T : class; + + /// + /// 获取单点数据集合:泛型-异步-无缓存 + /// + /// + /// + /// + /// + Task> GetSingleDataNoCacheAsync(SingleAction action, int companyId) where T : class; + + /// + /// 单点数据:可对接全部接口 + /// + /// 返回对象 + /// 请求对象 + /// 方法名称 + /// 请求对象 + /// 方法名称 + /// 控制器名称 + /// + Task GetSingleData(X dto, Y action, SingleControllerType type = SingleControllerType.Single) where T : class; + + /// + /// 单点数据:可对接全部接口-无缓存 + /// + /// + /// + /// + /// + /// + /// + /// + Task GetSingleDataNoCache(X dto, Y action, SingleControllerType type = SingleControllerType.Single) where T : class; + + /// + /// 获取单点数据:请求对象和接口方法名 + /// + /// + /// + /// + /// + /// + Task GetSysConfigData(X dto, SysConfigAction action); + + /// + /// 获取客户仓库 + /// + /// + /// + /// + string GetCustomerStock(int companyId, string customerStockCode); + } +} diff --git a/src/WMS.Web.Domain/Mappers/AppMapper.cs b/src/WMS.Web.Domain/Mappers/AppMapper.cs new file mode 100644 index 00000000..df5efc1c --- /dev/null +++ b/src/WMS.Web.Domain/Mappers/AppMapper.cs @@ -0,0 +1,17 @@ +using AutoMapper; +using System; +using System.Collections.Generic; +using System.Text; + +namespace WMS.Web.Domain.Mappers +{ + /// + /// mapper映射 + /// + public class AppMapper : Profile + { + public AppMapper() + { + } + } +} diff --git a/src/WMS.Web.Domain/Mappers/MapperList.cs b/src/WMS.Web.Domain/Mappers/MapperList.cs new file mode 100644 index 00000000..3d2b89d1 --- /dev/null +++ b/src/WMS.Web.Domain/Mappers/MapperList.cs @@ -0,0 +1,56 @@ +using AutoMapper; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using WMS.Web.Core; + +namespace WMS.Web.Domain.Mappers +{ + /// + /// 集合映射 + /// + public static class MapperList + { + /// + /// 映射实体里 集合属性 + /// + /// + /// + /// + /// + /// + /// + public static List
ToMapList(this IMapper mapper, List sourcList, List
destinationList) + where ST : EntityBase + where DT : EntityBase + { + for (int i = 0; i < destinationList.Count; i++) + { + int id = destinationList[i].Id; + var detail = sourcList.FirstOrDefault(f => f.Id == id); + if (detail == null) + { + destinationList.Remove(destinationList[i]); + i--;//在列表移除掉一条数据后 必须把index回拨一位 因为数据在移除一条后会调整下标 + } + } + + foreach (var st in sourcList) + { + if (st.Id == 0) + destinationList.Add(mapper.Map
(st)); + else + { + var detail = destinationList.FirstOrDefault(f => f.Id == st.Id); + + if (detail != null) + mapper.Map(st, detail); + //如果在目标数据里没找到这条id的数据 则不作处理 + } + } + + return destinationList; + } + } +} diff --git a/src/WMS.Web.Domain/Options/AppOptions.cs b/src/WMS.Web.Domain/Options/AppOptions.cs new file mode 100644 index 00000000..e0553f91 --- /dev/null +++ b/src/WMS.Web.Domain/Options/AppOptions.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WMS.Web.Domain.Options +{ + public class AppOptions + { + /// + /// 数据库 + /// + public string DBConnectionString { get; set; } + + /// + /// redis + /// + public string RedisConnectionString { get; set; } + + /// + /// 单点数据请求地址-后端使用接口地址 + /// + public string SingleBaseUrl { get; set; } + + /// + /// redis数据目录 + /// + public string RedisDirectory { get; set; } + + /// + /// 数据库类型 + /// + public string DBType { get; set; } + + /// + /// 是否允许缓存 + /// + public bool AllowCache { get; set; } + } +} diff --git a/src/WMS.Web.Domain/Options/SoaOptions.cs b/src/WMS.Web.Domain/Options/SoaOptions.cs new file mode 100644 index 00000000..3458899b --- /dev/null +++ b/src/WMS.Web.Domain/Options/SoaOptions.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WMS.Web.Domain.Options +{ + public class SoaOptions + { + /// + /// 单点系统地址 + /// + public string Url { get; set; } + + /// + /// 应用id + /// + public int ModuleID { get; set; } + + /// + /// AppId + /// + public string AppId { get; set; } + + /// + /// AppSecret + /// + public string AppSecret { get; set; } + + /// + /// 公钥 + /// + public string PublicKey { get; set; } + + /// + /// 私钥 + /// + public string PrivateKey { get; set; } + } +} diff --git a/src/WMS.Web.Domain/Services/Public/HttpClientService.cs b/src/WMS.Web.Domain/Services/Public/HttpClientService.cs new file mode 100644 index 00000000..db4f48e0 --- /dev/null +++ b/src/WMS.Web.Domain/Services/Public/HttpClientService.cs @@ -0,0 +1,230 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; +using WMS.Web.Core.Exceptions; +using WMS.Web.Domain.IService.Public; + +namespace WMS.Web.Domain.Services.Public +{ + public class HttpClientService : IHttpClientService + { + private readonly IHttpClientFactory _clientFactory; + private readonly ILogger _logger; + private Dictionary headers; + private Dictionary contentHeaders; + public HttpClientService(IHttpClientFactory clientFactory, ILogger logger) + { + _clientFactory = clientFactory; + _logger = logger; + headers = new Dictionary(); + headers.Add("Accept", "application/json"); + headers.Add("User-Agent", "HttpClientFactory-Sample"); + + contentHeaders = new Dictionary(); + contentHeaders.Add("Content-Type", "application/json; charset=utf-8"); + + } + + /// + /// Get方法 + /// + /// + /// + /// + /// + /// + public async Task GetAsync(string url, int timeoutSecond = 180) + { + try + { + var client = BuildHttpClient(headers, timeoutSecond); + var response = await client.GetAsync(url); + //var responseContent = await response.Content.ReadAsStreamAsync();//1.相比ReadAsString这个方法返回要快点,效率高 + var responseContent = await response.Content.ReadAsStringAsync(); //2.当前使用这里是为了迎合错误信息观看 + if (response.IsSuccessStatusCode) + { + var t = JsonSerializer.Deserialize(responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); + //var t = await JsonSerializer.DeserializeAsync(responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });//3.配合1的ReadAsStream使用 + return t; + } + + throw new WebHttpException(response.StatusCode.ToString(), "请求出错"); + } + catch (Exception ex) + { + _logger.LogError($"HttpGet:{url} Error:{ex.Message}"); + throw new Exception($"HttpGet:{url} Error", ex); + } + } + + /// + /// Get方法 + /// + /// + /// + /// + /// + /// + public async Task GetAsync(string url, Dictionary dicHeaders, int timeoutSecond = 180) + { + try + { + var client = BuildHttpClient(dicHeaders, timeoutSecond); + var response = await client.GetAsync(url); + //var responseContent = await response.Content.ReadAsStreamAsync();//1.相比ReadAsString这个方法返回要快点,效率高 + var responseContent = await response.Content.ReadAsStringAsync(); //2.当前使用这里是为了迎合错误信息观看 + if (response.IsSuccessStatusCode) + { + var t = JsonSerializer.Deserialize(responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); + //var t = await JsonSerializer.DeserializeAsync(responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });//3.配合1的ReadAsStream使用 + return t; + } + + throw new WebHttpException(response.StatusCode.ToString(), "请求出错"); + } + catch (Exception ex) + { + _logger.LogError($"HttpGet:{url} Error:{ex.Message}"); + throw new Exception($"HttpGet:{url} Error", ex); + } + } + + /// + /// Post方法 + /// + /// + /// + /// + /// + /// + /// + public async Task PostAsync(string url, string requestBody, Dictionary dicHeaders, int timeoutSecond = 180) + { + var client = BuildHttpClient(null, timeoutSecond); + var requestContent = GenerateStringContent(requestBody, dicHeaders); + var response = await client.PostAsync(url, requestContent); + var responseContent = await response.Content.ReadAsStringAsync(); + if (response.IsSuccessStatusCode) + { + var t = JsonSerializer.Deserialize(responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); + return t; + } + + _logger.LogError($"HttpGet:{url} Error:{responseContent}"); + throw new WebHttpException(response.StatusCode.ToString(), responseContent); + } + + /// + /// Post方法 + /// + /// + /// + /// + /// + /// + public async Task PostAsync(string url, string requestBody, int timeoutSecond = 180) + { + var client = BuildHttpClient(null, timeoutSecond); + var requestContent = GenerateStringContent(requestBody, contentHeaders); + var response = await client.PostAsync(url, requestContent); + var responseContent = await response.Content.ReadAsStringAsync(); + if (response.IsSuccessStatusCode) + { + var t = JsonSerializer.Deserialize(responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); + if (t == null) + _logger.LogInformation($"获取单点数据为空---{responseContent}"); + return t; + } + + _logger.LogError($"HttpGet:{url} Error:{responseContent}"); + throw new WebHttpException(response.StatusCode.ToString(), responseContent); + } + + /// + /// 公共http请求 + /// + /// + /// + /// + /// + /// + /// + /// + public async Task ExecuteAsync(string url, HttpMethod method, string requestBody, Dictionary dicHeaders, int timeoutSecond = 180) + { + var client = BuildHttpClient(null, timeoutSecond); + var request = GenerateHttpRequestMessage(url, requestBody, method, dicHeaders); + var response = await client.SendAsync(request); + var responseContent = await response.Content.ReadAsStringAsync(); + if (response.IsSuccessStatusCode) + { + var t = JsonSerializer.Deserialize(responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); + + return t; + } + + throw new WebHttpException(response.StatusCode.ToString(), responseContent); + } + + + /// + /// 设置HttpRequestMessage + /// + /// + /// + /// + /// + /// + private HttpRequestMessage GenerateHttpRequestMessage(string url, string requestBody, HttpMethod method, Dictionary dicHeaders) + { + var request = new HttpRequestMessage(method, url); + if (!string.IsNullOrEmpty(requestBody)) request.Content = new StringContent(requestBody); + if (dicHeaders != null) + foreach (var headerItme in dicHeaders) + request.Headers.Add(headerItme.Key, headerItme.Value); + return request; + } + + /// + /// 设置请求内容 + /// + /// + /// + /// + private StringContent GenerateStringContent(string requestBody, Dictionary dicHeaders) + { + var content = new StringContent(requestBody); + if (dicHeaders != null) + content.Headers.Remove("content-type"); + foreach (var headerItme in dicHeaders) + content.Headers.Add(headerItme.Key, headerItme.Value); + return content; + } + + + /// + /// 设置请求头和超时时间:返回client + /// + /// + /// + /// + private HttpClient BuildHttpClient(Dictionary dicDefaultHeaders, int? timeoutSecond) + { + var httpClient = _clientFactory.CreateClient("ops_client"); + httpClient.DefaultRequestHeaders.Clear(); //为了使客户端不受最后一个请求的影响,它需要清除DefaultRequestHeaders + httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + if (dicDefaultHeaders != null) + foreach (var headItem in dicDefaultHeaders) + if (!httpClient.DefaultRequestHeaders.Contains(headItem.Key)) + httpClient.DefaultRequestHeaders.Add(headItem.Key, headItem.Value); + + if (timeoutSecond != null) httpClient.Timeout = TimeSpan.FromSeconds(timeoutSecond.Value); + return httpClient; + } + } +} diff --git a/src/WMS.Web.Domain/Services/Public/LoginService.cs b/src/WMS.Web.Domain/Services/Public/LoginService.cs new file mode 100644 index 00000000..d6c62a0b --- /dev/null +++ b/src/WMS.Web.Domain/Services/Public/LoginService.cs @@ -0,0 +1,387 @@ +using AutoMapper; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Json; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WMS.Web.Core.Dto.Login; +using WMS.Web.Core.Dto.Login.Temp; +using WMS.Web.Core.Help; +using WMS.Web.Core.Internal.Results; +using WMS.Web.Core.Internal.Security; +using WMS.Web.Domain.IService.Public; +using WMS.Web.Domain.Options; +using WMS.Web.Domain.Values.Single; + +namespace WMS.Web.Domain.Services.Public +{ + public class LoginService : ILoginService + { + private IMapper _mapper; + private SoaOptions _soaOptions; + private ILogger _logger; + private HttpClientHelp _httpClientHelp; + private readonly ISingleDataService _singleDataService; + private readonly RedisClientService _redisClientService; + public LoginService( + IMapper mapper, + IOptions soaOptions, + ILogger logger, + HttpClientHelp httpClientHelp, + ISingleDataService singleDataService, + RedisClientService redisClientService) + { + this._redisClientService = redisClientService; + this._singleDataService = singleDataService; + this._soaOptions = soaOptions?.Value; + this._mapper = mapper; + this._logger = logger; + this._httpClientHelp = httpClientHelp; + } + + /// + /// 创建token + /// + /// + /// + /// + /// + private async Task CreateToken(UserInfoDto data, LoginTempDto tempDto, string NewToken) + { + return await Task.Run(() => + { + + DateTime expires_time = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)).AddSeconds(tempDto.expires_in); + AccessTokenDto accessToken = new AccessTokenDto() + { + Token = NewToken, + PhpToken = tempDto.access_token, + RefreshToken = tempDto.refresh_token, + Expired = expires_time + }; + return accessToken; + }); + } + + /// + /// 得到单点用户信息 + /// + /// + /// + public async Task> GetUserInfoAsync(string code) + { + JsonObject reqData = new JsonObject(); + reqData.Add("app_id", _soaOptions.AppId); + reqData.Add("app_secret", _soaOptions.AppSecret); + reqData.Add("code", code); + //这个是登录的时候给前端验证的token,以及传给php单点那边的一个session值,用于单点退出时,通知ops退出 + string NewToken = Guid.NewGuid().ToString("N"); + try + { + string result = _httpClientHelp.PostHttp(_soaOptions.Url + "/uc/authorize/access_token", reqData, true, NewToken); + var jObject = JsonObject.Parse(result); + + LoginInDto r = new LoginInDto(); + r.UserInfo = new UserInfoDto(); + r.TokenInfo = new AccessTokenDto(); + var login_result = jObject["errno"] == 0 ? "成功" : "失败"; + _logger.LogInformation($"登录信息:单点->{login_result}"); + + if (jObject["errno"] == 0) + { + string datajson = jObject["data"].ToString(); + var _loginDto = JsonConvert.DeserializeObject(datajson); + + #region 解码 + string enptStr = _loginDto.encryptedData; + List enptlist = enptStr.Trim().Split(',').ToList(); + string str = RSA.DecryptSection(_soaOptions.PrivateKey, enptlist); + var entity = JsonConvert.DeserializeObject(str); + #endregion + + //映射登录信息 + r.UserInfo = _mapper.Map(entity); + _logger.LogInformation($"登录信息:用户ID->{entity.uc_id}"); + + //HTTP请求获取登录信息:人员,客户,供应商,公司 + var loginRequest = new LoginSingleRequest() + { + UserId = entity.uc_id, + SupplierId = entity.supplier_id ?? 0, + CustomerId = entity.customer_id ?? 0 + }; + var loginResponse_result = await _singleDataService.GetSingleDataNoCache, LoginSingleRequest, SingleLoginAction> + (loginRequest, SingleLoginAction.All, type: SingleControllerType.Login); + + //绑定返回对象的登录信息 + var staffName = "Null"; + var token = await CreateToken(r.UserInfo, _loginDto, NewToken); + r.TokenInfo = token; + if (loginResponse_result.Success && loginResponse_result.Data != null) + { + var loginResponse = loginResponse_result.Data; + if (loginResponse.Supplier != null) + r.UserInfo.SupplierName = loginResponse.Supplier.Name; + if (loginResponse.Customer != null) + r.UserInfo.CustomerName = loginResponse.Customer.Name; + if (loginResponse.Staff != null) + { + r.UserInfo.StaffId = loginResponse.Staff.Id; + staffName = loginResponse.Staff.Name; + } + if (loginResponse.Company != null) + r.UserInfo.CompanyName = loginResponse.Company.Name; + } + r.UserInfo.UcId = entity.uc_id; + r.UserInfo.SeesionId = _loginDto?.uc_sessid; + r.UserInfo.CompanyId = entity.company_id.Value; + r.UserInfo.Identity = entity.identity; + r.UserInfo.OrgId = entity.org_id; + r.UserInfo.CustomerId = entity.customer_id; + r.UserInfo.SupplierId = entity.supplier_id; + r.SignedIn = true; + _logger.LogInformation($"登录信息:用户人员信息->{staffName}({r.UserInfo.StaffId}),公司名称->{r.UserInfo.CompanyName}"); + + //登录后缓存登录的用户信息和token信息 + var loginInfo = new LoginInDto(); + loginInfo.UserInfo = r.UserInfo; + loginInfo.TokenInfo = token; + + var ops_login_time = token.Expired.AddDays(1) - DateTime.Now;//用于正式 + _redisClientService.SetStringKey($"ops_login_{token.Token}", loginInfo, ops_login_time); + + //登录成功移出对应的用户token黑名单:应为新的token产生,移除登录的信息 + string blacktoken = _redisClientService.GetStringKey($"ops_black_token_{r.UserInfo.UcId}"); + if (!string.IsNullOrEmpty(blacktoken)) + { + this.RemoveLoginInfo(blacktoken); + _redisClientService.RemoveStringKey($"ops_black_token_{r.UserInfo.UcId}"); + } + if (r == null || r.UserInfo == null || r.TokenInfo == null) + return Result.ReFailure("授权失败,请重新登录", 401); + return Result.ReSuccess(r); + } + else + { + var errno_text = "登陆失败:" + jObject["errmsg"]; + r.SignedIn = false; + string datajson_sessid = jObject["data"]["uc_sessid"]; + //调用单点的退出接口 + result = _httpClientHelp.GetHttp(_soaOptions.Url + "/uc/authorize/signin_out", true, cookieValue: datajson_sessid); + jObject = JsonObject.Parse(result); + if (jObject["errno"] == 0) + { + _logger.LogInformation("用户信息登录:" + errno_text); + return Result.ReFailure("拒绝用户证书试图访问此web站点,请与站点管理员联系以建立用户证书权限", 403); + } + else + { + return Result.ReFailure(jObject["errmsg"], jObject["errno"]); + } + } + } + catch (Exception ex) + { + return Result.ReFailure("授权失败,请重新登录", 401); + } + } + + /// + /// 登录退出 + /// + /// + public async Task LoginOutAsync(LoginOutDto dto) + { + _logger.LogInformation("dto_SessionId:" + dto.SessionId); + //2.请求PHP单点登出接口 + JsonObject reqData = new JsonObject(); + reqData.Add("app_id", _soaOptions.AppId); + reqData.Add("app_secret", _soaOptions.AppSecret); + reqData.Add("access_token", dto.AccessToken); + string result = _httpClientHelp.PostHttp(_soaOptions.Url + "/uc/authorize/signin_out", reqData, true, dto.SessionId); + _logger.LogInformation("退出登录返回:" + result); + var jObject = JsonObject.Parse(result); + if (jObject["errno"] == 0) + { + //设置本地token的缓存:为黑名单的token做存储 + await CacheOutToken(dto); + return Result.ReSuccess(); + } + else + { + return Result.ReFailure(jObject["errmsg"], jObject["errno"]); + } + } + + /// + /// 刷新token + /// + /// + public async Task> RefreshToken(string Token, string RefreshToken) + { + _logger.LogInformation("RefreshToken:" + RefreshToken); + //1.根据旧token 找到登录对象 + var loginInfo = _redisClientService.GetStringKey($"ops_login_{Token}"); + //2.请求PHP单点登出接口 + JsonObject reqData = new JsonObject(); + reqData.Add("app_id", _soaOptions.AppId); + reqData.Add("app_secret", _soaOptions.AppSecret); + reqData.Add("refresh_token", RefreshToken); + string result = _httpClientHelp.PostHttp(_soaOptions.Url + "/uc/authorize/refresh_token", reqData, true, Token); + var jObject = JsonObject.Parse(result); + + LoginInDto r = new LoginInDto(); + r.UserInfo = new UserInfoDto(); + r.TokenInfo = new AccessTokenDto(); + + if (jObject["errno"] == 0) + { + string datajson = jObject["data"].ToString(); + var _loginDto = JsonConvert.DeserializeObject(datajson); + r.UserInfo = loginInfo.UserInfo; + r.SignedIn = true; + var token = await CreateToken(loginInfo.UserInfo, _loginDto, Token); + r.TokenInfo = token; + loginInfo.TokenInfo = token; + + var ops_login_time = token.Expired.AddDays(1) - DateTime.Now;//用于正式 + _redisClientService.SetStringKey($"ops_login_{token.Token}", loginInfo, ops_login_time); + return Result.ReSuccess(r); + } + else + { + //失败了1:就把登录的token清除 2: ucid添加到黑名单 + var time = new TimeSpan(r.TokenInfo.Expired.Day, r.TokenInfo.Expired.Hour, r.TokenInfo.Expired.Minute, r.TokenInfo.Expired.Second, r.TokenInfo.Expired.Millisecond); + _redisClientService.SetStringKey($"ops_black_token_{r.UserInfo.UcId}", r.TokenInfo.Token, time); + this.RemoveLoginInfo(r.TokenInfo.Token); + r.SignedIn = false; + return Result.ReFailure(jObject["errmsg"], jObject["errno"]); + } + } + + /// + /// 单点退出通知token失效 + /// + /// + /// + /// + /// + public async Task LoginOutSingleAsync(int ucid, string token, int expires_in) + { + await Task.Run(() => + { + var cache_token = _redisClientService.GetStringKey($"ops_black_token_{ucid}"); + if (string.IsNullOrEmpty(cache_token)) + { + DateTime expires_time = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)).AddSeconds(expires_in); + var time = new TimeSpan(expires_time.Day, expires_time.Hour, expires_time.Minute, expires_time.Second, expires_time.Millisecond); + _redisClientService.SetStringKey($"ops_black_token_{ucid}", token, time); + this.RemoveLoginInfo(token); + } + }); + } + + /// + /// 单点退出通知token失效 + /// + /// 这个是单点传过来的SeesionId + /// + public async Task LoginOutSingleAsync(string SeesionId) + { + var logininfo = _redisClientService.GetStringKey($"ops_login_{SeesionId}"); + await Task.Run(() => + { + if (logininfo != null) + { + var cache_token = _redisClientService.GetStringKey($"ops_black_token_{logininfo.UserInfo.UcId}"); + if (string.IsNullOrEmpty(cache_token)) + { + DateTime expires_time = logininfo.TokenInfo.Expired; + var time = new TimeSpan(expires_time.Day, expires_time.Hour, expires_time.Minute, expires_time.Second, expires_time.Millisecond); + _redisClientService.SetStringKey($"ops_black_token_{logininfo.UserInfo.UcId}", logininfo.TokenInfo.Token, time); + this.RemoveLoginInfo(logininfo.TokenInfo.Token); + } + } + }); + } + + /// + /// 缓存退出的token + /// + /// + /// + private async Task CacheOutToken(LoginOutDto dto) + { + await Task.Run(() => + { + if (!string.IsNullOrEmpty(dto.AccessToken)) + { + var time = new TimeSpan(dto.ExpiresIn.Day, dto.ExpiresIn.Hour, dto.ExpiresIn.Minute, dto.ExpiresIn.Second, dto.ExpiresIn.Millisecond); + _redisClientService.SetStringKey($"ops_black_token_{dto.UcId}", dto.AccessToken, time); + this.RemoveLoginInfo(dto.Token); + + } + }); + } + + /// + /// 获取登录后的信息 + /// + /// + /// + public LoginInDto GetLoginInfo(string authorization) + { + string token = string.Empty; + if (authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) + { + token = authorization.Substring("Bearer ".Length).Trim(); + } + var logininfo = _redisClientService.GetStringKey($"ops_login_{token}"); + return logininfo; + } + + /// + /// 移除登录后的用户信息 + /// + /// + private void RemoveLoginInfo(string token) + { + if (!string.IsNullOrEmpty(token)) + { + var info = _redisClientService.GetStringKey($"ops_login_{token}"); + if (info != null) + { + _redisClientService.RemoveStringKey($"ops_login_{token}"); + } + } + } + + /// + /// 单点-在线接口 + /// + /// + /// + public async Task Online(string sessionId) + { + var request = new { PHPSESSID = sessionId }; + string result = _httpClientHelp.PostHttpNoData(_soaOptions.Url + "/uc/user/online.html?app_id=" + _soaOptions.AppId, sessionId); + return Result.ReSuccess(); + } + + /// + /// 单点-下线接口 + /// + /// + /// + public async Task Offline(string sessionId) + { + var request = new { PHPSESSID = sessionId }; + string result = _httpClientHelp.PostHttpNoData(_soaOptions.Url + "/uc/user/offline.html?app_id=" + _soaOptions.AppId, sessionId); + return Result.ReSuccess(); + } + } +} diff --git a/src/WMS.Web.Domain/Services/Public/RedisClientService.cs b/src/WMS.Web.Domain/Services/Public/RedisClientService.cs new file mode 100644 index 00000000..a631ed9d --- /dev/null +++ b/src/WMS.Web.Domain/Services/Public/RedisClientService.cs @@ -0,0 +1,93 @@ +using Microsoft.Extensions.Options; +using Newtonsoft.Json; +using StackExchange.Redis; +using System; +using System.Collections.Generic; +using System.Text; +using WMS.Web.Domain.Options; + +namespace WMS.Web.Domain.Services.Public +{ + public class RedisClientService + { + private static readonly object Locker = new object(); + + private ConnectionMultiplexer redisMultiplexer; + IDatabase db = null; + private readonly AppOptions _options; + public RedisClientService(IOptions options) + { + _options = options?.Value; + redisMultiplexer = ConnectionMultiplexer.Connect(_options.RedisConnectionString); + db = redisMultiplexer.GetDatabase(); + } + + #region String + /// + /// 保存单个key value + /// + /// + /// + /// + /// + public bool SetStringKey(string key, string value, TimeSpan? expiry = default(TimeSpan?)) + { + var lastKey = _options.RedisDirectory + ":" + key; + return db.StringSet(lastKey, value, expiry); + } + + /// + /// 获取单个key的值 + /// + public RedisValue GetStringKey(string key) + { + var lastKey = _options.RedisDirectory + ":" + key; + return db.StringGet(lastKey); + } + + /// + /// 移除redis + /// + /// + /// + public bool RemoveStringKey(string key) + { + var lastKey = _options.RedisDirectory + ":" + key; + return db.KeyDelete(lastKey); + } + /// + /// 获取一个key的对象 + /// + public T GetStringKey(string key) + { + if (db == null) + { + return default; + } + var lastKey = _options.RedisDirectory + ":" + key; + var value = db.StringGet(lastKey); + if (value.IsNullOrEmpty) + { + return default; + } + return JsonConvert.DeserializeObject(value); + } + + /// + /// 保存一个对象 + /// + /// + public bool SetStringKey(string key, T obj, TimeSpan? expiry = default(TimeSpan?)) + { + if (db == null) + { + return false; + } + var lastKey = _options.RedisDirectory + ":" + key; + string json = JsonConvert.SerializeObject(obj); + return db.StringSet(lastKey, json, expiry); + } + + #endregion + } +} diff --git a/src/WMS.Web.Domain/Services/Public/SingleDataService.cs b/src/WMS.Web.Domain/Services/Public/SingleDataService.cs new file mode 100644 index 00000000..6740cfd6 --- /dev/null +++ b/src/WMS.Web.Domain/Services/Public/SingleDataService.cs @@ -0,0 +1,473 @@ +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; +using WMS.Web.Core.Dto.SingleData; +using WMS.Web.Core.Internal.Results; +using WMS.Web.Domain.IService.Public; +using WMS.Web.Domain.Options; +using WMS.Web.Domain.Values.Single; + +namespace WMS.Web.Domain.Services.Public +{ + /// + /// 单点数据返回服务 + /// + public class SingleDataService : ISingleDataService + { + private readonly AppOptions _options; + private readonly IHttpClientService _httpClientService; + private readonly ILogger _logger; + private readonly IMemoryCache _memoryCache; + private int hours = 10;//过期时间 默认10小时 + + public SingleDataService(IOptions options, IHttpClientService httpClientService, ILogger logger, IMemoryCache memoryCache) + { + this._memoryCache = memoryCache; + this._options = options?.Value; + this._httpClientService = httpClientService; + this._logger = logger; + } + + /// + /// 获取单点数据:根据接口方法名和公司ID + /// 后端列表查询统一使用 + /// + /// + /// + /// + public string GetSingleData(SingleAction action, int companyId, int id) + { + try + { + if (id == 0) + return ""; + + var cache_key = action + "_" + companyId + "_IdGetName"; + var dic = _memoryCache.Get>(cache_key); + if (dic == null || dic.Count <= 0 || !dic.ContainsKey(id)) + { + if (dic != null) + { + + string no_data_key = cache_key + "_NoData"; + var cache_id = _memoryCache.Get(no_data_key); + if (cache_id == true) return ""; + //未找到数据请求 + if (!dic.ContainsKey(id)) + { + _memoryCache.Set(no_data_key, true, new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromMinutes(30))); + } + } + var list = SingleDataPost(action, companyId, cache_key); + if (list.Count() <= 0) return ""; + dic = list.ToDictionary(s => s.Id, s => s.Name); + _memoryCache.Set(cache_key, dic, new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromHours(hours))); + } + if (!dic.ContainsKey(id)) return ""; + return dic[id]; + } + catch (Exception ex) + { + _logger.LogError($"请求单点数据错误:Action->{action.ToString()},CompanyeId->{companyId},Id->{id},(错误原因)=>{ex.Message}"); + return ""; + } + } + + /// + /// 获取单点数据:根据接口方法名和公司ID + /// 后端列表查询统一使用 + /// + /// + /// + /// + public decimal GetSingleDataNumber(SingleAction action, int companyId, int id) + { + try + { + if (id == 0) + return 0; + + var cache_key = action + "_" + companyId + "_IdGetNumber"; + var dic = _memoryCache.Get>(cache_key); + if (dic == null || dic.Count <= 0 || !dic.ContainsKey(id)) + { + if (dic != null) + { + string no_data_key = cache_key + "_NoData"; + var cache_id = _memoryCache.Get(no_data_key); + if (cache_id == true) return 0; + //未找到数据请求 + if (!dic.ContainsKey(id)) + { + _memoryCache.Set(no_data_key, true, new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromMinutes(30))); + } + } + + var list = SingleDataPost(action, companyId, cache_key); + if (list.Count() <= 0) return 0; + + dic = list.ToDictionary(s => s.Id, s => s.Number); + _memoryCache.Set(cache_key, dic, new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromHours(hours))); + } + + if (!dic.ContainsKey(id)) return 0; + return dic[id]; + } + catch (Exception ex) + { + _logger.LogError($"请求单点数据错误:{action.ToString()}=>{ex.Message}"); + return 0; + } + } + + /// + /// 获取单点数据:根据接口方法名和公司ID + /// 后端列表查询统一使用 + /// + /// + /// + /// + public string GetSingleDataCode(SingleAction action, int companyId, int id) + { + try + { + if (id == 0) + return ""; + + var cache_key = action + "_" + companyId + "_IdGetCode"; + var dic = _memoryCache.Get>(cache_key); + if (dic == null || dic.Count <= 0 || !dic.ContainsKey(id)) + { + if (dic != null) + { + string no_data_key = cache_key + "_NoData"; + var cache_id = _memoryCache.Get(no_data_key); + if (cache_id == true) return ""; + //未找到数据请求 + if (!dic.ContainsKey(id)) + { + _memoryCache.Set(no_data_key, true, new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromMinutes(30))); + } + } + + var list = SingleDataPost(action, companyId, cache_key); + if (list.Count() <= 0) return ""; + + dic = list.ToDictionary(s => s.Id, s => s.Code); + _memoryCache.Set(cache_key, dic, new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromHours(hours))); + } + + if (!dic.ContainsKey(id)) return ""; + return dic[id]; + } + catch (Exception ex) + { + _logger.LogError($"请求单点数据错误:{action.ToString()}=>{ex.Message}"); + return ""; + } + } + + /// + /// 根据名字模糊匹配 + /// + /// + /// + /// + /// + public List GetIdsBySingleName(SingleAction action, int companyId, string name) + { + try + { + var cache_key = action + "_" + companyId + "_NameGetIds"; + var dic = _memoryCache.Get>(cache_key); + if (dic == null || dic.Count <= 0) + { + var list = SingleDataPost(action, companyId, cache_key); + if (list.Count() <= 0) return new List(); + + dic = list.ToDictionary(s => s.Id, s => s.Name); + _memoryCache.Set(cache_key, dic, new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromHours(hours))); + } + var res = from d in dic where d.Value.Contains(name) select d; + return res.Select(s => s.Key).ToList(); + } + catch (Exception ex) + { + _logger.LogError($"请求单点数据错误:{action.ToString()}=>{ex.Message}"); + return new List(); + } + } + + /// + /// 获取单点数据:根据接口方法名和公司ID + /// 后端列表查询统一使用 + /// + /// + /// + /// + public string GetSingleData(SingleAction action, int companyId, string code) + { + try + { + if (string.IsNullOrEmpty(code)) + return ""; + + var cache_key = action + "_" + companyId + "_CodeGetName"; + var dic = _memoryCache.Get>(cache_key); + //仓库和客户仓库 不能为空了就重新请求 应为 这里是从仓库和客户仓库取值 有一个必然取不到 + if (dic == null || dic.Count <= 0) + { + if (dic != null) + { + string no_data_key = cache_key + "_NoData"; + var cache_id = _memoryCache.Get(no_data_key); + if (cache_id == true) return ""; + //未找到数据请求 + if (!dic.ContainsKey(code)) + { + _memoryCache.Set(no_data_key, true, new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromMinutes(30))); + } + } + + var list = SingleDataPost(action, companyId, cache_key); + if (list.Count() <= 0) return ""; + + dic = list.ToDictionary(s => s.Code, s => s.Name); + _memoryCache.Set(cache_key, dic, new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromHours(hours))); + } + + if (!dic.ContainsKey(code)) return ""; + return dic[code]; + } + catch (Exception ex) + { + _logger.LogError($"请求单点数据错误:{action.ToString()}=>{ex.Message}"); + return ""; + } + } + + /// + /// 获取单点数据集合:泛型-同步 + /// + /// + /// + /// + /// + public List GetSingleData(SingleAction action, int companyId) where T : class + { + try + { + var cache_key = action + "_list_" + companyId; + var list = _memoryCache.Get>(cache_key); + if (list == null || list.Count <= 0) + list = SingleDataPost(action, companyId, cache_key); + + return list; + } + catch (Exception ex) + { + _logger.LogError($"请求单点数据错误:{action.ToString()}=>{ex.Message}"); + return null; + } + } + + /// + /// 获取单点数据集合:泛型-异步 + /// + /// + /// + /// + /// + public async Task> GetSingleDataAsync(SingleAction action, int companyId) where T : class + { + try + { + var cache_key = action + "_list_" + companyId; + var list = _memoryCache.Get>(cache_key); + if (list == null || list.Count <= 0) + list = await SingleDataPostAsync(action, companyId, cache_key); + + return list; + } + catch (Exception ex) + { + _logger.LogError($"请求单点数据错误:{action.ToString()}=>{ex.Message}"); + return null; + } + } + + /// + /// 获取单点数据集合:泛型-异步-无缓存 + /// + /// + /// + /// + /// + public async Task> GetSingleDataNoCacheAsync(SingleAction action, int companyId) where T : class + { + try + { + var list = await SingleDataPostAsync(action, companyId, ""); + return list; + } + catch (Exception ex) + { + _logger.LogError($"请求单点数据错误:{action.ToString()}=>{ex.Message}"); + return null; + } + } + + /// + /// 单点数据:可对接全部接口 + /// + /// 返回对象 + /// 请求对象 + /// 方法名称 + /// 请求对象 + /// 方法名称 + /// 控制器名称 + /// + public async Task GetSingleData(X dto, Y action, SingleControllerType type = SingleControllerType.Single) where T : class + { + try + { + var para = JsonExtensions.SerializeToJson(dto); + var cache_key = action + "_list_" + type + "_" + para; + var list = _memoryCache.Get(cache_key); + if (list == null) + { + var url = _options.SingleBaseUrl + "/" + type.ToString() + "/" + action.ToString(); + var result = await _httpClientService.PostAsync(url, para); + _memoryCache.Set(cache_key, result, new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromHours(hours))); + } + return _memoryCache.Get(cache_key); + } + catch (Exception ex) + { + _logger.LogError($"请求单点数据错误:{action.ToString()}=>{ex.Message}"); + return default(T); + } + } + + /// + /// 单点数据:可对接全部接口 + /// + /// 返回对象 + /// 请求对象 + /// 方法名称 + /// 请求对象 + /// 方法名称 + /// 控制器名称 + /// + public async Task GetSingleDataNoCache(X dto, Y action, SingleControllerType type = SingleControllerType.Single) where T : class + { + try + { + var para = JsonExtensions.SerializeToJson(dto); + var url = _options.SingleBaseUrl + "/" + type.ToString() + "/" + action.ToString(); + var result = await _httpClientService.PostAsync(url, para); + return result; + } + catch (Exception ex) + { + _logger.LogError($"请求单点数据错误:{action.ToString()}=>{ex.Message}"); + return default(T); + } + } + + /// + /// 获取单点数据:配置项接口 + /// + /// + /// + /// + /// + /// + public async Task GetSysConfigData(X dto, SysConfigAction action) + { + try + { + var para = JsonExtensions.SerializeToJson(dto); + var url = _options.SingleBaseUrl + "/" + SingleControllerType.SysConfig.ToString() + "/" + action.ToString(); + var result = await _httpClientService.PostAsync(url, para); + return result; + } + catch (Exception ex) + { + _logger.LogError($"请求单点数据错误:{action.ToString()}=>{ex.Message}"); + return default(T); + } + } + + + #region 私有方法 + + /// + /// 请求单点服务接口:同步 + /// + /// + /// + /// + /// + private List SingleDataPost(SingleAction action, int companyId, string cache_key) + { + var dto = new SingleDataRequest(companyId); + //var para = JsonExtensions.SerializeToJson(dto); + var para = JsonSerializer.Serialize(dto); + var url = _options.SingleBaseUrl + "/" + SingleControllerType.Single.ToString() + "/" + action.ToString(); + var result = _httpClientService.PostAsync>(url, para).GetAwaiter().GetResult(); + if (!result.Success) + return new List(); + return result.Data.ToList(); + } + + /// + /// 请求单点服务接口:异步 + /// + /// + /// + /// + /// + private async Task> SingleDataPostAsync(SingleAction action, int companyId, string cache_key) + { + var dto = new SingleDataRequest(companyId); + var para = JsonSerializer.Serialize(dto); + var url = _options.SingleBaseUrl + "/" + SingleControllerType.Single.ToString() + "/" + action.ToString(); + var result = await _httpClientService.PostAsync>(url, para); + if (result.Success) + { + if (!string.IsNullOrEmpty(cache_key)) + { + _memoryCache.Set(cache_key, result.Data.ToList(), new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromHours(hours))); + return _memoryCache.Get>(cache_key); + } + return result.Data.ToList(); + } + return null; + } + + + + #endregion + /// + /// 获取客户仓库 + /// + /// + /// + /// + public string GetCustomerStock(int companyId, string customerStockCode) + { + return string.IsNullOrEmpty(this.GetSingleData(SingleAction.CustomerStocks, companyId, customerStockCode)) ? + this.GetSingleData(SingleAction.Stocks, companyId, customerStockCode) : + this.GetSingleData(SingleAction.CustomerStocks, companyId, customerStockCode); + } + + } +} diff --git a/src/WMS.Web.Domain/Values/ResultCodes.cs b/src/WMS.Web.Domain/Values/ResultCodes.cs new file mode 100644 index 00000000..95de178c --- /dev/null +++ b/src/WMS.Web.Domain/Values/ResultCodes.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WMS.Web.Domain.Values +{ + /// + /// 错误提示信息 + /// + public partial class ResultCodes + { + } +} diff --git a/src/WMS.Web.Domain/Values/Single/SingleAction.cs b/src/WMS.Web.Domain/Values/Single/SingleAction.cs new file mode 100644 index 00000000..9b7e3c14 --- /dev/null +++ b/src/WMS.Web.Domain/Values/Single/SingleAction.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Text; +using WMS.Web.Core; + +namespace WMS.Web.Domain.Values.Single +{ + /// + /// 对接单点的接口方法-枚举 + /// + public enum SingleAction + { + /// + /// 组织集合 + /// + [EnumRemark("组织")] + Orgs = 1, + /// + /// 用户集合 + /// + [EnumRemark("用户")] + Users = 2, + /// + /// 人员集合 + /// + [EnumRemark("人员")] + Staffs = 3, + /// + /// 供应商集合 + /// + [EnumRemark("供应商")] + Suppliers = 4, + /// + /// 客户集合 + /// + [EnumRemark("客户")] + Customers = 5, + /// + /// 收款条件集合 + /// + [EnumRemark("收款条件")] + CollectionTerms = 6, + /// + /// 付款条件集合 + /// + [EnumRemark("付款条件")] + PaymentTerms = 7, + /// + /// 结算方式集合 + /// + [EnumRemark("结算方式")] + SettlementMethods = 8, + /// + /// 结算币别集合 + /// + [EnumRemark("结算币别")] + SettlementCurrencys = 9, + /// + /// 税率集合 + /// + [EnumRemark("税率")] + TaxRates = 10, + /// + /// 汇率集合 + /// + [EnumRemark("汇率")] + ExchangeRates = 11, + /// + /// 仓库集合 + /// + [EnumRemark("仓库")] + Stocks = 12, + /// + /// 单位集合 + /// + [EnumRemark("单位")] + Units = 13, + /// + /// 客户仓库集合 + /// + [EnumRemark("客户仓库")] + CustomerStocks = 14, + /// + /// 部门集合 + /// + [EnumRemark("部门")] + Depts = 15, + /// + /// 仓库211集合 + /// + [EnumRemark("仓库211")] + StocksWith211 = 16, + /// + /// 供应商默认联系人集合 + /// + [EnumRemark("供应商默认联系人")] + SuppliersContacts = 17, + /// + /// 菜单集合 + /// + [EnumRemark("菜单")] + Menus = 18, + + } +} diff --git a/src/WMS.Web.Domain/Values/Single/SingleControllerType.cs b/src/WMS.Web.Domain/Values/Single/SingleControllerType.cs new file mode 100644 index 00000000..7561f8aa --- /dev/null +++ b/src/WMS.Web.Domain/Values/Single/SingleControllerType.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WMS.Web.Domain.Values.Single +{ + /// + /// 单点-控制器枚举 + /// + public enum SingleControllerType + { + /// + /// 单点OPS列表数据-控制器 + /// + Single = 1, + /// + /// 单点配置项数据-控制器 + /// + SysConfig = 2, + /// + /// 单点登录项数据-控制器 + /// + Login = 3, + /// + /// 单点公共接口数据-控制器 + /// + Public = 4 + } +} diff --git a/src/WMS.Web.Domain/Values/Single/SingleLoginAction.cs b/src/WMS.Web.Domain/Values/Single/SingleLoginAction.cs new file mode 100644 index 00000000..2f496ccb --- /dev/null +++ b/src/WMS.Web.Domain/Values/Single/SingleLoginAction.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WMS.Web.Domain.Values.Single +{ + /// + /// 单点数据接口-登录要使用的数据接口-方法枚举 + /// + public enum SingleLoginAction + { + /// + /// 菜单 + /// + Menus = 1, + /// + /// 人员 + /// + Staff = 2, + /// + /// 公司 + /// + Company = 3, + /// + /// 供应商 + /// + Supplier = 4, + /// + /// 客户 + /// + Customer = 5, + /// + /// 全部信息 + /// + All = 6, + /// + /// 公司信息 + /// + CompanyInfo = 7, + + } +} diff --git a/src/WMS.Web.Domain/Values/Single/SysConfigAction.cs b/src/WMS.Web.Domain/Values/Single/SysConfigAction.cs new file mode 100644 index 00000000..569ba8de --- /dev/null +++ b/src/WMS.Web.Domain/Values/Single/SysConfigAction.cs @@ -0,0 +1,186 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WMS.Web.Domain.Values.Single +{ + /// + /// 单点数据:配置项和公共接口的方法枚举值 + /// + public enum SysConfigAction + { + /// + /// 供应商-根据名称和公司 + /// + GetSupplierByNameAndCompany = 1, + /// + /// 组织-根据公司 + /// + GetOrgByCompany = 2, + /// + /// 部门-根据组织和公司 + /// + GetDeptByOrgAndCompany = 3, + /// + /// 人员-根据公司 + /// + GetStaffByCompany = 4, + /// + /// 人员-根据部门和公司 + /// + GetStaffByDeptAndCompany = 5, + /// + /// 人员-根据组织和公司 + /// + GetStaffByOrgAndCompany = 6, + /// + /// 客户-根据公司 + /// + GetCustomerByCompany = 7, + /// + /// 客户-根据客户和组织和公司 + /// + GetCustomerByCustomerAndOrgAndCompany = 8, + /// + /// 客户信息-根据客户和组织和公司 + /// + GetCustomerInfoByCustomerAndOrgAndCompany = 9, + /// + /// 收款条件-根据公司 + /// + GetCollectionTermsByCompany = 10, + /// + /// 付款条件-根据公司 + /// + GetPaymentTermByCompany = 11, + /// + /// 结算方式-根据公司 + /// + GetSettlementMethodByCompany = 12, + /// + /// 结算币别-根据公司 + /// + GetSettlementCurrencyByCompany = 13, + /// + /// 单位-根据公司 + /// + GetUnitByCompany = 14, + /// + /// 单位(部分属性)-根据公司 + /// + GetUnitPropertyByCompany = 15, + /// + /// 税率-根据公司 + /// + GetTaxRateByCompany = 16, + /// + /// 仓库-根据名称和公司 + /// + GetWarehouseByNameAndCompany = 17, + /// + /// 仓库-根据组织和公司 + /// + GetWarehouseByOrgAndCompany = 18, + /// + /// 仓库(不是调拨中转仓)-根据组织和公司 + /// + GetWarehouseByOrgAndCompanyForNotTransfer = 19, + /// + /// 仓库(211)-根据组织和公司 + /// + GetWarehouseByOrgAndCompanyFor211 = 20, + /// + /// 仓库-根据客户和公司 + /// + GetWareouseByCustomerAndCompany = 21, + + /// + /// 仓位-根据仓库和名称 + /// + GetChildWarehouseByPid = 22, + /// + /// 仓位-根据- + /// + GetChildWarehouse = 23, + /// + /// 汇率信息-根据原币、目标币和公司 + /// + GetRateInfoByFromToAndCompany = 24, + /// + /// 客户仓库-根据客户和组织和公司 + /// + GetCustomerStockByCustomerAndOrgAndCompany = 25, + /// + /// 付款条件,结算币别,结算方式,采购员,采购部门-根据供应商和组织 + /// + GetPtAndScAndSmAndBuyerAndDeptBySupplierAndOrg = 26, + /// + /// 获取仓库:根据仓库id + /// + GetWarehouseByIds = 27, + /// + /// 获取库存:根据组织和公司 + /// + GetCustomerByOrgAndCompany = 28, + + /// + /// 获取客户仓库:根据客户IDS和组织和公司 + /// + GetCustomerStockByCustomerListAndOrgAndCompany = 29, + /// + /// 汇率(所有) + /// + GetRateListByFromToAndCompany = 30, + + /// + /// 供应商选择后获取:付款条件,结算币别,结算方式,采购员,采购部门,根据组织IDS + /// + GetPtAndScAndSmAndBuyerAndDeptByOrgs = 31, + /// + /// 获取客户仓库:根据code集合 + /// + GetCustomerStockListByCodes = 32, + /// + /// 供应商:根据ids + /// + GetSupperByIds = 33, + /// + /// 根据公司搜索所有仓库(计算补货频次) + /// + GetWarehouseReplenDatebyCompany = 34, + /// + /// 获取仓库:根据codes + /// + GetWarehouseByCodes = 35, + /// + /// 获取客户仓库:根据codes + /// + GetCustomerStockByCodes = 36, + + /// + /// 获取调拨中转仓库:根据公司 + /// + GetWarehouseTransferByCompany = 37, + /// + /// 获取供应商数据根据ids + /// + GetSupperAbout1ByIds = 38, + /// + /// 获取仓库:根据默认补货客户 + /// + GetWarehouseByDefaultReplenishCustomer = 39, + /// + /// 获取用户(ID和Name):根据公司 + /// + GetUsersByCompany = 40, + /// + /// 全部部门-根据组织和公司:不处理子级 + /// + GetDeptAllByOrgAndCompany = 41, + + /// + /// 获取全部员工:根据公司和组织 + /// + GetStaffAllByOrgAndCompany = 42, + } +} diff --git a/src/WMS.Web.Domain/WMS.Web.Domain.csproj b/src/WMS.Web.Domain/WMS.Web.Domain.csproj index bcd91faa..f4b6e518 100644 --- a/src/WMS.Web.Domain/WMS.Web.Domain.csproj +++ b/src/WMS.Web.Domain/WMS.Web.Domain.csproj @@ -13,11 +13,6 @@ - - - - -