refactor 优化代码

This commit is contained in:
2024-11-26 15:26:12 +08:00
parent a32910f0d9
commit 623a5c4e49
88 changed files with 1820 additions and 941 deletions

View File

@@ -0,0 +1,13 @@
using Kurisu.RemoteCall.Abstractions;
using Microsoft.Extensions.DependencyInjection;
namespace Dlhis.Jip.Api.ClientHandlers;
public class JipClientHandler : IHttpRemoteCallPolicyHandler
{
/// <inheritdoc />
public IHttpClientBuilder ConfigureHttpClient(IHttpClientBuilder builder)
{
return builder;
}
}

View File

@@ -0,0 +1,47 @@
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Kurisu.RemoteCall.Abstractions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
namespace Dlhis.Jip.Api.ClientHandlers;
public class JipTokenHandler : IAsyncAuthTokenHandler
{
/// <inheritdoc />
public async Task<string> GetTokenAsync(IServiceProvider serviceProvider)
{
var configuration = serviceProvider.GetService<IConfiguration>()!;
var jwtKey = configuration.GetSection("JinkoOptions:Jip:Key").Value;
var jwtSecret = configuration.GetSection("JinkoOptions:Jip:Secret").Value;
const int min = 5;
var now = DateTime.Now.AddMinutes(-min);
var expires = DateTime.Now.AddMinutes(min);
var claims = new List<Claim>
{
new(JwtRegisteredClaimNames.Nbf, $"{new DateTimeOffset(now).ToUnixTimeSeconds()}"),
new(JwtRegisteredClaimNames.Exp, $"{new DateTimeOffset(expires).ToUnixTimeSeconds()}"),
new(JwtRegisteredClaimNames.Iss, jwtKey),
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSecret));
var descriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims),
Issuer = jwtKey,
IssuedAt = now,
NotBefore = now,
Expires = expires,
SigningCredentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256)
};
var jwtHandler = new JwtSecurityTokenHandler();
var securityToken = jwtHandler.CreateToken(descriptor);
return await Task.FromResult(jwtHandler.WriteToken(securityToken));
}
}

View File

@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Kurisu.RemoteCall" Version="0.4.5" />
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="6.10.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.10.0" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,15 @@
using Newtonsoft.Json;
namespace Dlhis.Jip.Api.Dto;
/// <summary>
/// sap机构信息
/// </summary>
public class SapOrganization
{
/// <summary>
/// 机构项
/// </summary>
[JsonProperty("item")]
public List<SapOrganizationItem> Items { get; set; }
}

View File

@@ -0,0 +1,66 @@
namespace Dlhis.Jip.Api.Dto;
public class SapOrganizationItem
{
/// <summary>
/// 开始日期
/// </summary>
public string BEGDA { get; set; }
/// <summary>
/// 结束日期
/// </summary>
public string ENDDA { get; set; }
/// <summary>
/// 语言
/// </summary>
public string LANGU { get; set; }
/// <summary>
/// 部门id
/// </summary>
public string OBJID { get; set; }
/// <summary>
/// 部门名称
/// </summary>
public string STEXT { get; set; }
/// <summary>
/// 上级部门
/// </summary>
public string SOBID { get; set; }
/// <summary>
/// 公司
/// </summary>
public string ORGID01 { get; set; }
/// <summary>
/// 事业部
/// </summary>
public string ORGID02 { get; set; }
}
//public partial class SapOrganizationItem : IEquatable<SapOrganizationItem>
//{
// public bool Equals(SapOrganizationItem other)
// {
// if (other is null)
// return false;
// return this.BEGDA == other.BEGDA
// && this.ENDDA == other.ENDDA
// && this.LANGU == other.LANGU
// && this.OBJID == other.OBJID
// && this.STEXT == other.STEXT
// && this.SOBID == other.SOBID
// && this.ORGID01 == other.ORGID01
// && this.ORGID02 == other.ORGID02;
// }
// public override bool Equals(object obj) => Equals(obj as SapOrganizationItem);
// public override int GetHashCode() => (BEGDA, ENDDA, LANGU, OBJID, STEXT, SOBID, ORGID01, ORGID02).GetHashCode();
//}

View File

@@ -0,0 +1,9 @@
using Newtonsoft.Json;
namespace Dlhis.Jip.Api.Dto;
public class SapPerson<T>
{
[JsonProperty("item")]
public List<T> Items { get; set; }
}

View File

