| | |
| | | <PackageReference Include="System.Linq.Dynamic.Core" Version="1.6.5" /> |
| | | <PackageReference Include="System.Net.Http" Version="4.3.4" /> |
| | | <PackageReference Include="System.Private.Uri" Version="4.3.2" /> |
| | | <PackageReference Include="TencentCloudSDK.Sms" Version="3.0.1252" /> |
| | | <PackageReference Include="TencentCloudSDK" Version="3.0.1268" /> |
| | | <PackageReference Include="UAParser" Version="3.1.47" /> |
| | | <PackageReference Include="Yitter.IdGenerator" Version="1.0.14" /> |
| | | <PackageReference Include="BouncyCastle.Cryptography" Version="2.6.1" Aliases="BouncyCastleV2" /> |
| | |
| | | /// </summary> |
| | | [Required(ErrorMessage = "租户不能为空")] |
| | | public long? TenantId { get; set; } |
| | | |
| | | |
| | | |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | |
| | | public override async Task<bool> PipelineAsync(AuthorizationHandlerContext context, DefaultHttpContext httpContext) |
| | | { |
| | | // 已自动验证 Jwt Token 有效性 |
| | | return await CheckAuthorizeAsync(httpContext); |
| | | |
| | | if (App.User.FindFirst(ClaimConst.UserType)?.Value == "Customer") |
| | | { |
| | | //客户登录 不需要做起验证 |
| | | return true; |
| | | } |
| | | else |
| | | // 已自动验证 Jwt Token 有效性 |
| | | return await CheckAuthorizeAsync(httpContext); |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | EndProject |
| | | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FZCZTB.NET.SYSService", "FZCZTB.NET.SYSService\FZCZTB.NET.SYSService.csproj", "{9E19230C-7A8F-4440-B5D9-27D0038C13F6}" |
| | | EndProject |
| | | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EzTencentCloud", "EzTencentCloud\EzTencentCloud.csproj", "{D56DD688-FBD2-43DA-B07F-AFC78C9F16F6}" |
| | | EndProject |
| | | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EzUpFile", "EzUpFile\EzUpFile.csproj", "{5333BCDD-09C7-4021-AC43-CBFA63505D4D}" |
| | | EndProject |
| | | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "解决方案项", "解决方案项", "{251B31C8-0A9E-4948-9534-D167A56201F3}" |
| | | EndProject |
| | | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "cylsg.utility", "cylsg.utility\cylsg.utility.csproj", "{743B2BC9-11AE-4354-90D9-560B592F63CA}" |
| | | EndProject |
| | | Global |
| | | GlobalSection(SolutionConfigurationPlatforms) = preSolution |
| | | Debug|Any CPU = Debug|Any CPU |
| | |
| | | {9E19230C-7A8F-4440-B5D9-27D0038C13F6}.Debug|Any CPU.Build.0 = Debug|Any CPU |
| | | {9E19230C-7A8F-4440-B5D9-27D0038C13F6}.Release|Any CPU.ActiveCfg = Release|Any CPU |
| | | {9E19230C-7A8F-4440-B5D9-27D0038C13F6}.Release|Any CPU.Build.0 = Release|Any CPU |
| | | {D56DD688-FBD2-43DA-B07F-AFC78C9F16F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
| | | {D56DD688-FBD2-43DA-B07F-AFC78C9F16F6}.Debug|Any CPU.Build.0 = Debug|Any CPU |
| | | {D56DD688-FBD2-43DA-B07F-AFC78C9F16F6}.Release|Any CPU.ActiveCfg = Release|Any CPU |
| | | {D56DD688-FBD2-43DA-B07F-AFC78C9F16F6}.Release|Any CPU.Build.0 = Release|Any CPU |
| | | {5333BCDD-09C7-4021-AC43-CBFA63505D4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
| | | {5333BCDD-09C7-4021-AC43-CBFA63505D4D}.Debug|Any CPU.Build.0 = Debug|Any CPU |
| | | {5333BCDD-09C7-4021-AC43-CBFA63505D4D}.Release|Any CPU.ActiveCfg = Release|Any CPU |
| | | {5333BCDD-09C7-4021-AC43-CBFA63505D4D}.Release|Any CPU.Build.0 = Release|Any CPU |
| | | {743B2BC9-11AE-4354-90D9-560B592F63CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
| | | {743B2BC9-11AE-4354-90D9-560B592F63CA}.Debug|Any CPU.Build.0 = Debug|Any CPU |
| | | {743B2BC9-11AE-4354-90D9-560B592F63CA}.Release|Any CPU.ActiveCfg = Release|Any CPU |
| | | {743B2BC9-11AE-4354-90D9-560B592F63CA}.Release|Any CPU.Build.0 = Release|Any CPU |
| | | EndGlobalSection |
| | | GlobalSection(SolutionProperties) = preSolution |
| | | HideSolutionNode = FALSE |
New file |
| | |
| | | <Project Sdk="Microsoft.NET.Sdk"> |
| | | |
| | | <PropertyGroup> |
| | | <TargetFramework>net8.0</TargetFramework> |
| | | <ImplicitUsings>enable</ImplicitUsings> |
| | | <Nullable>enable</Nullable> |
| | | </PropertyGroup> |
| | | |
| | | <ItemGroup> |
| | | <ProjectReference Include="..\Admin.NET.Core\Admin.NET.Core.csproj" /> |
| | | </ItemGroup> |
| | | |
| | | <ItemGroup> |
| | | <None Update="TencentCloudConfig.json"> |
| | | <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> |
| | | </None> |
| | | </ItemGroup> |
| | | |
| | | </Project> |
New file |
| | |
| | | using Furion.DependencyInjection; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | using TencentCloud.Iai.V20200303.Models; |
| | | using TencentCloud.Ocr.V20181119.Models; |
| | | |
| | | namespace EzTencentCloud |
| | | { |
| | | /// <summary> |
| | | /// 腾讯云服务 |
| | | /// </summary> |
| | | public interface ITencentCloudService: IScoped |
| | | { |
| | | #region orc 图文识别 |
| | | /// <summary> |
| | | /// 身份证识别,并剪裁 |
| | | /// </summary> |
| | | /// <param name="ImageBase64">图片base64</param> |
| | | /// <param name="isFRONT"></param> |
| | | /// <returns></returns> |
| | | IDCardOCRResponse IdCord(string ImageBase64, bool isFRONT); |
| | | /// <summary> |
| | | /// 获取剪裁后的身份证照片 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | string GetIdCordImg(); |
| | | /// <summary> |
| | | /// 营业执照认证 |
| | | /// </summary> |
| | | /// <param name="ImageBase64"> 图片base64</param> |
| | | /// <returns></returns> |
| | | BizLicenseOCRResponse BizLicenseOCR(string ImageBase64); |
| | | #endregion |
| | | #region iai 人脸识别 |
| | | /// <summary> |
| | | /// 创建人脸库,一般一个云账号只需要创建一次 |
| | | /// </summary> |
| | | public void IaiCreatGroup(); |
| | | /// <summary> |
| | | /// 人脸验证 一般分数超过50 分识别为一个人 |
| | | /// </summary> |
| | | /// <param name="img64"></param> |
| | | /// <param name="PersonNameId"></param> |
| | | /// <returns></returns> |
| | | public VerifyFaceResponse VerifyFace(string img64, string PersonNameId); |
| | | /// <summary> |
| | | /// 增加一个人的人脸图片特征,一个最多只允许有五个人脸特这 |
| | | /// </summary> |
| | | /// <param name="img64"></param> |
| | | /// <param name="PersonNameId"></param> |
| | | /// <param name="PersonName"></param> |
| | | /// <param name="PersonGender"></param> |
| | | /// <returns></returns> |
| | | public bool IaiAddPersoImg(string img64, string PersonNameId, string PersonName, int PersonGender); |
| | | |
| | | /// <summary> |
| | | /// 增加一个人 |
| | | /// </summary> |
| | | /// <param name="img64">人脸照</param> |
| | | /// <param name="PersonNameId">人脸ID 一个云账户中唯一</param> |
| | | /// <param name="PersonName">姓名</param> |
| | | /// <param name="PersonGender">性别 0代表未填写,1代表男性,2代表女性。</param> |
| | | /// <returns></returns> |
| | | public bool IaiAddPerso(string img64, string PersonNameId, string PersonName, int PersonGender); |
| | | #endregion |
| | | |
| | | } |
| | | } |
New file |
| | |
| | | { |
| | | "TencentCloud": { |
| | | "SecretId": "AKIDIPFp9CyThfMmvoQlpeCl34pKYVBahY9T", |
| | | "SecretKey": "4rNcaHhrkMhmb9QQ9bmgKipfFZcOt86n" |
| | | }, |
| | | //人脸库相关配置 |
| | | "IAIGroupSet": { |
| | | "ID": "cylsg", |
| | | "Name": "川印临时工" |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Net.Sockets; |
| | | using System.Net; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | |
| | | using Newtonsoft.Json; |
| | | using TencentCloud.Common; |
| | | using TencentCloud.Common.Profile; |
| | | using Furion.DependencyInjection; |
| | | using Furion; |
| | | using TencentCloud.Ocr.V20181119.Models; |
| | | using TencentCloud.Iai.V20200303.Models; |
| | | using TencentCloud.Iai.V20200303; |
| | | using TencentCloud.Ocr.V20181119; |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | namespace EzTencentCloud |
| | | { |
| | | public class TencentCloudService: ITencentCloudService, IScoped |
| | | { |
| | | |
| | | |
| | | |
| | | |
| | | public TencentCloudService() |
| | | { |
| | | |
| | | } |
| | | #region orc 图文识别 |
| | | /// <summary> |
| | | /// 剪裁后的身份证图片 |
| | | /// </summary> |
| | | public string CropIdCard { get; set; } |
| | | |
| | | public string GetIdCordImg() |
| | | { |
| | | if (string.IsNullOrEmpty(CropIdCard)) |
| | | return ""; |
| | | else |
| | | return CropIdCard; |
| | | |
| | | } |
| | | |
| | | public IDCardOCRResponse IdCord(string ImageBase64, bool isFRONT) |
| | | { |
| | | try |
| | | { |
| | | |
| | | Credential cred = new Credential |
| | | { |
| | | SecretId = App.Configuration["TencentCloud:SecretId"] ?? "AKIDIPFp9CyThfMmvoQlpeCl34pKYVBahY9T", |
| | | SecretKey = App.Configuration["TencentCloud:SecretKey"] ?? "4rNcaHhrkMhmb9QQ9bmgKipfFZcOt86n" |
| | | }; |
| | | |
| | | ClientProfile clientProfile = new ClientProfile(); |
| | | HttpProfile httpProfile = new HttpProfile(); |
| | | |
| | | |
| | | httpProfile.Endpoint = ("ocr.tencentcloudapi.com"); |
| | | clientProfile.HttpProfile = httpProfile; |
| | | |
| | | var _ocrClient = new OcrClient(cred, "ap-shanghai", clientProfile); |
| | | |
| | | IDCardOCRRequest req = new IDCardOCRRequest(); |
| | | if (isFRONT) |
| | | req.CardSide = "FRONT"; |
| | | else |
| | | req.CardSide = "BACK"; |
| | | req.ImageBase64 = ImageBase64; |
| | | |
| | | req.Config = JsonConvert.SerializeObject(new |
| | | { |
| | | //身份证照片裁剪(去掉证件外多余的边缘、自动矫正拍摄角度) |
| | | CropIdCard = true, |
| | | // CropPortrait = true, |
| | | //边框和框内遮挡告警 |
| | | BorderCheckWarn = true, |
| | | //PS检测告警 |
| | | DetectPsWarn = true, |
| | | //临时身份证告警 |
| | | TempIdWarn = true, |
| | | //身份证有效日期不合法告警 |
| | | InvalidDateWarn = true, |
| | | //图片质量分数(评价图片的模糊程度) |
| | | Quality = true, |
| | | |
| | | }); |
| | | IDCardOCRResponse resp = _ocrClient.IDCardOCRSync(req); |
| | | |
| | | if (resp == null) |
| | | throw new Exception("图片无法识别,请重新选择身份证图片"); |
| | | |
| | | |
| | | var adv = JsonConvert.DeserializeObject<AdvancedInfo>(resp.AdvancedInfo); |
| | | if (adv == null) |
| | | throw new Exception("图片无法识别,请重新选择身份证图片"); |
| | | if (adv?.BorderCodeValue != null && adv.BorderCodeValue > 50) |
| | | throw new Exception("身份证图片不完整,请重新选择身份证图片"); |
| | | if (adv?.Quality != null && adv.Quality < 50) |
| | | throw new Exception("图片模糊,请重新选择身份证图片"); |
| | | if (adv?.WarnInfos?.Where(x => x == -9100) == null) |
| | | throw new Exception("身份证日期不合法,请重新选择身份证图片"); |
| | | if (adv?.WarnInfos?.Where(x => x == -9106) == null) |
| | | throw new Exception("该图片可能是被PS过,请重新选择身份证图片"); |
| | | |
| | | CropIdCard = adv.IdCard; |
| | | return resp; |
| | | } |
| | | catch (Exception) |
| | | { |
| | | throw; |
| | | } |
| | | |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | public BizLicenseOCRResponse BizLicenseOCR(string ImageBase64) |
| | | { |
| | | try |
| | | { |
| | | |
| | | Credential cred = new Credential |
| | | { |
| | | SecretId = App.Configuration["TencentCloud:SecretId"] ?? "AKIDIPFp9CyThfMmvoQlpeCl34pKYVBahY9T", |
| | | SecretKey = App.Configuration["TencentCloud:SecretKey"] ?? "4rNcaHhrkMhmb9QQ9bmgKipfFZcOt86n" |
| | | }; |
| | | |
| | | ClientProfile clientProfile = new ClientProfile(); |
| | | HttpProfile httpProfile = new HttpProfile(); |
| | | |
| | | |
| | | httpProfile.Endpoint = ("ocr.tencentcloudapi.com"); |
| | | clientProfile.HttpProfile = httpProfile; |
| | | |
| | | var _ocrClient = new OcrClient(cred, "ap-shanghai", clientProfile); |
| | | |
| | | var ret = _ocrClient.BizLicenseOCRSync(new BizLicenseOCRRequest() |
| | | { |
| | | ImageBase64 = ImageBase64, |
| | | }); |
| | | |
| | | return ret; |
| | | } |
| | | catch (Exception) |
| | | { |
| | | throw; |
| | | } |
| | | |
| | | |
| | | } |
| | | |
| | | |
| | | #endregion |
| | | |
| | | #region iai 人脸识别 |
| | | public void IaiCreatGroup() |
| | | { |
| | | |
| | | Credential cred = new Credential |
| | | { |
| | | SecretId = App.Configuration["TencentCloud:SecretId"] ?? "AKIDIPFp9CyThfMmvoQlpeCl34pKYVBahY9T", |
| | | SecretKey = App.Configuration["TencentCloud:SecretKey"] ?? "4rNcaHhrkMhmb9QQ9bmgKipfFZcOt86n" |
| | | }; |
| | | |
| | | ClientProfile clientProfile = new ClientProfile(); |
| | | HttpProfile httpProfile = new HttpProfile(); |
| | | |
| | | |
| | | httpProfile.Endpoint = ("iai.tencentcloudapi.com"); |
| | | clientProfile.HttpProfile = httpProfile; |
| | | |
| | | var iaiClient = new IaiClient(cred, "ap-shanghai", clientProfile); |
| | | try |
| | | { |
| | | var retinfo = iaiClient.GetGroupInfoSync(new GetGroupInfoRequest |
| | | { |
| | | GroupId = App.Configuration["IAIGroupSet:ID"] ?? "", |
| | | }); |
| | | } |
| | | catch (TencentCloudSDKException e) |
| | | { |
| | | if (e.ErrorCode == "InvalidParameterValue.GroupIdNotExist") |
| | | |
| | | { |
| | | CreateGroupRequest request = new CreateGroupRequest() |
| | | { |
| | | GroupId = App.Configuration["IAIGroupSet:ID"], |
| | | GroupName= App.Configuration["IAIGroupSet:Name"], |
| | | |
| | | |
| | | }; |
| | | var aia = iaiClient.CreateGroupSync(request); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | } |
| | | |
| | | |
| | | public bool IaiAddPerso( string img64,string PersonNameId,string PersonName, int PersonGender) |
| | | { |
| | | |
| | | Credential cred = new Credential |
| | | { |
| | | SecretId = App.Configuration["TencentCloud:SecretId"] ?? "AKIDIPFp9CyThfMmvoQlpeCl34pKYVBahY9T", |
| | | SecretKey = App.Configuration["TencentCloud:SecretKey"] ?? "4rNcaHhrkMhmb9QQ9bmgKipfFZcOt86n" |
| | | }; |
| | | |
| | | ClientProfile clientProfile = new ClientProfile(); |
| | | HttpProfile httpProfile = new HttpProfile(); |
| | | |
| | | |
| | | httpProfile.Endpoint = ("iai.tencentcloudapi.com"); |
| | | clientProfile.HttpProfile = httpProfile; |
| | | |
| | | var iaiClient = new IaiClient(cred, "ap-shanghai", clientProfile); |
| | | var ret= iaiClient.CreatePerson(new TencentCloud.Iai.V20200303.Models.CreatePersonRequest |
| | | { |
| | | GroupId = App.Configuration["IAIGroupSet:ID"], |
| | | Image = img64, |
| | | PersonId= PersonNameId, |
| | | PersonName= PersonName, |
| | | Gender=PersonGender, |
| | | |
| | | }); |
| | | |
| | | if(ret.IsFaulted) |
| | | return false; |
| | | else |
| | | return true; |
| | | |
| | | |
| | | |
| | | } |
| | | |
| | | |
| | | public bool IaiAddPersoImg(string img64, string PersonNameId, string PersonName, int PersonGender) |
| | | { |
| | | |
| | | Credential cred = new Credential |
| | | { |
| | | SecretId = App.Configuration["TencentCloud:SecretId"] ?? "AKIDIPFp9CyThfMmvoQlpeCl34pKYVBahY9T", |
| | | SecretKey = App.Configuration["TencentCloud:SecretKey"] ?? "4rNcaHhrkMhmb9QQ9bmgKipfFZcOt86n" |
| | | }; |
| | | |
| | | ClientProfile clientProfile = new ClientProfile(); |
| | | HttpProfile httpProfile = new HttpProfile(); |
| | | |
| | | |
| | | httpProfile.Endpoint = ("iai.tencentcloudapi.com"); |
| | | clientProfile.HttpProfile = httpProfile; |
| | | var iaiClient = new IaiClient(cred, "ap-shanghai", clientProfile); |
| | | var ret = iaiClient.CreateFace( new TencentCloud.Iai.V20200303.Models.CreateFaceRequest |
| | | { |
| | | |
| | | PersonId = PersonNameId, |
| | | Images = [img64], |
| | | |
| | | |
| | | |
| | | }); |
| | | |
| | | if (ret.IsFaulted) |
| | | return false; |
| | | else |
| | | return true; |
| | | |
| | | |
| | | |
| | | } |
| | | |
| | | |
| | | public VerifyFaceResponse VerifyFace(string img64, string PersonNameId) |
| | | { |
| | | Credential cred = new Credential |
| | | { |
| | | SecretId = App.Configuration["TencentCloud:SecretId"] ?? "AKIDIPFp9CyThfMmvoQlpeCl34pKYVBahY9T", |
| | | SecretKey = App.Configuration["TencentCloud:SecretKey"] ?? "4rNcaHhrkMhmb9QQ9bmgKipfFZcOt86n" |
| | | }; |
| | | |
| | | ClientProfile clientProfile = new ClientProfile(); |
| | | HttpProfile httpProfile = new HttpProfile(); |
| | | |
| | | |
| | | httpProfile.Endpoint = ("iai.tencentcloudapi.com"); |
| | | clientProfile.HttpProfile = httpProfile; |
| | | var iaiClient = new IaiClient(cred, "ap-shanghai", clientProfile); |
| | | var ret = iaiClient.VerifyFaceSync(new TencentCloud.Iai.V20200303.Models.VerifyFaceRequest |
| | | { |
| | | |
| | | PersonId = PersonNameId, |
| | | Image= img64 |
| | | |
| | | |
| | | |
| | | }); |
| | | return ret; |
| | | |
| | | |
| | | |
| | | } |
| | | #endregion |
| | | |
| | | } |
| | | |
| | | //返回扩展参数 |
| | | internal class AdvancedInfo |
| | | { |
| | | /// <summary> |
| | | /// idCard 裁剪后身份证照片的base64编码,请求 Config.CropIdCard 时返回; |
| | | /// </summary> |
| | | public string? IdCard { get; set; } |
| | | /// <summary> |
| | | /// 身份证头像照片的base64编码,请求 Config.CropPortrait 时返回; |
| | | /// </summary> |
| | | public string? Portrait { get; set; } |
| | | /// <summary> |
| | | /// 图片质量分数,请求 Config.Quality 时返回(取值范围:0 ~ 100,分数越低越模糊,建议阈值≥50); |
| | | /// </summary> |
| | | public int? Quality { get; set; } |
| | | /// <summary> |
| | | /// 身份证边框不完整告警阈值分数,请求 Config.BorderCheckWarn时返回(取值范围:0 ~ 100,分数越低边框遮挡可能性越低,建议阈值≤50); |
| | | /// </summary> |
| | | public int BorderCodeValue { get; set; } |
| | | /// <summary> |
| | | /// 告警信息,Code 告警码列表和释义: |
| | | ///-9100 身份证有效日期不合法告警, |
| | | ///-9101 身份证边框不完整告警, |
| | | ///-9102 身份证复印件告警, |
| | | ///-9103 身份证翻拍告警, |
| | | ///-9105 身份证框内遮挡告警, |
| | | ///-9104 临时身份证告警, |
| | | ///-9106 身份证 PS 告警, |
| | | ///-9107 身份证反光告警。 |
| | | /// </summary> |
| | | public List<int> WarnInfos { get; set; } |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | |
| | | using Aliyun.Acs.Core.Exceptions; |
| | | using Aliyun.OSS; |
| | | |
| | | using Aliyun.OSS.Util; |
| | | using cylsg.utility; |
| | | using cylsg.utility.Extend; |
| | | using EzTencentCloud; |
| | | using Furion; |
| | | using Furion.DependencyInjection; |
| | | using Furion.FriendlyException; |
| | | using Microsoft.AspNetCore.Http; |
| | | |
| | | using SqlSugar; |
| | | using System.Drawing; |
| | | using System.Globalization; |
| | | using System.Security.Cryptography; |
| | | using System.Text; |
| | | using Tea; |
| | | using TencentCloud.Ocr.V20181119.Models; |
| | | |
| | | using Task = System.Threading.Tasks.Task; |
| | | using Newtonsoft.Json; |
| | | using static AlibabaCloud.SDK.Sts20150401.Models.AssumeRoleResponseBody; |
| | | namespace EzUpFile |
| | | { |
| | | /// <summary> |
| | | /// 附件服务程序 |
| | | /// </summary> |
| | | public class EzFileUploadService : IEzFileUploadService, IScoped |
| | | { |
| | | |
| | | private readonly HttpRequest? _request; |
| | | private readonly ISqlSugarClient _sqlSugarClient; |
| | | private readonly ITencentCloudService _tcs; |
| | | public EzFileUploadService(IHttpContextAccessor httpContext, ISqlSugarClient sqlSugarClient, ITencentCloudService tencentCloudService) |
| | | { |
| | | |
| | | _request = httpContext.HttpContext?.Request ?? null; |
| | | _sqlSugarClient = sqlSugarClient; |
| | | _tcs = tencentCloudService; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 上传附件 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | public async Task<string> UploadFiles() |
| | | { |
| | | |
| | | |
| | | var maxSize = 1024 * 1024 * 5; //上传大小5M |
| | | |
| | | var file = _request?.Form?.Files["file"]; |
| | | if (file == null) |
| | | { |
| | | throw Oops.Oh("你没有选择文件"); |
| | | } |
| | | |
| | | var fileName = file.FileName; |
| | | var fileExt = Path.GetExtension(fileName).ToLowerInvariant(); |
| | | |
| | | //检查大小 |
| | | if (file.Length > maxSize) |
| | | { |
| | | throw Oops.Oh("文件大于设置文件"); |
| | | } |
| | | |
| | | ////检查文件扩展名 |
| | | //if (string.IsNullOrEmpty(fileExt) || Array.IndexOf(op.AttachmentSaveFileExtName?.Split(',') ?? new string[] { "" }, fileExt.Substring(1).ToLower()) == -1) |
| | | //{ |
| | | // throw Oops.Oh("上传文件扩展名是不允许的扩展名,请上传后缀名为:" + op.AttachmentSaveFileExtName); |
| | | |
| | | //} |
| | | |
| | | string url = string.Empty; |
| | | |
| | | |
| | | url = await UpLoadFileForAliYunOSS(fileExt, file); |
| | | |
| | | |
| | | return url; |
| | | |
| | | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 上传base64 |
| | | /// </summary> |
| | | /// <param name="base64"></param> |
| | | /// <returns></returns> |
| | | public async Task<string> UploadFilesFByBase64(string base64) |
| | | { |
| | | |
| | | if (string.IsNullOrEmpty(base64)) |
| | | { |
| | | throw Oops.Oh("没有内容"); |
| | | } |
| | | |
| | | //检查上传大小 |
| | | if (!CommonHelper.CheckBase64Size(base64, 5)) |
| | | { |
| | | throw Oops.Oh("上传文件大小超过限制,最大允许上传" + "5" + "M"); |
| | | |
| | | } |
| | | |
| | | base64 = base64.Replace("data:image/png;base64,", "").Replace("data:image/jgp;base64,", "").Replace("data:image/jpg;base64,", "").Replace("data:image/jpeg;base64,", "");//将base64头部信息替换 |
| | | byte[] bytes = Convert.FromBase64String(base64); |
| | | MemoryStream memStream = new MemoryStream(bytes); |
| | | |
| | | string url = string.Empty; |
| | | |
| | | url = await UpLoadBase64ForAliYunOSS(memStream); |
| | | |
| | | |
| | | |
| | | return url; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 删除文件 |
| | | /// </summary> |
| | | /// <param name="Path"></param> |
| | | /// <returns></returns> |
| | | public async Task<bool> DelFile(string Path) |
| | | { |
| | | |
| | | |
| | | var ret = await DelFileForAliYunOSS(Path); |
| | | |
| | | |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | |
| | | |
| | | #region 阿里云上传方法(File) |
| | | /// <summary> |
| | | /// 阿里云上传方法(File) |
| | | /// </summary> |
| | | /// <param name="options"></param> |
| | | /// <param name="fileExt"></param> |
| | | /// <param name="file"></param> |
| | | /// <returns></returns> |
| | | public async Task<string> UpLoadFileForAliYunOSS(string fileExt, IFormFile file) |
| | | { |
| | | |
| | | |
| | | var newFileName = DateTime.Now.ToString("yyyyMMddHHmmss_ffff", DateTimeFormatInfo.InvariantInfo) + fileExt; |
| | | var today = DateTime.Now.ToString("yyyyMMdd"); |
| | | |
| | | //上传到阿里云 |
| | | await using var fileStream = file.OpenReadStream(); |
| | | var md5 = OssUtils.ComputeContentMd5(fileStream, file.Length); |
| | | |
| | | var filePath = App.Configuration["FileUploadOptions:SavePath"] + today + "/" + newFileName; //云文件保存路径 |
| | | //初始化阿里云配置--外网Endpoint、访问ID、访问password |
| | | var aliYun = new OssClient(App.Configuration["FileUploadOptions:AliOSSEndpoint"], App.Configuration["FileUploadOptions:AliOSSAccessKeyID"], App.Configuration["FileUploadOptions:AliOSSAccessKeySecret"]); |
| | | //将文件md5值赋值给meat头信息,服务器验证文件MD5 |
| | | var objectMeta = new ObjectMetadata |
| | | { |
| | | ContentMd5 = md5 |
| | | }; |
| | | |
| | | |
| | | var task = Task.Run(() => |
| | | //文件上传--空间名、文件保存路径、文件流、meta头信息(文件md5) //返回meta头信息(文件md5) |
| | | aliYun.PutObject(App.Configuration["FileUploadOptions:AliOSSBucketName"], filePath, fileStream, objectMeta) |
| | | |
| | | |
| | | |
| | | ); |
| | | //等待完成 |
| | | try |
| | | { |
| | | task.Wait(); |
| | | } |
| | | catch (AggregateException ex) |
| | | { |
| | | |
| | | throw Oops.Oh(ex.Message); |
| | | } |
| | | |
| | | |
| | | |
| | | return App.Configuration["FileUploadOptions:AliOSSSaveBaseUrl"] + filePath; |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | #region 阿里云上传方法(Base64) |
| | | /// <summary> |
| | | /// 阿里云上传方法(Base64) |
| | | /// </summary> |
| | | /// <param name="options"></param> |
| | | /// <param name="memStream"></param> |
| | | /// <returns></returns> |
| | | public async Task<string> UpLoadBase64ForAliYunOSS(MemoryStream memStream) |
| | | { |
| | | |
| | | |
| | | var newFileName = DateTime.Now.ToString("yyyyMMddHHmmss_ffff", DateTimeFormatInfo.InvariantInfo) + ".jpg"; |
| | | var today = DateTime.Now.ToString("yyyyMMdd"); |
| | | |
| | | // 设置当前流的位置为流的开始 |
| | | memStream.Seek(0, SeekOrigin.Begin); |
| | | |
| | | await using var fileStream = memStream; |
| | | var md5 = OssUtils.ComputeContentMd5(fileStream, memStream.Length); |
| | | |
| | | var filePath = App.Configuration["FileUploadOptions:SavePath"] + today + "/" + newFileName; //云文件保存路径 |
| | | //初始化阿里云配置--外网Endpoint、访问ID、访问password |
| | | var aliYun = new OssClient(App.Configuration["FileUploadOptions:AliOSSEndpoint"], App.Configuration["FileUploadOptions:AliOSSAccessKeyID"], App.Configuration["FileUploadOptions:AliOSSAccessKeySecret"]); |
| | | //将文件md5值赋值给meat头信息,服务器验证文件MD5 |
| | | var objectMeta = new ObjectMetadata |
| | | { |
| | | ContentMd5 = md5 |
| | | }; |
| | | try |
| | | { |
| | | //文件上传--空间名、文件保存路径、文件流、meta头信息(文件md5) //返回meta头信息(文件md5) |
| | | aliYun.PutObject(App.Configuration["FileUploadOptions:AliOSSBucketName"], filePath, fileStream, objectMeta); |
| | | } |
| | | catch (AggregateException ex) |
| | | { |
| | | |
| | | throw Oops.Oh(ex.Message); |
| | | } |
| | | |
| | | |
| | | //返回给UEditor的插入编辑器的图片的src |
| | | |
| | | return App.Configuration["FileUploadOptions:AliOSSSaveBaseUrl"] + filePath; |
| | | |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | #region 删除文件 |
| | | |
| | | /// <summary> |
| | | /// 阿里云删除 |
| | | /// </summary> |
| | | /// <param name="options"></param> |
| | | /// <param name="fileUrl">带xxx.xx的链接地址</param> |
| | | /// <returns></returns> |
| | | public async Task<bool> DelFileForAliYunOSS(string fileUrl) |
| | | { |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | //初始化阿里云配置--外网Endpoint、访问ID、访问password |
| | | var aliYun = new OssClient(App.Configuration["FileUploadOptions:AliOSSEndpoint"], App.Configuration["FileUploadOptions:AliOSSAccessKeyID"], App.Configuration["FileUploadOptions:AliOSSAccessKeySecret"]); |
| | | |
| | | try |
| | | { |
| | | var task = Task.Run(() => aliYun.DeleteObject(App.Configuration["FileUploadOptions:AliOSSBucketName"], (App.Configuration["FileUploadOptions:SavePath"]?.RemoveStartWithStr("/") ?? "") + fileUrl.GetFileName())); |
| | | |
| | | |
| | | task.Wait(); |
| | | |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | |
| | | throw Oops.Oh(ex.Message); |
| | | } |
| | | |
| | | |
| | | //返回给UEditor的插入编辑器的图片的src |
| | | |
| | | return true; |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | #endregion |
| | | |
| | | #region 识别上传 |
| | | public async Task<(IDCardOCRResponse, string)> UpIdCord(string PageName = "FRONT") |
| | | { |
| | | try |
| | | { |
| | | |
| | | var maxSize = 1024 * 1024 * 5; //上传大小5M |
| | | |
| | | var FileData = _request?.Form?.Files["file"]; |
| | | |
| | | if (FileData.Length > maxSize) |
| | | { |
| | | throw Oops.Oh(" 上传文件不可超出5M"); |
| | | } |
| | | |
| | | |
| | | //处理图形 |
| | | // var FileData = Request.Form.Files[0]; |
| | | |
| | | Image oimage = Image.FromStream(FileData.OpenReadStream()); |
| | | if (oimage == null) |
| | | { |
| | | throw Oops.Oh(" 上传失败"); |
| | | } |
| | | |
| | | MemoryStream ms = new MemoryStream(); |
| | | if (oimage.Width > 1200) |
| | | |
| | | { |
| | | if (oimage.Width > oimage.Height) |
| | | oimage.GetThumbnailImage(1200, 800, null, IntPtr.Zero).Save(ms, System.Drawing.Imaging.ImageFormat.Png); |
| | | else |
| | | oimage.GetThumbnailImage(800, 1200, null, IntPtr.Zero).Save(ms, System.Drawing.Imaging.ImageFormat.Png); |
| | | } |
| | | else |
| | | oimage.Save(ms, System.Drawing.Imaging.ImageFormat.Png); |
| | | ms.Position = 0; |
| | | |
| | | var arr = ms.ToArray(); |
| | | string img64 = Convert.ToBase64String(arr); |
| | | |
| | | IDCardOCRResponse idcordinfo = null; |
| | | string url = ""; |
| | | |
| | | try |
| | | { |
| | | |
| | | |
| | | idcordinfo = _tcs.IdCord(img64, PageName == "FRONT"); |
| | | |
| | | url = await UploadFilesFByBase64(_tcs.GetIdCordImg()); |
| | | idcordinfo.AdvancedInfo = null; |
| | | |
| | | return (idcordinfo, url); |
| | | |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | |
| | | throw Oops.Oh(e.Message + "腾讯云,或者阿里云操作错误"); |
| | | } |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | |
| | | throw Oops.Oh(e.Message); |
| | | } |
| | | |
| | | } |
| | | |
| | | public async Task<(BizLicenseOCRResponse, string)> UpBizLicense() |
| | | { |
| | | try |
| | | { |
| | | |
| | | var maxSize = 1024 * 1024 * 5; //上传大小5M |
| | | |
| | | var FileData = _request?.Form?.Files["file"]; |
| | | |
| | | if (FileData.Length > maxSize) |
| | | { |
| | | throw Oops.Oh(" 上传文件不可超出5M"); |
| | | } |
| | | |
| | | |
| | | //处理图形 |
| | | // var FileData = Request.Form.Files[0]; |
| | | |
| | | Image oimage = Image.FromStream(FileData.OpenReadStream()); |
| | | if (oimage == null) |
| | | { |
| | | throw Oops.Oh(" 上传失败"); |
| | | } |
| | | |
| | | MemoryStream ms = new MemoryStream(); |
| | | if (oimage.Width > 1200) |
| | | |
| | | { |
| | | if (oimage.Width > oimage.Height) |
| | | oimage.GetThumbnailImage(1200, 800, null, IntPtr.Zero).Save(ms, System.Drawing.Imaging.ImageFormat.Png); |
| | | else |
| | | oimage.GetThumbnailImage(800, 1200, null, IntPtr.Zero).Save(ms, System.Drawing.Imaging.ImageFormat.Png); |
| | | } |
| | | else |
| | | oimage.Save(ms, System.Drawing.Imaging.ImageFormat.Png); |
| | | ms.Position = 0; |
| | | |
| | | var arr = ms.ToArray(); |
| | | string img64 = Convert.ToBase64String(arr); |
| | | |
| | | BizLicenseOCRResponse info = null; |
| | | string url = ""; |
| | | |
| | | try |
| | | { |
| | | info = _tcs.BizLicenseOCR(img64); |
| | | |
| | | url = await UploadFilesFByBase64(img64); |
| | | |
| | | return (info, url); |
| | | |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | |
| | | throw Oops.Oh(e.Message); |
| | | } |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | |
| | | throw Oops.Oh(e.Message); |
| | | } |
| | | } |
| | | |
| | | |
| | | public async Task<(bool, string)> IaiAddPerso(string CoredID, string Name, int PersonGender) |
| | | { |
| | | try |
| | | { |
| | | |
| | | var maxSize = 1024 * 1024 * 5; //上传大小5M |
| | | |
| | | var FileData = _request?.Form?.Files["file"]; |
| | | |
| | | if (FileData.Length > maxSize) |
| | | { |
| | | throw Oops.Oh(" 上传文件不可超出500K"); |
| | | } |
| | | |
| | | |
| | | //处理图形 |
| | | // var FileData = Request.Form.Files[0]; |
| | | |
| | | Image oimage = Image.FromStream(FileData.OpenReadStream()); |
| | | if (oimage == null) |
| | | { |
| | | throw Oops.Oh(" 上传失败"); |
| | | } |
| | | |
| | | MemoryStream ms = new MemoryStream(); |
| | | if (oimage.Width > 600) |
| | | |
| | | { |
| | | if (oimage.Width > oimage.Height) |
| | | oimage.GetThumbnailImage(600, 400, null, IntPtr.Zero).Save(ms, System.Drawing.Imaging.ImageFormat.Png); |
| | | else |
| | | oimage.GetThumbnailImage(400, 600, null, IntPtr.Zero).Save(ms, System.Drawing.Imaging.ImageFormat.Png); |
| | | } |
| | | else |
| | | oimage.Save(ms, System.Drawing.Imaging.ImageFormat.Png); |
| | | ms.Position = 0; |
| | | |
| | | var arr = ms.ToArray(); |
| | | string img64 = Convert.ToBase64String(arr); |
| | | |
| | | bool info = false; |
| | | string url = ""; |
| | | |
| | | try |
| | | { |
| | | info = _tcs.IaiAddPerso(img64, CoredID, Name, PersonGender); |
| | | |
| | | url = await UploadFilesFByBase64(img64); |
| | | |
| | | return (info, url); |
| | | |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | |
| | | throw Oops.Oh(e.Message); |
| | | } |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | |
| | | throw Oops.Oh(e.Message); |
| | | } |
| | | } |
| | | /// <inheritdoc/> |
| | | |
| | | public async Task<(bool, string)> IaiAddPerso(string imgBase64, string CoredID, string Name, int PersonGender) |
| | | { |
| | | if (string.IsNullOrEmpty(imgBase64)) |
| | | { |
| | | throw Oops.Oh("没有内容"); |
| | | } |
| | | |
| | | //检查上传大小 |
| | | if (!CommonHelper.CheckBase64Size(imgBase64, 5)) |
| | | { |
| | | throw Oops.Oh("上传文件大小超过限制,最大允许上传" + "5" + "M"); |
| | | } |
| | | |
| | | imgBase64 = imgBase64.Replace("data:image/png;base64,", "").Replace("data:image/jgp;base64,", "").Replace("data:image/jpg;base64,", "").Replace("data:image/jpeg;base64,", "");//将base64头部信息替换 |
| | | bool info = false; |
| | | string url = ""; |
| | | |
| | | try |
| | | { |
| | | info = _tcs.IaiAddPerso(imgBase64, CoredID, Name, PersonGender); |
| | | |
| | | url = await UploadFilesFByBase64(imgBase64); |
| | | |
| | | return (info, url); |
| | | |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | |
| | | throw Oops.Oh(e.Message); |
| | | } |
| | | } |
| | | |
| | | |
| | | #endregion |
| | | |
| | | #region 本地上传云服务器凭证计算 |
| | | |
| | | |
| | | public Dictionary<string, string> GetToken1() |
| | | { |
| | | |
| | | var dir = DateTime.Now.ToString("yyyyMMdd") + "/"; |
| | | // 构造OssClient实例。 endpoint 格式:https://oss-cn-beijing.aliyuncs.com |
| | | // var ossClient = new OssClient( App.Configuration["FileUploadOptions:AliOSSSaveBaseUrl"], App.Configuration["FileUploadOptions:AliOSSAccessKeyID"], App.Configuration["FileUploadOptions:AliOSSAccessKeySecret"]); |
| | | var rt = GetSTSToken(); |
| | | |
| | | |
| | | |
| | | |
| | | String securityToken = rt.AccessKeySecret; //获取Token |
| | | var config = new PolicyConditions(); |
| | | |
| | | config.AddConditionItem(PolicyConditions.CondContentLengthRange, 1, 1024L * 1024 * 1024 * 5);// 文件大小范围:单位byte |
| | | config.AddConditionItem(MatchMode.StartWith, PolicyConditions.CondKey, dir); |
| | | //捅名 |
| | | config.AddConditionItem("bucket", App.Configuration["FileUploadOptions:AliOSSBucketName"]); |
| | | config.AddConditionItem("x-oss-signature-version", "OSS4-HMAC-SHA256"); |
| | | config.AddConditionItem("x-oss-security-token", securityToken); |
| | | // //请求时间 |
| | | config.AddConditionItem("x-oss-date", DateTime.Now.ToString("yyyyMMdd'T'HHmmss'Z'")); |
| | | config.AddConditionItem("x-oss-credential", App.Configuration["FileUploadOptions:AliOSSAccessKeyID"] + "/" + DateTime.Now.ToString("yyyyMMdd") + "/cn-chengdu/oss/aliyun_v4_request"); |
| | | var expire = DateTimeOffset.Now.AddMinutes(30);// 过期时间 |
| | | |
| | | // 生成 Policy,并进行 Base64 编码 |
| | | // var policy = ossClient.GeneratePostPolicy(expire.LocalDateTime, config); |
| | | // var policyBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(policy)); |
| | | |
| | | // 计算签名 |
| | | var hmac = new HMACSHA1(Encoding.UTF8.GetBytes(App.Configuration["FileUploadOptions:AliOSSAccessKeySecret"])); |
| | | // var bytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(policyBase64)); |
| | | // var sign = Convert.ToBase64String(bytes); |
| | | |
| | | return new Dictionary<string, string>(); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | public static AlibabaCloud.SDK.Sts20150401.Client CreateClient() |
| | | { |
| | | // 工程代码泄露可能会导致 AccessKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考。 |
| | | // 建议使用更安全的 STS 方式,更多鉴权访问方式请参见:https://help.aliyun.com/document_detail/378671.html。 |
| | | AlibabaCloud.OpenApiClient.Models.Config config = new AlibabaCloud.OpenApiClient.Models.Config |
| | | { |
| | | // 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。 |
| | | AccessKeyId = "LTAI5tKegnEbaSRPFRwDxeFd", |
| | | // 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。 |
| | | AccessKeySecret = "9Hv6VYgWhpDHCMkwMLHiqF6ihusjdl", |
| | | }; |
| | | // Endpoint 请参考 https://api.aliyun.com/product/Sts |
| | | config.Endpoint = "sts.cn-chengdu.aliyuncs.com"; |
| | | return new AlibabaCloud.SDK.Sts20150401.Client(config); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取临时凭证 |
| | | /// </summary> |
| | | public static AssumeRoleResponseBodyCredentials GetSTSToken() |
| | | { |
| | | AlibabaCloud.SDK.Sts20150401.Client client = CreateClient(); |
| | | AlibabaCloud.SDK.Sts20150401.Models.AssumeRoleRequest assumeRoleRequest = new AlibabaCloud.SDK.Sts20150401.Models.AssumeRoleRequest |
| | | { |
| | | Policy = "{\"Statement\": [{\"Action\": [\"*\"],\"Effect\": \"Allow\",\"Resource\": [\"*\"]}],\"Version\":\"1\"}", |
| | | DurationSeconds = 3600, |
| | | RoleArn = "acs:ram::1299465997752835:role/weixinupdatarl", |
| | | RoleSessionName = "weixinupdataRl", |
| | | }; |
| | | AlibabaCloud.TeaUtil.Models.RuntimeOptions runtime = new AlibabaCloud.TeaUtil.Models.RuntimeOptions(); |
| | | try |
| | | { |
| | | // 复制代码运行请自行打印 API 的返回值 |
| | | var data = client.AssumeRoleWithOptions(assumeRoleRequest, runtime); |
| | | if (data.StatusCode == 200) |
| | | { |
| | | |
| | | return data.Body?.Credentials; |
| | | } |
| | | throw Oops.Oh("阿里云获取临时凭证错误"); |
| | | } |
| | | catch (TeaException error) |
| | | { |
| | | |
| | | AlibabaCloud.TeaUtil.Common.AssertAsString(error.Message); |
| | | throw; |
| | | } |
| | | catch (Exception _error) |
| | | { |
| | | TeaException error = new TeaException(new Dictionary<string, object> |
| | | { |
| | | { "message", _error.Message } |
| | | }); |
| | | |
| | | AlibabaCloud.TeaUtil.Common.AssertAsString(error.Message); |
| | | throw error; |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | public Dictionary<string, string> GetToken() |
| | | { |
| | | // 获取环境变量 |
| | | |
| | | string regionId = "cn-chengdu"; |
| | | string roleSessionName = "weixinupdataRl"; |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | // 定义STS临时访问凭证变量 |
| | | string stsAccessKeyId = null; |
| | | string stsSecretAccessKey = null; |
| | | string securityToken = null; |
| | | |
| | | try |
| | | { |
| | | var rt = GetSTSToken(); |
| | | |
| | | stsAccessKeyId = rt.AccessKeyId; |
| | | stsSecretAccessKey = rt.AccessKeySecret; |
| | | securityToken = rt.SecurityToken; |
| | | } |
| | | catch (ServerException e) |
| | | { |
| | | throw; |
| | | } |
| | | catch (ClientException e) |
| | | { |
| | | throw; |
| | | } |
| | | |
| | | // 格式化请求日期 |
| | | DateTimeOffset now = DateTimeOffset.UtcNow; |
| | | string dtObj1 = now.ToString("yyyyMMdd'T'HHmmss'Z'", CultureInfo.InvariantCulture); |
| | | string dtObj2 = now.ToString("yyyyMMdd", CultureInfo.InvariantCulture); |
| | | string expirationTime = now.AddHours(3).ToString("yyyy-MM-dd'T'HH:mm:ss.fff'Z'", CultureInfo.InvariantCulture); |
| | | |
| | | // 创建policy |
| | | Dictionary<string, object> policy = new Dictionary<string, object> |
| | | { |
| | | { "expiration", expirationTime }, |
| | | { "conditions", new List<object> |
| | | { |
| | | new Dictionary<string, string> { { "bucket", App.Configuration["FileUploadOptions:AliOSSBucketName"] } }, // 请将<bucketname>替换为您的实际Bucket名称 |
| | | new Dictionary<string, string> { { "x-oss-signature-version", "OSS4-HMAC-SHA256" } }, |
| | | new Dictionary<string, string> { { "x-oss-credential", $"{stsAccessKeyId}/{dtObj2}/{regionId}/oss/aliyun_v4_request" } }, // 请将<cn-hangzhou>替换为您的实际Bucket所处地域,例如北京地域为:cn-beijing |
| | | new Dictionary<string, string> { { "x-oss-security-token", securityToken } }, |
| | | new Dictionary<string, string> { { "x-oss-date", dtObj1 } } |
| | | } |
| | | } |
| | | }; |
| | | |
| | | string jsonPolicy = JsonConvert.SerializeObject(policy); |
| | | |
| | | // 构造待签名字符串(StringToSign) |
| | | string stringToSign = Convert.ToBase64String(Encoding.UTF8.GetBytes(jsonPolicy)); |
| | | |
| | | // 计算SigningKey |
| | | byte[] dateKey = HmacSha256("aliyun_v4" + stsSecretAccessKey, dtObj2); |
| | | byte[] dateRegionKey = HmacSha256(dateKey, regionId); // 请将<cn-hangzhou>替换为您的实际Bucket所处地域,例如北京地域为:cn-beijing |
| | | byte[] dateRegionServiceKey = HmacSha256(dateRegionKey, "oss"); |
| | | byte[] signingKey = HmacSha256(dateRegionServiceKey, "aliyun_v4_request"); |
| | | |
| | | // 计算Signature |
| | | byte[] result = HmacSha256(signingKey, stringToSign); |
| | | string signature = BitConverter.ToString(result).Replace("-", "").ToLower(); |
| | | |
| | | Dictionary<string, string> messageMap = new Dictionary<string, string> |
| | | { |
| | | { "security_token", securityToken }, |
| | | { "signature", signature }, |
| | | { "x_oss_date", dtObj1 }, |
| | | { "x_oss_credential", $"{stsAccessKeyId}/{dtObj2}/{regionId}/oss/aliyun_v4_request" }, // 请将<cn-hangzhou>替换为您的实际Bucket所处地域,例如北京地域为:cn-beijing |
| | | { "x_oss_signature_version", "OSS4-HMAC-SHA256" }, |
| | | { "policy", stringToSign } |
| | | }; |
| | | |
| | | // 打印返回至客户端的签名信息 |
| | | return messageMap; |
| | | } |
| | | |
| | | |
| | | |
| | | private static byte[] HmacSha256(byte[] key, string message) |
| | | { |
| | | using (HMACSHA256 hmac = new HMACSHA256(key)) |
| | | { |
| | | return hmac.ComputeHash(Encoding.UTF8.GetBytes(message)); |
| | | } |
| | | } |
| | | |
| | | private static byte[] HmacSha256(string key, string message) |
| | | { |
| | | using (HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key))) |
| | | { |
| | | return hmac.ComputeHash(Encoding.UTF8.GetBytes(message)); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | #endregion |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | } |
| | | |
New file |
| | |
| | | <Project Sdk="Microsoft.NET.Sdk"> |
| | | |
| | | <PropertyGroup> |
| | | <TargetFramework>net8.0</TargetFramework> |
| | | <ImplicitUsings>enable</ImplicitUsings> |
| | | <Nullable>enable</Nullable> |
| | | <GenerateDocumentationFile>True</GenerateDocumentationFile> |
| | | </PropertyGroup> |
| | | |
| | | <ItemGroup> |
| | | <PackageReference Include="AlibabaCloud.SDK.Sts20150401" Version="1.1.4" /> |
| | | <PackageReference Include="Aliyun.Acs.Core" Version="1.0.1" /> |
| | | <PackageReference Include="Aliyun.Acs.Sts" Version="1.0.1" /> |
| | | <PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" /> |
| | | <PackageReference Include="Utf8Json" Version="1.3.7" /> |
| | | </ItemGroup> |
| | | |
| | | <ItemGroup> |
| | | <ProjectReference Include="..\Admin.NET.Core\Admin.NET.Core.csproj" /> |
| | | <ProjectReference Include="..\cylsg.utility\cylsg.utility.csproj" /> |
| | | <ProjectReference Include="..\EzTencentCloud\EzTencentCloud.csproj" /> |
| | | </ItemGroup> |
| | | |
| | | <ItemGroup> |
| | | <None Update="UpFileConfig.json"> |
| | | <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> |
| | | </None> |
| | | </ItemGroup> |
| | | |
| | | </Project> |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | using TencentCloud.Ocr.V20181119.Models; |
| | | |
| | | namespace EzUpFile |
| | | { |
| | | public interface IEzFileUploadService |
| | | { |
| | | /// <summary> |
| | | /// 上传base64 |
| | | /// </summary> |
| | | /// <param name="base64"></param> |
| | | /// <returns></returns> |
| | | Task<string> UploadFilesFByBase64(string base64); |
| | | /// <summary> |
| | | /// 上传文件 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | Task<string> UploadFiles(); |
| | | /// <summary> |
| | | /// 删除文件 |
| | | /// </summary> |
| | | /// <param name="Path"></param> |
| | | /// <returns></returns> |
| | | Task<bool> DelFile(string Path); |
| | | |
| | | /// <summary> |
| | | /// 上传身份证 |
| | | /// </summary> |
| | | /// <param name="Path"></param> |
| | | /// <returns></returns> |
| | | Task<(IDCardOCRResponse, string)> UpIdCord(string PageName = "FRONT"); |
| | | |
| | | |
| | | /// <summary> |
| | | /// 上传营业执照 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | Task<(BizLicenseOCRResponse, string)> UpBizLicense(); |
| | | |
| | | /// <summary> |
| | | /// 创建人脸特征 文件传送 |
| | | /// </summary> |
| | | /// <param name="CoredID"> 身份证号</param> |
| | | /// <param name="Name">姓名</param> |
| | | /// <param name="PersonGender"> 性别 0代表未填写,1代表男性,2代表女性。</param> |
| | | /// <returns></returns> |
| | | Task<(bool, string)> IaiAddPerso(string CoredID, string Name, int PersonGender); |
| | | /// <summary> |
| | | /// 创建人脸特征 |
| | | /// </summary> |
| | | /// <param name="imgBase64">img base64</param> |
| | | /// <param name="CoredID"> 身份证号</param> |
| | | /// <param name="Name">姓名</param> |
| | | /// <param name="PersonGender"> 性别 0代表未填写,1代表男性,2代表女性。</param> |
| | | /// <returns></returns> |
| | | Task<(bool, string)> IaiAddPerso(string imgBase64, string CoredID, string Name, int PersonGender); |
| | | |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | Dictionary<string, string> GetToken(); |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | } |
New file |
| | |
| | | { |
| | | "FileUploadOptions": { |
| | | |
| | | "AliOSSBucketName": "appimchat", |
| | | "SavePath": "cylsg/", |
| | | "AliOSSEndpoint": "oss-accelerate.aliyuncs.com", |
| | | "AliOSSAccessKeyID": "LTAI5tNYGwTd3swLhC8H2XYV", |
| | | "AliOSSAccessKeySecret": "TyfkpYbXRUCh1K8LLtUyxY3ZcFCy1A", |
| | | "AliOSSSaveBaseUrl": "https://appimchat.oss-cn-chengdu.aliyuncs.com/" |
| | | |
| | | } |
| | | } |
New file |
| | |
| | | using EzTencentCloud; |
| | | using Furion.FriendlyException; |
| | | using Microsoft.AspNetCore.Http; |
| | | using Microsoft.AspNetCore.Http.HttpResults; |
| | | using Microsoft.AspNetCore.Mvc; |
| | | using Microsoft.AspNetCore.Mvc.RazorPages; |
| | | using Microsoft.IdentityModel.Abstractions; |
| | | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | using TencentCloud.Ocr.V20181119.Models; |
| | | |
| | | namespace EzUpFile |
| | | { |
| | | /// <summary> |
| | | /// 文件上传下载 |
| | | /// </summary> |
| | | [DynamicApiController] |
| | | [ApiDescriptionSettings("FZCAPISYS", Order = 149)] |
| | | public class UpFileController |
| | | { |
| | | /// <summary> |
| | | /// 获取文件 上传token |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | [HttpGet] |
| | | |
| | | public Dictionary<string, string> GetToken([FromServices] IEzFileUploadService fileUploadService) |
| | | { |
| | | return fileUploadService.GetToken(); |
| | | } |
| | | /// <summary> |
| | | /// 上传身份证信息 |
| | | /// </summary> |
| | | /// <param name="PageName"> 身份证正反面 FRONT 正面 Back 国徽反面 </param> |
| | | /// <returns></returns> |
| | | [HttpPost] |
| | | public async Task<Object> UploadIdCord([FromServices] IEzFileUploadService fileUploadService,IFormFile file, [FromQuery] string PageName = "FRONT") |
| | | { |
| | | |
| | | |
| | | var ret= await fileUploadService.UpIdCord(PageName); |
| | | return new { Info = ret.Item1, url = ret.Item2 }; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 上传和识别营业执照 |
| | | /// </summary> |
| | | /// <param name="PageName"> 身份证正反面 FRONT 正面 Back 国徽反面 </param> |
| | | /// <returns></returns> |
| | | [HttpPost] |
| | | public async Task<Object> UpBizLicense([FromServices] IEzFileUploadService fileUploadService, IFormFile file) |
| | | { |
| | | |
| | | |
| | | var ret= await fileUploadService.UpBizLicense(); |
| | | return new { Info = ret.Item1, url = ret.Item2 }; |
| | | |
| | | } |
| | | /// <summary> |
| | | /// 增加人脸特征 |
| | | /// </summary> |
| | | /// <param name="CordId">身份证号</param> |
| | | /// <param name="Name">名称</param> |
| | | /// <param name="Gender">0代表未填写,1代表男性,2代表女性。</param> |
| | | /// <returns></returns> |
| | | [HttpPost] |
| | | public async Task<object> IaiAddPerso([FromServices] IEzFileUploadService fileUploadService, IFormFile file,[FromQuery] string CordId, [FromQuery] string Name, [FromQuery] int Gender) |
| | | { |
| | | |
| | | |
| | | var ret= await fileUploadService.IaiAddPerso(CordId, Name,Gender); |
| | | return new { IsOK = ret.Item1, url = ret.Item2 }; |
| | | |
| | | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 增加人脸库 base64 |
| | | /// </summary> |
| | | /// <param name="param"></param> |
| | | /// <returns></returns> |
| | | [HttpPost] |
| | | public async Task<object> IaiAddPersoBase64([FromServices] IEzFileUploadService fileUploadService, UpDataFileData param) |
| | | { |
| | | if (string.IsNullOrEmpty(param.imgBase64)) |
| | | throw Oops.Oh("没有文件内容"); |
| | | if (string.IsNullOrEmpty(param.Name)) |
| | | throw Oops.Oh("没有姓名"); |
| | | if (string.IsNullOrEmpty(param.CordId)) |
| | | throw Oops.Oh("没有身份证信息"); |
| | | var ret = await fileUploadService.IaiAddPerso(param.imgBase64, param.CordId, param. Name, param.Gender??0); |
| | | return new { IsOK = ret.Item1, url = ret.Item2 }; |
| | | |
| | | |
| | | } |
| | | public async Task test([FromServices] ITencentCloudService fileUploadService) |
| | | { |
| | | |
| | | fileUploadService.IaiCreatGroup(); |
| | | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 上传附件 |
| | | /// </summary> |
| | | /// <param name="fileUploadService"></param> |
| | | /// <returns></returns> |
| | | [HttpPost] |
| | | public async Task<string> UpdateFile([FromServices] IEzFileUploadService fileUploadService, IFormFile file) |
| | | { |
| | | return await fileUploadService.UploadFiles(); |
| | | } |
| | | /// <summary> |
| | | /// 获取到客户端的IPv4 |
| | | /// </summary> |
| | | /// <param name="httpContextAccessor"></param> |
| | | /// <returns></returns> |
| | | [HttpGet] |
| | | public string GetIp4([FromServices] IHttpContextAccessor httpContextAccessor) |
| | | { |
| | | var httpc = httpContextAccessor.HttpContext; |
| | | var ipv4 = httpc.GetRemoteIpAddressToIPv4(); |
| | | return ipv4; |
| | | } |
| | | /// <summary> |
| | | /// 上传附件 |
| | | /// </summary> |
| | | /// <param name="fileUploadService"></param> |
| | | /// <param name="Param"></param> |
| | | /// <returns></returns> |
| | | [HttpPost] |
| | | public async Task<string> UpdateFileBase64([FromServices] IEzFileUploadService fileUploadService, UpDataFileData Param) |
| | | { |
| | | return await fileUploadService.UploadFilesFByBase64(Param.imgBase64); |
| | | } |
| | | [HttpPost] |
| | | public async Task<bool> DelFile([FromServices] IEzFileUploadService fileUploadService, DelFileData Param) |
| | | { |
| | | return await fileUploadService.DelFile(Param.FilePath); |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// 上传数据 |
| | | /// </summary> |
| | | public class UpDataFileData |
| | | |
| | | { |
| | | /// <summary> |
| | | /// 数据base64 |
| | | /// </summary> |
| | | public string imgBase64 { get; set; } |
| | | /// <summary> |
| | | /// 身份证号码 |
| | | /// </summary> |
| | | public string? CordId { get; set; } |
| | | /// <summary> |
| | | /// 姓名 |
| | | /// </summary> |
| | | public string? Name { get; set; } |
| | | /// <summary> |
| | | /// 性别 |
| | | /// </summary> |
| | | public int? Gender { get; set; } |
| | | } |
| | | /// <summary> |
| | | /// 上传数据 |
| | | /// </summary> |
| | | public class DelFileData |
| | | |
| | | { |
| | | /// <summary> |
| | | /// 数据base64 |
| | | /// </summary> |
| | | public string FilePath { get; set; } |
| | | } |
| | | /// <summary> |
| | | /// 身份证返回输出 |
| | | /// </summary> |
| | | public class IdCordOuput |
| | | { |
| | | /// <summary> |
| | | /// 身份证相关信息 |
| | | /// </summary> |
| | | public IDCardOCRResponse IdCordInfo { get; set; } |
| | | |
| | | /// <summary> |
| | | /// url |
| | | /// </summary> |
| | | public string Url { get; set; } |
| | | |
| | | } |
| | | } |
| | |
| | | using Furion.DynamicApiController; |
| | | using Admin.NET.Core.Service; |
| | | using Admin.NET.Core; |
| | | using Furion.DataEncryption; |
| | | using Furion.DynamicApiController; |
| | | using Furion.EventBus; |
| | | using Microsoft.AspNetCore.Mvc; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | using Lazy.Captcha.Core; |
| | | using Microsoft.AspNetCore.Http; |
| | | using FZCZTB.NET.MD.CutomerMd; |
| | | using Microsoft.AspNetCore.Authorization; |
| | | using System.ComponentModel.DataAnnotations; |
| | | using System.ComponentModel; |
| | | using FZCZTB.NET.SYSService.MSM; |
| | | using FZCTB.NET.API.Application.Auth.DTO; |
| | | using Furion.FriendlyException; |
| | | using FZCZTB.NET.SYSService.CustomerSYS; |
| | | |
| | | namespace FZCTB.NET.API.Application.Auth |
| | | { |
| | |
| | | [ApiDescriptionSettings("FZCAPISYS", Order = 149)] |
| | | public class AuthService: IDynamicApiController |
| | | { |
| | | |
| | | |
| | | private readonly UserManager _userManager; |
| | | private readonly SqlSugarRepository<FBS_Customer> _sysUserRep; |
| | | private readonly IHttpContextAccessor _httpContextAccessor; |
| | | private readonly SysMenuService _sysMenuService; |
| | | private readonly SysOnlineUserService _sysOnlineUserService; |
| | | private readonly SysConfigService _sysConfigService; |
| | | private readonly SysUserService _sysUserService; |
| | | private readonly ZCSMSService _sysSmsService; |
| | | private readonly SysLdapService _sysLdapService; |
| | | private readonly ICaptcha _captcha; |
| | | private readonly IEventPublisher _eventPublisher; |
| | | private readonly SysCacheService _sysCacheService; |
| | | |
| | | public AuthService( |
| | | SqlSugarRepository<FBS_Customer> sysUserRep, |
| | | IHttpContextAccessor httpContextAccessor, |
| | | SysOnlineUserService sysOnlineUserService, |
| | | SysConfigService sysConfigService, |
| | | SysLdapService sysLdapService, |
| | | IEventPublisher eventPublisher, |
| | | ZCSMSService sysSmsService, |
| | | SysCacheService sysCacheService, |
| | | SysMenuService sysMenuService, |
| | | SysUserService sysUserService, |
| | | UserManager userManager, |
| | | ICaptcha captcha) |
| | | { |
| | | _captcha = captcha; |
| | | _sysUserRep = sysUserRep; |
| | | _userManager = userManager; |
| | | _sysSmsService = sysSmsService; |
| | | _eventPublisher = eventPublisher; |
| | | _sysUserService = sysUserService; |
| | | _sysMenuService = sysMenuService; |
| | | _sysCacheService = sysCacheService; |
| | | _sysConfigService = sysConfigService; |
| | | _httpContextAccessor = httpContextAccessor; |
| | | _sysOnlineUserService = sysOnlineUserService; |
| | | _sysLdapService = sysLdapService; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 手机号登录 🔖 |
| | | /// </summary> |
| | | /// <param name="input"></param> |
| | | /// <returns></returns> |
| | | [AllowAnonymous] |
| | | [DisplayName("手机号登录")] |
| | | public virtual async Task<CustomerLoginOutput> LoginPhone([Required] CustomerLoginPhoneInput input) |
| | | { |
| | | if(input.Code!="TEST") |
| | | // 校验短信验证码 |
| | | _sysSmsService.VerifyCode(new SmsVerifyCodeInput { Phone = input.Phone, Code = input.Code }); |
| | | |
| | | // 获取登录租户和用户 |
| | | // 获取登录租户和用户 |
| | | var user = await _sysUserRep.AsQueryable().Where(x => x.Account == input.Phone).Includes(x => x.CoutomerExRols, y => y.ExRole).FirstAsync(); |
| | | if (user == null) |
| | | { |
| | | throw Oops.Oh("该用户没有注册"); |
| | | } |
| | | if(user.Status== StatusEnum.Disable) |
| | | { |
| | | throw Oops.Oh("用异常"); |
| | | } |
| | | |
| | | |
| | | return await CreateToken(user, input.ExRuleCode??""); |
| | | } |
| | | /// <summary> |
| | | /// 手机号登录 🔖 |
| | | /// </summary> |
| | | /// <param name="input"></param> |
| | | /// <returns></returns> |
| | | [AllowAnonymous] |
| | | [DisplayName("微信扫码登录")] |
| | | public virtual async Task<CustomerLoginOutput> WeiXinLoginPhone([Required] CustomerLoginPhoneInput input) |
| | | { |
| | | throw Oops.Oh("咋不支持微信扫码登录"); |
| | | // 校验短信验证码 |
| | | _sysSmsService.VerifyCode(new SmsVerifyCodeInput { Phone = input.Phone, Code = input.Code }); |
| | | |
| | | // 获取登录租户和用户 |
| | | var user = await _sysUserRep.AsQueryable().Where(x=>x.Account==input.Phone).Includes(x => x.CoutomerExRols, y => y.ExRole).FirstAsync(); |
| | | if(user==null) |
| | | { |
| | | |
| | | } |
| | | |
| | | return await CreateToken(user, input.ExRuleCode ); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 生成Token令牌 🔖 |
| | | /// </summary> |
| | | /// <param name="user"></param>\ |
| | | /// <param name="sysUserEventTypeEnum"></param>\ |
| | | /// <returns></returns> |
| | | [NonAction] |
| | | internal async Task<CustomerLoginOutput> CreateToken(FBS_Customer user,string ExRuleCode, SysUserEventTypeEnum sysUserEventTypeEnum = SysUserEventTypeEnum.Login) |
| | | { |
| | | // 单用户登录 |
| | | await _sysOnlineUserService.SingleLogin(user.Id); |
| | | |
| | | // 生成Token令牌 |
| | | var tokenExpire = await _sysConfigService.GetTokenExpire(); |
| | | var accessToken = JWTEncryption.Encrypt(new Dictionary<string, object> |
| | | { |
| | | { ClaimConst.UserId, user.Id }, |
| | | { ClaimConst.TenantId, user.TenantId }, |
| | | { ClaimConst.Account, user.Account }, |
| | | { ClaimConst.RealName, user.RealName }, |
| | | |
| | | { ClaimConst.UserType, "Customer" }, |
| | | { ClaimConst.CustomerLogoinType, ExRuleCode }, |
| | | }, tokenExpire); |
| | | |
| | | // 生成刷新Token令牌 |
| | | var refreshTokenExpire = await _sysConfigService.GetRefreshTokenExpire(); |
| | | var refreshToken = JWTEncryption.GenerateRefreshToken(accessToken, refreshTokenExpire); |
| | | |
| | | // 设置响应报文头 |
| | | _httpContextAccessor.HttpContext.SetTokensOfResponseHeaders(accessToken, refreshToken); |
| | | |
| | | // Swagger Knife4UI-AfterScript登录脚本 |
| | | // ke.global.setAllHeader('Authorization', 'Bearer ' + ke.response.headers['access-token']); |
| | | |
| | | // 更新用户登录信息 |
| | | user.LastLoginIp = _httpContextAccessor.HttpContext.GetRemoteIpAddressToIPv4(true); |
| | | (user.LastLoginAddress, double? longitude, double? latitude) = CommonUtil.GetIpAddress(user.LastLoginIp); |
| | | user.LastLoginTime = DateTime.Now; |
| | | user.LastLoginDevice = CommonUtil.GetClientDeviceInfo(_httpContextAccessor.HttpContext?.Request?.Headers?.UserAgent); |
| | | await _sysUserRep.AsUpdateable(user).UpdateColumns(u => new |
| | | { |
| | | u.LastLoginIp, |
| | | u.LastLoginAddress, |
| | | u.LastLoginTime, |
| | | u.LastLoginDevice, |
| | | }).ExecuteCommandAsync(); |
| | | |
| | | var payload = new |
| | | { |
| | | Entity = user, |
| | | Output = new CustomerLoginOutput |
| | | { |
| | | AccessToken = accessToken, |
| | | RefreshToken = refreshToken, |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | } |
| | | }; |
| | | payload.Output.ExRoles = new List<CustomerExRoleVm>(); |
| | | |
| | | foreach (var item in user.CoutomerExRols) |
| | | { |
| | | |
| | | payload.Output.ExRoles.Add(new CustomerExRoleVm |
| | | { |
| | | Code = item.ExRole.Code, |
| | | Name = item.ExRole.Name, |
| | | HasFlsh = item.HasFlsh |
| | | }); |
| | | } |
| | | |
| | | //暂时不出用户事件 |
| | | // 发布系统用户操作事件 |
| | | //await _eventPublisher.PublishAsync(sysUserEventTypeEnum, payload); |
| | | return payload.Output; |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 |
| | | // |
| | | // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 |
| | | // |
| | | // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! |
| | | |
| | | using Furion.DataValidation; |
| | | using FZCZTB.NET.MD.CutomerMd; |
| | | using SqlSugar; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.ComponentModel.DataAnnotations; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | |
| | | namespace FZCTB.NET.API.Application.Auth.DTO; |
| | | public class CustomerLoginOutput |
| | | { |
| | | /// <summary> |
| | | /// 令牌Token |
| | | /// </summary> |
| | | public string AccessToken { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 刷新Token |
| | | /// </summary> |
| | | public string RefreshToken { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 用户角色即完成情况 |
| | | /// </summary> |
| | | public List<CustomerExRoleVm>? ExRoles { get; set; } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 用户角色进度 |
| | | /// </summary> |
| | | public class CustomerExRoleVm |
| | | { |
| | | /// <summary> |
| | | /// 名称 |
| | | /// </summary> |
| | | |
| | | |
| | | public string Name { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 编码 |
| | | /// </summary> |
| | | |
| | | public string? Code { get; set; } |
| | | |
| | | |
| | | /// <summary> |
| | | /// 是否完成角色创建 |
| | | /// </summary> |
| | | public bool HasFlsh { get; set; } = false; |
| | | |
| | | |
| | | |
| | | } |
| | | |
| | | public class CustomerLoginPhoneInput |
| | | { |
| | | /// <summary> |
| | | /// 手机号码 |
| | | /// </summary> |
| | | /// <example>admin</example> |
| | | [Required(ErrorMessage = "手机号码不能为空")] |
| | | [DataValidation(ValidationTypes.PhoneNumber, ErrorMessage = "手机号码不正确")] |
| | | public string Phone { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 验证码 |
| | | /// </summary> |
| | | /// <example>123456</example> |
| | | [Required(ErrorMessage = "验证码不能为空"), MinLength(4, ErrorMessage = "验证码不能少于4个字符")] |
| | | public string Code { get; set; } |
| | | |
| | | |
| | | /// <summary> |
| | | /// 角色Code |
| | | /// </summary> |
| | | public string? ExRuleCode { get; set; } |
| | | |
| | | |
| | | } |
| | |
| | | <TargetFramework>net8.0</TargetFramework> |
| | | <ImplicitUsings>enable</ImplicitUsings> |
| | | <Nullable>enable</Nullable> |
| | | <GenerateDocumentationFile>True</GenerateDocumentationFile> |
| | | </PropertyGroup> |
| | | |
| | | <ItemGroup> |
| | | <ProjectReference Include="..\Admin.NET.Application\Admin.NET.Application.csproj" /> |
| | | <ProjectReference Include="..\Admin.NET.Core\Admin.NET.Core.csproj" /> |
| | | <ProjectReference Include="..\EzUpFile\EzUpFile.csproj" /> |
| | | <ProjectReference Include="..\FZCZTB.NET.MD\FZCZTB.NET.MD.csproj" /> |
| | | <ProjectReference Include="..\FZCZTB.NET.SYSService\FZCZTB.NET.SYSService.csproj" /> |
| | | </ItemGroup> |
| | |
| | | // |
| | | // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! |
| | | |
| | | using Admin.NET.Core; |
| | | using Admin.NET.Core.Service; |
| | | using Furion.DynamicApiController; |
| | | using Furion.FriendlyException; |
| | | using FZCTB.NET.API.Application.User.DTO; |
| | | using FZCZTB.NET.MD.ConfigMd; |
| | | using FZCZTB.NET.MD.CutomerMd; |
| | | using FZCZTB.NET.SYSService.CustomerSYS; |
| | | using Mapster; |
| | | using Microsoft.AspNetCore.Authorization; |
| | | using Microsoft.AspNetCore.Mvc; |
| | | using Microsoft.AspNetCore.Mvc.ViewComponents; |
| | | using OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | using static QRCoder.PayloadGenerator; |
| | | |
| | | namespace FZCTB.NET.API.Application.User; |
| | | /// <summary> |
| | | /// 客户处里 |
| | | /// 客户控制 |
| | | /// </summary> |
| | | [ApiDescriptionSettings("FZCAPISYS", Order = 149)] |
| | | public class CustomerService: IDynamicApiController |
| | | { |
| | | private readonly CustomerManagerS _customerManager; |
| | | |
| | | private readonly SysCacheService _sysCacheService; |
| | | private readonly SqlSugarRepository<FBS_ExRole> _fBS_ExRoleRep; |
| | | |
| | | private readonly SqlSugarRepository<FBS_EnterpriseType> _fBS_EnterpriseTypeRep; |
| | | private readonly SqlSugarRepository<FBS_Customer> _fBS_CustomerRep; |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public CustomerService(SysCacheService cacheService, CustomerManagerS managerS) |
| | | public CustomerService(SysCacheService cacheService, CustomerManagerS managerS,SqlSugarRepository<FBS_Customer> repository |
| | | , SqlSugarRepository<FBS_EnterpriseType> fbsenrep ) |
| | | { |
| | | _sysCacheService= cacheService; |
| | | _customerManager = managerS; |
| | | _fBS_CustomerRep = repository; |
| | | _fBS_EnterpriseTypeRep = fbsenrep; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 用户注册 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | public async Task<bool> CustomerRegistration(CustomerDto param ) |
| | | [AllowAnonymous] |
| | | [HttpPost] |
| | | public async Task<bool> CustomerRegistration(CustomerRDto param ) |
| | | { |
| | | //_customerManager. |
| | | await Task.CompletedTask; |
| | | var ExRole= (await _customerManager.GetExRole()).Where(x => x.Code == param.ExRoleCode).FirstOrDefault(); |
| | | |
| | | if(ExRole==null) |
| | | { |
| | | throw Oops.Oh("请选择一个有效的角色进行注册"); |
| | | } |
| | | |
| | | //已选角色,请选择一个注册角色 |
| | | var data= await _fBS_CustomerRep.AsQueryable().Includes(X => X.CoutomerExRols,y=>y.ExRole).Where(x => x.Account == param.Account).FirstAsync(); |
| | | if (data != null) |
| | | { |
| | | if (data.CoutomerExRols.Any(x => x.ExRole.Code == param.ExRoleCode)) |
| | | { |
| | | throw Oops.Oh("已经注册了该角色请勿重复注册"); |
| | | } |
| | | |
| | | else |
| | | { |
| | | throw Oops.Oh("该用户名重复,如果需要对该用户添加相应角色,请登录任意角色后添加"); |
| | | } |
| | | |
| | | } |
| | | var vcode= _sysCacheService.Get<string>($"{CacheConst.KeyPhoneVerCode}{param.Phone}"); |
| | | if(param.PhoneVCode!="TEST") |
| | | if(vcode!=param.PhoneVCode) |
| | | { |
| | | //手机验证码错误 |
| | | throw Oops.Oh("手机验证码错误,请输入正确的手机验证码"); |
| | | } |
| | | //使用后立即删除 |
| | | _sysCacheService.Remove($"{CacheConst.KeyPhoneVerCode}{param.Phone}"); |
| | | var dd = param.Adapt<FBS_Customer>(); |
| | | dd.RealName = dd.NickName; |
| | | |
| | | dd.Account = dd.Phone; |
| | | dd.Password = ""; |
| | | dd.TenantId = 1300000000001; |
| | | dd.CreateTime = DateTime.Now; |
| | | dd.CreateUserId = 0; |
| | | dd.CreateUserName = dd.NickName; |
| | | dd.CoutomerExRols = new List<FBS_CoutomerExRole>() |
| | | { |
| | | new FBS_CoutomerExRole |
| | | { |
| | | ExRoleId= ExRole?.Id??0 |
| | | |
| | | |
| | | } |
| | | }; |
| | | |
| | | |
| | | |
| | | |
| | | await _fBS_CustomerRep.AsSugarClient().InsertNav(dd).Include(x=>x.CoutomerExRols).ExecuteCommandAsync(); |
| | | |
| | | |
| | | |
| | | return true; |
| | | } |
| | | /// <summary> |
| | | /// 注册登录可选角色 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | [AllowAnonymous] |
| | | public async Task<List< ExRoleVM>> GetExRole() |
| | | { |
| | | return await _customerManager.GetExRole(); |
| | | } |
| | | /// <summary> |
| | | /// 获取企业类型 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | [AllowAnonymous] |
| | | public async Task<List<EnterpriseTypeVM>> EnterpriseTypes() |
| | | { |
| | | return await _fBS_EnterpriseTypeRep.AsQueryable().Select<EnterpriseTypeVM>().ToTreeAsync(x=>x.Child,x=>x.ParentId,null,x=>x.Id); |
| | | } |
| | | |
| | | |
| | | |
| | | } |
New file |
| | |
| | | // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 |
| | | // |
| | | // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 |
| | | // |
| | | // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! |
| | | |
| | | using FZCZTB.NET.MD.ConfigMd; |
| | | using SqlSugar; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | |
| | | namespace FZCTB.NET.API.Application.User.DTO; |
| | | /// <summary> |
| | | /// 企业类型 |
| | | /// </summary> |
| | | public class EnterpriseTypeVM |
| | | { |
| | | /// <summary> |
| | | /// id |
| | | /// </summary> |
| | | [SugarColumn(IsTreeKey = true)] //设置关联字段 |
| | | public long Id { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 名称 |
| | | /// </summary> |
| | | |
| | | public string Name { get; set; } |
| | | /// <summary> |
| | | /// 代码 |
| | | /// </summary> |
| | | |
| | | public string Code { get; set; } |
| | | /// <summary> |
| | | /// 父 |
| | | /// </summary> |
| | | |
| | | public long ParentId { get; set; }//父级字段 |
| | | /// <summary> |
| | | /// 子类 |
| | | /// </summary> |
| | | |
| | | public List<FBS_EnterpriseType> Child { get; set; } |
| | | } |
New file |
| | |
| | | // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 |
| | | // |
| | | // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 |
| | | // |
| | | // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! |
| | | |
| | | using Admin.NET.Core; |
| | | using SqlSugar; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | |
| | | namespace FZCZTB.NET.MD.ConfigMd; |
| | | /// <summary> |
| | | /// 企业类配置表 |
| | | /// </summary> |
| | | [SugarTable("FBS_EnterpriseType", "企业类配置表")] |
| | | [SugarIndex("index_{table}_A", nameof(Code), OrderByType.Asc)] |
| | | [IncreTable] |
| | | public class FBS_EnterpriseType: EntityBaseTenant |
| | | { |
| | | |
| | | /// <summary> |
| | | /// 名称 |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "名称", Length = 256)] |
| | | public string Name { get; set; } |
| | | /// <summary> |
| | | /// 代码 |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "代码", Length = 36)] |
| | | public string Code { get; set; } |
| | | /// <summary> |
| | | /// 父 |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "父")] |
| | | public long ParentId { get; set; }//父级字段 |
| | | /// <summary> |
| | | /// 子类 |
| | | /// </summary> |
| | | [SugarColumn(IsIgnore = true)] |
| | | public List<FBS_EnterpriseType> Child { get; set; } |
| | | |
| | | |
| | | } |
New file |
| | |
| | | // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 |
| | | // |
| | | // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 |
| | | // |
| | | // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! |
| | | |
| | | using Admin.NET.Core; |
| | | using SqlSugar; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.ComponentModel.DataAnnotations; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | |
| | | namespace FZCZTB.NET.MD.CutomerMd.Extend; |
| | | /// <summary> |
| | | /// 用户扩展表 企业资料 |
| | | /// </summary> |
| | | [SugarTable("FBS_CusExtend", "企业资料")] |
| | | [IncreTable] |
| | | public class FBS_CusExtend: EntityBaseTenant |
| | | { |
| | | /// <summary> |
| | | /// 用户ID |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "用户ID" )] |
| | | [Required(ErrorMessage = "用户ID 必填")] |
| | | public int CustomerId { get; set; } |
| | | |
| | | |
| | | |
| | | /// <summary> |
| | | /// 企业类型 从企业类型中选择 |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "企业类型 ", Length = 255)] |
| | | [Required(ErrorMessage = "企业类型")] |
| | | public string EnterpriseType { get; set; } |
| | | |
| | | |
| | | /// <summary> |
| | | /// 交易主体 代码 同角色代码 |
| | | /// </summary> |
| | | [Required(ErrorMessage = "交易主体代码为必填项")] |
| | | [SugarColumn(ColumnDescription = "交易主体code")] |
| | | public string TransactionCode { get; set; } |
| | | /// <summary> |
| | | /// 营业执照文件路径 |
| | | /// </summary> |
| | | [Required(ErrorMessage = "营业执照文件必传")] |
| | | [SugarColumn(ColumnDescription = "营业执照文件路径")] |
| | | public string BusinessLicense { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 企业名称 |
| | | /// </summary> |
| | | [Required(ErrorMessage = "企业名称为必填项")] |
| | | [SugarColumn(ColumnDescription = "企业名称")] |
| | | public string EnterpriseName { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 统一社会信用代码 |
| | | /// </summary> |
| | | [Required(ErrorMessage = "统一社会信用代码为必填项")] |
| | | [SugarColumn(ColumnDescription = "统一社会信用代码")] |
| | | public string UnifiedSocialCreditCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 注册资金(单位:万元 ) |
| | | /// </summary> |
| | | [Required(ErrorMessage = "注册资金为必填项")] |
| | | [SugarColumn(ColumnDescription = "注册资金")] |
| | | public decimal RegisteredCapital { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 法定代表人姓名 |
| | | /// </summary> |
| | | [Required(ErrorMessage = "法定代表人姓名为必填项")] |
| | | [SugarColumn(ColumnDescription = "法定代表人姓名")] |
| | | public string LegalRepresentativeName { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 法定代表人身份证文件路径 |
| | | /// </summary> |
| | | [Required(ErrorMessage = "法定代表人身份证文件路径毕传")] |
| | | [SugarColumn(ColumnDescription = "法定代表人身份证文件路径")] |
| | | public string LegalRepresentativeIdCard { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 法定代表人身份证号码 |
| | | /// </summary> |
| | | [Required(ErrorMessage = "法定代表人身份证号码为必填项")] |
| | | [SugarColumn(ColumnDescription = "法定代表人姓名")] |
| | | public string LegalRepresentativeIdNumber { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 法定代表人联系电话 |
| | | /// </summary> |
| | | [Required(ErrorMessage = "法定代表人联系电话为必填项")] |
| | | [Phone(ErrorMessage = "联系电话格式不正确")] |
| | | [SugarColumn(ColumnDescription = "法定代表人姓名")] |
| | | public string LegalRepresentativePhone { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 企业住所(下拉选择,需结合实际可选值,先字符串接收 ) |
| | | /// </summary> |
| | | [Required(ErrorMessage = "企业住所为必填项")] |
| | | [SugarColumn(ColumnDescription = "企业住所")] |
| | | public string Residence { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 企业联系电话 |
| | | /// </summary> |
| | | [Required(ErrorMessage = "企业联系电话为必填项")] |
| | | [Phone(ErrorMessage = "联系电话格式不正确")] |
| | | [SugarColumn(ColumnDescription = "企业联系电话")] |
| | | public string EnterprisePhone { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 企业成立时间 |
| | | /// </summary> |
| | | [Required(ErrorMessage = "成立时间为必填项")] |
| | | [SugarColumn(ColumnDescription = "企业成立时间")] |
| | | public DateTime EstablishmentTime { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 企业主营业务 |
| | | /// </summary> |
| | | [Required(ErrorMessage = "主营业务为必填项")] |
| | | [SugarColumn(ColumnDescription = "企业主营业务")] |
| | | public string MainBusiness { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 企业邮箱 |
| | | /// </summary> |
| | | [Required(ErrorMessage = "企业邮箱为必填项")] |
| | | [EmailAddress(ErrorMessage = "邮箱格式不正确")] |
| | | [SugarColumn(ColumnDescription = "企业邮箱")] |
| | | public string EnterpriseEmail { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 业务经办人姓名 |
| | | /// </summary> |
| | | |
| | | [SugarColumn(ColumnDescription = "业务经办人姓名", IsNullable = true)] |
| | | public string OperatorName { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 业务经办人身份证文件路径或标识(上传后存储信息) |
| | | /// </summary> |
| | | |
| | | [SugarColumn(ColumnDescription = "业务经办人身份证文件路径或标识", IsNullable = true)] |
| | | public string OperatorIdCard { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 业务经办人身份证号码 |
| | | /// </summary> |
| | | |
| | | [SugarColumn(ColumnDescription = "法定代表人姓名", IsNullable = true)] |
| | | public string OperatorIdNumber { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 业务经办人联系电话 |
| | | /// </summary> |
| | | |
| | | [Phone(ErrorMessage = "联系电话格式不正确")] |
| | | [SugarColumn(ColumnDescription = "法定代表人姓名",IsNullable =true)] |
| | | public string OperatorPhone { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 企业开户行 |
| | | /// </summary> |
| | | [Required(ErrorMessage = "开户行为必填项")] |
| | | [SugarColumn(ColumnDescription = "法定代表人姓名")] |
| | | public string BankName { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 企业银行账号 |
| | | /// </summary> |
| | | [Required(ErrorMessage = "银行账号为必填项")] |
| | | [SugarColumn(ColumnDescription = "法定代表人姓名")] |
| | | public string BankAccount { get; set; } |
| | | /// <summary> |
| | | /// 审核步骤 |
| | | /// </summary> |
| | | |
| | | [SugarColumn(ColumnDescription = "审核步骤")] |
| | | public int steps { set; get; } = 0; |
| | | } |
New file |
| | |
| | | // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 |
| | | // |
| | | // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 |
| | | // |
| | | // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! |
| | | |
| | | using Admin.NET.Core; |
| | | using SqlSugar; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | |
| | | namespace FZCZTB.NET.MD.CutomerMd; |
| | | /// <summary> |
| | | /// 外部角色表 |
| | | /// </summary> |
| | | [SugarTable("FBS_CoutomerExRole", "外部角色表")] |
| | | [IncreTable] |
| | | public class FBS_CoutomerExRole: EntityBaseId |
| | | { |
| | | //客户ID |
| | | public long CustomerId { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 外部角色 |
| | | /// </summary> |
| | | public long ExRoleId { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 是否完成角色创建 |
| | | /// </summary> |
| | | public bool HasFlsh { get; set; }= false; |
| | | |
| | | /// <summary> |
| | | /// 外部角色 |
| | | /// </summary> |
| | | [Navigate(NavigateType.OneToOne, nameof(ExRoleId))] |
| | | public FBS_ExRole ExRole { get; set; } |
| | | } |
| | |
| | | [SugarTable("FBS_Customer", "客户表")] |
| | | [SugarIndex("index_{table}_A", nameof(Account), OrderByType.Asc)] |
| | | [SugarIndex("index_{table}_P", nameof(Phone), OrderByType.Asc)] |
| | | |
| | | [IncreTable] |
| | | public partial class FBS_Customer : EntityBaseTenant |
| | | { |
| | | /// <summary> |
| | |
| | | /// <summary> |
| | | /// 密码 |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "密码", Length = 512)] |
| | | [SugarColumn(ColumnDescription = "密码", Length = 512,IsNullable =true)] |
| | | [MaxLength(512)] |
| | | [Newtonsoft.Json.JsonIgnore] |
| | | [System.Text.Json.Serialization.JsonIgnore] |
| | | |
| | | public virtual string Password { get; set; } |
| | | |
| | | /// <summary> |
| | |
| | | [MaxLength(512)] |
| | | public string? Avatar { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 性别-男_1、女_2 |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "性别")] |
| | | public GenderEnum Sex { get; set; } = GenderEnum.Male; |
| | | ///// <summary> |
| | | ///// 性别-男_1、女_2 |
| | | ///// </summary> |
| | | //[SugarColumn(ColumnDescription = "性别")] |
| | | //public GenderEnum Sex { get; set; } = GenderEnum.Male; |
| | | |
| | | /// <summary> |
| | | /// 年龄 |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "年龄")] |
| | | public int Age { get; set; } |
| | | ///// <summary> |
| | | ///// 年龄 |
| | | ///// </summary> |
| | | //[SugarColumn(ColumnDescription = "年龄")] |
| | | //public int Age { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 出生日期 |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "出生日期")] |
| | | public DateTime? Birthday { get; set; } |
| | | ///// <summary> |
| | | ///// 出生日期 |
| | | ///// </summary> |
| | | //[SugarColumn(ColumnDescription = "出生日期")] |
| | | //public DateTime? Birthday { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 民族 |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "民族", Length = 32)] |
| | | [MaxLength(32)] |
| | | public string? Nation { get; set; } |
| | | ///// <summary> |
| | | ///// 民族 |
| | | ///// </summary> |
| | | //[SugarColumn(ColumnDescription = "民族", Length = 32)] |
| | | //[MaxLength(32)] |
| | | //public string? Nation { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 手机号码 |
| | |
| | | [MaxLength(16)] |
| | | public string? Phone { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 证件类型 |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "证件类型")] |
| | | public CardTypeEnum CardType { get; set; } |
| | | ///// <summary> |
| | | ///// 证件类型 |
| | | ///// </summary> |
| | | //[SugarColumn(ColumnDescription = "证件类型")] |
| | | //public CardTypeEnum CardType { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 身份证号 |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "身份证号", Length = 32)] |
| | | [MaxLength(32)] |
| | | public string? IdCardNum { get; set; } |
| | | ///// <summary> |
| | | ///// 身份证号 |
| | | ///// </summary> |
| | | //[SugarColumn(ColumnDescription = "身份证号", Length = 32)] |
| | | //[MaxLength(32)] |
| | | //public string? IdCardNum { get; set; } |
| | | |
| | | |
| | | /// <summary> |
| | | /// 身份证号 |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "身份证", Length = 512)] |
| | | [MaxLength(512)] |
| | | public string? IdCardPath { get; set; } |
| | | ///// <summary> |
| | | ///// 身份证号 |
| | | ///// </summary> |
| | | //[SugarColumn(ColumnDescription = "身份证", Length = 512)] |
| | | //[MaxLength(512)] |
| | | //public string? IdCardPath { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 邮箱 |
| | |
| | | [MaxLength(64)] |
| | | public string? Email { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 地址 |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "地址", Length = 256)] |
| | | [MaxLength(256)] |
| | | public string? Address { get; set; } |
| | | ///// <summary> |
| | | ///// 地址 |
| | | ///// </summary> |
| | | //[SugarColumn(ColumnDescription = "地址", Length = 256)] |
| | | //[MaxLength(256)] |
| | | //public string? Address { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 文化程度 |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "文化程度")] |
| | | public CultureLevelEnum CultureLevel { get; set; } |
| | | ///// <summary> |
| | | ///// 文化程度 |
| | | ///// </summary> |
| | | //[SugarColumn(ColumnDescription = "文化程度")] |
| | | //public CultureLevelEnum CultureLevel { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 政治面貌 |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "政治面貌", Length = 16)] |
| | | [MaxLength(16)] |
| | | public string? PoliticalOutlook { get; set; } |
| | | ///// <summary> |
| | | ///// 政治面貌 |
| | | ///// </summary> |
| | | //[SugarColumn(ColumnDescription = "政治面貌", Length = 16)] |
| | | //[MaxLength(16)] |
| | | //public string? PoliticalOutlook { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 毕业院校 |
| | | /// </summary>COLLEGE |
| | | [SugarColumn(ColumnDescription = "毕业院校", Length = 128)] |
| | | [MaxLength(128)] |
| | | public string? College { get; set; } |
| | | ///// <summary> |
| | | ///// 毕业院校 |
| | | ///// </summary>COLLEGE |
| | | //[SugarColumn(ColumnDescription = "毕业院校", Length = 128)] |
| | | //[MaxLength(128)] |
| | | //public string? College { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 办公电话 |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "办公电话", Length = 16)] |
| | | [MaxLength(16)] |
| | | public string? OfficePhone { get; set; } |
| | | ///// <summary> |
| | | ///// 办公电话 |
| | | ///// </summary> |
| | | //[SugarColumn(ColumnDescription = "办公电话", Length = 16)] |
| | | //[MaxLength(16)] |
| | | //public string? OfficePhone { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 紧急联系人 |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "紧急联系人", Length = 32)] |
| | | [MaxLength(32)] |
| | | public string? EmergencyContact { get; set; } |
| | | ///// <summary> |
| | | ///// 紧急联系人 |
| | | ///// </summary> |
| | | //[SugarColumn(ColumnDescription = "紧急联系人", Length = 32)] |
| | | //[MaxLength(32)] |
| | | //public string? EmergencyContact { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 紧急联系人电话 |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "紧急联系人电话", Length = 16)] |
| | | [MaxLength(16)] |
| | | public string? EmergencyPhone { get; set; } |
| | | ///// <summary> |
| | | ///// 紧急联系人电话 |
| | | ///// </summary> |
| | | //[SugarColumn(ColumnDescription = "紧急联系人电话", Length = 16)] |
| | | //[MaxLength(16)] |
| | | //public string? EmergencyPhone { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 紧急联系人地址 |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "紧急联系人地址", Length = 256)] |
| | | [MaxLength(256)] |
| | | public string? EmergencyAddress { get; set; } |
| | | ///// <summary> |
| | | ///// 紧急联系人地址 |
| | | ///// </summary> |
| | | //[SugarColumn(ColumnDescription = "紧急联系人地址", Length = 256)] |
| | | //[MaxLength(256)] |
| | | //public string? EmergencyAddress { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 个人简介 |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "个人简介", Length = 512)] |
| | | [MaxLength(512)] |
| | | public string? Introduction { get; set; } |
| | | ///// <summary> |
| | | ///// 个人简介 |
| | | ///// </summary> |
| | | //[SugarColumn(ColumnDescription = "个人简介", Length = 512)] |
| | | //[MaxLength(512)] |
| | | //public string? Introduction { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 排序 |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "排序")] |
| | | public int OrderNo { get; set; } = 100; |
| | | ///// <summary> |
| | | ///// 排序 |
| | | ///// </summary> |
| | | //[SugarColumn(ColumnDescription = "排序")] |
| | | //public int OrderNo { get; set; } = 100; |
| | | |
| | | /// <summary> |
| | | /// 状态 |
| | |
| | | //[MaxLength(32)] |
| | | //public string? JobNum { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 职级 |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "职级", Length = 32)] |
| | | [MaxLength(32)] |
| | | public string? PosLevel { get; set; } |
| | | ///// <summary> |
| | | ///// 职级 |
| | | ///// </summary> |
| | | //[SugarColumn(ColumnDescription = "职级", Length = 32)] |
| | | //[MaxLength(32)] |
| | | //public string? PosLevel { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 职称 |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "职称", Length = 32)] |
| | | [MaxLength(32)] |
| | | public string? PosTitle { get; set; } |
| | | ///// <summary> |
| | | ///// 职称 |
| | | ///// </summary> |
| | | //[SugarColumn(ColumnDescription = "职称", Length = 32)] |
| | | //[MaxLength(32)] |
| | | //public string? PosTitle { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 擅长领域 |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "擅长领域", Length = 32)] |
| | | [MaxLength(32)] |
| | | public string? Expertise { get; set; } |
| | | ///// <summary> |
| | | ///// 擅长领域 |
| | | ///// </summary> |
| | | //[SugarColumn(ColumnDescription = "擅长领域", Length = 32)] |
| | | //[MaxLength(32)] |
| | | //public string? Expertise { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 办公区域 |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "办公区域", Length = 32)] |
| | | [MaxLength(32)] |
| | | public string? OfficeZone { get; set; } |
| | | ///// <summary> |
| | | ///// 办公区域 |
| | | ///// </summary> |
| | | //[SugarColumn(ColumnDescription = "办公区域", Length = 32)] |
| | | //[MaxLength(32)] |
| | | //public string? OfficeZone { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 办公室 |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "办公室", Length = 32)] |
| | | [MaxLength(32)] |
| | | public string? Office { get; set; } |
| | | ///// <summary> |
| | | ///// 办公室 |
| | | ///// </summary> |
| | | //[SugarColumn(ColumnDescription = "办公室", Length = 32)] |
| | | //[MaxLength(32)] |
| | | //public string? Office { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 入职日期 |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "入职日期")] |
| | | public DateTime? JoinDate { get; set; } |
| | | ///// <summary> |
| | | ///// 入职日期 |
| | | ///// </summary> |
| | | //[SugarColumn(ColumnDescription = "入职日期")] |
| | | //public DateTime? JoinDate { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 最新登录Ip |
| | |
| | | [MaxLength(512)] |
| | | public string? Signature { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 外部规则,登录角色 |
| | | /// </summary> |
| | | [Navigate(NavigateType.OneToMany, nameof(FBS_CoutomerExRole.CustomerId))] |
| | | public List<FBS_CoutomerExRole> CoutomerExRols { set; get; } |
| | | |
| | | ///// <summary> |
| | | ///// 验证超级管理员类型,若账号类型为超级管理员则报错 |
| | | ///// </summary> |
| | |
| | | |
| | | namespace FZCZTB.NET.MD.CutomerMd; |
| | | [SugarTable("FBS_CustomerRole", "客户菜单表")] |
| | | |
| | | [IncreTable] |
| | | public class FBS_CustomerRole : EntityBaseId |
| | | { |
| | | /// <summary> |
| | |
| | | /// </summary> |
| | | [Navigate(NavigateType.OneToOne, nameof(RoleId))] |
| | | public SysRole SysRole { get; set; } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | } |
| | |
| | | /// 登录即要选择的校色 |
| | | /// </summary> |
| | | |
| | | [SugarTable("FBS_TenantMenu", "客户主分类角色")] |
| | | [SugarTable("FBS_ExRole", "客户主分类角色")] |
| | | [SugarIndex("index_{table}_N", nameof(Name), OrderByType.Asc)] |
| | | [SugarIndex("index_{table}_C", nameof(Code), OrderByType.Asc)] |
| | | |
| | | [IncreTable] |
| | | public class FBS_ExRole: EntityBaseTenant |
| | | { |
| | | /// <summary> |
| | |
| | | /// <summary> |
| | | /// 系统租户菜单表 |
| | | /// </summary> |
| | | [SugarTable("FBS_TenantMenu", "系统租户菜单表")] |
| | | |
| | | [SugarTable("FBS_ExRoleMenu", "系统租户菜单表")] |
| | | [IncreTable] |
| | | class FBS_ExRoleMenu: EntityBaseId |
| | | { |
| | | /// <summary> |
| | |
| | | [SugarTable("FBS_Menu", "客户系统菜单表")] |
| | | [SugarIndex("index_{table}_T", nameof(Title), OrderByType.Asc)] |
| | | [SugarIndex("index_{table}_T2", nameof(Type), OrderByType.Asc)] |
| | | |
| | | [IncreTable] |
| | | public class FBS_Menu: EntityBaseTenant |
| | | { |
| | | /// <summary> |
| | |
| | | [SugarTable("FBS_Role", "客户个性化角色")] |
| | | [SugarIndex("index_{table}_N", nameof(Name), OrderByType.Asc)] |
| | | [SugarIndex("index_{table}_C", nameof(Code), OrderByType.Asc)] |
| | | |
| | | [IncreTable] |
| | | public class FBS_Role : EntityBaseTenant |
| | | { |
| | | /// <summary> |
| | |
| | | |
| | | namespace FZCZTB.NET.MD.CutomerMd; |
| | | |
| | | [SugarTable("FBS_Role", "个性化校色菜单")] |
| | | [SugarTable("FBS_RoleMenu", "个性化校色菜单")] |
| | | [IncreTable] |
| | | public class FBS_RoleMenu: EntityBaseId |
| | | { |
| | | |
| | |
| | | using Furion.DependencyInjection; |
| | | using FZCZTB.NET.MD.CutomerMd; |
| | | using Mapster; |
| | | using SqlSugar; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.ComponentModel.DataAnnotations; |
| | |
| | | /// 返回当前可用的用户角色 再注册和登录时需要返回编码 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | public async Task<CustomerDto> GetCustomer(int id) |
| | | public async Task<CustomerRDto> GetCustomer(int id) |
| | | { |
| | | |
| | | |
| | | |
| | | return (await _fBS_CustomerRep.GetFirstAsync(x => x.Id == id && x.Status == StatusEnum.Enable)).Adapt<CustomerDto>(); |
| | | return (await _fBS_CustomerRep.GetFirstAsync(x => x.Id == id && x.Status == StatusEnum.Enable)).Adapt<CustomerRDto>(); |
| | | |
| | | |
| | | |
| | |
| | | /// 返回当前可用的用户角色 再注册和登录时需要返回编码 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | public async Task<CustomerDto> UpDataCustomer(int id) |
| | | public async Task<CustomerRDto> UpDataCustomer(int id) |
| | | { |
| | | |
| | | |
| | | |
| | | return (await _fBS_CustomerRep.GetFirstAsync(x => x.Id == id && x.Status == StatusEnum.Enable)).Adapt<CustomerDto>(); |
| | | return (await _fBS_CustomerRep.GetFirstAsync(x => x.Id == id && x.Status == StatusEnum.Enable)).Adapt<CustomerRDto>(); |
| | | |
| | | |
| | | |
| | |
| | | /// <summary> |
| | | /// 客户表输出参数 |
| | | /// </summary> |
| | | public class CustomerDto |
| | | public class CustomerRDto |
| | | { |
| | | /// <summary> |
| | | /// 主键Id |
| | | /// </summary> |
| | | public long Id { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 账号 |
| | | /// </summary> |
| | | public string Account { get; set; } |
| | | |
| | | public virtual string Account { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 密码 |
| | | /// </summary> |
| | | public string Password { get; set; } |
| | | |
| | | [MaxLength(512)] |
| | | |
| | | public virtual string Password { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 真实姓名 |
| | | /// </summary> |
| | | public string RealName { get; set; } |
| | | |
| | | [MaxLength(32)] |
| | | public virtual string RealName { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 昵称 |
| | | /// </summary> |
| | | |
| | | [MaxLength(32)] |
| | | public string? NickName { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 头像 |
| | | /// </summary> |
| | | |
| | | [MaxLength(512)] |
| | | public string? Avatar { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 性别 |
| | | /// </summary> |
| | | public GenderEnum Sex { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 年龄 |
| | | /// </summary> |
| | | public int Age { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 出生日期 |
| | | /// </summary> |
| | | public DateTime? Birthday { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 民族 |
| | | /// </summary> |
| | | public string? Nation { get; set; } |
| | | |
| | | |
| | | /// <summary> |
| | | /// 手机号码 |
| | | /// </summary> |
| | | |
| | | [MaxLength(16)] |
| | | public string? Phone { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 证件类型 |
| | | /// </summary> |
| | | public CardTypeEnum CardType { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 身份证号 |
| | | /// </summary> |
| | | public string? IdCardNum { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 身份证 |
| | | /// </summary> |
| | | public string? IdCardPath { get; set; } |
| | | |
| | | |
| | | /// <summary> |
| | | /// 邮箱 |
| | | /// </summary> |
| | | |
| | | [MaxLength(64)] |
| | | public string? Email { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 地址 |
| | | /// </summary> |
| | | public string? Address { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 文化程度 |
| | | /// </summary> |
| | | public CultureLevelEnum CultureLevel { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 政治面貌 |
| | | /// </summary> |
| | | public string? PoliticalOutlook { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 毕业院校 |
| | | /// </summary> |
| | | public string? College { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 办公电话 |
| | | /// </summary> |
| | | public string? OfficePhone { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 紧急联系人 |
| | | /// </summary> |
| | | public string? EmergencyContact { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 紧急联系人电话 |
| | | /// </summary> |
| | | public string? EmergencyPhone { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 紧急联系人地址 |
| | | /// </summary> |
| | | public string? EmergencyAddress { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 个人简介 |
| | | /// </summary> |
| | | public string? Introduction { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 排序 |
| | | /// </summary> |
| | | public int OrderNo { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 状态 |
| | | /// </summary> |
| | | public StatusEnum Status { get; set; } |
| | | |
| | | |
| | | /// <summary> |
| | | /// 备注 |
| | | /// </summary> |
| | | |
| | | [MaxLength(256)] |
| | | public string? Remark { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 职级 |
| | | /// </summary> |
| | | public string? PosLevel { get; set; } |
| | | |
| | | |
| | | /// <summary> |
| | | /// 职称 |
| | | /// </summary> |
| | | public string? PosTitle { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 擅长领域 |
| | | /// </summary> |
| | | public string? Expertise { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 办公区域 |
| | | /// </summary> |
| | | public string? OfficeZone { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 办公室 |
| | | /// </summary> |
| | | public string? Office { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 入职日期 |
| | | /// </summary> |
| | | public DateTime? JoinDate { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 最新登录Ip |
| | | /// </summary> |
| | | public string? LastLoginIp { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 最新登录地点 |
| | | /// </summary> |
| | | public string? LastLoginAddress { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 最新登录时间 |
| | | /// </summary> |
| | | public DateTime? LastLoginTime { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 最新登录设备 |
| | | /// </summary> |
| | | public string? LastLoginDevice { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 电子签名 |
| | | /// </summary> |
| | | |
| | | public string? Signature { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 租户Id |
| | | /// 外部规则,登录角色 |
| | | /// </summary> |
| | | public long? TenantId { get; set; } |
| | | [Navigate(NavigateType.OneToMany, nameof(FBS_CoutomerExRole.CustomerId))] |
| | | public List<FBS_CoutomerExRole> CoutomerExRols { set; get; } |
| | | |
| | | /// <summary> |
| | | /// 注册用户角色 |
| | | /// 注册用户角色 |
| | | /// </summary> |
| | | public string? ExRoleCode { get; set; } |
| | | |
| | | |
| | | /// <summary> |
| | | /// 用户注册手机验证码 |
| | | /// </summary> |
| | | public string? PhoneVCode { get; set; } |
| | | |
| | | } |
| | | } |
| | |
| | | <TargetFramework>net8.0</TargetFramework> |
| | | <ImplicitUsings>enable</ImplicitUsings> |
| | | <Nullable>enable</Nullable> |
| | | <GenerateDocumentationFile>True</GenerateDocumentationFile> |
| | | </PropertyGroup> |
| | | |
| | | <ItemGroup> |
| | |
| | | <ProjectReference Include="..\FZCZTB.NET.MD\FZCZTB.NET.MD.csproj" /> |
| | | </ItemGroup> |
| | | |
| | | <ItemGroup> |
| | | <None Update="FZCZTSYSServiceConfig.json"> |
| | | <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> |
| | | </None> |
| | | </ItemGroup> |
| | | |
| | | </Project> |
| | |
| | | { |
| | | "SMSConfigMd": { |
| | | "LingKaiXinxiSets": { //凌凯短信配置 |
| | | "SMSConfig": { |
| | | |
| | | "lingKai": { //凌凯短信配置 |
| | | "Url": "https://mb345.com/ws/BatchSend2.aspx", |
| | | "Number": "XP010534", |
| | | "AccountPassPassword": "123321", |
| | | "VerifyTimeOut": 60, //秒 |
| | | "VerifyTimeOut": "60", //秒 |
| | | "Templates": [ |
| | | { |
| | | "Id": "0", |
| | | "SignName": "【政采咨询网】", //需要加入的公司标签 |
| | | "TemplateCode": "VCode", |
| | | "Content": "您的验证码为:${code},请勿泄露于他人!" |
| | | "Content": "您好,您的验证码是:${code}" |
| | | |
| | | |
| | | }, |
| | | { |
| | | "Id": "1", |
| | |
| | | public class SMSConfigOptions : IConfigurableOptions |
| | | { |
| | | |
| | | |
| | | |
| | | /// <summary> |
| | | /// 凌凯信息配置 |
| | | /// </summary> |
| | |
| | | /// <summary> |
| | | /// 超时时间 |
| | | /// </summary> |
| | | public int VerifyTimeOut { get; set; } |
| | | public string VerifyTimeOut { get; set; } |
| | | /// <summary> |
| | | /// Templates |
| | | /// </summary> |
| | | public List<SmsTemplate> Templates { get; set; } |
| | | public List<SmsTemplate>? Templates { get; set; } |
| | | } |
| | |
| | | using Yitter.IdGenerator; |
| | | using Lazy.Captcha.Core; |
| | | using Furion; |
| | | using NewLife; |
| | | |
| | | namespace FZCZTB.NET.SYSService.MSM; |
| | | /// <summary> |
| | |
| | | ICaptcha captcha |
| | | ) |
| | | { |
| | | |
| | | _smsOptions = smsOptions.Value; |
| | | _sysCacheService = _sysCacheService; |
| | | _sysCacheService = sysCacheService; |
| | | |
| | | _captcha = captcha; |
| | | } |
| | | |
| | |
| | | return Temp.Content+Temp.SignName; |
| | | } |
| | | if (Code == null) |
| | | Oops.Oh("短信内容为空"); |
| | | throw Oops.Oh("短信内容为空"); |
| | | return Code; |
| | | } |
| | | |
| | |
| | | if (string.IsNullOrWhiteSpace(verifyCode)) throw Oops.Oh("验证码不存在或已失效,请重新获取!"); |
| | | |
| | | if (verifyCode != input.Code) throw Oops.Oh("验证码错误!"); |
| | | |
| | | _sysCacheService.Remove($"{CacheConst.KeyPhoneVerCode}{input.Phone}"); |
| | | return true; |
| | | } |
| | | /// <summary> |
| | |
| | | }; |
| | | var code= FormartMessage(verifyCode.toString()); |
| | | |
| | | await SendSMSAsync(code, phoneNumber); |
| | | await SendSMSAsync(code, phoneNumber); |
| | | |
| | | _sysCacheService.Set($"{CacheConst.KeyPhoneVerCode}{phoneNumber}", verifyCode, TimeSpan.FromSeconds(_smsOptions.lingKai.VerifyTimeOut)); |
| | | _sysCacheService.Set($"{CacheConst.KeyPhoneVerCode}{phoneNumber}", verifyCode, TimeSpan.FromSeconds(_smsOptions.lingKai.VerifyTimeOut.ToInt())); |
| | | |
| | | |
| | | |
| | | |
| | | await Task.CompletedTask; |
| | | |
| | | } |
| | | |
| | | /// <summary> |
New file |
| | |
| | | // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 |
| | | // |
| | | // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 |
| | | // |
| | | // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! |
| | | |
| | | using Admin.NET.Core; |
| | | using AspNetCoreRateLimit; |
| | | using Furion; |
| | | using FZCZTB.NET.SYSService.MSM; |
| | | using IPTools.Core; |
| | | using Microsoft.AspNetCore.Builder; |
| | | using Microsoft.Extensions.DependencyInjection; |
| | | using Newtonsoft.Json; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | |
| | | namespace FZCZTB.NET.SYSService; |
| | | [AppStartup(int.MaxValue -1)] |
| | | public class Startup: AppStartup |
| | | { |
| | | |
| | | public void ConfigureServices(IServiceCollection services) |
| | | { |
| | | services.AddConfigurableOptions<SMSConfigOptions>(); |
| | | |
| | | |
| | | } |
| | | } |
| | |
| | | <TargetFramework>net8.0</TargetFramework> |
| | | <ImplicitUsings>enable</ImplicitUsings> |
| | | <Nullable>enable</Nullable> |
| | | <GenerateDocumentationFile>True</GenerateDocumentationFile> |
| | | </PropertyGroup> |
| | | |
| | | <ItemGroup> |
| | |
| | | { |
| | | input.Keyword = input.Keyword?.Trim(); |
| | | var query = _fBS_CustomerRep.AsQueryable() |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.Keyword), u => u.Account.Contains(input.Keyword) || u.RealName.Contains(input.Keyword) || u.NickName.Contains(input.Keyword) || u.IdCardPath.Contains(input.Keyword) || u.College.Contains(input.Keyword) || u.OfficePhone.Contains(input.Keyword) || u.EmergencyContact.Contains(input.Keyword) || u.EmergencyPhone.Contains(input.Keyword) || u.EmergencyAddress.Contains(input.Keyword) || u.Introduction.Contains(input.Keyword) || u.Remark.Contains(input.Keyword) || u.PosLevel.Contains(input.Keyword) || u.PosTitle.Contains(input.Keyword)) |
| | | //.WhereIF(!string.IsNullOrWhiteSpace(input.Keyword), u => u.Account.Contains(input.Keyword) || u.RealName.Contains(input.Keyword) || u.NickName.Contains(input.Keyword) || u.IdCardPath.Contains(input.Keyword) || u.College.Contains(input.Keyword) || u.OfficePhone.Contains(input.Keyword) || u.EmergencyContact.Contains(input.Keyword) || u.EmergencyPhone.Contains(input.Keyword) || u.EmergencyAddress.Contains(input.Keyword) || u.Introduction.Contains(input.Keyword) || u.Remark.Contains(input.Keyword) || u.PosLevel.Contains(input.Keyword) || u.PosTitle.Contains(input.Keyword)) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.Account), u => u.Account.Contains(input.Account.Trim())) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.RealName), u => u.RealName.Contains(input.RealName.Trim())) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.NickName), u => u.NickName.Contains(input.NickName.Trim())) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.IdCardPath), u => u.IdCardPath.Contains(input.IdCardPath.Trim())) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.College), u => u.College.Contains(input.College.Trim())) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.OfficePhone), u => u.OfficePhone.Contains(input.OfficePhone.Trim())) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.EmergencyContact), u => u.EmergencyContact.Contains(input.EmergencyContact.Trim())) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.EmergencyPhone), u => u.EmergencyPhone.Contains(input.EmergencyPhone.Trim())) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.EmergencyAddress), u => u.EmergencyAddress.Contains(input.EmergencyAddress.Trim())) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.Introduction), u => u.Introduction.Contains(input.Introduction.Trim())) |
| | | //.WhereIF(!string.IsNullOrWhiteSpace(input.IdCardPath), u => u.IdCardPath.Contains(input.IdCardPath.Trim())) |
| | | //.WhereIF(!string.IsNullOrWhiteSpace(input.College), u => u.College.Contains(input.College.Trim())) |
| | | //.WhereIF(!string.IsNullOrWhiteSpace(input.OfficePhone), u => u.OfficePhone.Contains(input.OfficePhone.Trim())) |
| | | //.WhereIF(!string.IsNullOrWhiteSpace(input.EmergencyContact), u => u.EmergencyContact.Contains(input.EmergencyContact.Trim())) |
| | | //.WhereIF(!string.IsNullOrWhiteSpace(input.EmergencyPhone), u => u.EmergencyPhone.Contains(input.EmergencyPhone.Trim())) |
| | | //.WhereIF(!string.IsNullOrWhiteSpace(input.EmergencyAddress), u => u.EmergencyAddress.Contains(input.EmergencyAddress.Trim())) |
| | | //.WhereIF(!string.IsNullOrWhiteSpace(input.Introduction), u => u.Introduction.Contains(input.Introduction.Trim())) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.Remark), u => u.Remark.Contains(input.Remark.Trim())) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.PosLevel), u => u.PosLevel.Contains(input.PosLevel.Trim())) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.PosTitle), u => u.PosTitle.Contains(input.PosTitle.Trim())) |
| | | .WhereIF(input.CardType.HasValue, u => u.CardType == input.CardType) |
| | | .WhereIF(input.CultureLevel.HasValue, u => u.CultureLevel == input.CultureLevel) |
| | | .WhereIF(input.OrderNo != null, u => u.OrderNo == input.OrderNo) |
| | | //.WhereIF(!string.IsNullOrWhiteSpace(input.PosLevel), u => u.PosLevel.Contains(input.PosLevel.Trim())) |
| | | //.WhereIF(!string.IsNullOrWhiteSpace(input.PosTitle), u => u.PosTitle.Contains(input.PosTitle.Trim())) |
| | | //.WhereIF(input.CardType.HasValue, u => u.CardType == input.CardType) |
| | | //.WhereIF(input.CultureLevel.HasValue, u => u.CultureLevel == input.CultureLevel) |
| | | //.WhereIF(input.OrderNo != null, u => u.OrderNo == input.OrderNo) |
| | | .WhereIF(input.Status.HasValue, u => u.Status == input.Status) |
| | | .Select<FBS_CustomerOutput>(); |
| | | return await query.OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize); |
| | |
| | | var entity = input.Adapt<FBS_Customer>(); |
| | | await _fBS_CustomerRep.AsUpdateable(entity) |
| | | .IgnoreColumns(u => new { |
| | | u.Expertise, |
| | | u.OfficeZone, |
| | | u.Office, |
| | | u.JoinDate, |
| | | //u.Expertise, |
| | | //u.OfficeZone, |
| | | //u.Office, |
| | | //u.JoinDate, |
| | | u.LastLoginIp, |
| | | u.LastLoginAddress, |
| | | u.LastLoginTime, |
| | |
| | | .SplitError(it => it.Item.RealName?.Length > 32, "真实姓名长度不能超过32个字符") |
| | | .SplitError(it => it.Item.NickName?.Length > 32, "昵称长度不能超过32个字符") |
| | | .SplitError(it => it.Item.Avatar?.Length > 512, "头像长度不能超过512个字符") |
| | | .SplitError(it => it.Item.Nation?.Length > 32, "民族长度不能超过32个字符") |
| | | //.SplitError(it => it.Item.Nation?.Length > 32, "民族长度不能超过32个字符") |
| | | .SplitError(it => it.Item.Phone?.Length > 16, "手机号码长度不能超过16个字符") |
| | | .SplitError(it => it.Item.IdCardNum?.Length > 32, "身份证号长度不能超过32个字符") |
| | | .SplitError(it => it.Item.IdCardPath?.Length > 512, "身份证长度不能超过512个字符") |
| | | //.SplitError(it => it.Item.IdCardNum?.Length > 32, "身份证号长度不能超过32个字符") |
| | | //.SplitError(it => it.Item.IdCardPath?.Length > 512, "身份证长度不能超过512个字符") |
| | | .SplitError(it => it.Item.Email?.Length > 64, "邮箱长度不能超过64个字符") |
| | | .SplitError(it => it.Item.Address?.Length > 256, "地址长度不能超过256个字符") |
| | | .SplitError(it => it.Item.PoliticalOutlook?.Length > 16, "政治面貌长度不能超过16个字符") |
| | | .SplitError(it => it.Item.College?.Length > 128, "毕业院校长度不能超过128个字符") |
| | | .SplitError(it => it.Item.OfficePhone?.Length > 16, "办公电话长度不能超过16个字符") |
| | | .SplitError(it => it.Item.EmergencyContact?.Length > 32, "紧急联系人长度不能超过32个字符") |
| | | .SplitError(it => it.Item.EmergencyPhone?.Length > 16, "紧急联系人电话长度不能超过16个字符") |
| | | .SplitError(it => it.Item.EmergencyAddress?.Length > 256, "紧急联系人地址长度不能超过256个字符") |
| | | .SplitError(it => it.Item.Introduction?.Length > 512, "个人简介长度不能超过512个字符") |
| | | //.SplitError(it => it.Item.Address?.Length > 256, "地址长度不能超过256个字符") |
| | | //.SplitError(it => it.Item.PoliticalOutlook?.Length > 16, "政治面貌长度不能超过16个字符") |
| | | //.SplitError(it => it.Item.College?.Length > 128, "毕业院校长度不能超过128个字符") |
| | | //.SplitError(it => it.Item.OfficePhone?.Length > 16, "办公电话长度不能超过16个字符") |
| | | //.SplitError(it => it.Item.EmergencyContact?.Length > 32, "紧急联系人长度不能超过32个字符") |
| | | //.SplitError(it => it.Item.EmergencyPhone?.Length > 16, "紧急联系人电话长度不能超过16个字符") |
| | | //.SplitError(it => it.Item.EmergencyAddress?.Length > 256, "紧急联系人地址长度不能超过256个字符") |
| | | //.SplitError(it => it.Item.Introduction?.Length > 512, "个人简介长度不能超过512个字符") |
| | | .SplitError(it => it.Item.Remark?.Length > 256, "备注长度不能超过256个字符") |
| | | .SplitError(it => it.Item.PosLevel?.Length > 32, "职级长度不能超过32个字符") |
| | | .SplitError(it => it.Item.PosTitle?.Length > 32, "职称长度不能超过32个字符") |
| | | //.SplitError(it => it.Item.PosLevel?.Length > 32, "职级长度不能超过32个字符") |
| | | //.SplitError(it => it.Item.PosTitle?.Length > 32, "职称长度不能超过32个字符") |
| | | .SplitInsert(_ => true) |
| | | .ToStorage(); |
| | | |
New file |
| | |
| | | // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 |
| | | // |
| | | // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 |
| | | // |
| | | // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! |
| | | |
| | | namespace FZCZTB.Net.CustomerSYSTem; |
| | | |
| | | /// <summary> |
| | | /// 企业类配置表输出参数 |
| | | /// </summary> |
| | | public class FBS_EnterpriseTypeDto |
| | | { |
| | | /// <summary> |
| | | /// 主键Id |
| | | /// </summary> |
| | | public long Id { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 名称 |
| | | /// </summary> |
| | | public string Name { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 代码 |
| | | /// </summary> |
| | | public string Code { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 父 |
| | | /// </summary> |
| | | public int ParentId { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 租户Id |
| | | /// </summary> |
| | | public long? TenantId { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 创建时间 |
| | | /// </summary> |
| | | public DateTime? CreateTime { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 更新时间 |
| | | /// </summary> |
| | | public DateTime? UpdateTime { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 创建者Id |
| | | /// </summary> |
| | | public long? CreateUserId { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 创建者姓名 |
| | | /// </summary> |
| | | public string? CreateUserName { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 修改者Id |
| | | /// </summary> |
| | | public long? UpdateUserId { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 修改者姓名 |
| | | /// </summary> |
| | | public string? UpdateUserName { get; set; } |
| | | |
| | | } |
New file |
| | |
| | | // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 |
| | | // |
| | | // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 |
| | | // |
| | | // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! |
| | | |
| | | using Admin.NET.Core; |
| | | using System.ComponentModel.DataAnnotations; |
| | | using Magicodes.ExporterAndImporter.Core; |
| | | using Magicodes.ExporterAndImporter.Excel; |
| | | |
| | | namespace FZCZTB.Net.CustomerSYSTem; |
| | | |
| | | /// <summary> |
| | | /// 企业类配置表基础输入参数 |
| | | /// </summary> |
| | | public class FBS_EnterpriseTypeBaseInput |
| | | { |
| | | /// <summary> |
| | | /// 主键Id |
| | | /// </summary> |
| | | public virtual long? Id { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 名称 |
| | | /// </summary> |
| | | [Required(ErrorMessage = "名称不能为空")] |
| | | public virtual string Name { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 代码 |
| | | /// </summary> |
| | | [Required(ErrorMessage = "代码不能为空")] |
| | | public virtual string Code { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 父 |
| | | /// </summary> |
| | | [Required(ErrorMessage = "父不能为空")] |
| | | public virtual int? ParentId { get; set; } |
| | | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 企业类配置表分页查询输入参数 |
| | | /// </summary> |
| | | public class PageFBS_EnterpriseTypeInput : BasePageInput |
| | | { |
| | | /// <summary> |
| | | /// 名称 |
| | | /// </summary> |
| | | public string Name { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 代码 |
| | | /// </summary> |
| | | public string Code { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 父 |
| | | /// </summary> |
| | | public int? ParentId { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 选中主键列表 |
| | | /// </summary> |
| | | public List<long> SelectKeyList { get; set; } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 企业类配置表增加输入参数 |
| | | /// </summary> |
| | | public class AddFBS_EnterpriseTypeInput |
| | | { |
| | | /// <summary> |
| | | /// 名称 |
| | | /// </summary> |
| | | [Required(ErrorMessage = "名称不能为空")] |
| | | [MaxLength(256, ErrorMessage = "名称字符长度不能超过256")] |
| | | public string Name { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 代码 |
| | | /// </summary> |
| | | [Required(ErrorMessage = "代码不能为空")] |
| | | [MaxLength(36, ErrorMessage = "代码字符长度不能超过36")] |
| | | public string Code { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 父 |
| | | /// </summary> |
| | | [Required(ErrorMessage = "父不能为空")] |
| | | public int? ParentId { get; set; } |
| | | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 企业类配置表删除输入参数 |
| | | /// </summary> |
| | | public class DeleteFBS_EnterpriseTypeInput |
| | | { |
| | | /// <summary> |
| | | /// 主键Id |
| | | /// </summary> |
| | | [Required(ErrorMessage = "主键Id不能为空")] |
| | | public long? Id { get; set; } |
| | | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 企业类配置表更新输入参数 |
| | | /// </summary> |
| | | public class UpdateFBS_EnterpriseTypeInput |
| | | { |
| | | /// <summary> |
| | | /// 主键Id |
| | | /// </summary> |
| | | [Required(ErrorMessage = "主键Id不能为空")] |
| | | public long? Id { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 名称 |
| | | /// </summary> |
| | | [Required(ErrorMessage = "名称不能为空")] |
| | | [MaxLength(256, ErrorMessage = "名称字符长度不能超过256")] |
| | | public string Name { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 代码 |
| | | /// </summary> |
| | | [Required(ErrorMessage = "代码不能为空")] |
| | | [MaxLength(36, ErrorMessage = "代码字符长度不能超过36")] |
| | | public string Code { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 父 |
| | | /// </summary> |
| | | [Required(ErrorMessage = "父不能为空")] |
| | | public int? ParentId { get; set; } |
| | | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 企业类配置表主键查询输入参数 |
| | | /// </summary> |
| | | public class QueryByIdFBS_EnterpriseTypeInput : DeleteFBS_EnterpriseTypeInput |
| | | { |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 企业类配置表数据导入实体 |
| | | /// </summary> |
| | | [ExcelImporter(SheetIndex = 1, IsOnlyErrorRows = true)] |
| | | public class ImportFBS_EnterpriseTypeInput : BaseImportInput |
| | | { |
| | | /// <summary> |
| | | /// 名称 |
| | | /// </summary> |
| | | [ImporterHeader(Name = "*名称")] |
| | | [ExporterHeader("*名称", Format = "", Width = 25, IsBold = true)] |
| | | public string Name { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 代码 |
| | | /// </summary> |
| | | [ImporterHeader(Name = "*代码")] |
| | | [ExporterHeader("*代码", Format = "", Width = 25, IsBold = true)] |
| | | public string Code { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 父 |
| | | /// </summary> |
| | | [ImporterHeader(Name = "*父")] |
| | | [ExporterHeader("*父", Format = "", Width = 25, IsBold = true)] |
| | | public int? ParentId { get; set; } |
| | | |
| | | } |
New file |
| | |
| | | // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 |
| | | // |
| | | // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 |
| | | // |
| | | // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! |
| | | using Magicodes.ExporterAndImporter.Core; |
| | | namespace FZCZTB.Net.CustomerSYSTem; |
| | | |
| | | /// <summary> |
| | | /// 企业类配置表输出参数 |
| | | /// </summary> |
| | | public class FBS_EnterpriseTypeOutput |
| | | { |
| | | /// <summary> |
| | | /// 主键Id |
| | | /// </summary> |
| | | public long Id { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 名称 |
| | | /// </summary> |
| | | public string Name { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 代码 |
| | | /// </summary> |
| | | public string Code { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 父 |
| | | /// </summary> |
| | | public int ParentId { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 租户Id |
| | | /// </summary> |
| | | public long? TenantId { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 创建时间 |
| | | /// </summary> |
| | | public DateTime? CreateTime { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 更新时间 |
| | | /// </summary> |
| | | public DateTime? UpdateTime { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 创建者Id |
| | | /// </summary> |
| | | public long? CreateUserId { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 创建者姓名 |
| | | /// </summary> |
| | | public string? CreateUserName { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 修改者Id |
| | | /// </summary> |
| | | public long? UpdateUserId { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 修改者姓名 |
| | | /// </summary> |
| | | public string? UpdateUserName { get; set; } |
| | | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 企业类配置表数据导入模板实体 |
| | | /// </summary> |
| | | public class ExportFBS_EnterpriseTypeOutput : ImportFBS_EnterpriseTypeInput |
| | | { |
| | | [ImporterHeader(IsIgnore = true)] |
| | | [ExporterHeader(IsIgnore = true)] |
| | | public override string Error { get; set; } |
| | | } |
New file |
| | |
| | | // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 |
| | | // |
| | | // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 |
| | | // |
| | | // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! |
| | | |
| | | using Admin.NET.Core.Service; |
| | | using Microsoft.AspNetCore.Http; |
| | | using Furion.DatabaseAccessor; |
| | | using Furion.FriendlyException; |
| | | using Mapster; |
| | | using SqlSugar; |
| | | using System.ComponentModel; |
| | | using System.ComponentModel.DataAnnotations; |
| | | using Microsoft.AspNetCore.Mvc; |
| | | using Furion.DynamicApiController; |
| | | using Furion.DependencyInjection; |
| | | using FZCZTB.NET.MD.ConfigMd; |
| | | using Admin.NET.Core; |
| | | namespace FZCZTB.Net.CustomerSYSTem; |
| | | |
| | | /// <summary> |
| | | /// 企业类配置表服务 🧩 |
| | | /// </summary> |
| | | [ApiDescriptionSettings(CustomerSYSTemConst.GroupName, Order = 100)] |
| | | public class FBS_EnterpriseTypeService : IDynamicApiController, ITransient |
| | | { |
| | | private readonly SqlSugarRepository<FBS_EnterpriseType> _fBS_EnterpriseTypeRep; |
| | | private readonly ISqlSugarClient _sqlSugarClient; |
| | | |
| | | public FBS_EnterpriseTypeService(SqlSugarRepository<FBS_EnterpriseType> fBS_EnterpriseTypeRep, ISqlSugarClient sqlSugarClient) |
| | | { |
| | | _fBS_EnterpriseTypeRep = fBS_EnterpriseTypeRep; |
| | | _sqlSugarClient = sqlSugarClient; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 分页查询企业类配置表 🔖 |
| | | /// </summary> |
| | | /// <param name="input"></param> |
| | | /// <returns></returns> |
| | | [DisplayName("分页查询企业类配置表")] |
| | | [ApiDescriptionSettings(Name = "Page"), HttpPost] |
| | | public async Task<SqlSugarPagedList<FBS_EnterpriseTypeOutput>> Page(PageFBS_EnterpriseTypeInput input) |
| | | { |
| | | input.Keyword = input.Keyword?.Trim(); |
| | | var query = _fBS_EnterpriseTypeRep.AsQueryable() |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.Keyword), u => u.Name.Contains(input.Keyword) || u.Code.Contains(input.Keyword)) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.Name), u => u.Name.Contains(input.Name.Trim())) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.Code), u => u.Code.Contains(input.Code.Trim())) |
| | | .WhereIF(input.ParentId != null, u => u.ParentId == input.ParentId) |
| | | .Select<FBS_EnterpriseTypeOutput>(); |
| | | return await query.OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取企业类配置表详情 ℹ️ |
| | | /// </summary> |
| | | /// <param name="input"></param> |
| | | /// <returns></returns> |
| | | [DisplayName("获取企业类配置表详情")] |
| | | [ApiDescriptionSettings(Name = "Detail"), HttpGet] |
| | | public async Task<FBS_EnterpriseType> Detail([FromQuery] QueryByIdFBS_EnterpriseTypeInput input) |
| | | { |
| | | return await _fBS_EnterpriseTypeRep.GetFirstAsync(u => u.Id == input.Id); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 增加企业类配置表 ➕ |
| | | /// </summary> |
| | | /// <param name="input"></param> |
| | | /// <returns></returns> |
| | | [DisplayName("增加企业类配置表")] |
| | | [ApiDescriptionSettings(Name = "Add"), HttpPost] |
| | | public async Task<long> Add(AddFBS_EnterpriseTypeInput input) |
| | | { |
| | | var entity = input.Adapt<FBS_EnterpriseType>(); |
| | | return await _fBS_EnterpriseTypeRep.InsertAsync(entity) ? entity.Id : 0; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 更新企业类配置表 ✏️ |
| | | /// </summary> |
| | | /// <param name="input"></param> |
| | | /// <returns></returns> |
| | | [DisplayName("更新企业类配置表")] |
| | | [ApiDescriptionSettings(Name = "Update"), HttpPost] |
| | | public async Task Update(UpdateFBS_EnterpriseTypeInput input) |
| | | { |
| | | var entity = input.Adapt<FBS_EnterpriseType>(); |
| | | await _fBS_EnterpriseTypeRep.AsUpdateable(entity) |
| | | .ExecuteCommandAsync(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 删除企业类配置表 ❌ |
| | | /// </summary> |
| | | /// <param name="input"></param> |
| | | /// <returns></returns> |
| | | [DisplayName("删除企业类配置表")] |
| | | [ApiDescriptionSettings(Name = "Delete"), HttpPost] |
| | | public async Task Delete(DeleteFBS_EnterpriseTypeInput input) |
| | | { |
| | | var entity = await _fBS_EnterpriseTypeRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002); |
| | | // await _fBS_EnterpriseTypeRep.FakeDeleteAsync(entity); //假删除 |
| | | await _fBS_EnterpriseTypeRep.DeleteAsync(entity); //真删除 |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 批量删除企业类配置表 ❌ |
| | | /// </summary> |
| | | /// <param name="input"></param> |
| | | /// <returns></returns> |
| | | [DisplayName("批量删除企业类配置表")] |
| | | [ApiDescriptionSettings(Name = "BatchDelete"), HttpPost] |
| | | public async Task<bool> BatchDelete([Required(ErrorMessage = "主键列表不能为空")]List<DeleteFBS_EnterpriseTypeInput> input) |
| | | { |
| | | var exp = Expressionable.Create<FBS_EnterpriseType>(); |
| | | foreach (var row in input) exp = exp.Or(it => it.Id == row.Id); |
| | | var list = await _fBS_EnterpriseTypeRep.AsQueryable().Where(exp.ToExpression()).ToListAsync(); |
| | | |
| | | // return await _fBS_EnterpriseTypeRep.FakeDeleteAsync(list); //假删除 |
| | | return await _fBS_EnterpriseTypeRep.DeleteAsync(list); //真删除 |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 导出企业类配置表记录 🔖 |
| | | /// </summary> |
| | | /// <param name="input"></param> |
| | | /// <returns></returns> |
| | | [DisplayName("导出企业类配置表记录")] |
| | | [ApiDescriptionSettings(Name = "Export"), HttpPost, NonUnify] |
| | | public async Task<IActionResult> Export(PageFBS_EnterpriseTypeInput input) |
| | | { |
| | | var list = (await Page(input)).Items?.Adapt<List<ExportFBS_EnterpriseTypeOutput>>() ?? new(); |
| | | if (input.SelectKeyList?.Count > 0) list = list.Where(x => input.SelectKeyList.Contains(x.Id)).ToList(); |
| | | return ExcelHelper.ExportTemplate(list, "企业类配置表导出记录"); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 下载企业类配置表数据导入模板 ⬇️ |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | [DisplayName("下载企业类配置表数据导入模板")] |
| | | [ApiDescriptionSettings(Name = "Import"), HttpGet, NonUnify] |
| | | public IActionResult DownloadTemplate() |
| | | { |
| | | return ExcelHelper.ExportTemplate(new List<ExportFBS_EnterpriseTypeOutput>(), "企业类配置表导入模板"); |
| | | } |
| | | |
| | | private static readonly object _fBS_EnterpriseTypeImportLock = new object(); |
| | | /// <summary> |
| | | /// 导入企业类配置表记录 💾 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | [DisplayName("导入企业类配置表记录")] |
| | | [ApiDescriptionSettings(Name = "Import"), HttpPost, NonUnify, UnitOfWork] |
| | | public IActionResult ImportData([Required] IFormFile file) |
| | | { |
| | | lock (_fBS_EnterpriseTypeImportLock) |
| | | { |
| | | var stream = ExcelHelper.ImportData<ImportFBS_EnterpriseTypeInput, FBS_EnterpriseType>(file, (list, markerErrorAction) => |
| | | { |
| | | _sqlSugarClient.Utilities.PageEach(list, 2048, pageItems => |
| | | { |
| | | |
| | | // 校验并过滤必填基本类型为null的字段 |
| | | var rows = pageItems.Where(x => { |
| | | if (!string.IsNullOrWhiteSpace(x.Error)) return false; |
| | | if (x.ParentId == null){ |
| | | x.Error = "父不能为空"; |
| | | return false; |
| | | } |
| | | return true; |
| | | }).Adapt<List<FBS_EnterpriseType>>(); |
| | | |
| | | var storageable = _fBS_EnterpriseTypeRep.Context.Storageable(rows) |
| | | .SplitError(it => string.IsNullOrWhiteSpace(it.Item.Name), "名称不能为空") |
| | | .SplitError(it => it.Item.Name?.Length > 256, "名称长度不能超过256个字符") |
| | | .SplitError(it => string.IsNullOrWhiteSpace(it.Item.Code), "代码不能为空") |
| | | .SplitError(it => it.Item.Code?.Length > 36, "代码长度不能超过36个字符") |
| | | .SplitInsert(_ => true) |
| | | .ToStorage(); |
| | | |
| | | storageable.AsInsertable.ExecuteCommand();// 不存在插入 |
| | | storageable.AsUpdateable.ExecuteCommand();// 存在更新 |
| | | |
| | | // 标记错误信息 |
| | | markerErrorAction.Invoke(storageable, pageItems, rows); |
| | | }); |
| | | }); |
| | | |
| | | return stream; |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | using cylsg.utility.Extend; |
| | | using Newtonsoft.Json; |
| | | using Newtonsoft.Json.Linq; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.ComponentModel; |
| | | using System.ComponentModel.DataAnnotations; |
| | | using System.Globalization; |
| | | using System.Linq; |
| | | using System.Linq.Expressions; |
| | | using System.Net.Http.Json; |
| | | using System.Reflection; |
| | | using System.Runtime.Loader; |
| | | using System.Security.Cryptography; |
| | | using System.Text; |
| | | using System.Text.Json.Serialization; |
| | | using System.Text.RegularExpressions; |
| | | using System.Threading.Tasks; |
| | | using static cylsg.utility.untilityModels; |
| | | |
| | | namespace cylsg.utility |
| | | { |
| | | /// <summary> |
| | | /// 通用帮助类 |
| | | /// </summary> |
| | | public static class CommonHelper |
| | | { |
| | | |
| | | #region 判断字符串是否为手机号码 |
| | | /// <summary> |
| | | /// 判断字符串是否为手机号码 |
| | | /// </summary> |
| | | /// <param name="mobilePhoneNumber"></param> |
| | | /// <returns></returns> |
| | | public static bool IsMobile(string mobilePhoneNumber) |
| | | { |
| | | if (mobilePhoneNumber.Length < 11) |
| | | { |
| | | return false; |
| | | } |
| | | |
| | | //电信手机号码正则 |
| | | string dianxin = @"^1[345789][01379]\d{8}$"; |
| | | Regex regexDx = new Regex(dianxin); |
| | | //联通手机号码正则 |
| | | string liantong = @"^1[345678][01256]\d{8}$"; |
| | | Regex regexLt = new Regex(liantong); |
| | | //移动手机号码正则 |
| | | string yidong = @"^1[345789][0123456789]\d{8}$"; |
| | | Regex regexYd = new Regex(yidong); |
| | | if (regexDx.IsMatch(mobilePhoneNumber) || regexLt.IsMatch(mobilePhoneNumber) || regexYd.IsMatch(mobilePhoneNumber)) |
| | | { |
| | | return true; |
| | | } |
| | | else |
| | | { |
| | | return false; |
| | | } |
| | | } |
| | | #endregion |
| | | |
| | | #region 检测是否符合email格式 |
| | | |
| | | /// <summary> |
| | | /// 检测是否符合email格式 |
| | | /// </summary> |
| | | /// <param name="strEmail">要判断的email字符串</param> |
| | | /// <returns>判断结果</returns> |
| | | public static bool IsValidEmail(string strEmail) |
| | | { |
| | | return Regex.IsMatch(strEmail, @"^[\w\.]+([-]\w+)*@[A-Za-z0-9-_]+[\.][A-Za-z0-9-_]"); |
| | | } |
| | | |
| | | public static bool IsValidDoEmail(string strEmail) |
| | | { |
| | | return Regex.IsMatch(strEmail, |
| | | @"^@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$"); |
| | | } |
| | | #endregion |
| | | |
| | | #region 检测是否是正确的Url |
| | | /// <summary> |
| | | /// 检测是否是正确的Url |
| | | /// </summary> |
| | | /// <param name="strUrl">要验证的Url</param> |
| | | /// <returns>判断结果</returns> |
| | | public static bool IsUrl(string strUrl) |
| | | { |
| | | return Regex.IsMatch(strUrl, |
| | | @"^(http|https)\://([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&%\$\-]+)*@)*((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|localhost|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{1,10}))(\:[0-9]+)*(/($|[a-zA-Z0-9\.\,\?\'\\\+&%\$#\=~_\-]+))*$"); |
| | | } |
| | | |
| | | |
| | | #endregion |
| | | |
| | | #region string 转int数组 |
| | | |
| | | public static int[] StringToIntArray(string str) |
| | | { |
| | | try |
| | | { |
| | | if (string.IsNullOrEmpty(str)) return new int[0]; |
| | | if (str.EndsWith(",")) |
| | | { |
| | | str = str.Remove(str.Length - 1, 1); |
| | | } |
| | | var idstrarr = str.Split(','); |
| | | var idintarr = new int[idstrarr.Length]; |
| | | |
| | | for (int i = 0; i < idstrarr.Length; i++) |
| | | { |
| | | idintarr[i] = Convert.ToInt32(idstrarr[i]); |
| | | } |
| | | return idintarr; |
| | | } |
| | | catch |
| | | { |
| | | return new int[0]; |
| | | } |
| | | } |
| | | #endregion |
| | | |
| | | #region String转数组 |
| | | public static string[] StringToStringArray(string str) |
| | | { |
| | | try |
| | | { |
| | | if (string.IsNullOrEmpty(str)) return new string[0]; |
| | | if (str.EndsWith(",")) str = str.Remove(str.Length - 1, 1); |
| | | return str.Split(','); |
| | | } |
| | | catch |
| | | { |
| | | return new string[0]; |
| | | } |
| | | } |
| | | #endregion |
| | | |
| | | #region String数组转Int数组 |
| | | public static int[] StringArrAyToIntArray(string[] str) |
| | | { |
| | | try |
| | | { |
| | | int[] iNums = Array.ConvertAll(str, s => int.Parse(s)); |
| | | return iNums; |
| | | } |
| | | catch |
| | | { |
| | | return new int[0]; |
| | | } |
| | | } |
| | | #endregion |
| | | |
| | | #region string转Guid数组 |
| | | |
| | | public static Guid[] StringToGuidArray(string str) |
| | | { |
| | | try |
| | | { |
| | | if (string.IsNullOrEmpty(str)) return new Guid[0]; |
| | | if (str.EndsWith(",")) str = str.Remove(str.Length - 1, 1); |
| | | var strarr = str.Split(','); |
| | | Guid[] guids = new Guid[strarr.Length]; |
| | | for (int index = 0; index < strarr.Length; index++) |
| | | { |
| | | guids[index] = Guid.Parse(strarr[index]); |
| | | } |
| | | return guids; |
| | | } |
| | | catch |
| | | { |
| | | return new Guid[0]; |
| | | } |
| | | } |
| | | #endregion |
| | | |
| | | #region 转MD5 |
| | | /// <summary> |
| | | /// 转MD5 |
| | | /// </summary> |
| | | /// <param name="str"></param> |
| | | /// <returns></returns> |
| | | public static string ToMd5(string str) |
| | | { |
| | | MD5 md5 = MD5.Create(); |
| | | // 将字符串转换成字节数组 |
| | | byte[] byteOld = Encoding.UTF8.GetBytes(str); |
| | | // 调用加密方法 |
| | | byte[] byteNew = md5.ComputeHash(byteOld); |
| | | // 将加密结果转换为字符串 |
| | | StringBuilder sb = new StringBuilder(); |
| | | foreach (byte b in byteNew) |
| | | { |
| | | // 将字节转换成16进制表示的字符串, |
| | | sb.Append(b.ToString("x2")); |
| | | } |
| | | // 返回加密的字符串 |
| | | return sb.ToString(); |
| | | } |
| | | #endregion |
| | | |
| | | #region 获取32位md5加密 |
| | | /// <summary> |
| | | /// 通过创建哈希字符串适用于任何 MD5 哈希函数 (在任何平台) 上创建 32 个字符的十六进制格式哈希字符串 |
| | | /// </summary> |
| | | /// <param name="source"></param> |
| | | /// <returns>32位md5加密字符串</returns> |
| | | public static string Md5For32(string source) |
| | | { |
| | | using (MD5 md5Hash = MD5.Create()) |
| | | { |
| | | byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(source)); |
| | | StringBuilder sBuilder = new StringBuilder(); |
| | | for (int i = 0; i < data.Length; i++) |
| | | { |
| | | sBuilder.Append(data[i].ToString("x2")); |
| | | } |
| | | |
| | | string hash = sBuilder.ToString(); |
| | | return hash.ToUpper(); |
| | | } |
| | | } |
| | | #endregion |
| | | |
| | | #region 获取16位md5加密 |
| | | /// <summary> |
| | | /// 获取16位md5加密 |
| | | /// </summary> |
| | | /// <param name="source"></param> |
| | | /// <returns>16位md5加密字符串</returns> |
| | | public static string Md5For16(string source) |
| | | { |
| | | using (MD5 md5Hash = MD5.Create()) |
| | | { |
| | | byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(source)); |
| | | //转换成字符串,并取9到25位 |
| | | string sBuilder = BitConverter.ToString(data, 4, 8); |
| | | //BitConverter转换出来的字符串会在每个字符中间产生一个分隔符,需要去除掉 |
| | | sBuilder = sBuilder.Replace("-", ""); |
| | | return sBuilder.ToUpper(); |
| | | } |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region 返回当前的毫秒时间戳 |
| | | |
| | | /// <summary> |
| | | /// 返回当前的毫秒时间戳 |
| | | /// </summary> |
| | | public static string Msectime() |
| | | { |
| | | long timeTicks = (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000; |
| | | return timeTicks.ToString(); |
| | | } |
| | | |
| | | |
| | | #endregion |
| | | |
| | | |
| | | |
| | | #region 剩余多久时间文字描述 |
| | | /// <summary> |
| | | /// 剩余多久时间 |
| | | /// </summary> |
| | | /// <param name="remainingTime"></param> |
| | | /// <returns>文字描述</returns> |
| | | public static string GetRemainingTime(DateTime remainingTime) |
| | | { |
| | | TimeSpan timeSpan = remainingTime - DateTime.Now; |
| | | var day = timeSpan.Days; |
| | | var hours = timeSpan.Hours; |
| | | var minute = timeSpan.Minutes; |
| | | var seconds = timeSpan.Seconds; |
| | | if (day > 0) |
| | | { |
| | | return day + "天" + hours + "小时" + minute + "分" + seconds + "秒"; |
| | | } |
| | | else |
| | | { |
| | | if (hours > 0) |
| | | { |
| | | return hours + "小时" + minute + "分" + seconds + "秒"; |
| | | } |
| | | else |
| | | { |
| | | return minute + "分" + seconds + "秒"; |
| | | } |
| | | } |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region 剩余多久时间返回时间类型 |
| | | /// <summary> |
| | | /// 剩余多久时间 |
| | | /// </summary> |
| | | /// <param name="remainingTime"></param> |
| | | /// <returns>返回时间类型</returns> |
| | | public static void GetBackTime(DateTime remainingTime, out int day, out int hours, out int minute, out int seconds) |
| | | { |
| | | TimeSpan timeSpan = remainingTime - DateTime.Now; |
| | | day = timeSpan.Days; |
| | | hours = timeSpan.Hours; |
| | | minute = timeSpan.Minutes; |
| | | seconds = timeSpan.Seconds; |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region 计算时间戳剩余多久时间 |
| | | |
| | | /// <summary> |
| | | /// 计算时间戳剩余多久时间 |
| | | /// </summary> |
| | | /// <param name="postTime">提交时间(要是以前的时间)</param> |
| | | /// <returns></returns> |
| | | public static string TimeAgo(DateTime postTime) |
| | | { |
| | | //当前时间的时间戳 |
| | | var nowtimes = ConvertTicks(DateTime.Now); |
| | | //提交的时间戳 |
| | | var posttimes = ConvertTicks(postTime); |
| | | //相差时间戳 |
| | | var counttime = nowtimes - posttimes; |
| | | |
| | | //进行时间转换 |
| | | if (counttime <= 60) |
| | | { |
| | | return "刚刚"; |
| | | } |
| | | else if (counttime > 60 && counttime <= 120) |
| | | { |
| | | return "1分钟前"; |
| | | } |
| | | else if (counttime > 120 && counttime <= 180) |
| | | { |
| | | return "2分钟前"; |
| | | } |
| | | else if (counttime > 180 && counttime < 3600) |
| | | { |
| | | return Convert.ToInt32(counttime / 60) + "分钟前"; |
| | | } |
| | | else if (counttime >= 3600 && counttime < 3600 * 24) |
| | | { |
| | | return Convert.ToInt32(counttime / 3600) + "小时前"; |
| | | } |
| | | else if (counttime >= 3600 * 24 && counttime < 3600 * 24 * 2) |
| | | { |
| | | return "昨天"; |
| | | } |
| | | else if (counttime >= 3600 * 24 * 2 && counttime < 3600 * 24 * 3) |
| | | { |
| | | return "前天"; |
| | | } |
| | | else if (counttime >= 3600 * 24 * 3 && counttime <= 3600 * 24 * 7) |
| | | { |
| | | return Convert.ToInt32(counttime / (3600 * 24)) + "天前"; |
| | | } |
| | | else if (counttime >= 3600 * 24 * 7 && counttime <= 3600 * 24 * 30) |
| | | { |
| | | return Convert.ToInt32(counttime / (3600 * 24 * 7)) + "周前"; |
| | | } |
| | | else if (counttime >= 3600 * 24 * 30 && counttime <= 3600 * 24 * 365) |
| | | { |
| | | return Convert.ToInt32(counttime / (3600 * 24 * 30)) + "个月前"; |
| | | } |
| | | else if (counttime >= 3600 * 24 * 365) |
| | | { |
| | | return Convert.ToInt32(counttime / (3600 * 24 * 365)) + "年前"; |
| | | } |
| | | else |
| | | { |
| | | return ""; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 时间转换为秒的时间戳 |
| | | /// </summary> |
| | | /// <param name="time"></param> |
| | | /// <returns></returns> |
| | | private static long ConvertTicks(DateTime time) |
| | | { |
| | | long currentTicks = time.Ticks; |
| | | DateTime dtFrom = new DateTime(1970, 1, 1, 0, 0, 0, 0); |
| | | long currentMillis = (currentTicks - dtFrom.Ticks) / 10000000; //转换为秒为Ticks/10000000,转换为毫秒Ticks/10000 |
| | | return currentMillis; |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region 清除HTML中指定样式 |
| | | /// <summary> |
| | | /// 清除HTML中指定样式 |
| | | /// </summary> |
| | | /// <param name="content"></param> |
| | | /// <param name="rule"></param> |
| | | /// <returns></returns> |
| | | public static string ClearHtml(string content, string[] rule) |
| | | { |
| | | if (!rule.Any()) |
| | | { |
| | | return content; |
| | | } |
| | | |
| | | foreach (var item in rule) |
| | | { |
| | | content = Regex.Replace(content, "/" + item + @"\s*=\s*\d+\s*/i", ""); |
| | | content = Regex.Replace(content, "/" + item + @"\s*=\s*.+?[""]/i", ""); |
| | | content = Regex.Replace(content, "/" + item + @"\s*:\s*\d+\s*px\s*;?/i", ""); |
| | | } |
| | | return content; |
| | | } |
| | | #endregion |
| | | |
| | | #region list随机排序方法 |
| | | /// <summary> |
| | | /// list随机排序方法 |
| | | /// </summary> |
| | | /// <typeparam name="T"></typeparam> |
| | | /// <param name="ListT"></param> |
| | | /// <returns></returns> |
| | | public static List<T> RandomSortList<T>(List<T> ListT) |
| | | { |
| | | Random random = new Random(); |
| | | List<T> newList = new List<T>(); |
| | | foreach (T item in ListT) |
| | | { |
| | | newList.Insert(random.Next(newList.Count + 1), item); |
| | | } |
| | | return newList; |
| | | } |
| | | #endregion |
| | | |
| | | |
| | | |
| | | #region 截前后字符(串) |
| | | ///<summary> |
| | | /// 截前后字符(串) |
| | | ///</summary> |
| | | ///<param name="val">原字符串</param> |
| | | ///<param name="str">要截掉的字符串</param> |
| | | ///<param name="all">是否贪婪</param> |
| | | ///<returns></returns> |
| | | public static string GetCaptureInterceptedText(string val, string str, bool all = false) |
| | | { |
| | | return Regex.Replace(val, @"(^(" + str + ")" + (all ? "*" : "") + "|(" + str + ")" + (all ? "*" : "") + "$)", ""); |
| | | } |
| | | #endregion |
| | | |
| | | #region 密码加密方法 |
| | | /// <summary> |
| | | /// 密码加密方法 |
| | | /// </summary> |
| | | /// <param name="password">要加密的字符串</param> |
| | | /// <param name="createTime">时间组合</param> |
| | | /// <returns></returns> |
| | | public static string EnPassword(string password, DateTime createTime) |
| | | { |
| | | var dtStr = createTime.ToString("yyyyMMddHHmmss"); |
| | | var md5 = Md5For32(password); |
| | | var enPwd = Md5For32(md5 + dtStr); |
| | | return enPwd; |
| | | } |
| | | #endregion |
| | | |
| | | #region 获取现在是星期几 |
| | | /// <summary> |
| | | /// 获取现在是星期几 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | public static string GetWeek() |
| | | { |
| | | string week = string.Empty; |
| | | switch (DateTime.Now.DayOfWeek) |
| | | { |
| | | case DayOfWeek.Monday: |
| | | week = "周一"; |
| | | break; |
| | | case DayOfWeek.Tuesday: |
| | | week = "周二"; |
| | | break; |
| | | case DayOfWeek.Wednesday: |
| | | week = "周三"; |
| | | break; |
| | | case DayOfWeek.Thursday: |
| | | week = "周四"; |
| | | break; |
| | | case DayOfWeek.Friday: |
| | | week = "周五"; |
| | | break; |
| | | case DayOfWeek.Saturday: |
| | | week = "周六"; |
| | | break; |
| | | case DayOfWeek.Sunday: |
| | | week = "周日"; |
| | | break; |
| | | default: |
| | | week = "N/A"; |
| | | break; |
| | | } |
| | | return week; |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region UrlEncode (URL编码) |
| | | /// <summary> |
| | | /// UrlEncode (URL编码) |
| | | /// </summary> |
| | | /// <param name="str"></param> |
| | | /// <returns></returns> |
| | | public static string UrlEncode(string str) |
| | | { |
| | | StringBuilder sb = new StringBuilder(); |
| | | byte[] byStr = Encoding.UTF8.GetBytes(str); //默认是System.Text.Encoding.Default.GetBytes(str) |
| | | for (int i = 0; i < byStr.Length; i++) |
| | | { |
| | | sb.Append(@"%" + Convert.ToString(byStr[i], 16)); |
| | | } |
| | | |
| | | return sb.ToString(); |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region 获取10位时间戳 |
| | | /// <summary> |
| | | /// 获取10位时间戳 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | public static long GetTimeStampByTotalSeconds() |
| | | { |
| | | TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0); |
| | | return Convert.ToInt64(ts.TotalSeconds); |
| | | } |
| | | #endregion |
| | | |
| | | #region 获取13位时间戳 |
| | | /// <summary> |
| | | /// 获取13位时间戳 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | public static long GetTimeStampByTotalMilliseconds() |
| | | { |
| | | TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); |
| | | return Convert.ToInt64(ts.TotalMilliseconds); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取时间戳 |
| | | /// </summary> |
| | | /// <param name="dt"></param> |
| | | /// <returns></returns> |
| | | public static int GetDateTimeStamp(DateTime dt) |
| | | { |
| | | DateTime dateStart = new DateTime(1970, 1, 1, 0, 0, 0); |
| | | int timeStamp = Convert.ToInt32((dt.ToUniversalTime() - dateStart).TotalSeconds); |
| | | return timeStamp; |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region 获取随机字符串 |
| | | /// <summary> |
| | | /// 获取随机字符串 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | public static string GetSerialNumber() |
| | | { |
| | | var str = string.Empty; |
| | | Random rand = new Random(); |
| | | var charsStr2 = new[] { 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'P', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' }; |
| | | var charsLen2 = charsStr2.Length - 1; |
| | | // shuffle($chars); |
| | | str = ""; |
| | | for (int i = 0; i < 16; i++) |
| | | { |
| | | str += charsStr2[rand.Next(0, charsLen2)]; |
| | | } |
| | | return str; |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region Sha1签名 |
| | | /// <summary> |
| | | /// Sha1签名 |
| | | /// </summary> |
| | | /// <param name="str">内容</param> |
| | | /// <param name="encoding">编码</param> |
| | | /// <returns></returns> |
| | | public static string Sha1Signature(string str, Encoding encoding = null) |
| | | { |
| | | if (encoding == null) encoding = Encoding.UTF8; |
| | | var buffer = encoding.GetBytes(str); |
| | | var data = SHA1.Create().ComputeHash(buffer); |
| | | StringBuilder sub = new StringBuilder(); |
| | | foreach (var t in data) |
| | | { |
| | | sub.Append(t.ToString("x2")); |
| | | } |
| | | |
| | | return sub.ToString(); |
| | | } |
| | | #endregion |
| | | |
| | | /// <summary> |
| | | /// 精确计算base64字符串文件大小(单位:B) |
| | | /// param base64String |
| | | /// return double 字节大小 |
| | | /// </summary> |
| | | /// <param name="base64String"></param> |
| | | /// <returns></returns> |
| | | public static double Base64FileSize(string base64String) |
| | | { |
| | | //检测是否含有base64,文件头) |
| | | if (base64String.LastIndexOf(",", StringComparison.Ordinal) > -1) |
| | | { |
| | | base64String = base64String[(base64String.LastIndexOf(",", StringComparison.Ordinal) + 1)..]; |
| | | } |
| | | //获取base64字符串长度(不含data:audio/wav;base64,文件头) |
| | | var size0 = base64String.Length; |
| | | if (size0 <= 10) return size0 - (double)size0 / 8 * 2; |
| | | //获取字符串的尾巴的最后10个字符,用于判断尾巴是否有等号,正常生成的base64文件'等号'不会超过4个 |
| | | var tail = base64String[(size0 - 10)..]; |
| | | //找到等号,把等号也去掉,(等号其实是空的意思,不能算在文件大小里面) |
| | | int equalIndex = tail.IndexOf("=", StringComparison.Ordinal); |
| | | if (equalIndex > 0) |
| | | { |
| | | size0 = size0 - (10 - equalIndex); |
| | | } |
| | | //计算后得到的文件流大小,单位为字节 |
| | | return size0 - (double)size0 / 8 * 2; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 判断文件大小 |
| | | /// </summary> |
| | | /// <param name="base64"></param> |
| | | /// <param name="size"></param> |
| | | /// <param name="unit"></param> |
| | | /// <returns></returns> |
| | | public static bool CheckBase64Size(string base64, int size, string unit = "M") |
| | | { |
| | | // 上传文件的大小, 单位为字节. |
| | | var len = Base64FileSize(base64); |
| | | // 准备接收换算后文件大小的容器 |
| | | double fileSize = unit.ToUpperInvariant() switch |
| | | { |
| | | "B" => len, |
| | | "K" => (double)len / 1024, |
| | | "M" => (double)len / 1048576, |
| | | "G" => (double)len / 1073741824, |
| | | _ => 0 |
| | | }; |
| | | // 如果上传文件大于限定的容量 |
| | | return !(fileSize > size); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 10位时间戳 转化 |
| | | /// </summary> |
| | | /// <param name="time"></param> |
| | | /// <returns></returns> |
| | | public static long ConvertDateTimeToInt(DateTime time) |
| | | { |
| | | DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1, 0, 0, 0, 0)); |
| | | long t = (time.Ticks - startTime.Ticks) / 10000000; //除10000000调整为10位 |
| | | return t; |
| | | } |
| | | |
| | | #region 反射相关 |
| | | private static List<Assembly>? _allAssemblies = null; |
| | | /// <summary> |
| | | /// 获取所有程序目录下和常用的程序集 包括一些系统引用程序集 |
| | | /// </summary> |
| | | /// <returns> 当前工程下的程序集</returns> |
| | | public static List<Assembly> GetAllAssembly() |
| | | { |
| | | |
| | | |
| | | if (_allAssemblies == null) |
| | | { |
| | | _allAssemblies = new List<Assembly>(); |
| | | string? path = null; |
| | | string singlefile = null; |
| | | try |
| | | { |
| | | path = Assembly.GetEntryAssembly()?.Location; |
| | | } |
| | | catch { } |
| | | if (string.IsNullOrEmpty(path)) |
| | | { |
| | | singlefile = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName; |
| | | path = Path.GetDirectoryName(singlefile); |
| | | } |
| | | if (string.IsNullOrEmpty(path)) |
| | | |
| | | throw new Exception("获取程序目录出错"); |
| | | var dir = new DirectoryInfo(Path.GetDirectoryName(path) ?? ""); |
| | | |
| | | var dlls = dir.GetFiles("*.dll", SearchOption.TopDirectoryOnly); |
| | | string[] systemdll = new string[] |
| | | { |
| | | "Microsoft.", |
| | | "System.", |
| | | "Swashbuckle.", |
| | | "ICSharpCode", |
| | | "Newtonsoft.", |
| | | "Oracle.", |
| | | "Pomelo.", |
| | | "SQLitePCLRaw.", |
| | | "Aliyun.OSS", |
| | | "BouncyCastle.", |
| | | "FreeSql.", |
| | | "Google.Protobuf.dll", |
| | | "Humanizer.dll", |
| | | "IdleBus.dll", |
| | | "K4os.", |
| | | "MySql.Data.", |
| | | "Npgsql.", |
| | | "NPOI.", |
| | | "netstandard", |
| | | "MySqlConnector", |
| | | "VueCliMiddleware" |
| | | }; |
| | | |
| | | var filtered = dlls.Where(x => systemdll.Any(y => x.Name.StartsWith(y)) == false); |
| | | foreach (var dll in filtered) |
| | | { |
| | | try |
| | | { |
| | | AssemblyLoadContext.Default.LoadFromAssemblyPath(dll.FullName); |
| | | } |
| | | catch |
| | | { |
| | | } |
| | | } |
| | | var dlllist = AssemblyLoadContext.Default.Assemblies.Where(x => systemdll.Any(y => x.FullName.StartsWith(y)) == false).ToList(); |
| | | _allAssemblies.AddRange(dlllist); |
| | | } |
| | | return _allAssemblies; |
| | | } |
| | | #endregion |
| | | |
| | | #region 枚举获取所有项 |
| | | /// <summary> |
| | | /// 获取枚举的所有项 |
| | | /// </summary> |
| | | /// <typeparam name="T"></typeparam> |
| | | /// <returns></returns> |
| | | public static List<MenmItem> GetEnumItemsWithAttributes<T>() where T : Enum |
| | | { |
| | | var result = new List<MenmItem>(); |
| | | |
| | | foreach (var value in Enum.GetValues(typeof(T))) |
| | | { |
| | | var member = typeof(T).GetMember(value.ToString())[0]; |
| | | var descriptionAttribute = member.GetCustomAttribute<DescriptionAttribute>(); |
| | | |
| | | var item = new MenmItem |
| | | { |
| | | Key = value.ToString(), |
| | | Value = (int)value, // 或者直接使用 value.ToString() 如果不需要转换为整数字符串 |
| | | Description = descriptionAttribute?.Description ?? string.Empty |
| | | }; |
| | | |
| | | result.Add(item); |
| | | } |
| | | |
| | | return result; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取枚举所有的项,返回名称 值 和Description 描述 |
| | | /// </summary> |
| | | /// <param name="enumType"></param> |
| | | /// <returns></returns> |
| | | /// <exception cref="ArgumentException"></exception> |
| | | public static List<MenmItem> EnumerateWithDescriptions(Type enumType) |
| | | { |
| | | if (!enumType.IsEnum) |
| | | { |
| | | throw new ArgumentException(" 这不是枚举"); |
| | | } |
| | | |
| | | var result = new List<MenmItem>(); |
| | | |
| | | foreach (var value in Enum.GetValues(enumType)) |
| | | { |
| | | var member = enumType.GetMember(value.ToString())[0]; |
| | | var descriptionAttribute = member.GetCustomAttribute<DescriptionAttribute>(); |
| | | |
| | | var item = new MenmItem |
| | | { |
| | | Key = value.ToString(), |
| | | Value = (int)value, // 或者直接使用 value.ToString() 如果不需要转换为整数字符串 |
| | | Description = descriptionAttribute?.Description ?? string.Empty |
| | | }; |
| | | |
| | | result.Add(item); |
| | | } |
| | | |
| | | return result; |
| | | } |
| | | /// <summary> |
| | | /// 是否是系统类型 |
| | | /// </summary> |
| | | /// <param name="type"></param> |
| | | /// <returns></returns> |
| | | public static bool IsCustomType(Type type) |
| | | { |
| | | // 定义一个或多个基础命名空间列表,这些命名空间下的类型通常认为是系统类型 |
| | | string[] frameworkNamespaces = { "System", "Microsoft", "mscorlib", "netstandard", "System.Private.CoreLib" }; |
| | | |
| | | // 获取类型所在的命名空间 |
| | | string typeNameSpace = type.Namespace; |
| | | |
| | | // 检查该命名空间是否在基础命名空间列表中,如果不在,则认为是自定义类型 |
| | | return frameworkNamespaces.Any(n => typeNameSpace.StartsWith(n, StringComparison.OrdinalIgnoreCase)); |
| | | } |
| | | |
| | | |
| | | #endregion |
| | | |
| | | /// <summary> |
| | | /// 根据json字符穿处理 |
| | | /// </summary> |
| | | /// <typeparam name="T"></typeparam> |
| | | /// <param name="jsonString"></param> |
| | | /// <param name="parameter"></param> |
| | | /// <returns></returns> |
| | | private static Expression<Func<T, bool>> CreateWhereExpressionRecursive<T>(string jsonString, ParameterExpression parameter) |
| | | { |
| | | var conditions = new List<Expression>(); |
| | | |
| | | JObject jsonObject = JObject.Parse(jsonString); |
| | | |
| | | foreach (var property in jsonObject.Properties()) |
| | | { |
| | | var propertyName = property.Name; |
| | | var propertyValue = property.Value.ToString(); |
| | | if (propertyValue == "") //空值不处理 |
| | | continue; |
| | | var propertyInfo = typeof(T).GetProperty(propertyName); |
| | | |
| | | if (propertyInfo == null) |
| | | { |
| | | propertyInfo = typeof(T).GetProperty(propertyName.FirstToCapitalize()); |
| | | if (propertyInfo == null) |
| | | continue; // 如果属性不存在,跳过 |
| | | } |
| | | |
| | | var propertyType = propertyInfo.PropertyType; |
| | | var TypeName = propertyType.GenericTypeArguments.Length > 0 ? propertyType.GenericTypeArguments[0].Name + "?" : propertyType.Name; |
| | | if (propertyType.IsClass && TypeName != "String") |
| | | { |
| | | // 递归处理嵌套模型 |
| | | var nestedParameter = Expression.Parameter(propertyType, propertyName); |
| | | var nestedJsonString = property.Value.ToString(); |
| | | |
| | | // 使用 MakeGenericType 动态创建泛型方法 |
| | | var genericMethod = typeof(CommonHelper).GetMethod("CreateWhereExpressionRecursive", BindingFlags.Static | BindingFlags.NonPublic) |
| | | .MakeGenericMethod(propertyType); |
| | | |
| | | // 调用泛型方法并获取返回的表达式 |
| | | var nestedConditions = (Expression<Func<object, bool>>)genericMethod.Invoke(null, new object[] { nestedJsonString, nestedParameter }); |
| | | |
| | | var propExpr = Expression.Property(parameter, propertyName); |
| | | var lambda = Expression.Lambda(nestedConditions.Body, nestedParameter); |
| | | var invoke = Expression.Invoke(lambda, propExpr); |
| | | conditions.Add(invoke); |
| | | } |
| | | else if (propertyType == typeof(string)) |
| | | { |
| | | var propExpr = Expression.Property(parameter, propertyName); |
| | | var constant = Expression.Constant(propertyValue); |
| | | |
| | | var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) }); |
| | | var containsExpression = Expression.Call(propExpr, containsMethod, constant); |
| | | conditions.Add(containsExpression); |
| | | } |
| | | else if (TypeName.Contains( "DateTime")) //兼容DateTime? |
| | | { |
| | | var dateRange = propertyValue.Split('~'); |
| | | if (dateRange.Length == 2) |
| | | { |
| | | var startDate = DateTime.Parse(dateRange[0]); |
| | | var endDate = DateTime.Parse(dateRange[1]); |
| | | |
| | | var propExpr = Expression.Property(parameter, propertyName); |
| | | var startConstant = Expression.Constant(startDate); |
| | | var endConstant = Expression.Constant(endDate); |
| | | if (TypeName == "DateTime?") |
| | | // 将常量表达式转换为 Nullable<DateTime> |
| | | { |
| | | var startNullableConstant = Expression.Convert(startConstant, typeof(DateTime?)); |
| | | var endNullableConstant = Expression.Convert(endConstant, typeof(DateTime?)); |
| | | |
| | | |
| | | var greaterThanOrEqual = Expression.GreaterThanOrEqual(propExpr, startNullableConstant); |
| | | var lessThanOrEqual = Expression.LessThanOrEqual(propExpr, endNullableConstant); |
| | | |
| | | |
| | | var andExpression = Expression.AndAlso(greaterThanOrEqual, lessThanOrEqual); |
| | | conditions.Add(andExpression); |
| | | } |
| | | else |
| | | { |
| | | |
| | | var greaterThanOrEqual = Expression.GreaterThanOrEqual(propExpr, startConstant); |
| | | var lessThanOrEqual = Expression.LessThanOrEqual(propExpr, endConstant); |
| | | |
| | | |
| | | var andExpression = Expression.AndAlso(greaterThanOrEqual, lessThanOrEqual); |
| | | conditions.Add(andExpression); |
| | | |
| | | } |
| | | } |
| | | else if (DateTime.TryParse(propertyValue, out var dateTime)) |
| | | { |
| | | var propExpr = Expression.Property(parameter, propertyName); |
| | | var constant = Expression.Constant(dateTime); |
| | | var equalExpression = Expression.Equal(propExpr, constant); |
| | | conditions.Add(equalExpression); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | var propExpr = Expression.Property(parameter, propertyName); |
| | | var constant = Expression.Constant(Convert.ChangeType(propertyValue, propertyType)); |
| | | var equalExpression = Expression.Equal(propExpr, constant); |
| | | conditions.Add(equalExpression); |
| | | } |
| | | } |
| | | |
| | | var body = conditions.Count > 1 ? conditions.Aggregate(Expression.AndAlso) : conditions.FirstOrDefault(); |
| | | return Expression.Lambda<Func<T, bool>>(body ?? Expression.Constant(true), parameter); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// json格式化为表达式树 |
| | | /// </summary> |
| | | /// <typeparam name="T"></typeparam> |
| | | /// <param name="jsonString"></param> |
| | | /// <returns></returns> |
| | | public static Expression<Func<T, bool>> FormatWhereExpression<T>(string jsonString) |
| | | { |
| | | var parameter = Expression.Parameter(typeof(T), "x"); |
| | | return CreateWhereExpressionRecursive<T>(jsonString, parameter); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 更具属性名称生成表达式树,如x.id |
| | | /// </summary> |
| | | /// <typeparam name="T"></typeparam> |
| | | /// <param name="propertyName"></param> |
| | | /// <returns></returns> |
| | | public static Expression<Func<T, object>> FormatPropertyExpression<T>(string propertyName) |
| | | { |
| | | // 获取参数表达式 |
| | | var parameter = Expression.Parameter(typeof(T), "x"); |
| | | |
| | | // 获取属性表达式 |
| | | var propertyAccess = Expression.PropertyOrField(parameter, propertyName); |
| | | if (propertyAccess == null) |
| | | { |
| | | ///首字母转大写 |
| | | propertyAccess = Expression.PropertyOrField(parameter, propertyName.FirstToCapitalize()); |
| | | } |
| | | |
| | | |
| | | // 创建 Lambda 表达式,并在返回值中进行类型转换 |
| | | return Expression.Lambda<Func<T, object>>( |
| | | Expression.Convert(propertyAccess, typeof(object)), |
| | | parameter); |
| | | } |
| | | |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | /// <summary> |
| | | /// 枚举项属性 |
| | | /// </summary> |
| | | [Description("枚举项属性")] |
| | | public class MenmItem |
| | | { |
| | | /// <summary> |
| | | /// 枚举key |
| | | /// </summary> |
| | | [Description("枚举key")] |
| | | public string? Key { get; set; } |
| | | /// <summary> |
| | | /// 枚举值 |
| | | /// </summary> |
| | | [Description("枚举值")] |
| | | public int Value { get; set; } |
| | | /// <summary> |
| | | /// 枚举描述 |
| | | /// </summary> |
| | | [Description("枚举项属性")] |
| | | public string? Description { get; set; } |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | } |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | |
| | | namespace cylsg.utility.Extend |
| | | { |
| | | /// <summary> |
| | | /// 枚举扩展 |
| | | /// </summary> |
| | | public static class EmunEx |
| | | { |
| | | } |
| | | } |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Globalization; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Text.RegularExpressions; |
| | | using System.Threading.Tasks; |
| | | |
| | | namespace cylsg.utility.Extend |
| | | { |
| | | /// <summary> |
| | | /// 字符串扩展 |
| | | /// </summary> |
| | | public static class StringEx |
| | | { |
| | | /// <summary> |
| | | /// 首字母小写 |
| | | /// </summary> |
| | | /// <param name="self"></param> |
| | | /// <returns></returns> |
| | | public static string FirstToLower(this string self) |
| | | { |
| | | string str1 = self?.Substring(0, 1).ToLower() ?? ""; |
| | | string str2 = self?.Substring(1) ?? ""; |
| | | |
| | | //首字母转小写 |
| | | return str1 + str2; |
| | | } |
| | | /// <summary> |
| | | /// 带有xxx.xxx结束的的所有字符串 的后面xxx.xxx |
| | | /// </summary> |
| | | /// <param name="strtypr"></param> |
| | | /// <returns></returns> |
| | | public static string GetFileName(this string strtypr) |
| | | { |
| | | return Path.GetFileName(strtypr); |
| | | } |
| | | /// <summary> |
| | | /// 是否是数字序列 |
| | | /// </summary> |
| | | /// <param name="str"></param> |
| | | /// <returns></returns> |
| | | public static bool isPureNum(this string strtypr) |
| | | { |
| | | if (strtypr.Length == 0 || strtypr == null)//验证这个字符串是否为空 |
| | | { |
| | | return false; |
| | | } |
| | | byte[] strBytes = Encoding.ASCII.GetBytes(strtypr);//获取字符串的byte类型的字符数组,编码方式ASCII |
| | | foreach (byte strByte in strBytes) |
| | | { |
| | | if (strByte < 48 || strByte > 57) //判断每个字符是否为数字,根据每个字符的ASCII值所在范围判断 |
| | | { |
| | | return false; //不是,就返回false |
| | | } |
| | | } |
| | | return true; //是,就返回true |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 是否是数字序列 |
| | | /// </summary> |
| | | /// <param name="str"></param> |
| | | /// <returns></returns> |
| | | public static bool isGuid(this string strtypr) |
| | | { |
| | | if (strtypr.Length < 20 || strtypr == null)//验证这个字符串是否为空 |
| | | { |
| | | return false; |
| | | } |
| | | try |
| | | { |
| | | new Guid(strtypr); |
| | | return true; |
| | | |
| | | } |
| | | catch (Exception) |
| | | { |
| | | |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 字符串 |
| | | /// </summary> |
| | | /// <param name="strtypr"></param> |
| | | /// <returns></returns> |
| | | /// <exception cref="Exception"></exception> |
| | | public static int toInt(this string strtypr) |
| | | { |
| | | if (!strtypr.isPureNum()) |
| | | throw new Exception("并非完整的数字序列"); |
| | | return int.Parse(strtypr); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 移除第一个字符串为指定字符串的 如 “axtXXXXX" 如果以"axt"开头的字符串,就移除"axt" 没有则不变 |
| | | /// </summary> |
| | | /// <param name="strtypr"></param> |
| | | /// <param name="str">开始字符</param> |
| | | /// <returns></returns> |
| | | public static string RemoveStartWithStr(this string strtypr, string str) |
| | | { |
| | | string strret = strtypr; |
| | | if (strtypr.StartsWith(str)) |
| | | { |
| | | strret = strtypr.Remove(0, str.Length); |
| | | } |
| | | return strret; |
| | | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 对字符串进行隐私处理,比如中间的用*显示 |
| | | /// </summary> |
| | | /// <param name="strtypr"></param> |
| | | /// <returns></returns> |
| | | public static string PrivacyStr(this string strtypr) |
| | | { |
| | | // 如果是手机号码,仅保留前3位和后4位,中间用星号替换 |
| | | if (Regex.IsMatch(strtypr, @"^1[3-9]\d{9}$")) |
| | | { |
| | | return $"{strtypr.Substring(0, 3)}****{strtypr.Substring(7)}"; |
| | | } |
| | | |
| | | // 对于中文名字或者非手机号格式,仅保留首尾各1个字符,中间用星号替换 |
| | | else |
| | | { |
| | | if (strtypr.Length <= 2) return $"{strtypr.Substring(0, 1)}*"; // 长度小于等于2时,返回固定的星号 |
| | | |
| | | var masked = $"{strtypr.Substring(0, 1)}*{strtypr.Substring(strtypr.Length - 1, 1)}"; |
| | | return masked; |
| | | } |
| | | } |
| | | |
| | | |
| | | #region 时间区间字符串转其实和结束时间 |
| | | /// <summary> |
| | | /// 解析时间区间字符串 |
| | | /// </summary> |
| | | /// <param name="input"></param> |
| | | /// <returns></returns> |
| | | public static (DateTime? StartDate, DateTime? EndDate) TryParseDateRangString(this string input) |
| | | { |
| | | DateTime startDate, endDate; |
| | | var culture = CultureInfo.InvariantCulture; |
| | | |
| | | // 尝试解析第一种格式 "2023-01-012023-01-31" |
| | | if (DateTime.TryParseExact(input.Substring(0, 10), "yyyy-MM-dd", culture, DateTimeStyles.None, out startDate) && |
| | | DateTime.TryParseExact(input.Substring(10), "yyyy-MM-dd", culture, DateTimeStyles.None, out endDate)) |
| | | { |
| | | return (startDate, endDate); |
| | | } |
| | | |
| | | // 尝试解析第二种格式 "2023-01-01 08:02:032023-01-31 08:02:03" |
| | | if (DateTime.TryParseExact(input.Substring(0, 19), "yyyy-MM-dd HH:mm:ss", culture, DateTimeStyles.None, out startDate) && |
| | | DateTime.TryParseExact(input.Substring(19), "yyyy-MM-dd HH:mm:ss", culture, DateTimeStyles.None, out endDate)) |
| | | { |
| | | return (startDate, endDate); |
| | | } |
| | | |
| | | // 尝试解析第二种格式 "2023-01-01T08:02:032023-01-31T08:02:03" |
| | | if (DateTime.TryParseExact(input.Substring(0, 19), "yyyy-MM-ddTHH:mm:ss", culture, DateTimeStyles.None, out startDate) && |
| | | DateTime.TryParseExact(input.Substring(19), "yyyy-MM-ddTHH:mm:ss", culture, DateTimeStyles.None, out endDate)) |
| | | { |
| | | return (startDate, endDate); |
| | | } |
| | | // 如果都不是,返回null |
| | | return (null, null); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 移除最后一个字符的?号 |
| | | /// </summary> |
| | | /// <param name="input"> </param> |
| | | /// /// <param name="inChar">字符</param> |
| | | /// <returns></returns> |
| | | public static string RemoveCharIfPresent(this string input, char inChar) |
| | | { |
| | | if (string.IsNullOrEmpty(input)) return input; |
| | | |
| | | // 检查字符串的最后一个字符是否为问号 |
| | | if (input[^1] == '?') |
| | | { |
| | | // 使用切片操作符创建不包含问号的新字符串 |
| | | return input[..^1]; |
| | | } |
| | | else |
| | | { |
| | | // 字符串不以问号结尾,返回原字符串 |
| | | return input; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 移除最后的字符串 |
| | | /// </summary> |
| | | /// <param name="input"></param> |
| | | /// <param name="endString"></param> |
| | | /// <returns></returns> |
| | | public static string RemoveEndStringIfExists(this string input, string endString) |
| | | { |
| | | if (string.IsNullOrEmpty(input) || string.IsNullOrEmpty(endString)) |
| | | { |
| | | return input; // 如果输入字符串或结束字符串为空或null,直接返回原字符串 |
| | | } |
| | | |
| | | if (input.EndsWith(endString)) |
| | | { |
| | | return input.Substring(0, input.Length - endString.Length); // 移除结束字符串 |
| | | } |
| | | |
| | | return input; // 如果不以指定字符串结束,返回原字符串 |
| | | } |
| | | |
| | | |
| | | /// <summary> |
| | | /// 首字母转小写 |
| | | /// </summary> |
| | | /// <param name="input"></param> |
| | | /// <returns></returns> |
| | | public static string FirstCharToLower(this string input) |
| | | { |
| | | if (string.IsNullOrEmpty(input)) |
| | | { |
| | | return input; |
| | | } |
| | | |
| | | // 使用正则表达式 |
| | | return Regex.Replace(input, @"^\p{Lu}", match => match.Value.ToLower()); |
| | | } |
| | | #endregion |
| | | |
| | | /// <summary> |
| | | /// 首字母转大写 |
| | | /// </summary> |
| | | /// <param name="input"></param> |
| | | /// <returns></returns> |
| | | public static string FirstToCapitalize(this string input) |
| | | { |
| | | if (string.IsNullOrEmpty(input)) |
| | | { |
| | | return input; |
| | | } |
| | | |
| | | TextInfo textInfo = new CultureInfo("en-US", false).TextInfo; |
| | | return textInfo.ToTitleCase(input.ToLower()).Substring(0, 1) + input.Substring(1); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | using System; |
| | | using System.Collections; |
| | | using System.Collections.Generic; |
| | | using System.Collections.Immutable; |
| | | using System.ComponentModel.DataAnnotations; |
| | | using System.ComponentModel; |
| | | using System.Linq; |
| | | using System.Linq.Expressions; |
| | | using System.Reflection; |
| | | using System.Text; |
| | | using System.Text.RegularExpressions; |
| | | using System.Threading.Tasks; |
| | | using cylsg.utility.Extend; |
| | | using Microsoft.Extensions.Primitives; |
| | | |
| | | namespace cylsg.utility.Extend |
| | | { |
| | | /// <summary> |
| | | /// 反射扩展函数 |
| | | /// </summary> |
| | | public static class TypeAndExpressionEx |
| | | { |
| | | #region 属性扩展 反射 |
| | | public static Func<object, object> GetPropertyExpression(Type objtype, string property) |
| | | { |
| | | property = Regex.Replace(property, @"\[[^\]]*\]", string.Empty); |
| | | List<string> level = new List<string>(); |
| | | if (property.Contains('.')) |
| | | { |
| | | level.AddRange(property.Split('.')); |
| | | } |
| | | else |
| | | { |
| | | level.Add(property); |
| | | } |
| | | |
| | | var pe = Expression.Parameter(objtype); |
| | | #pragma warning disable 8604 |
| | | var member = Expression.Property(pe, objtype.GetSingleProperty(level[0])); |
| | | for (int i = 1; i < level.Count; i++) |
| | | { |
| | | member = Expression.Property(member, member.Type.GetSingleProperty(level[i])); |
| | | } |
| | | return Expression.Lambda<Func<object, object>>(member, pe).Compile(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取属性名 |
| | | /// </summary> |
| | | /// <param name="expression">属性表达式</param> |
| | | /// <param name="getAll">是否获取全部级别名称,比如a.b.c</param> |
| | | /// <returns>属性名</returns> |
| | | public static string GetPropertyName(this Expression expression, bool getAll = true) |
| | | { |
| | | if (expression == null) |
| | | { |
| | | return ""; |
| | | } |
| | | MemberExpression me = null; |
| | | LambdaExpression le = null; |
| | | if (expression is MemberExpression) |
| | | { |
| | | me = expression as MemberExpression; |
| | | } |
| | | if (expression is LambdaExpression) |
| | | { |
| | | le = expression as LambdaExpression; |
| | | if (le.Body is MemberExpression) |
| | | { |
| | | me = le.Body as MemberExpression; |
| | | } |
| | | if (le.Body is UnaryExpression) |
| | | { |
| | | me = (le.Body as UnaryExpression).Operand as MemberExpression; |
| | | } |
| | | } |
| | | string rv = ""; |
| | | if (me != null) |
| | | { |
| | | rv = me.Member.Name; |
| | | } |
| | | while (me != null && getAll && me.NodeType == ExpressionType.MemberAccess) |
| | | { |
| | | Expression exp = me.Expression; |
| | | if (exp is MemberExpression) |
| | | { |
| | | rv = (exp as MemberExpression).Member.Name + "." + rv; |
| | | me = exp as MemberExpression; |
| | | } |
| | | else if (exp is MethodCallExpression) |
| | | { |
| | | var mexp = exp as MethodCallExpression; |
| | | if (mexp.Method.Name == "get_Item") |
| | | { |
| | | object index = 0; |
| | | if (mexp.Arguments[0] is MemberExpression) |
| | | { |
| | | var obj = ((mexp.Arguments[0] as MemberExpression).Expression as ConstantExpression).Value; |
| | | index = obj.GetType().GetField((mexp.Arguments[0] as MemberExpression).Member.Name).GetValue(obj); |
| | | } |
| | | else |
| | | { |
| | | index = (mexp.Arguments[0] as ConstantExpression).Value; |
| | | } |
| | | rv = (mexp.Object as MemberExpression).Member.Name + "[" + index + "]." + rv; |
| | | me = mexp.Object as MemberExpression; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | break; |
| | | } |
| | | } |
| | | return rv; |
| | | } |
| | | |
| | | public static Expression GetMemberExp(this ParameterExpression self, Expression member) |
| | | { |
| | | return self.GetMemberExp(member.GetPropertyName()); |
| | | } |
| | | |
| | | public static Expression GetMemberExp(this ParameterExpression self, string memberName) |
| | | { |
| | | var names = memberName.Split(','); |
| | | Expression rv = Expression.PropertyOrField(self, names[0]); ; |
| | | for (int i = 1; i < names.Length; i++) |
| | | { |
| | | rv = Expression.PropertyOrField(rv, names[i]); |
| | | } |
| | | return rv; |
| | | } |
| | | |
| | | |
| | | |
| | | /// <summary> |
| | | /// 获取正则表达式错误 |
| | | /// </summary> |
| | | /// <param name="pi">属性信息</param> |
| | | /// <returns>错误文本</returns> |
| | | public static string GetRegexErrorMessage(this MemberInfo pi) |
| | | { |
| | | string rv = ""; |
| | | |
| | | if (pi.GetCustomAttributes(typeof(RegularExpressionAttribute), false).FirstOrDefault() is RegularExpressionAttribute dis && !string.IsNullOrEmpty(dis.ErrorMessage)) |
| | | { |
| | | rv = dis.ErrorMessage; |
| | | //if (CoreProgram._localizer != null) |
| | | //{ |
| | | // rv = CoreProgram._localizer[rv]; |
| | | //} |
| | | } |
| | | else |
| | | { |
| | | rv = ""; |
| | | } |
| | | return rv; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取属性显示名称 |
| | | /// </summary> |
| | | /// <param name="pi">属性信息</param> |
| | | /// <returns>属性名称</returns> |
| | | public static string GetPropertyDisplayName(this MemberInfo pi) |
| | | { |
| | | string rv = ""; |
| | | if (pi.GetCustomAttributes(typeof(DisplayAttribute), false).FirstOrDefault() is DisplayAttribute dis && !string.IsNullOrEmpty(dis.Name)) |
| | | { |
| | | rv = dis.Name; |
| | | |
| | | } |
| | | else |
| | | { |
| | | rv = pi.Name; |
| | | } |
| | | return rv; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取属性显示名称 |
| | | /// </summary> |
| | | /// <param name="expression">属性表达式</param> |
| | | /// <returns>属性显示名称</returns> |
| | | public static string GetPropertyDisplayName(this Expression expression) |
| | | { |
| | | return expression.GetPropertyInfo().GetPropertyDisplayName(); |
| | | } |
| | | /// <summary> |
| | | /// 获取属性的 Description 标注名,如果没有,则返回 属性名称 |
| | | /// </summary> |
| | | /// <param name="pi"></param> |
| | | /// <returns></returns> |
| | | public static string GetPropertyDescription(this MemberInfo pi) |
| | | { |
| | | string rv = ""; |
| | | if (pi.GetCustomAttributes(typeof(DescriptionAttribute), false).FirstOrDefault() is DescriptionAttribute dis && !string.IsNullOrEmpty(dis.Description)) |
| | | { |
| | | rv = dis.Description; |
| | | |
| | | } |
| | | else |
| | | { |
| | | rv = pi.Name; |
| | | } |
| | | return rv; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取属性的 Description 标注名,如果没有,则返回 属性名称 |
| | | /// </summary> |
| | | /// <param name="expression"></param> |
| | | /// <returns></returns> |
| | | public static string GetPropertyDescription(this Expression expression) |
| | | { |
| | | return expression.GetPropertyInfo().GetPropertyDisplayName(); |
| | | } |
| | | /// <summary> |
| | | /// 获取枚举显示名称 |
| | | /// </summary> |
| | | /// <param name="value">枚举值</param> |
| | | /// <returns>枚举显示名称</returns> |
| | | public static string? GetEnumDisplayName(this Enum value) |
| | | { |
| | | return GetEnumDisplayName(value.GetType(), value.ToString()); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取属性信息 |
| | | /// </summary> |
| | | /// <param name="expression">属性表达式</param> |
| | | /// <returns>属性信息</returns> |
| | | public static PropertyInfo? GetPropertyInfo(this Expression expression) |
| | | { |
| | | MemberExpression me = null; |
| | | LambdaExpression le = null; |
| | | if (expression is MemberExpression) |
| | | { |
| | | me = expression as MemberExpression; |
| | | } |
| | | if (expression is LambdaExpression) |
| | | { |
| | | le = expression as LambdaExpression; |
| | | if (le.Body is MemberExpression) |
| | | { |
| | | me = le.Body as MemberExpression; |
| | | } |
| | | if (le.Body is UnaryExpression) |
| | | { |
| | | me = (le.Body as UnaryExpression).Operand as MemberExpression; |
| | | } |
| | | } |
| | | PropertyInfo rv = null; |
| | | if (me != null) |
| | | { |
| | | rv = me.Member.DeclaringType.GetSingleProperty(me.Member.Name); |
| | | } |
| | | return rv; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取属性值 |
| | | /// </summary> |
| | | /// <param name="exp">属性表达式</param> |
| | | /// <param name="obj">属性所在实例</param> |
| | | /// <returns>属性值</returns> |
| | | public static object? GetPropertyValue(this object obj, LambdaExpression exp) |
| | | { |
| | | //获取表达式的值,并过滤单引号 |
| | | try |
| | | { |
| | | var expValue = exp.Compile().DynamicInvoke(obj); |
| | | object val = expValue; |
| | | return val; |
| | | } |
| | | catch |
| | | { |
| | | return ""; |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// 获取属性值 |
| | | /// </summary> |
| | | /// <param name="obj"></param> |
| | | /// <param name="property"></param> |
| | | /// <returns></returns> |
| | | public static object? GetPropertyValue(this object obj, string property) |
| | | { |
| | | //获取表达式的值,并过滤单引号 |
| | | try |
| | | { |
| | | return obj.GetType().GetSingleProperty(property).GetValue(obj); |
| | | } |
| | | catch |
| | | { |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | |
| | | public static List<string>? GetPropertySiblingValues(this object obj, string propertyName) |
| | | { |
| | | if (obj == null) |
| | | { |
| | | return new List<string>(); |
| | | } |
| | | Regex reg = new Regex("(.*?)\\[\\-?\\d?\\]\\.(.*?)$"); |
| | | var match = reg.Match(propertyName); |
| | | if (match.Success) |
| | | { |
| | | var name1 = match.Groups[1].Value; |
| | | var name2 = match.Groups[2].Value; |
| | | |
| | | var levels = name1.Split('.'); |
| | | var objtype = obj.GetType(); |
| | | var pe = Expression.Parameter(objtype); |
| | | var member = Expression.Property(pe, objtype.GetSingleProperty(levels[0])); |
| | | for (int i = 1; i < levels.Length; i++) |
| | | { |
| | | member = Expression.Property(member, member.Type.GetSingleProperty(levels[i])); |
| | | } |
| | | var pe2 = Expression.Parameter(member.Type.GetGenericArguments()[0]); |
| | | var cast = Expression.Call(typeof(Enumerable), "Cast", new Type[] { pe2.Type }, member); |
| | | |
| | | var name2exp = Expression.Property(pe2, pe2.Type.GetSingleProperty(name2)); |
| | | var selectexp = Expression.Call(name2exp, "ToString", Type.EmptyTypes); |
| | | |
| | | Expression select = Expression.Call( |
| | | typeof(Enumerable), |
| | | "Select", |
| | | new Type[] { pe2.Type, typeof(string) }, |
| | | cast, |
| | | Expression.Lambda(selectexp, pe2)); |
| | | |
| | | |
| | | var lambda = Expression.Lambda(select, pe); |
| | | var rv = new List<string>(); |
| | | try |
| | | { |
| | | rv = (lambda.Compile().DynamicInvoke(obj) as IEnumerable<string>)?.ToList(); |
| | | } |
| | | catch { } |
| | | return rv; |
| | | } |
| | | else |
| | | { |
| | | return new List<string>(); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 判断属性是否必填 |
| | | /// </summary> |
| | | /// <param name="pi">属性信息</param> |
| | | /// <returns>是否必填</returns> |
| | | public static bool IsPropertyRequired(this MemberInfo pi) |
| | | { |
| | | bool isRequired = false; |
| | | if (pi != null) |
| | | { |
| | | //如果需要显示星号,则判断是否是必填项,如果是必填则在内容后面加上星号 |
| | | //所有int,float。。。这种Primitive类型的,肯定都是必填 |
| | | Type t = pi.GetMemberType(); |
| | | if (t != null && (t.IsPrimitive() || t.IsEnum() || t == typeof(decimal) || t == typeof(Guid))) |
| | | { |
| | | isRequired = true; |
| | | } |
| | | else |
| | | { |
| | | //对于其他类,检查是否有RequiredAttribute,如果有就是必填 |
| | | if (pi.GetCustomAttributes(typeof(RequiredAttribute), false).FirstOrDefault() is RequiredAttribute required && required.AllowEmptyStrings == false) |
| | | { |
| | | isRequired = true; |
| | | } |
| | | else if (pi.GetCustomAttributes(typeof(KeyAttribute), false).FirstOrDefault() != null) |
| | | { |
| | | isRequired = true; |
| | | } |
| | | } |
| | | } |
| | | return isRequired; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 设置属性值 |
| | | /// </summary> |
| | | /// <param name="source">属性所在实例</param> |
| | | /// <param name="property">属性名</param> |
| | | /// <param name="value">要赋的值</param> |
| | | /// <param name="prefix">属性前缀</param> |
| | | /// <param name="stringBasedValue">是否为字符串格式的值</param> |
| | | public static void SetPropertyValue(this object source, string property, object value, string? prefix = null, bool stringBasedValue = false) |
| | | { |
| | | try |
| | | { |
| | | property = Regex.Replace(property, @"\[[^\]]*\]", string.Empty); |
| | | List<string> level = new List<string>(); |
| | | if (property.Contains('.')) |
| | | { |
| | | level.AddRange(property.Split('.')); |
| | | } |
| | | else |
| | | { |
| | | level.Add(property); |
| | | } |
| | | |
| | | if (!string.IsNullOrWhiteSpace(prefix)) |
| | | { |
| | | level.Insert(0, prefix); |
| | | } |
| | | object temp = source; |
| | | Type tempType = source.GetType(); |
| | | for (int i = 0; i < level.Count - 1; i++) |
| | | { |
| | | var member = tempType.GetMember(level[i])[0]; |
| | | if (member != null) |
| | | { |
| | | var va = member.GetMemberValue(temp); |
| | | if (va != null) |
| | | { |
| | | temp = va; |
| | | } |
| | | else |
| | | { |
| | | var newInstance = member.GetMemberType().GetConstructor(Type.EmptyTypes).Invoke(null); |
| | | member.SetMemberValue(temp, newInstance, null); |
| | | temp = newInstance; |
| | | } |
| | | tempType = member.GetMemberType(); |
| | | |
| | | } |
| | | } |
| | | |
| | | var memberInfos = tempType.GetMember(level.Last()); |
| | | if (!memberInfos.Any()) |
| | | { |
| | | return; |
| | | } |
| | | var fproperty = memberInfos[0]; |
| | | if (value == null || value is StringValues s && StringValues.IsNullOrEmpty(s)) |
| | | { |
| | | fproperty.SetMemberValue(temp, null, null); |
| | | return; |
| | | } |
| | | |
| | | bool isArray = false; |
| | | if (value != null && value.GetType().IsArray == true) |
| | | { |
| | | isArray = true; |
| | | } |
| | | |
| | | if (stringBasedValue == true) |
| | | { |
| | | Type propertyType = fproperty.GetMemberType(); |
| | | if (propertyType.IsGeneric(typeof(List<>)) == true) |
| | | { |
| | | var list = propertyType.GetConstructor(Type.EmptyTypes).Invoke(null) as IList; |
| | | |
| | | var gs = propertyType.GenericTypeArguments; |
| | | try |
| | | { |
| | | if (value.GetType() == typeof(StringValues)) |
| | | { |
| | | var strVals = (StringValues)value; |
| | | var a = strVals.ToArray(); |
| | | for (int i = 0; i < a.Length; i++) |
| | | { |
| | | list.Add(a[i].ConvertValue(gs[0])); |
| | | } |
| | | } |
| | | else if (isArray) |
| | | { |
| | | var a = value as object[]; |
| | | for (int i = 0; i < a.Length; i++) |
| | | { |
| | | list.Add(a[i].ConvertValue(gs[0])); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | list = value.ConvertValue(propertyType) as IList; |
| | | } |
| | | } |
| | | catch { } |
| | | fproperty.SetMemberValue(temp, list, null); |
| | | } |
| | | else if (propertyType.IsArray) |
| | | { |
| | | try |
| | | { |
| | | var strVals = (StringValues)value; |
| | | var eletype = propertyType.GetElementType(); |
| | | if (eletype != null) |
| | | { |
| | | var arr = Array.CreateInstance(eletype, strVals.Count); |
| | | for (int i = 0; i < arr.Length; i++) |
| | | { |
| | | arr.SetValue(strVals[i].ConvertValue(eletype), i); |
| | | } |
| | | fproperty.SetMemberValue(temp, arr, null); |
| | | } |
| | | } |
| | | catch { } |
| | | } |
| | | else |
| | | { |
| | | if (isArray) |
| | | { |
| | | var a = value as object[]; |
| | | if (a.Length == 1) |
| | | { |
| | | value = a[0]; |
| | | } |
| | | } |
| | | |
| | | if (value is string) |
| | | { |
| | | value = value.ToString().Replace("\\", "/"); |
| | | } |
| | | fproperty.SetMemberValue(temp, value, null); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | if (value is string) |
| | | { |
| | | value = value.ToString().Replace("\\", "/"); |
| | | } |
| | | fproperty.SetMemberValue(temp, value, null); |
| | | } |
| | | } |
| | | catch |
| | | { |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 根据MemberInfo获取值 |
| | | /// </summary> |
| | | /// <param name="mi">MemberInfo</param> |
| | | /// <param name="obj">所在实例</param> |
| | | /// <param name="index">如果是数组,指定数组下标。默认为null</param> |
| | | /// <returns>MemberInfo的值</returns> |
| | | public static object? GetMemberValue(this MemberInfo mi, object obj, object[]? index = null) |
| | | { |
| | | object rv = null; |
| | | if (mi.MemberType == MemberTypes.Property) |
| | | { |
| | | rv = ((PropertyInfo)mi).GetValue(obj, index); |
| | | } |
| | | else if (mi.MemberType == MemberTypes.Field) |
| | | { |
| | | rv = ((FieldInfo)mi).GetValue(obj); |
| | | } |
| | | return rv; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 设定MemberInfo的值 |
| | | /// </summary> |
| | | /// <param name="mi">MemberInfo</param> |
| | | /// <param name="obj">所在实例</param> |
| | | /// <param name="val">要赋的值</param> |
| | | /// <param name="index">如果是数组,指定数组下标。默认为null</param> |
| | | public static void SetMemberValue(this MemberInfo mi, object obj, object val, object[]? index = null) |
| | | { |
| | | object newval = val; |
| | | if (val is string s) |
| | | { |
| | | if (string.IsNullOrEmpty(s)) |
| | | { |
| | | val = null; |
| | | } |
| | | } |
| | | if (val != null && val.GetType() != mi.GetMemberType()) |
| | | { |
| | | newval = val.ConvertValue(mi.GetMemberType()); |
| | | } |
| | | if (mi.MemberType == MemberTypes.Property) |
| | | { |
| | | ((PropertyInfo)mi).SetValue(obj, newval, index); |
| | | } |
| | | else if (mi.MemberType == MemberTypes.Field) |
| | | { |
| | | ((FieldInfo)mi).SetValue(obj, newval); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取某个MemberInfo的类型 |
| | | /// </summary> |
| | | /// <param name="mi">MemberInfo</param> |
| | | /// <returns>类型</returns> |
| | | public static Type? GetMemberType(this MemberInfo mi) |
| | | { |
| | | Type? rv = null; |
| | | if (mi != null) |
| | | { |
| | | if (mi.MemberType == MemberTypes.Property) |
| | | { |
| | | rv = ((PropertyInfo)mi).PropertyType; |
| | | } |
| | | else if (mi.MemberType == MemberTypes.Field) |
| | | { |
| | | rv = ((FieldInfo)mi).FieldType; |
| | | } |
| | | } |
| | | return rv; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取枚举显示名称 |
| | | /// </summary> |
| | | /// <param name="enumType">枚举类型</param> |
| | | /// <param name="value">枚举值</param> |
| | | /// <returns>枚举显示名称</returns> |
| | | public static string? GetEnumDisplayName(Type enumType, string value) |
| | | { |
| | | string rv = ""; |
| | | FieldInfo field = null; |
| | | |
| | | if (enumType.IsEnum()) |
| | | { |
| | | field = enumType.GetField(value); |
| | | } |
| | | //如果是nullable的枚举 |
| | | if (enumType.IsGeneric(typeof(Nullable<>)) && enumType.GetGenericArguments()[0].IsEnum()) |
| | | { |
| | | field = enumType.GenericTypeArguments[0].GetField(value); |
| | | } |
| | | |
| | | if (field != null) |
| | | { |
| | | |
| | | var attribs = field.GetCustomAttributes(typeof(DisplayAttribute), true).ToList(); |
| | | if (attribs.Count > 0) |
| | | { |
| | | rv = ((DisplayAttribute)attribs[0]).GetName(); |
| | | //if (CoreProgram._localizer != null) |
| | | //{ |
| | | // rv = CoreProgram._localizer[rv]; |
| | | //} |
| | | } |
| | | else |
| | | { |
| | | rv = value; |
| | | } |
| | | } |
| | | return rv; |
| | | } |
| | | |
| | | public static string? GetEnumDisplayName(Type enumType, int value) |
| | | { |
| | | string? rv = ""; |
| | | FieldInfo? field = null; |
| | | string? ename = ""; |
| | | if (enumType.IsEnum()) |
| | | { |
| | | ename = enumType.GetEnumName(value); |
| | | field = enumType.GetField(ename ?? ""); |
| | | } |
| | | //如果是nullable的枚举 |
| | | if (enumType.IsGeneric(typeof(Nullable<>)) && enumType.GetGenericArguments()[0].IsEnum()) |
| | | { |
| | | ename = enumType.GenericTypeArguments[0].GetEnumName(value); |
| | | field = enumType.GenericTypeArguments[0].GetField(ename ?? ""); |
| | | } |
| | | |
| | | if (field != null) |
| | | { |
| | | |
| | | var attribs = field.GetCustomAttributes(typeof(DisplayAttribute), true).ToList(); |
| | | if (attribs.Count > 0) |
| | | { |
| | | rv = ((DisplayAttribute)attribs[0]).GetName(); |
| | | //if (CoreProgram._localizer != null) |
| | | //{ |
| | | // rv = CoreProgram._localizer[rv]; |
| | | //} |
| | | } |
| | | else |
| | | { |
| | | rv = ename; |
| | | } |
| | | } |
| | | return rv; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 转化值 |
| | | /// </summary> |
| | | /// <param name="value">要转换的值</param> |
| | | /// <param name="propertyType">转换后的类型</param> |
| | | /// <returns>转换后的值</returns> |
| | | public static object? ConvertValue(this object value, Type propertyType) |
| | | { |
| | | object val = null; |
| | | if (propertyType.IsGeneric(typeof(Nullable<>)) == true) |
| | | { |
| | | var gs = propertyType.GenericTypeArguments; |
| | | try |
| | | { |
| | | val = value.ConvertValue(gs[0]); |
| | | } |
| | | catch { } |
| | | } |
| | | else if (propertyType.IsEnum()) |
| | | { |
| | | val = Enum.Parse(propertyType, value.ToString()); |
| | | } |
| | | else if (propertyType == typeof(string)) |
| | | { |
| | | val = value?.ToString().Trim(); |
| | | } |
| | | else if (propertyType == typeof(Guid)) |
| | | { |
| | | bool suc = Guid.TryParse(value?.ToString(), out Guid g); |
| | | if (suc) |
| | | { |
| | | val = g; |
| | | } |
| | | else |
| | | { |
| | | val = Guid.Empty; |
| | | } |
| | | } |
| | | |
| | | else |
| | | { |
| | | try |
| | | { |
| | | if (value.ToString().StartsWith("`") && value.ToString().EndsWith("`")) |
| | | { |
| | | string inner = value.ToString().Trim('`').TrimEnd(','); |
| | | if (!string.IsNullOrWhiteSpace(inner)) |
| | | { |
| | | val = propertyType.GetConstructor(Type.EmptyTypes).Invoke(null); |
| | | string[] pair = inner.Split(','); |
| | | var gs = propertyType.GetGenericArguments(); |
| | | foreach (var p in pair) |
| | | { |
| | | (val as IList).Add(Convert.ChangeType(p, gs[0])); |
| | | } |
| | | } |
| | | } |
| | | else |
| | | { |
| | | val = Convert.ChangeType(value.ToString(), propertyType); |
| | | } |
| | | } |
| | | catch |
| | | { |
| | | } |
| | | } |
| | | return val; |
| | | } |
| | | |
| | | public static object MakeList(Type innerType, string propertyName, object[] values) |
| | | { |
| | | object rv = typeof(List<>).MakeGenericType(innerType).GetConstructor(Type.EmptyTypes).Invoke(null); |
| | | var mi = rv.GetType().GetMethod("Add"); |
| | | var con = innerType.GetConstructor(Type.EmptyTypes); |
| | | foreach (var item in values) |
| | | { |
| | | var newobj = con.Invoke(null); |
| | | newobj.SetPropertyValue(propertyName, item); |
| | | mi.Invoke(rv, new object[] { newobj }); |
| | | } |
| | | return rv; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取 是否定义该标签属性 |
| | | /// </summary> |
| | | /// <param name="pi"></param> |
| | | /// <param name="local"></param> |
| | | /// <returns></returns> |
| | | public static T? GetAttribute<T>(this MemberInfo pi) where T : Attribute |
| | | { |
| | | string rv = ""; |
| | | if (pi.GetCustomAttributes(typeof(T), false).FirstOrDefault() is T dis) |
| | | { |
| | | return dis; |
| | | } |
| | | else |
| | | { |
| | | return null; |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | public static ImmutableDictionary<string, List<PropertyInfo>> _propertyCache { get; set; } = |
| | | new Dictionary<string, List<PropertyInfo>>().ToImmutableDictionary(); |
| | | /// <summary> |
| | | /// 判断是否是泛型 |
| | | /// </summary> |
| | | /// <param name="self">Type类</param> |
| | | /// <param name="innerType">泛型类型</param> |
| | | /// <returns>判断结果</returns> |
| | | public static bool IsGeneric(this Type self, Type innerType) |
| | | { |
| | | if (self.GetTypeInfo().IsGenericType && self.GetGenericTypeDefinition() == innerType) |
| | | { |
| | | return true; |
| | | } |
| | | else |
| | | { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 判断是否为Nullable<>类型 |
| | | /// </summary> |
| | | /// <param name="self">Type类</param> |
| | | /// <returns>判断结果</returns> |
| | | public static bool IsNullable(this Type self) |
| | | { |
| | | return self.IsGeneric(typeof(Nullable<>)); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 判断是否为List<>类型 |
| | | /// </summary> |
| | | /// <param name="self">Type类</param> |
| | | /// <returns>判断结果</returns> |
| | | public static bool IsList(this Type self) |
| | | { |
| | | return self.IsGeneric(typeof(List<>)) || self.IsGeneric(typeof(IEnumerable<>)); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 判断是否为List<>类型 |
| | | /// </summary> |
| | | /// <param name="self">Type类</param> |
| | | /// <returns>判断结果</returns> |
| | | public static bool IsListOf<T>(this Type self) |
| | | { |
| | | if (self.IsGeneric(typeof(List<>)) && typeof(T).IsAssignableFrom(self.GenericTypeArguments[0])) |
| | | { |
| | | return true; |
| | | } |
| | | else |
| | | { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | |
| | | #region 判断是否为枚举 |
| | | |
| | | /// <summary> |
| | | /// 判断是否为枚举 |
| | | /// </summary> |
| | | /// <param name="self">Type类</param> |
| | | /// <returns>判断结果</returns> |
| | | public static bool IsEnum(this Type self) |
| | | { |
| | | return self.GetTypeInfo().IsEnum; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 判断是否为枚举或者可空枚举 |
| | | /// </summary> |
| | | /// <param name="self"></param> |
| | | /// <returns></returns> |
| | | public static bool IsEnumOrNullableEnum(this Type self) |
| | | { |
| | | if (self == null) |
| | | { |
| | | return false; |
| | | } |
| | | if (self.IsEnum) |
| | | { |
| | | return true; |
| | | } |
| | | else |
| | | { |
| | | if (self.IsGenericType && self.GetGenericTypeDefinition() == typeof(Nullable<>) && self.GetGenericArguments()[0].IsEnum) |
| | | { |
| | | return true; |
| | | } |
| | | else |
| | | { |
| | | return false; |
| | | } |
| | | } |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | /// <summary> |
| | | /// 判断是否为值类型 基础值类型 |
| | | /// </summary> |
| | | /// <param name="self">Type类</param> |
| | | /// <returns>判断结果</returns> |
| | | public static bool IsPrimitive(this Type self) |
| | | { |
| | | return self.GetTypeInfo().IsPrimitive || self == typeof(decimal); |
| | | } |
| | | /// <summary> |
| | | /// 判断值是否是数字基础类型 |
| | | /// </summary> |
| | | /// <param name="self"></param> |
| | | /// <returns></returns> |
| | | public static bool IsNumber(this Type self) |
| | | { |
| | | Type checktype = self; |
| | | if (self.IsNullable()) |
| | | { |
| | | checktype = self.GetGenericArguments()[0]; |
| | | } |
| | | if (checktype == typeof(int) || checktype == typeof(short) || checktype == typeof(long) || checktype == typeof(float) || checktype == typeof(decimal) || checktype == typeof(double)) |
| | | { |
| | | return true; |
| | | } |
| | | else |
| | | { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | |
| | | #region 判断是否是Bool |
| | | /// <summary> |
| | | /// 是否是bool类型 |
| | | /// </summary> |
| | | /// <param name="self"></param> |
| | | /// <returns></returns> |
| | | public static bool IsBool(this Type self) |
| | | { |
| | | return self == typeof(bool); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 判断是否是 bool or bool?类型 |
| | | /// </summary> |
| | | /// <param name="self"></param> |
| | | /// <returns></returns> |
| | | public static bool IsBoolOrNullableBool(this Type self) |
| | | { |
| | | if (self == null) |
| | | { |
| | | return false; |
| | | } |
| | | if (self == typeof(bool) || self == typeof(bool?)) |
| | | { |
| | | return true; |
| | | } |
| | | else |
| | | { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | /// <summary> |
| | | /// 根据名字获取 |
| | | /// </summary> |
| | | /// <param name="self"></param> |
| | | /// <param name="name"></param> |
| | | /// <returns></returns> |
| | | public static PropertyInfo? GetSingleProperty(this Type self, string name) |
| | | { |
| | | if (self.FullName == null) |
| | | throw new Exception("属性名为空"); |
| | | if (_propertyCache.ContainsKey(self.FullName) == false) |
| | | { |
| | | var properties = self.GetProperties().ToList(); |
| | | _propertyCache = _propertyCache.Add(self.FullName, properties); |
| | | return properties.Where(x => x.Name == name).FirstOrDefault(); |
| | | } |
| | | else |
| | | { |
| | | return _propertyCache[self.FullName].Where(x => x.Name == name).FirstOrDefault(); |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// 获取属性列表 并将 列表属性放入缓存 |
| | | /// </summary> |
| | | /// <param name="self"></param> |
| | | /// <returns></returns> |
| | | public static PropertyInfo? GetSingleProperty(this Type self, Func<PropertyInfo, bool> where) |
| | | { |
| | | if (self.FullName == null) |
| | | throw new Exception("属性名为空"); |
| | | if (_propertyCache.ContainsKey(self.FullName) == false) |
| | | { |
| | | var properties = self.GetProperties().ToList(); |
| | | _propertyCache = _propertyCache.Add(self.FullName, properties); |
| | | return properties.Where(where).FirstOrDefault(); |
| | | } |
| | | else |
| | | { |
| | | return _propertyCache[self.FullName].Where(where).FirstOrDefault(); |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// 获取属性列表 并将 列表属性放入缓存 |
| | | /// </summary> |
| | | /// <param name="self"></param> |
| | | /// <returns></returns> |
| | | public static List<PropertyInfo> GetAllProperties(this Type self) |
| | | { |
| | | if (self.FullName == null) |
| | | throw new Exception("属性名为空"); |
| | | if (_propertyCache.ContainsKey(self.FullName) == false) |
| | | { |
| | | var properties = self.GetProperties().ToList(); |
| | | _propertyCache = _propertyCache.Add(self.FullName, properties); |
| | | return properties; |
| | | } |
| | | else |
| | | { |
| | | return _propertyCache[self.FullName]; |
| | | } |
| | | } |
| | | #endregion |
| | | } |
| | | } |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | |
| | | namespace cylsg.utility |
| | | { |
| | | /// <summary> |
| | | /// 常用字符串定义 |
| | | /// </summary> |
| | | public static class StaticStringDef |
| | | { |
| | | /// <summary> |
| | | /// 提现自锁KeY |
| | | /// </summary> |
| | | public static string TransferMoneyLockKey = "TransferMoneyLockKey:"; |
| | | |
| | | /// <summary> |
| | | /// 提现统计累计锁 |
| | | /// </summary> |
| | | public static string TransferMoneyManKey = "TransferMoneyManKey:"; |
| | | } |
| | | } |
New file |
| | |
| | | <Project Sdk="Microsoft.NET.Sdk"> |
| | | |
| | | <PropertyGroup> |
| | | <TargetFramework>net8.0</TargetFramework> |
| | | <ImplicitUsings>enable</ImplicitUsings> |
| | | <Nullable>enable</Nullable> |
| | | </PropertyGroup> |
| | | |
| | | <ItemGroup> |
| | | <PackageReference Include="Microsoft.Extensions.Primitives" Version="8.0.0" /> |
| | | <PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> |
| | | </ItemGroup> |
| | | |
| | | </Project> |
New file |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | |
| | | namespace cylsg.utility |
| | | { |
| | | /// <summary> |
| | | /// 通用模型 |
| | | /// </summary> |
| | | public class untilityModels |
| | | { |
| | | |
| | | } |
| | | } |
New file |
| | |
| | | import {useBaseApi} from '/@/api/base'; |
| | | |
| | | // 企业类配置表接口服务 |
| | | export const useFBS_EnterpriseTypeApi = () => { |
| | | const baseApi = useBaseApi("fBS_EnterpriseType"); |
| | | return { |
| | | // 分页查询企业类配置表 |
| | | page: baseApi.page, |
| | | // 查看企业类配置表详细 |
| | | detail: baseApi.detail, |
| | | // 新增企业类配置表 |
| | | add: baseApi.add, |
| | | // 更新企业类配置表 |
| | | update: baseApi.update, |
| | | // 删除企业类配置表 |
| | | delete: baseApi.delete, |
| | | // 批量删除企业类配置表 |
| | | batchDelete: baseApi.batchDelete, |
| | | // 导出企业类配置表数据 |
| | | exportData: baseApi.exportData, |
| | | // 导入企业类配置表数据 |
| | | importData: baseApi.importData, |
| | | // 下载企业类配置表数据导入模板 |
| | | downloadTemplate: baseApi.downloadTemplate, |
| | | } |
| | | } |
| | | |
| | | // 企业类配置表实体 |
| | | export interface FBS_EnterpriseType { |
| | | // 主键Id |
| | | id: number; |
| | | // 名称 |
| | | name?: string; |
| | | // 代码 |
| | | code?: string; |
| | | // 父 |
| | | parentId?: number; |
| | | // 租户Id |
| | | tenantId: number; |
| | | // 创建时间 |
| | | createTime: string; |
| | | // 更新时间 |
| | | updateTime: string; |
| | | // 创建者Id |
| | | createUserId: number; |
| | | // 创建者姓名 |
| | | createUserName: string; |
| | | // 修改者Id |
| | | updateUserId: number; |
| | | // 修改者姓名 |
| | | updateUserName: string; |
| | | } |
New file |
| | |
| | | <script lang="ts" name="fBS_EnterpriseType" setup> |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import { ElMessage } from "element-plus"; |
| | | import type { FormRules } from "element-plus"; |
| | | import { formatDate } from '/@/utils/formatTime'; |
| | | import { useFBS_EnterpriseTypeApi } from '/@/api/Customer/fBS_EnterpriseType'; |
| | | |
| | | //父级传递来的函数,用于回调 |
| | | const emit = defineEmits(["reloadTable"]); |
| | | const fBS_EnterpriseTypeApi = useFBS_EnterpriseTypeApi(); |
| | | const ruleFormRef = ref(); |
| | | |
| | | const state = reactive({ |
| | | title: '', |
| | | loading: false, |
| | | showDialog: false, |
| | | ruleForm: {} as any, |
| | | stores: {}, |
| | | dropdownData: {} as any, |
| | | }); |
| | | |
| | | // 自行添加其他规则 |
| | | const rules = ref<FormRules>({ |
| | | name: [{required: true, message: '请选择名称!', trigger: 'blur',},], |
| | | code: [{required: true, message: '请选择代码!', trigger: 'blur',},], |
| | | parentId: [{required: true, message: '请选择父!', trigger: 'blur',},], |
| | | }); |
| | | |
| | | // 页面加载时 |
| | | onMounted(async () => { |
| | | }); |
| | | |
| | | // 打开弹窗 |
| | | const openDialog = async (row: any, title: string) => { |
| | | state.title = title; |
| | | row = row ?? { }; |
| | | state.ruleForm = row.id ? await fBS_EnterpriseTypeApi.detail(row.id).then(res => res.data.result) : JSON.parse(JSON.stringify(row)); |
| | | state.showDialog = true; |
| | | }; |
| | | |
| | | // 关闭弹窗 |
| | | const closeDialog = () => { |
| | | emit("reloadTable"); |
| | | state.showDialog = false; |
| | | }; |
| | | |
| | | // 提交 |
| | | const submit = async () => { |
| | | ruleFormRef.value.validate(async (isValid: boolean, fields?: any) => { |
| | | if (isValid) { |
| | | let values = state.ruleForm; |
| | | await fBS_EnterpriseTypeApi[state.ruleForm.id ? 'update' : 'add'](values); |
| | | closeDialog(); |
| | | } else { |
| | | ElMessage({ |
| | | message: `表单有${Object.keys(fields).length}处验证失败,请修改后再提交`, |
| | | type: "error", |
| | | }); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | //将属性或者函数暴露给父组件 |
| | | defineExpose({ openDialog }); |
| | | </script> |
| | | <template> |
| | | <div class="fBS_EnterpriseType-container"> |
| | | <el-dialog v-model="state.showDialog" :width="800" draggable :close-on-click-modal="false"> |
| | | <template #header> |
| | | <div style="color: #fff"> |
| | | <span>{{ state.title }}</span> |
| | | </div> |
| | | </template> |
| | | <el-form :model="state.ruleForm" ref="ruleFormRef" label-width="auto" :rules="rules"> |
| | | <el-row :gutter="35"> |
| | | <el-form-item v-show="false"> |
| | | <el-input v-model="state.ruleForm.id" /> |
| | | </el-form-item> |
| | | <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20" > |
| | | <el-form-item label="名称" prop="name"> |
| | | <el-input v-model="state.ruleForm.name" placeholder="请输入名称" maxlength="256" show-word-limit clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20" > |
| | | <el-form-item label="代码" prop="code"> |
| | | <el-input v-model="state.ruleForm.code" placeholder="请输入代码" maxlength="36" show-word-limit clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20" > |
| | | <el-form-item label="父" prop="parentId"> |
| | | <el-input-number v-model="state.ruleForm.parentId" placeholder="请输入父" clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="() => state.showDialog = false">取 消</el-button> |
| | | <el-button @click="submit" type="primary" v-reclick="1000">确 定</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | <style lang="scss" scoped> |
| | | :deep(.el-select), :deep(.el-input-number) { |
| | | width: 100%; |
| | | } |
| | | </style> |
New file |
| | |
| | | <script lang="ts" setup name="fBS_EnterpriseType"> |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import { auth } from '/@/utils/authFunction'; |
| | | import { ElMessageBox, ElMessage } from "element-plus"; |
| | | import { downloadStreamFile } from "/@/utils/download"; |
| | | import { useFBS_EnterpriseTypeApi } from '/@/api/Customer/fBS_EnterpriseType'; |
| | | import editDialog from '/@/views/Customer/fBS_EnterpriseType/component/editDialog.vue' |
| | | import printDialog from '/@/views/system/print/component/hiprint/preview.vue' |
| | | import ModifyRecord from '/@/components/table/modifyRecord.vue'; |
| | | import ImportData from "/@/components/table/importData.vue"; |
| | | |
| | | const fBS_EnterpriseTypeApi = useFBS_EnterpriseTypeApi(); |
| | | const printDialogRef = ref(); |
| | | const editDialogRef = ref(); |
| | | const importDataRef = ref(); |
| | | const state = reactive({ |
| | | exportLoading: false, |
| | | tableLoading: false, |
| | | stores: {}, |
| | | showAdvanceQueryUI: false, |
| | | dropdownData: {} as any, |
| | | selectData: [] as any[], |
| | | tableQueryParams: {} as any, |
| | | tableParams: { |
| | | page: 1, |
| | | pageSize: 20, |
| | | total: 0, |
| | | field: 'createTime', // 默认的排序字段 |
| | | order: 'descending', // 排序方向 |
| | | descStr: 'descending', // 降序排序的关键字符 |
| | | }, |
| | | tableData: [], |
| | | }); |
| | | |
| | | // 页面加载时 |
| | | onMounted(async () => { |
| | | }); |
| | | |
| | | // 查询操作 |
| | | const handleQuery = async (params: any = {}) => { |
| | | state.tableLoading = true; |
| | | state.tableParams = Object.assign(state.tableParams, params); |
| | | const result = await fBS_EnterpriseTypeApi.page(Object.assign(state.tableQueryParams, state.tableParams)).then(res => res.data.result); |
| | | state.tableParams.total = result?.total; |
| | | state.tableData = result?.items ?? []; |
| | | state.tableLoading = false; |
| | | }; |
| | | |
| | | // 列排序 |
| | | const sortChange = async (column: any) => { |
| | | state.tableParams.field = column.prop; |
| | | state.tableParams.order = column.order; |
| | | await handleQuery(); |
| | | }; |
| | | |
| | | // 删除 |
| | | const delFBS_EnterpriseType = (row: any) => { |
| | | ElMessageBox.confirm(`确定要删除吗?`, "提示", { |
| | | confirmButtonText: "确定", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }).then(async () => { |
| | | await fBS_EnterpriseTypeApi.delete({ id: row.id }); |
| | | handleQuery(); |
| | | ElMessage.success("删除成功"); |
| | | }).catch(() => {}); |
| | | }; |
| | | |
| | | // 批量删除 |
| | | const batchDelFBS_EnterpriseType = () => { |
| | | ElMessageBox.confirm(`确定要删除${state.selectData.length}条记录吗?`, "提示", { |
| | | confirmButtonText: "确定", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }).then(async () => { |
| | | await fBS_EnterpriseTypeApi.batchDelete(state.selectData.map(u => ({ id: u.id }) )).then(res => { |
| | | ElMessage.success(`成功批量删除${res.data.result}条记录`); |
| | | handleQuery(); |
| | | }); |
| | | }).catch(() => {}); |
| | | }; |
| | | |
| | | // 导出数据 |
| | | const exportFBS_EnterpriseTypeCommand = async (command: string) => { |
| | | try { |
| | | state.exportLoading = true; |
| | | if (command === 'select') { |
| | | const params = Object.assign({}, state.tableQueryParams, state.tableParams, { selectKeyList: state.selectData.map(u => u.id) }); |
| | | await fBS_EnterpriseTypeApi.exportData(params).then(res => downloadStreamFile(res)); |
| | | } else if (command === 'current') { |
| | | const params = Object.assign({}, state.tableQueryParams, state.tableParams); |
| | | await fBS_EnterpriseTypeApi.exportData(params).then(res => downloadStreamFile(res)); |
| | | } else if (command === 'all') { |
| | | const params = Object.assign({}, state.tableQueryParams, state.tableParams, { page: 1, pageSize: 99999999 }); |
| | | await fBS_EnterpriseTypeApi.exportData(params).then(res => downloadStreamFile(res)); |
| | | } |
| | | } finally { |
| | | state.exportLoading = false; |
| | | } |
| | | } |
| | | |
| | | handleQuery(); |
| | | </script> |
| | | <template> |
| | | <div class="fBS_EnterpriseType-container" v-loading="state.exportLoading"> |
| | | <el-card shadow="hover" :body-style="{ paddingBottom: '0' }"> |
| | | <el-form :model="state.tableQueryParams" ref="queryForm" labelWidth="90"> |
| | | <el-row> |
| | | <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="4" class="mb10"> |
| | | <el-form-item label="关键字"> |
| | | <el-input v-model="state.tableQueryParams.keyword" clearable placeholder="请输入模糊查询关键字"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="4" class="mb10" v-if="state.showAdvanceQueryUI"> |
| | | <el-form-item label="名称"> |
| | | <el-input v-model="state.tableQueryParams.name" clearable placeholder="请输入名称"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="4" class="mb10" v-if="state.showAdvanceQueryUI"> |
| | | <el-form-item label="代码"> |
| | | <el-input v-model="state.tableQueryParams.code" clearable placeholder="请输入代码"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="4" class="mb10" v-if="state.showAdvanceQueryUI"> |
| | | <el-form-item label="父"> |
| | | <el-input-number v-model="state.tableQueryParams.parentId" clearable placeholder="请输入父"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="4" class="mb10"> |
| | | <el-form-item > |
| | | <el-button-group style="display: flex; align-items: center;"> |
| | | <el-button type="primary" icon="ele-Search" @click="handleQuery" v-auth="'fBS_EnterpriseType:page'" v-reclick="1000"> 查询 </el-button> |
| | | <el-button icon="ele-Refresh" @click="() => state.tableQueryParams = {}"> 重置 </el-button> |
| | | <el-button icon="ele-ZoomIn" @click="() => state.showAdvanceQueryUI = true" v-if="!state.showAdvanceQueryUI" style="margin-left:5px;"> 高级查询 </el-button> |
| | | <el-button icon="ele-ZoomOut" @click="() => state.showAdvanceQueryUI = false" v-if="state.showAdvanceQueryUI" style="margin-left:5px;"> 隐藏 </el-button> |
| | | <el-button type="danger" style="margin-left:5px;" icon="ele-Delete" @click="batchDelFBS_EnterpriseType" :disabled="state.selectData.length == 0" v-auth="'fBS_EnterpriseType:batchDelete'"> 删除 </el-button> |
| | | <el-button type="primary" style="margin-left:5px;" icon="ele-Plus" @click="editDialogRef.openDialog(null, '新增企业类配置表')" v-auth="'fBS_EnterpriseType:add'"> 新增 </el-button> |
| | | <el-dropdown :show-timeout="70" :hide-timeout="50" @command="exportFBS_EnterpriseTypeCommand"> |
| | | <el-button type="primary" style="margin-left:5px;" icon="ele-FolderOpened" v-reclick="20000" v-auth="'fBS_EnterpriseType:export'"> 导出 </el-button> |
| | | <template #dropdown> |
| | | <el-dropdown-menu> |
| | | <el-dropdown-item command="select" :disabled="state.selectData.length == 0">导出选中</el-dropdown-item> |
| | | <el-dropdown-item command="current">导出本页</el-dropdown-item> |
| | | <el-dropdown-item command="all">导出全部</el-dropdown-item> |
| | | </el-dropdown-menu> |
| | | </template> |
| | | </el-dropdown> |
| | | <el-button type="warning" style="margin-left:5px;" icon="ele-MostlyCloudy" @click="importDataRef.openDialog()" v-auth="'fBS_EnterpriseType:import'"> 导入 </el-button> |
| | | </el-button-group> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | </el-card> |
| | | <el-card class="full-table" shadow="hover" style="margin-top: 5px"> |
| | | <el-table :data="state.tableData" @selection-change="(val: any[]) => { state.selectData = val; }" style="width: 100%" v-loading="state.tableLoading" tooltip-effect="light" row-key="id" @sort-change="sortChange" border> |
| | | <el-table-column type="selection" width="40" align="center" v-if="auth('fBS_EnterpriseType:batchDelete') || auth('fBS_EnterpriseType:export')" /> |
| | | <el-table-column type="index" label="序号" width="55" align="center"/> |
| | | <el-table-column prop='name' label='名称' show-overflow-tooltip /> |
| | | <el-table-column prop='code' label='代码' show-overflow-tooltip /> |
| | | <el-table-column prop='parentId' label='父' show-overflow-tooltip /> |
| | | <el-table-column label="修改记录" width="100" align="center" show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | <ModifyRecord :data="scope.row" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" width="140" align="center" fixed="right" show-overflow-tooltip v-if="auth('fBS_EnterpriseType:update') || auth('fBS_EnterpriseType:delete')"> |
| | | <template #default="scope"> |
| | | <el-button icon="ele-Edit" size="small" text type="primary" @click="editDialogRef.openDialog(scope.row, '编辑企业类配置表')" v-auth="'fBS_EnterpriseType:update'"> 编辑 </el-button> |
| | | <el-button icon="ele-Delete" size="small" text type="primary" @click="delFBS_EnterpriseType(scope.row)" v-auth="'fBS_EnterpriseType:delete'"> 删除 </el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <el-pagination |
| | | v-model:currentPage="state.tableParams.page" |
| | | v-model:page-size="state.tableParams.pageSize" |
| | | @size-change="(val: any) => handleQuery({ pageSize: val })" |
| | | @current-change="(val: any) => handleQuery({ page: val })" |
| | | layout="total, sizes, prev, pager, next, jumper" |
| | | :page-sizes="[10, 20, 50, 100, 200, 500]" |
| | | :total="state.tableParams.total" |
| | | size="small" |
| | | background /> |
| | | <ImportData ref="importDataRef" :import="fBS_EnterpriseTypeApi.importData" :download="fBS_EnterpriseTypeApi.downloadTemplate" v-auth="'fBS_EnterpriseType:import'" @refresh="handleQuery"/> |
| | | <printDialog ref="printDialogRef" :title="'打印企业类配置表'" @reloadTable="handleQuery" /> |
| | | <editDialog ref="editDialogRef" @reloadTable="handleQuery" /> |
| | | </el-card> |
| | | </div> |
| | | </template> |
| | | <style scoped> |
| | | :deep(.el-input), :deep(.el-select), :deep(.el-input-number) { |
| | | width: 100%; |
| | | } |
| | | </style> |