@@ -0,0 +1,19 @@
// namespace Dlhis.ScheduledTask.Common.Dto
// {
// public class SapPersonDepartmentStatus
// {
// public string ZWORKCODE { get; set; }
//
// public DateTime BEGDA { get; set; }
//
// public DateTime ENDDA { get; set; }
//
// public string WERKS { get; set; }
//
// /// <summary>
// /// 部门号
// /// </summary>
// public string ORGEH { get; set; }
//
// }
// }

View File

@@ -0,0 +1,211 @@
namespace Dlhis.Jip.Api.Dto;
public class SapPersonItem
{
public string KOSTL { get; set; }
/// <summary>
/// 离职日期
/// </summary>
public DateTime? ZLZRQ { get; set; }
public string ZZ_SFZH { get; set; }
public string STELL { get; set; }
public string STELL_NM { get; set; }
public string ZZ_KLX { get; set; }
/// <summary>
///
/// </summary>
public string PERNR { get; set; }
/// <summary>
///
/// </summary>
public string ZWORKCODE { get; set; }
/// <summary>
///
/// </summary>
public string MASSN { get; set; }
/// <summary>
/// 数据变更
/// </summary>
public string MNTXT { get; set; }
/// <summary>
///
/// </summary>
public string MASSG { get; set; }
/// <summary>
/// 数据变更
/// </summary>
public string MGTXT { get; set; }
/// <summary>
///
/// </summary>
public string ZSTATUS { get; set; }
/// <summary>
///
/// </summary>
public string STAT2 { get; set; }
/// <summary>
///
/// </summary>
public string BEGDA { get; set; }
/// <summary>
///
/// </summary>
public string ENDDA { get; set; }
/// <summary>
///
/// </summary>
public string WERKS { get; set; }
/// <summary>
///
/// </summary>
public string PERSG { get; set; }
/// <summary>
///
/// </summary>
public string PERSK { get; set; }
/// <summary>
///
/// </summary>
public string BTRTL { get; set; }
/// <summary>
///
/// </summary>
public string ANSVH { get; set; }
/// <summary>
///
/// </summary>
public string MOABW { get; set; }
/// <summary>
///
/// </summary>
public string ORGEH { get; set; }
/// <summary>
///
/// </summary>
public string PLANS { get; set; }
/// <summary>
///
/// </summary>
public string ZZ_ZYSF { get; set; }
/// <summary>
///
/// </summary>
public string ZZ_AQJB { get; set; }
/// <summary>
///
/// </summary>
public string ZZ_ZD { get; set; }
/// <summary>
///
/// </summary>
public string ZZ_SJGH { get; set; }
/// <summary>
///
/// </summary>
public string ZZ_BGZT { get; set; }
/// <summary>
///
/// </summary>
public string Z_ZJ { get; set; }
/// <summary>
///
/// </summary>
public string ZZ_XSQY { get; set; }
/// <summary>
/// 上海
/// </summary>
public string ZZ_LOC { get; set; }
/// <summary>
///
/// </summary>
public string ZZ_COUN { get; set; }
/// <summary>
///
/// </summary>
public string ZZ_CITY { get; set; }
/// <summary>
///
/// </summary>
public string NACHN { get; set; }
/// <summary>
///
/// </summary>
public string VORNA { get; set; }
/// <summary>
///
/// </summary>
public string NAME { get; set; }
/// <summary>
///
/// </summary>
public string GESCH { get; set; }
/// <summary>
///
/// </summary>
public DateTime GBDAT { get; set; }
/// <summary>
///
/// </summary>
public string NATIO { get; set; }
/// <summary>
///
/// </summary>
public string ZZ_QFRQ { get; set; }
/// <summary>
///
/// </summary>
public string ZMOBILE { get; set; }
/// <summary>
///
/// </summary>
public string ZEMAIL { get; set; }
/// <summary>
///
/// </summary>
public string ZADZH { get; set; }
/// <summary>
///
/// </summary>
public DateTime ZRZRQ { get; set; }
/// <summary>
///
/// </summary>
public string DAT01 { get; set; }
/// <summary>
///
/// </summary>
public string ZCJRQ { get; set; }
/// <summary>
///
/// </summary>
public string ZZZRQ { get; set; }
/// <summary>
/// 本科
/// </summary>
public string ZXUELI { get; set; }
/// <summary>
///
/// </summary>
public string ZZ_ZPQD { get; set; }
/// <summary>
/// 国家
/// </summary>
public string ZZ_COUNNM { get; set; }
/// <summary>
/// 基地
/// </summary>
public string ZZ_GZDJDNM { get; set; }
/// <summary>
/// 厂区
/// </summary>
public string ZZ_GZDCQNM { get; set; }
}

View File

@@ -0,0 +1,16 @@
// namespace Dlhis.ScheduledTask.Common.Dto
// {
// public class SapPersonJobStatus
// {
// public string ZWORKCODE { get; set; }
//
// public DateTime BEGDA { get; set; }
//
// public DateTime ENDDA { get; set; }
//
// /// <summary>
// /// 0离职
// /// </summary>
// public string STAT2 { get; set; }
// }
// }

View File

@@ -0,0 +1,10 @@
using Newtonsoft.Json;
namespace Dlhis.Jip.Api.Dto;
public class SapPosition
{
[JsonProperty("item")]
public List<SapPositionItem> Items { get; set; }
}

View File

@@ -0,0 +1,40 @@
namespace Dlhis.Jip.Api.Dto
{
public class SapPositionItem
{
/// <summary>
/// 开始日期
/// </summary>
public string BEGDA { get; set; }
/// <summary>
/// 结束日期
/// </summary>
public string ENDDA { get; set; }
/// <summary>
/// 语言代码
/// </summary>
public string LANGU { get; set; }
/// <summary>
/// 岗位编码
/// </summary>
public string ZJOBID { get; set; }
/// <summary>
/// 岗位名称
/// </summary>
public string ZJOBNAME { get; set; }
/// <summary>
///
/// </summary>
public string ZZWID { get; set; }
/// <summary>
/// 所属部门ID
/// </summary>
public string ZDEPID { get; set; }
}
}

View File

@@ -0,0 +1,86 @@
using Dlhis.Jip.Api.ClientHandlers;
using Dlhis.Jip.Api.Request;
using Dlhis.Jip.Api.RequestContentHandlers;
using Dlhis.Jip.Api.Requests;
using Dlhis.Jip.Api.Responses;
using Dlhis.Jip.Api.ResultHandlers;
using Kurisu.RemoteCall.Attributes;
namespace Dlhis.Jip.Api;
/// <summary>
/// jinko-jip api https://jip.jinkosolar.com
/// </summary>
[Auth(TokenHandler = typeof(JipTokenHandler))]
[EnableRemoteClient(Name = "jip-service", BaseUrl = "${JinkoOptions:Jip:BaseUrl}", PolicyHandler = typeof(JipClientHandler))]
public interface IJinkoJipApi
{
/// <summary>
/// 上传考勤记录
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[Post("/JIP/HCM/HCM_SWIPE_DATA_SAVE")]
Task<UploadAttendanceResponse> UploadAttendancesAsync(UploadAttendanceRequest request);
/// <summary>
/// 获取出差信息
/// </summary>
/// <param name="factory">厂区</param>
/// <param name="start">开始时间</param>
/// <param name="end">结束时间</param>
/// <code>
/// var obj = new
/// {
/// I_PAGE = 1,
/// I_LINE = 500,
/// IV_BEGDA = beginDay,
/// IV_ENDDA = endDay,
/// IT_CCMDD = new List{object}
/// {
/// new
/// {
/// IV_CCMDD = factory
/// }
/// }
/// }
/// </code>
/// <code>
///var obj = new
///{
/// IV_BEGDA = beginDay,
/// IV_ENDDA = endDay,
/// IT_2002GH = new List{object}
/// {
/// new
/// {
/// IV_GONGH = userCode
/// }
/// }
///};
/// </code>
/// <returns></returns>
[Post("/JIP/HCM/HCM_TRAVELINFO")]
[RequestContentHandler(typeof(BusinessTripContentHandler))]
Task<SapBusinessTripInfoResponse> GetBusinessTripInfosByFactoryAsync(string factory, DateTime start, DateTime end);
/// <summary>
/// 同步餐补状态
/// </summary>
/// <param name="requests"></param>
/// <returns></returns>
[Post("/JIP/DHR/DHR_DL_CALLBACK")]
[RequestResultHandler(typeof(DHRResultHandler))]
Task<string> SyncMealSupplementRecordsAsync(List<SyncMealSupplementRecordRequest> requests);
/// <summary>
/// 同步照片到sap
/// </summary>
/// <param name="userCode"></param>
/// <param name="base64"></param>
/// <returns></returns>
[Post("/JIP/HCM/HCM_I_PHOTO")]
[RequestContentHandler(typeof(SyncFaceContentHandler))]
Task<SapFaceSyncResponse> SyncFaceToSapAsync(string userCode, string base64);
}

View File

@@ -0,0 +1,36 @@
using System.Text;
using Kurisu.RemoteCall;
using Kurisu.RemoteCall.Abstractions;
using Newtonsoft.Json;
namespace Dlhis.Jip.Api.RequestContentHandlers;
public class BusinessTripContentHandler : IContentHandler
{
/// <inheritdoc />
public HttpContent Create(List<ParameterValue> values)
{
var factory = values.First(x => x.Parameter.Name.Equals("factory", StringComparison.OrdinalIgnoreCase)).GetValue<string>();
var start = values.First(x => x.Parameter.Name.Equals("start", StringComparison.OrdinalIgnoreCase)).GetValue<DateTime>().ToString("yyyy-MM-dd");
var end = values.First(x => x.Parameter.Name.Equals("end", StringComparison.OrdinalIgnoreCase)).GetValue<DateTime>().ToString("yyyy-MM-dd");
var obj = new
{
I_PAGE = 1,
I_LINE = 500,
IV_BEGDA = start,
IV_ENDDA = end,
IT_CCMDD = new List<object>
{
new
{
IV_CCMDD = factory
}
}
};
var json = JsonConvert.SerializeObject(obj);
return new StringContent(json, Encoding.UTF8, "application/json");
}
}

View File

@@ -0,0 +1,26 @@
using System.Text;
using Kurisu.RemoteCall;
using Kurisu.RemoteCall.Abstractions;
using Newtonsoft.Json;
namespace Dlhis.Jip.Api.RequestContentHandlers;
public class SyncFaceContentHandler : IContentHandler
{
/// <inheritdoc />
public HttpContent Create(List<ParameterValue> values)
{
var userCode = values.First(x => x.Parameter.Name.Equals("userCode", StringComparison.OrdinalIgnoreCase)).GetValue<string>();
var base64 = values.First(x => x.Parameter.Name.Equals("base64", StringComparison.OrdinalIgnoreCase)).GetValue<string>();
var obj = new
{
I_WORKCODE = userCode,
I_PHOTO_STR = base64
};
var json = JsonConvert.SerializeObject(obj);
return new StringContent(json, Encoding.UTF8, "application/json");
}
}

View File

@@ -0,0 +1,12 @@
namespace Dlhis.Jip.Api.Requests
{
public class GetBusinessTripInfosByFactoryRequest
{
public DateTime Start { get; set; }
public DateTime End { get; set; }
public int PageIndex { get; set; }
public int PageSize { get; set; }
}
}

View File

@@ -0,0 +1,12 @@
using System.ComponentModel.DataAnnotations;
namespace Dlhis.Jip.Api.Request;
public class SapNoRequest
{
/// <summary>
/// Code
/// </summary>
[Required(ErrorMessage = "编号不能为空")]
public string Code { get; set; }
}

View File

@@ -0,0 +1,17 @@
namespace Dlhis.Jip.Api.Request;
public class SyncMealSupplementRecordRequest
{
/// <summary>
/// 唯一id
/// </summary>
public string UniqueId { get; set; }
/// <summary>
/// FAIL SUCCESS
/// </summary>
public string Status { get; set; }
public string Msg { get; set; }
}

View File

@@ -0,0 +1,41 @@
using Newtonsoft.Json;
namespace Dlhis.Jip.Api.Requests;
public class UploadAttendanceRequest
{
/// <summary>
/// 考勤数据包
/// </summary>
[JsonProperty("T_DATA")]
public List<UploadAttendanceRequestItem> Data { get; set; }
}
public class UploadAttendanceRequestItem
{
[JsonIgnore]
public long Id { get; set; }
/// <summary>
/// item.CardNo.TrimEnd('\0')
/// </summary>
public string ZWORKCODE { get; set; }
[JsonIgnore]
public DateTime RaiseDateTime { get; set; }
/// <summary>
/// yyyy-MM-dd
/// </summary>
public string ZDATE => RaiseDateTime.ToString("yyyy-MM-dd");
/// <summary>
/// HH:mm:ss
/// </summary>
public string ZTIME => RaiseDateTime.ToString("HH:mm:ss");
/// <summary>
/// 设备位置
/// </summary>
public string ZNOTE { get; set; }
}

View File

@@ -0,0 +1,11 @@
namespace Dlhis.Jip.Api.Responses;
public class DHRResponse<T>
{
/// <summary>
/// 200:success
/// </summary>
public int Code { get; set; }
public string Message { get; set; }
public T Data { get; set; }
}

View File

@@ -0,0 +1,87 @@
using Newtonsoft.Json;
namespace Dlhis.Jip.Api.Responses;
public class SapBusinessTripInfoResponse
{
/// <summary>
/// 明细数据
/// </summary>
[JsonProperty("OT_2002")]
public List<SapBusinessTripInfoItem> Items { get; set; }
}
public class SapBusinessTripInfoItem
{
/// <summary>
/// 工号
/// </summary>
[JsonProperty("OV_GONGH")]
public string Code { get; set; }
/// <summary>
/// 姓名
/// </summary>
[JsonProperty("OV_ENAME")]
public string Name { get; set; }
/// <summary>
/// 开始日期
/// </summary>
[JsonProperty("OV_BEGDA")]
public DateTime BeginDate { get; set; }
/// <summary>
/// 结束日期
/// </summary>
[JsonProperty("OV_ENDDA")]
public DateTime EndDate { get; set; }
/// <summary>
/// 开始时间
/// </summary>
[JsonProperty("OV_BEGUZ")]
public TimeOnly? BeginDateTime { get; set; }
/// <summary>
/// 结束时间
/// </summary>
[JsonProperty("OV_ENDUZ")]
public TimeOnly? EndDateTime { get; set; }
/// <summary>
/// 出差类型
/// </summary>
[JsonProperty("OV_AWART")]
public string Type { get; set; }
/// <summary>
/// 出差类型描述
/// </summary>
[JsonProperty("OV_ATEXT")]
public string TypeDesc { get; set; }
/// <summary>
/// 出差时数
/// </summary>
[JsonProperty("OV_STDAZ")]
public double Hour { get; set; }
/// <summary>
/// 出差天数
/// </summary>
[JsonProperty("OV_ABWTG")]
public double Day { get; set; }
/// <summary>
/// 出差目的地
/// </summary>
[JsonProperty("OV_CCMDD")]
public string Destination { get; set; }
/// <summary>
/// 出差目的地描述
/// </summary>
[JsonProperty("OV_CCMDDMS")]
public string DestinationDesc { get; set; }
}

View File

@@ -0,0 +1,11 @@
namespace Dlhis.Jip.Api.Responses;
public class SapFaceSyncResponse
{
/// <summary>
/// S 成功
/// </summary>
public string OLX { get; set; }
public string OMS { get; set; }
}

View File

@@ -0,0 +1,10 @@
using Dlhis.Jip.Api.Dto;
using Newtonsoft.Json;
namespace Dlhis.Jip.Api.Responses;
public class SapOrganizationResponse
{
[JsonProperty("T_ORG")]
public SapOrganization Org { get; set; }
}

View File

@@ -0,0 +1,26 @@
using Dlhis.Jip.Api.Dto;
using Newtonsoft.Json;
namespace Dlhis.Jip.Api.Responses;
public class SapPersonResponse
{
/// <summary>
///
/// </summary>
[JsonProperty("T_PERSON")]
public SapPerson<SapPersonItem> Person { get; set; }
// /// <summary>
// /// 离职状态
// /// </summary>
// [JsonProperty("T_0000")]
// public SapPerson<SapPersonJobStatus> JobStatusInfo { get; set; }
//
// /// <summary>
// /// 部门变更信息
// /// </summary>
// [JsonProperty("T_0001")]
// public SapPerson<SapPersonDepartmentStatus> DepartmentInfo { get; set; }
}

View File

@@ -0,0 +1,10 @@
using Dlhis.Jip.Api.Dto;
using Newtonsoft.Json;
namespace Dlhis.Jip.Api.Responses;
public class SapPositionResponse
{
[JsonProperty("T_POST")]
public SapPosition Position { get; set; }
}

View File

@@ -0,0 +1,11 @@
namespace Dlhis.Jip.Api.Responses;
public class UploadAttendanceResponse
{
/// <summary>
/// 0 成功
/// </summary>
public string OLX { get; set; }
public string OMS { get; set; }
}

View File

@@ -0,0 +1,22 @@
using System.Net;
using Dlhis.Jip.Api.Responses;
using Kurisu.RemoteCall.Abstractions;
using Mapster;
using Newtonsoft.Json;
namespace Dlhis.Jip.Api.ResultHandlers;
public class DHRResultHandler : IRemoteCallResultHandler
{
/// <inheritdoc />
public TResult Handle<TResult>(HttpStatusCode statusCode, string responseBody)
{
var apiResult = JsonConvert.DeserializeObject<DHRResponse<object>>(responseBody);
if (statusCode != HttpStatusCode.OK || apiResult.Code != 200)
{
throw new Exception(apiResult?.Message);
}
return responseBody.Adapt<TResult>();
}
}